Skip to content

Commit

Permalink
Highlight code blocks, fix emphasis (#712)
Browse files Browse the repository at this point in the history
* Highlight code blocks, fix emphasis

* Fix reviewed changes, fix Markdown emphasis

* Fix reviewed changes
  • Loading branch information
wiinci authored and rniwa committed Dec 4, 2017
1 parent 631ef0a commit 8f353b6
Showing 1 changed file with 27 additions and 29 deletions.
56 changes: 27 additions & 29 deletions proposals/Template-Instantiation.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,27 @@ partial interface HTMLTemplateElement {

Concretely, use case (1) is addressed by the component instancing a template as follows:

```
``` js
// shadowRoot is the shadow root of a contact card component
shadowRoot.appendChild(template.createInstance());
```

Use case (2) is addressed as follows:

```
// Template content is `'<section><h1>{{name}}</h1>Email: <a href="mailto:{{email}}">{{email}}</a></section>'`
``` js
// Template content is `<section><h1>{{name}}</h1>Email: <a href="mailto:{{email}}">{{email}}</a></section>`
shadowRoot.appendChild(template.createInstance({name: "Ryosuke Niwa", email: "[email protected]"}));
```

When `createInstance` is called with a JavaScript object, we automatically substitute every mustache syntax with the corresponding value of the property in the object. The resultant DOM would look as though we parsed the following HTML:

```
``` html
<section><h1>Ryosuke Niwa</h1>Email: <a href="mailto:[email protected]”>[email protected]</a></section>
```
For use case (3), `TemplateInstance`'s `update` method can be used as follows:
```
``` js
let content = template.createInstance({name: "Ryosuke Niwa", email: "[email protected]"});
shadowRoot.appendChild(content);
...
Expand All @@ -73,7 +73,7 @@ content.update({name: "Ryosuke Niwa", email: "[email protected]"});
That would update the DOM tree of the template instance to look like:
```
``` html
<section><h1>Ryosuke Niwa</h1>Email: <a href="mailto:[email protected]>[email protected]</a></section>
```

Expand All @@ -85,7 +85,7 @@ Because multiple mustache syntaxes within a template work together to absorb var

In order to support use cases (4) and (5), let’s say we have the following `template` element:

```
``` html
<template id="foo"><div class="foo {{ f(y) }}">{{ x }} world</div></template>
```

Expand All @@ -95,34 +95,34 @@ For example, suppose a library wanted to provide an ability to auto-linkify a UR

Conceptually we need two objects, say *FY* and *X*, that represent `{{ f(y) }}` and `{{ x }}` which libraries and frameworks can use to read the original expression in each mustache, and use it to update the DOM. We call these objects **template parts**. Template parts should allow the inspection of content of `{{~}}` like so:

```
``` js
FY.expression; // Returns "f(y)"
X.expression; // Returns "x".
```

Template parts should allow the assignment of a new value after libraries and frameworks evaluated `f(y)` (here, assume `f(y)` evaluates to “bar” and `x` evaluates to “hello”:

```
``` js
FY.value = 'bar'; // Equivalent to div.setAttribute('class', 'foo bar').
X.value = 'hello'; // Equivalent to div.textContent = 'hello world’.
```

For template parts which appear as text nodes should also support taking multiple and arbitrary DOM nodes instead of just a text value:

```
``` js
// Insert span and a text node in place of {{ x }}.
X.replace([document.createElement('span'), 'hello']);
```

Or perhaps we would even want to parse HTML:

```
``` js
X.replaceHTML('<b>hello</b>');
```

For use case (5), we need to be able to inspect the attribute name of a template part as in:

```
``` js
FY.attributeName; // Returns "class"
```

Expand All @@ -138,15 +138,13 @@ Each template part represents an occurrence of a mustache syntax in the template

Consider, for example, the following template:

```
<template type="my-template-type" id="contactTemplate">
<section><h1>{{name}}</h1>Email: <a href="mailto:{{email}}">{{email}}</a></section>
</template>
``` html
<template type="my-template-type" id="contactTemplate"><section><h1>{{name}}</h1>Email: <a href="mailto:{{email}}">{{email}}</a></section></template>
```

That template creates template parts: `NodeTemplatePart` for `{{name}}`, `AttributeTemplatePart` for `{{email}}` in the `href` attribute of the anchor element, and `NodeTemplatePart` for `{{email}}` for the occurrence inside the anchor element. In order to use this template, a template library or the page author would have had to define a `my-template-type` template type; e.g.:

```
``` js
document.defineTemplateType('my-template-type', {
processCallback: function (instance, parts, state) {
for (const part of parts)
Expand All @@ -157,14 +155,14 @@ document.defineTemplateType('my-template-type', {

This template process callback, for illustration purposes, is a simplified version of the **default template process callback**, which is used when the `type` content attribute is omitted on a `template` element. It goes through each template part (i.e., each occurrence of `{{ X }}`) and replaces it with the state object's value looked up by the template part's expression (e.g. `X` for `{{ X }}`). Once defined, this template process callback is invoked whenever the `createInstance` method is invoked on a `template` element of the type `my-template-type`; e.g.:

```
``` js
rniwa = {name: "R. Niwa", email: "[email protected]"};
document.body.appendChild(contactTemplate.createInstance(rniwa));
```

The above code produces the same DOM as the following code under `document.body`:

```
``` js
document.body.innerHTML = '<section><h1>R. Niwa</h1>Email:'
+ ' <a href="mailto:[email protected]">[email protected]</a></section>';
```
Expand All @@ -179,7 +177,7 @@ We allow inserting and removing preceding siblings and succeeding siblings in so

Let's suppose we wanted to create a template type which remembers the state object being passed when it was created, and automatically updates the instance whenever property values are changed at some checkpoints (e.g., at the next `requestAnimationFrame`). We can implement this using a template create callback as follows:

```
``` js
document.defineTemplateType('self-updating-template', {
createCallback: function (instance, parts, state) {
onCheckPoint(() => instance.update(state));
Expand Down Expand Up @@ -246,7 +244,7 @@ In the default template process callback, the fallback or default value of a tem

Note that with this approach, we have an option to address the need to [declaratively instantiate a shadow tree](https://github.com/whatwg/dom/issues/510) by adding a new callback which gets called for each appearance of a template element as follows if we so desired:

```
``` html
<template type="shadow-root">~</template>
<script>
document.defineTemplateType("shadow-root", {
Expand All @@ -269,7 +267,7 @@ With API proposed thus far, conditional statements for use case (8) can be imple

However, this approach won't work for use case (9). To see why, suppose we had the following template:

```
``` html
<template type="with-for-each" id="list">
<ul>
{{foreach items}}
Expand All @@ -281,7 +279,7 @@ However, this approach won't work for use case (9). To see why, suppose we had t

We can detect `{{foreach items}}` the same way we detect `{{if x}}`, but we there is exactly one template part object for `{{class}}`, `{{value}}`, and `{{label}}`, not per an element in items, and the browser engine doesn't have a way of ignoring out how many parts are needed unless we standardized the exact semantics foreach:

```
``` js
document.defineTemplateType('with-for-each', { processCallback: (instance, parts, state) => {
for (const part of parts) {
...
Expand All @@ -302,7 +300,7 @@ In fact, when `update` method of `TemplateInstance` is subsequently called, we m
As suggested by others in the past discussions, we propose to use nested templates for these cases:
```
``` html
<template type="with-for-each" id="list">
<ul>
<template directive="foreach" expression="items">
Expand All @@ -314,7 +312,7 @@ As suggested by others in the past discussions, we propose to use nested templat
In this approach, each inner template appear as its own template part, and the template process callback which supports foreach **directive** would instantiate the inner template as many times as needed as follows:
```
``` js
document.defineTemplateType("with-for-each", { processCallback: function (instance, parts, state) {
for (const part of parts) {
...
Expand All @@ -340,7 +338,7 @@ To make this process more streamlined, we propose treating inner template elemen
With this interface, the template process callback that implements foreach and other kinds of looping constructs could simply call `replace` with newly constructed elements as follows:
```
``` js
document.defineTemplateType("with-for-each", {
processCallback: function (instance, parts, state) {
for (const part of parts) {
Expand Down Expand Up @@ -397,7 +395,7 @@ The `createInstance(optional any state)` method on `HTMLTemplateElement`, when
4. Let *parts* be an empty list.
5. For every [descendent](https://dom.spec.whatwg.org/#concept-tree-descendant) node *currentNode* of *instance* in [tree order](https://dom.spec.whatwg.org/#concept-tree-order), run these steps:
1. If *currentNode* is a [template element](https://html.spec.whatwg.org/multipage/scripting.html#the-template-element):
1. Run the concept to _adjust single node case_ with *currentNode***.**
1. Run the concept to _adjust single node case_ with *currentNode*.
2. Let *nodeValueSetter* be a new instance of the _node value setter_ with *currentNode*, the [previous sibling](https://dom.spec.whatwg.org/#concept-tree-next-sibling) of *currentNode*, the [next sibling](https://dom.spec.whatwg.org/#concept-tree-next-sibling) of *currentNode*, an empty _previous replacement nodes_, fully templatized set to the result of running the concept to _determine full templatizability_ with *currentNode*, and an empty _node template part list_.
3. Let *innerPart* be a new instance of `InnerTemplatePart` associated with *currentNode*, an empty _replacement node list_, and *nodeValueSetter*.
4. Append *innerPart* to the end of *parts.*
Expand All @@ -420,7 +418,7 @@ The `createInstance(optional any state)` method on `HTMLTemplateElement`, when
1. Let *value* be *currentNode*'s [data](https://dom.spec.whatwg.org/#concept-cd-data) after [stripping leading and trailing ASCII whitespace](https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace).
2. Let *tokens* to be the result of running the concept to _parse a template string_ on *value*.
3. If *tokens* contains exactly one string, abort the rest of steps and go to the next node.
4. Run the concept to _adjust single node case_ with *currentNode***.**
4. Run the concept to _adjust single node case_ with *currentNode*.
5. Let *nodeValueSetter* be a new instance of the _node value setter_ with the [parent](https://dom.spec.whatwg.org/#concept-tree-parent) [node](https://dom.spec.whatwg.org/#concept-node) of c*urrentNode*, the [previous sibling](https://dom.spec.whatwg.org/#concept-tree-next-sibling) of *currentNode*, an empty _previous replacement nodes_, fully templatized flag set to the result of running the concept to _determine full templatizability_ with *currentNode*, and an empty _node template part list_.
6. For every *token* in *tokens*:
1. If the type of *token* is “string”,
Expand Down Expand Up @@ -549,7 +547,7 @@ To **apply attribute template part list** with an _attribute value setter_ *attr
2. If *partList* contains exactly one _attribute template part_ (this is the fully templatized case):
1. Let *fullTemplate* be the _attribute template part_ in *tokenList*.
2. If the value string of *fullTemplate* is null, [remove an attribute](https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-namespace) with the namespace of the associated attribute of *attributeValueSetter*, the [local name](https://dom.spec.whatwg.org/#concept-attribute-local-name) of the associated attribute of *attributeValueSetter*, and the associated element of *attributeValueSetter.*
3. Otherwise (if the value string of *fullTemplate* is not null*)*, invoke [setAttributeNS](https://dom.spec.whatwg.org/#dom-element-setattributens) with the namespace of the associated attribute of *attributeValueSetter*, the [qualified name](https://dom.spec.whatwg.org/#concept-attribute-qualified-name) of the associated attribute of *attributeValueSetter*, and the value string of *attributeValueSetter* on the associated element of *attributeValueSetter.*
3. Otherwise (if the value string of *fullTemplate* is not null), invoke [setAttributeNS](https://dom.spec.whatwg.org/#dom-element-setattributens) with the namespace of the associated attribute of *attributeValueSetter*, the [qualified name](https://dom.spec.whatwg.org/#concept-attribute-qualified-name) of the associated attribute of *attributeValueSetter*, and the value string of *attributeValueSetter* on the associated element of *attributeValueSetter.*
3. Otherwise:
1. Let *newValue* be an empty string.
2. For each *part* in *partList*:
Expand Down

0 comments on commit 8f353b6

Please sign in to comment.