@webqit/oohtml 3.2.0 → 4.0.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/README.md +161 -68
- 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 +16 -16
- 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 +23 -23
- package/dist/main.js.map +3 -3
- package/dist/main.lite.js +24 -30
- 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 +4 -4
- package/src/data-binding/index.js +3 -3
- package/src/namespaced-html/index.js +204 -141
- package/src/scoped-css/index.js +43 -32
- package/src/scoped-js/index.js +12 -11
- package/src/util.js +11 -0
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Building Single Page Applications? OOHTML is a special love letter! Writing Web
|
|
|
19
19
|
|
|
20
20
|
## Polyfill
|
|
21
21
|
|
|
22
|
-
OOHTML is being developed as something to be used today. This implementation adheres closely to the spec and
|
|
22
|
+
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
23
|
|
|
24
24
|
<details><summary>Load from a CDN<br>
|
|
25
25
|
└───────── <a href="https://bundlephobia.com/result?p=@webqit/oohtml"><img align="right" src="https://img.shields.io/badge/21.8%20kB-black"></a></summary>
|
|
@@ -114,12 +114,12 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
114
114
|
|
|
115
115
|
...still gives the `window` object in the console.
|
|
116
116
|
|
|
117
|
-
+ **Syntax**. The syntax for attribute names and API names across features - e.g. the `def` and `ref` attributes, the `
|
|
117
|
+
+ **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
118
|
|
|
119
119
|
```html
|
|
120
120
|
<head>
|
|
121
121
|
<!-- Configurations come before the polyfil -->
|
|
122
|
-
<meta name="data-binding" content="attr.
|
|
122
|
+
<meta name="data-binding" content="attr.render=render;">
|
|
123
123
|
<meta name="namespaced-html" content="attr.id=id;">
|
|
124
124
|
<meta name="html-imports" content="attr.def=def; attr.ref=ref;">
|
|
125
125
|
<script src="https://unpkg.com/@webqit/oohtml/dist/main.js"></script>
|
|
@@ -143,16 +143,16 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
143
143
|
+ `document.bindings` now becomes: `document.wqBindings`,
|
|
144
144
|
+ etc.
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
<details><summary>Show the full syntax table</summary>
|
|
147
147
|
|
|
148
|
-
Spec:
|
|
148
|
+
**Spec: `<meta name="data-binding">`**
|
|
149
149
|
|
|
150
150
|
| Config | Default Syntax | Description |
|
|
151
151
|
| :----- | :------------- | :---------- |
|
|
152
|
-
| `attr.
|
|
152
|
+
| `attr.render` | `render` | The "render" attribute for inline data binding. ([Docs](#inline-data-binding)) |
|
|
153
153
|
| `attr.itemIndex` | `data-index` | The "item index" attribute for assigning indexes to list items. ([Docs](#inline-data-binding)) |
|
|
154
154
|
|
|
155
|
-
Spec:
|
|
155
|
+
**Spec: `<meta name="bindings-api">`**
|
|
156
156
|
|
|
157
157
|
| Config | Default Syntax | Description |
|
|
158
158
|
| :----- | :------------- | :---------- |
|
|
@@ -160,14 +160,14 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
160
160
|
| `api.bind` | `bind` | The `document.bind()` and `Element.prototype.bind()` methods. ([Docs](#the-bindings-api)) |
|
|
161
161
|
| `api.bindings` | `bindings` | The `document.bindings` and `Element.prototype.bindings` object properties. ([Docs](#the-bindings-api)) |
|
|
162
162
|
|
|
163
|
-
Spec:
|
|
163
|
+
**Spec: `<meta name="context-api">`**
|
|
164
164
|
|
|
165
165
|
| Config | Default Syntax | Description |
|
|
166
166
|
| :----- | :------------- | :---------- |
|
|
167
167
|
| `attr.contextname` | `contextname` | The "context name" attribute on arbitrary elements. ([Docs](#the-context-api)) |
|
|
168
168
|
| `api.contexts` | `contexts` | The `document.contexts` and `Element.prototype.contexts` object properties. ([Docs](#the-context-api)) |
|
|
169
169
|
|
|
170
|
-
Spec:
|
|
170
|
+
**Spec: `<meta name="html-imports">`**
|
|
171
171
|
|
|
172
172
|
| Config | Default Syntax | Description |
|
|
173
173
|
| :----- | :------------- | :---------- |
|
|
@@ -182,7 +182,8 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
182
182
|
| `api.defs` | `defs` | The readonly object property for accessing a `<template>`'s list of definitions. ([Docs](#module-definition)) |
|
|
183
183
|
| `api.import` | `import` | The `document.import()` and `Element.prototype.import()` methods. ([Docs](#imperative-module-imports)) |
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
|
|
186
|
+
**Spec: `<meta name="namespaced-html">`**
|
|
186
187
|
|
|
187
188
|
| Config | Default Syntax | Description |
|
|
188
189
|
| :----- | :------------- | :---------- |
|
|
@@ -190,9 +191,11 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
190
191
|
| `attr.id` | `id` | The "id" attribute on arbitrary elements. ([Docs](#namespacing)) |
|
|
191
192
|
| `api.namespace` | `namespace` | The "namespace" object property on arbitrary elements. ([Docs](#namespacing)) |
|
|
192
193
|
|
|
193
|
-
Spec:
|
|
194
|
+
**Spec: `<meta name="scoped-css">`** (TODO)
|
|
195
|
+
|
|
196
|
+
**Spec: `<meta name="scoped-js">`** (TODO)
|
|
194
197
|
|
|
195
|
-
|
|
198
|
+
</details>
|
|
196
199
|
|
|
197
200
|
</details>
|
|
198
201
|
|
|
@@ -202,7 +205,7 @@ If you'll be going ahead to build a real app with OOHTML, you may want to consid
|
|
|
202
205
|
|
|
203
206
|
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
207
|
|
|
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!
|
|
208
|
+
"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
209
|
|
|
207
210
|
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
211
|
|
|
@@ -219,7 +222,7 @@ OOHTML is effectively different from Web Components (and from the related Declar
|
|
|
219
222
|
|
|
220
223
|
## Modular HTML
|
|
221
224
|
|
|
222
|
-
|
|
225
|
+
The modern UI is best approached with a modular architecture (think UI component frameworks) wherein we are able to author the bits and pieces as self-contained objects - enabling us *encapsulate* structure, styling and logic!
|
|
223
226
|
|
|
224
227
|
OOHTML makes this possible by introducing "namespacing" and style and script scoping!
|
|
225
228
|
|
|
@@ -227,7 +230,23 @@ OOHTML makes this possible by introducing "namespacing" and style and script sco
|
|
|
227
230
|
|
|
228
231
|
Naming things is hard! That's especially so where you have one global namespace and a miriad of potentially conflicting identifiers to coordinate!
|
|
229
232
|
|
|
230
|
-
|
|
233
|
+
<details><summary>Learn more</summary>
|
|
234
|
+
|
|
235
|
+
You want to see how IDs are, in fact, by default, exposed as global variables:
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<div id="foo"><div>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```js
|
|
242
|
+
console.log(window.foo); // div
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
[Read more](https://stackoverflow.com/questions/6381425/is-there-a-spec-that-the-id-of-elements-should-be-made-global-variable)
|
|
246
|
+
|
|
247
|
+
</details>
|
|
248
|
+
|
|
249
|
+
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
250
|
|
|
232
251
|
```html
|
|
233
252
|
<form>
|
|
@@ -240,7 +259,7 @@ Here, we get a modular naming convention using the `namespace` attribute. This a
|
|
|
240
259
|
|
|
241
260
|
<label for="~city">City</label>
|
|
242
261
|
<input id="city">
|
|
243
|
-
|
|
262
|
+
<fieldset>
|
|
244
263
|
|
|
245
264
|
<fieldset namespace>
|
|
246
265
|
<legend>Delivery Address</legend>
|
|
@@ -250,14 +269,21 @@ Here, we get a modular naming convention using the `namespace` attribute. This a
|
|
|
250
269
|
|
|
251
270
|
<label for="~city">City</label>
|
|
252
271
|
<input id="city">
|
|
253
|
-
|
|
272
|
+
<fieldset>
|
|
254
273
|
|
|
255
274
|
</form>
|
|
256
275
|
```
|
|
257
276
|
|
|
258
|
-
This lets us have repeating structures with identical but non-conflicting identifiers
|
|
277
|
+
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.
|
|
259
278
|
|
|
260
|
-
|
|
279
|
+
Local `IDREFS` are resolved within the namespace where they're used (not globally; not deeply):
|
|
280
|
+
|
|
281
|
+
```js
|
|
282
|
+
// Matches "#city" within the fieldset's namespace; not super namespace, not sub namespace
|
|
283
|
+
const city = fieldset.querySelector('#~city');
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
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
287
|
|
|
262
288
|
```html
|
|
263
289
|
<div id="user" namespace>
|
|
@@ -268,6 +294,29 @@ And this also translates well to an object model:
|
|
|
268
294
|
</div>
|
|
269
295
|
```
|
|
270
296
|
|
|
297
|
+
```js
|
|
298
|
+
// Namespace aware ID selectors
|
|
299
|
+
console.log(document.querySelector('#user')); // div#user
|
|
300
|
+
console.log(document.querySelector('#~user')); // div#user
|
|
301
|
+
|
|
302
|
+
console.log(document.getElementById('user')); // div#user
|
|
303
|
+
console.log(document.getElementById('~user')); // div#user
|
|
304
|
+
|
|
305
|
+
console.log(document.querySelector('#url')); // a#url
|
|
306
|
+
console.log(document.querySelector('#~url')); // null... not directly in the "document" namespace
|
|
307
|
+
|
|
308
|
+
console.log(document.getElementById('url')); // a#url
|
|
309
|
+
console.log(document.getElementById('~url')); // null... not directly in the "document" namespace
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
And these also play well as navigation targets, with additional support for path expressions given a hierarchy of namespaces:
|
|
313
|
+
|
|
314
|
+
```html
|
|
315
|
+
<a href="#~user/email">Jump to Email</a>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
And JavaScript applications are able to consume namespace structures as an object model:
|
|
319
|
+
|
|
271
320
|
```html
|
|
272
321
|
user
|
|
273
322
|
├── url
|
|
@@ -275,8 +324,6 @@ user
|
|
|
275
324
|
└── email
|
|
276
325
|
```
|
|
277
326
|
|
|
278
|
-
with a complementary API that exposes said structure to JavaScript applications:
|
|
279
|
-
|
|
280
327
|
```js
|
|
281
328
|
// The document.namespace API
|
|
282
329
|
let { user } = document.namespace;
|
|
@@ -313,27 +360,55 @@ function changeCallback(changes) {
|
|
|
313
360
|
}
|
|
314
361
|
```
|
|
315
362
|
|
|
316
|
-
</details>
|
|
363
|
+
</details>
|
|
317
364
|
|
|
318
|
-
<details><summary>
|
|
365
|
+
<details><summary>Implementation details</summary>
|
|
319
366
|
|
|
320
|
-
|
|
367
|
+
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
368
|
|
|
322
369
|
```html
|
|
323
|
-
|
|
370
|
+
<!-- Original -->
|
|
371
|
+
<label for="~real-id">Question 1:</label>
|
|
372
|
+
<input id="real-id">
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```html
|
|
376
|
+
<!-- Transformed -->
|
|
377
|
+
<label for="~hg3j:real-id">Question 1:</label>
|
|
378
|
+
<input id="~hg3j:real-id">
|
|
324
379
|
```
|
|
325
380
|
|
|
381
|
+
the values your application sees are the unprefixed IDs and IDREFs:
|
|
382
|
+
|
|
326
383
|
```js
|
|
327
|
-
console.log(
|
|
384
|
+
console.log(label.htmlFor); // ~real-id
|
|
385
|
+
console.log(input.id); // real-id
|
|
386
|
+
|
|
387
|
+
console.log(label.getAttribute('for')); // ~real-id
|
|
388
|
+
console.log(input.attributes[0].value); // real-id
|
|
328
389
|
```
|
|
329
390
|
|
|
330
|
-
|
|
391
|
+
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:
|
|
392
|
+
|
|
393
|
+
```css
|
|
394
|
+
.\:target {
|
|
395
|
+
background-color: whitesmoke;
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
or, to be more complete:
|
|
400
|
+
|
|
401
|
+
```css
|
|
402
|
+
:target, .\:target {
|
|
403
|
+
background-color: whitesmoke;
|
|
404
|
+
}
|
|
405
|
+
```
|
|
331
406
|
|
|
332
407
|
</details>
|
|
333
408
|
|
|
334
409
|
### Style and Script Scoping
|
|
335
410
|
|
|
336
|
-
We often need a way to keep component-specific
|
|
411
|
+
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
412
|
|
|
338
413
|
Here, we get a new `scoped` attribute that lets us do just that:
|
|
339
414
|
|
|
@@ -351,7 +426,22 @@ Here, we get a new `scoped` attribute that lets us do just that:
|
|
|
351
426
|
</div>
|
|
352
427
|
```
|
|
353
428
|
|
|
354
|
-
|
|
429
|
+
And the special namespace-aware ID selector is supported from within scoped style sheets:
|
|
430
|
+
|
|
431
|
+
```html
|
|
432
|
+
<div namespace>
|
|
433
|
+
<a id="url" href="https://example.org">
|
|
434
|
+
<span id="name">Joe Bloggs</span>
|
|
435
|
+
</a>
|
|
436
|
+
<a id="email" href="mailto:joebloggs@example.com" >joebloggs@example.com</a>
|
|
437
|
+
|
|
438
|
+
<style scoped>
|
|
439
|
+
#\~name { color: red }
|
|
440
|
+
</style>
|
|
441
|
+
</div>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
And everything comes with a complementary low-level API that exposes said assets to tools:
|
|
355
445
|
|
|
356
446
|
```js
|
|
357
447
|
let { styleSheets, scripts } = user; // APIs that are analogous to the document.styleSheets, document.scripts properties
|
|
@@ -362,15 +452,15 @@ let { styleSheets, scripts } = user; // APIs that are analogous to the document.
|
|
|
362
452
|
Here, the `scoped` attribute has two effects on the `<script>` element:
|
|
363
453
|
|
|
364
454
|
+ The `this` keyword is implicitly bound to the script's host element
|
|
365
|
-
+ The `<script>` element is executed
|
|
455
|
+
+ The `<script>` element is (re)executed on each re-insertion into the DOM
|
|
366
456
|
|
|
367
457
|
</details>
|
|
368
458
|
|
|
369
459
|
## HTML Imports
|
|
370
460
|
|
|
371
|
-
HTML Imports is a realtime *import* system for HTML that's drawn entirely on HTML - and
|
|
461
|
+
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
462
|
|
|
373
|
-
Here, we get a way to both define and
|
|
463
|
+
Here, we get a way to both define and reuse a snippet out of *same* document:
|
|
374
464
|
|
|
375
465
|
```html
|
|
376
466
|
<head>
|
|
@@ -387,7 +477,7 @@ Here, we get a way to both define and use a snippet within *same* document:
|
|
|
387
477
|
</body>
|
|
388
478
|
```
|
|
389
479
|
|
|
390
|
-
...
|
|
480
|
+
...while optionally supporting remote content without a change in paradigm:
|
|
391
481
|
|
|
392
482
|
```html
|
|
393
483
|
<head>
|
|
@@ -443,7 +533,7 @@ Here, we get the `def` attribute for defining those - both at the `<template>` e
|
|
|
443
533
|
|
|
444
534
|
We shouldn't need a different mechanism to work with remote content.
|
|
445
535
|
|
|
446
|
-
Here, OOHTML
|
|
536
|
+
Here, OOHTML extends the `<template>` with an `src` attribute that lets us have self-loading `<template>` elements:
|
|
447
537
|
|
|
448
538
|
```html
|
|
449
539
|
<template def="foo" src="/foo.html"></template>
|
|
@@ -597,7 +687,7 @@ setTimeout(() => {
|
|
|
597
687
|
}, 1000);
|
|
598
688
|
```
|
|
599
689
|
|
|
600
|
-
|
|
690
|
+
<!--<details><summary>Extended Imports concepts</summary>-->
|
|
601
691
|
|
|
602
692
|
### Lazy-Loading Modules
|
|
603
693
|
|
|
@@ -829,19 +919,19 @@ const contextElement = document.querySelector('div');
|
|
|
829
919
|
const result = contextElement.import('foo#fragment2'); // the local module: foo#fragment2, and if not found, the inherited module: /bar/nested#fragment2
|
|
830
920
|
```
|
|
831
921
|
|
|
832
|
-
|
|
922
|
+
<!--</details>-->
|
|
833
923
|
|
|
834
924
|
## Data Binding
|
|
835
925
|
|
|
836
|
-
Data binding is
|
|
926
|
+
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
927
|
|
|
838
|
-
OOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `<?{ }?>` and a complementary new `
|
|
928
|
+
OOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `<?{ }?>` and a complementary new `render` attribute!
|
|
839
929
|
|
|
840
|
-
And for when we need to write
|
|
930
|
+
And for when we need to write extensive reactive logic on the UI, a perfect answer: Quantum Scripts!
|
|
841
931
|
|
|
842
932
|
### Discrete Data-Binding
|
|
843
933
|
|
|
844
|
-
Here, we get a comment-based data-binding
|
|
934
|
+
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
935
|
|
|
846
936
|
```js
|
|
847
937
|
<html>
|
|
@@ -906,10 +996,12 @@ Now, on getting to the client, that extra bit of information gets decoded, and o
|
|
|
906
996
|
|
|
907
997
|
### Inline Data-Binding
|
|
908
998
|
|
|
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 "
|
|
999
|
+
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:
|
|
1000
|
+
|
|
1001
|
+
> Note that in OOHTML <= v3 the `render` attribute was `expr`.
|
|
910
1002
|
|
|
911
1003
|
```html
|
|
912
|
-
<div
|
|
1004
|
+
<div render="<directive> <param>: <arg>;"></div>
|
|
913
1005
|
```
|
|
914
1006
|
|
|
915
1007
|
**-->** *where*:
|
|
@@ -921,36 +1013,36 @@ For attribute-based data binding, OOHTML deviates from the usual (and problemati
|
|
|
921
1013
|
**-->** *which would give us the following for a CSS property*:
|
|
922
1014
|
|
|
923
1015
|
```html
|
|
924
|
-
<div
|
|
1016
|
+
<div render="& color:someColor; & backgroundColor:'red'"></div>
|
|
925
1017
|
```
|
|
926
1018
|
|
|
927
1019
|
**-->** *without being space-sensitive*:
|
|
928
1020
|
|
|
929
1021
|
```html
|
|
930
|
-
<div
|
|
1022
|
+
<div render="& color:someColor; &backgroundColor: 'red'"></div>
|
|
931
1023
|
```
|
|
932
1024
|
|
|
933
1025
|
**-->** *the rest of which can be seen below*:
|
|
934
1026
|
|
|
935
1027
|
| Directive | Type | Usage |
|
|
936
1028
|
| :---- | :---- | :---- |
|
|
937
|
-
| `&` | CSS Property | `<div
|
|
938
|
-
| `%` | Class Name | `<div
|
|
939
|
-
| `~` | Attribute Name | `<a
|
|
940
|
-
| | Boolean Attribute | `<a
|
|
1029
|
+
| `&` | CSS Property | `<div render="& color:someColor; & backgroundColor:someBgColor;"></div>` |
|
|
1030
|
+
| `%` | Class Name | `<div render="% active:app.isActive; % expanded:app.isExpanded;"></div>` |
|
|
1031
|
+
| `~` | Attribute Name | `<a render="~ href:person.profileUrl+'#bio'; ~ title:'Click me';"></a>` |
|
|
1032
|
+
| | Boolean Attribute | `<a render="~ ?required:formField.required; ~ ?aria-checked: formField.checked"></a>` |
|
|
941
1033
|
| `@` | Structural Directive: | *See below* |
|
|
942
|
-
| `@text` | Plain text content | `<span
|
|
943
|
-
| `@html` | Markup content | `<span
|
|
1034
|
+
| `@text` | Plain text content | `<span render="@text:firstName+' '+lastName;"></span>` |
|
|
1035
|
+
| `@html` | Markup content | `<span render="@html: '<i>'+firstName+'</i>';"></span>` |
|
|
944
1036
|
| `@items` | A list, of the following format | `<declaration> <of\|in> <iterable> / <importRef>`<br>*See next two tables* |
|
|
945
1037
|
|
|
946
1038
|
<details><summary><code>For ... Of</code> Loops</summary>
|
|
947
1039
|
|
|
948
1040
|
| Idea | Usage |
|
|
949
1041
|
| :---- | :---- |
|
|
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
|
|
1042
|
+
| A `for...of` loop over an array/iterable | `<ul render="@items: value of [1,2,3] / 'foo#fragment';"></ul>` |
|
|
1043
|
+
| Same as above but with a `key` declaration | `<ul render="@items: (value,key) of [1,2,3] / 'foo#fragment';"></ul>` |
|
|
1044
|
+
| Same as above but with different variable names | `<ul render="@items: (product,id) of store.products / 'foo#fragment';"></ul>` |
|
|
1045
|
+
| Same as above but with a dynamic `importRef` | `<ul render="@items: (product,id) of store.products / store.importRef;"></ul>` |
|
|
954
1046
|
|
|
955
1047
|
</details>
|
|
956
1048
|
|
|
@@ -958,8 +1050,8 @@ For attribute-based data binding, OOHTML deviates from the usual (and problemati
|
|
|
958
1050
|
|
|
959
1051
|
| Idea | Usage |
|
|
960
1052
|
| :---- | :---- |
|
|
961
|
-
| A `for...in` loop over an object | `<ul
|
|
962
|
-
| Same as above but with a `value` and `index` declaration | `<ul
|
|
1053
|
+
| A `for...in` loop over an object | `<ul render="@items: key in {a:1,b:2} / 'foo#fragment';"></ul>` |
|
|
1054
|
+
| 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
1055
|
|
|
964
1056
|
</details>
|
|
965
1057
|
|
|
@@ -1111,10 +1203,11 @@ Now, in each case above, reactivity terminates on script's removal from the DOM
|
|
|
1111
1203
|
```js
|
|
1112
1204
|
const script = document.querySelector('script[quantum]');
|
|
1113
1205
|
// const script = document.querySelector('main').scripts[0];
|
|
1114
|
-
script.
|
|
1206
|
+
script.state.dispose();
|
|
1207
|
+
// which also happens on doing script.remove()
|
|
1115
1208
|
```
|
|
1116
1209
|
|
|
1117
|
-
But
|
|
1210
|
+
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
1211
|
|
|
1119
1212
|
</details>
|
|
1120
1213
|
|
|
@@ -1170,7 +1263,7 @@ node.bindings.style = 'tall-dark';
|
|
|
1170
1263
|
node.bindings.normalize = true;
|
|
1171
1264
|
```
|
|
1172
1265
|
|
|
1173
|
-
**-->** *with a complementary `bind()` method that lets us make mutations in batch*:
|
|
1266
|
+
**-->** *with a complementary `bind()` method that lets us make multiple mutations in one batch*:
|
|
1174
1267
|
|
|
1175
1268
|
```js
|
|
1176
1269
|
// ------------
|
|
@@ -1223,7 +1316,7 @@ const node = document.querySelector('my-element');
|
|
|
1223
1316
|
node.bindings.style = 'tall-dark';
|
|
1224
1317
|
```
|
|
1225
1318
|
|
|
1226
|
-
<details><summary>
|
|
1319
|
+
<details><summary>Implementation details</summary>
|
|
1227
1320
|
|
|
1228
1321
|
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
1322
|
|
|
@@ -1243,9 +1336,9 @@ Observer.deleteProperty(document.bindings.app, 'title');
|
|
|
1243
1336
|
|
|
1244
1337
|
### The Context API
|
|
1245
1338
|
|
|
1246
|
-
Component trees on the typical UI often call for more than the normal top-down flow of data that the Bindings API facilitates.
|
|
1339
|
+
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
1340
|
|
|
1248
|
-
Interestingly, the Context API is the underlying resolution
|
|
1341
|
+
Interestingly, the Context API is the underlying "resolution" infrastructure for the Namespace API and the Data Binding and HTML Imports features in OOHTML!
|
|
1249
1342
|
|
|
1250
1343
|
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
1344
|
|
|
@@ -1574,8 +1667,8 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1574
1667
|
<div id="ss_elem_list"
|
|
1575
1668
|
tabindex="0"
|
|
1576
1669
|
role="listbox"
|
|
1577
|
-
aria-labelledby="ss_elem">
|
|
1578
|
-
<ul role="group" aria-labelledby="cat"
|
|
1670
|
+
aria-labelledby="~ss_elem">
|
|
1671
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1579
1672
|
<li role="presentation" id="cat">
|
|
1580
1673
|
Land
|
|
1581
1674
|
</li>
|
|
@@ -1595,7 +1688,7 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1595
1688
|
Raccoon
|
|
1596
1689
|
</li>
|
|
1597
1690
|
</ul>
|
|
1598
|
-
<ul role="group" aria-labelledby="cat"
|
|
1691
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1599
1692
|
<li role="presentation" id="cat">
|
|
1600
1693
|
Water
|
|
1601
1694
|
</li>
|
|
@@ -1609,7 +1702,7 @@ The following is a Listbox component lifted directly from the [ARIA Authoring Pr
|
|
|
1609
1702
|
Eel
|
|
1610
1703
|
</li>
|
|
1611
1704
|
</ul>
|
|
1612
|
-
<ul role="group" aria-labelledby="cat"
|
|
1705
|
+
<ul role="group" namespace aria-labelledby="~cat">
|
|
1613
1706
|
<li role="presentation" id="cat">
|
|
1614
1707
|
Air
|
|
1615
1708
|
</li>
|
|
@@ -1694,11 +1787,11 @@ The following is a hypothetical list page!
|
|
|
1694
1787
|
|
|
1695
1788
|
<!-- The "items" template -->
|
|
1696
1789
|
<template def="item" scoped>
|
|
1697
|
-
<li><a
|
|
1790
|
+
<li><a render="~href: '/animals#'+name;"><?{ index+': '+name }?></a></li>
|
|
1698
1791
|
</template>
|
|
1699
1792
|
|
|
1700
1793
|
<!-- The loop -->
|
|
1701
|
-
<ul
|
|
1794
|
+
<ul render="@items: (name,index) of ['dog','cat','ram'] / 'item';"></ul>
|
|
1702
1795
|
|
|
1703
1796
|
</section>
|
|
1704
1797
|
```
|