Skip to content

Commit eeb6437

Browse files
authored
Explain nested processing instructions (#91)
1 parent cc14aee commit eeb6437

File tree

1 file changed

+72
-22
lines changed

1 file changed

+72
-22
lines changed

patching-explainer.md

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ Patches can be be applied later in the page lifecycle using JavaScript, see [int
2222

2323
### Proposed markup
2424

25-
Proposing to introduce processing instructions into HTML.
26-
Those are already supported in XML and in the DOM spec, and are currently parsed as bogus comments.
25+
Proposing to introduce processing instructions (PIs) into HTML. Those are already supported in XML and in the DOM spec, and are currently parsed as bogus comments.
2726

28-
All processing instructions (apart from block-listed ones like `<?xml` and `<?xml-stylesheet`) would be parsed as such.
29-
and a few special "targets" would be used towards marking: `start`, `end`, and `marker`, the latter being a "void".
27+
All processing instructions (apart from block-listed ones like `<?xml` and `<?xml-stylesheet`) would be parsed as such. A few special "targets" would be used towards marking: `start`, `end`, and `marker`, the latter being a "void".
3028

3129
Example where a placeholder is replaced with actual content:
3230

@@ -48,6 +46,10 @@ The processing instructions and everything between them is replaced, so the resu
4846
</section>
4947
```
5048

49+
The `<?end>` processing instruction is optional, but recommended for clarity. If it is not present, the patch range is assumed to end at the end of the current element.
50+
51+
The `<?end>` processing instruction closes the nearest open `<?start>` processing instruction. This means processing instructions cannot partially overlap (for example, open a, open b, close a, close b) since the `<?end>` would close the nearest open `<?start>`. See also [Nested Patching](#nested-patching) for more considerations here with nested ranges.
52+
5153
To insert at a single point, a single `<?marker>` is used:
5254

5355
```html
@@ -66,13 +68,13 @@ To support multiple ranges, processing instructions can be named. Any number of
6668

6769
```html
6870
<div marker="results">
69-
<?start name="part-one">
70-
Placeholder content
71-
<?end>
72-
<hr>
73-
<?start name="part-two">
74-
Placeholder content
75-
<?end>
71+
<?start name="part-one">
72+
Placeholder content
73+
<?end>
74+
<hr>
75+
<?start name="part-two">
76+
Placeholder content
77+
<?end>
7678
</div>
7779

7880
<template for="results#part-one">
@@ -88,9 +90,9 @@ Multiple `<?marker>` elements without place-holder content is also supported in
8890

8991
```html
9092
<div marker="results">
91-
<?marker name="part-one">
92-
<hr>
93-
<?marker name="part-two">
93+
<?marker name="part-one">
94+
<hr>
95+
<?marker name="part-two">
9496
</div>
9597

9698
<template for="results#part-one">
@@ -102,23 +104,25 @@ Multiple `<?marker>` elements without place-holder content is also supported in
102104
</template>
103105
```
104106

107+
When `<?start>` or `<?marker>` processing instructions are named, the template `for` attribute has to include the name as well, separated by `#` for the template to be valid and patching to occur.
108+
105109
A few details about patching:
106110

107-
- Templates with a valid `for` attribute are not attached to the DOM, while templates that don't apply are attached to signal an error.
108-
- `<?end>` does not have a `name` attribute. A `<?start>` processing instruction would match the next `<?end>` sibling.
111+
- Templates with a valid `for` attribute are not attached to the DOM, while templates that don't apply are attached to signal an error (note since templates are hidden by default, templates without a valid `for` will not be visible on the page to the user, but they will be visible in the DOM to the developer).
112+
- `<?end>` does not have a `name` attribute. A `<?start>` processing instruction matches the nearest unmatched `<?end>` sibling (or the closing of its parent element is no `<?end>` is found).
109113
- If the patching element is not a direct child of `<body>`, the target element has to have a common ancestor with the patching element's parent.
110114
- The patch template has to be in the same tree (shadow) scope as the target element.
111115
- When the template's target is discovered, the content between the markers is removed, but the markers are left in the tree until the template is closed.
112-
- New content is always inserted into the element with the corresponding marker attribute. If the original `<?end>` or `<?marker>` PI is still there, it is inserted before that node. Otherwise, it is appended.
116+
- New content is always inserted into the element with the corresponding marker attribute. If the original `<?end>` or `<?marker>` processing instruction is still there, it is inserted before that node. Otherwise, it is appended (effectively, the missing processing instruction is assumed to exist at the end of the element).
113117
- Marker targets have two parts: the element identifier and the marker name, separated by `#`. The marker name is optional.
114118

115119
### Interleaved patching
116120

117121
An element can be patched multiple times and patches for different elements can be interleaved. This allows for updates to different parts of the document to be interleaved. For example:
118122

119123
```html
120-
<div range="product-carousel"><?start>Loading...</div>
121-
<div range="search-results"><?start>Loading...</div>
124+
<div range="product-carousel"><?start>Loading...<?end></div>
125+
<div range="search-results"><?start>Loading...<?end></div>
122126
```
123127

124128
In this example, the search results populate in three steps while the product carousel populates in one step in between:
@@ -146,6 +150,50 @@ In this example, the search results populate in three steps while the product ca
146150
</template>
147151
```
148152

153+
### Nested patching
154+
155+
Processing can be nested within a single element. In this case the browser will handle matching the `<?end>` processing instruction with the nearest `<?start>` processing instruction.
156+
157+
For example, to support named processing instructions for "all results" in the previous example and also specific numbered results:
158+
159+
```html
160+
<div marker="results">
161+
<?start name="all-results">
162+
<?start name="part-one">
163+
Placeholder content
164+
<?end>
165+
<hr>
166+
<?start name="part-two">
167+
Placeholder content
168+
<?end>
169+
<?end>
170+
</div>
171+
```
172+
173+
Note that, since processing instructions are not DOM elements, they are not technically nested (hence shown without intentaion).
174+
175+
For this reason, a cleaner alternative is to provide nesting with actual DOM elements such as `<div>`s and separate markers:
176+
177+
```html
178+
<div marker="results">
179+
<?start>
180+
<div marker="part-one">
181+
<?start>
182+
Placeholder content
183+
<?end>
184+
</div>
185+
<hr>
186+
<div marker="part-two">
187+
<?start>
188+
Placeholder content
189+
<?end>
190+
</div>
191+
<?end>
192+
</div>
193+
```
194+
195+
Both of these options (nesting processing instructions within the same direct parent element, or use of DOM elements to provide the nesting structure) are supported for nesting.
196+
149197
## Marker APIs
150198

151199
The new `<?marker>`, `<?start>`, and `<?end>` nodes would be represented with the `ProcessingInstruction` interface. That interface would receive `getAttribute`, `setAttribute` methods etc. See https://github.com/whatwg/dom/pull/1454.
@@ -198,13 +246,15 @@ Named ranges created by processing instructions are similar to the named highlig
198246

199247
See https://github.com/w3c/csswg-drafts/issues/13381 for discussion.
200248

249+
Note however that presently, ranges cannot partially overlap while custom highlights can.
250+
201251
## DOM Parts integration
202252

203253
[DOM Parts](https://github.com/WICG/webcomponents/blob/gh-pages/proposals/DOM-Parts.md) could make use of processing instructions to annotate ranges created by the "{{}}" syntax, so that the ranges are represented in the DOM and not just in the `<template>` and JS APIs.
204254

205255
### Implicit markers
206256

207-
To simplify the common case of replacing all children of an element without requiring a `<!start>` node, the `marker` attribute could have a microsyntax to target ranges. Example:
257+
To simplify the common case of replacing all children of an element without requiring a `<?start>` node, the `marker` attribute could have a microsyntax to target ranges. Example:
208258

209259
```html
210260
<section range="gallery:all">
@@ -244,9 +294,9 @@ Enabling remote fetching of patch content would act as a script in terms of CSP,
244294

245295
### Marker pointers on `Element`
246296

247-
The main proposal treats `<!start>` and `<!end>` as two nodes, which can appear in any number and order. Error handling is done when trying to apply a `<template>` patch.
297+
The main proposal treats `<?start>` and `<?end>` as two nodes, which can appear in any number and order. Error handling is done when trying to apply a `<template>` patch.
248298

249-
An alternative is that the parser doesn't create `Marker` nodes, but instead sets pointers `element.beforeFirstMarker` and `element.afterLastMarker`. Serializing would insert `<!start>` and `<!end>` at the appropriate places.
299+
An alternative is that the parser doesn't create `Marker` nodes, but instead sets pointers `element.beforeFirstMarker` and `element.afterLastMarker`. Serializing would insert `<?start>` and `<?end>` at the appropriate places.
250300

251301
The chief downside of this approach is that it requires bookkeeping similar to live `Range` objects.
252302

0 commit comments

Comments
 (0)