You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: patching-explainer.md
+72-22Lines changed: 72 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,11 +22,9 @@ Patches can be be applied later in the page lifecycle using JavaScript, see [int
22
22
23
23
### Proposed markup
24
24
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.
27
26
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".
30
28
31
29
Example where a placeholder is replaced with actual content:
32
30
@@ -48,6 +46,10 @@ The processing instructions and everything between them is replaced, so the resu
48
46
</section>
49
47
```
50
48
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
+
51
53
To insert at a single point, a single `<?marker>` is used:
52
54
53
55
```html
@@ -66,13 +68,13 @@ To support multiple ranges, processing instructions can be named. Any number of
66
68
67
69
```html
68
70
<divmarker="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>
76
78
</div>
77
79
78
80
<templatefor="results#part-one">
@@ -88,9 +90,9 @@ Multiple `<?marker>` elements without place-holder content is also supported in
88
90
89
91
```html
90
92
<divmarker="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">
94
96
</div>
95
97
96
98
<templatefor="results#part-one">
@@ -102,23 +104,25 @@ Multiple `<?marker>` elements without place-holder content is also supported in
102
104
</template>
103
105
```
104
106
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
+
105
109
A few details about patching:
106
110
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).
109
113
- 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.
110
114
- The patch template has to be in the same tree (shadow) scope as the target element.
111
115
- 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).
113
117
- Marker targets have two parts: the element identifier and the marker name, separated by `#`. The marker name is optional.
114
118
115
119
### Interleaved patching
116
120
117
121
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:
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
146
150
</template>
147
151
```
148
152
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
+
<divmarker="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
+
<divmarker="results">
179
+
<?start>
180
+
<divmarker="part-one">
181
+
<?start>
182
+
Placeholder content
183
+
<?end>
184
+
</div>
185
+
<hr>
186
+
<divmarker="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
+
149
197
## Marker APIs
150
198
151
199
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
198
246
199
247
See https://github.com/w3c/csswg-drafts/issues/13381 for discussion.
200
248
249
+
Note however that presently, ranges cannot partially overlap while custom highlights can.
250
+
201
251
## DOM Parts integration
202
252
203
253
[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.
204
254
205
255
### Implicit markers
206
256
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:
208
258
209
259
```html
210
260
<sectionrange="gallery:all">
@@ -244,9 +294,9 @@ Enabling remote fetching of patch content would act as a script in terms of CSP,
244
294
245
295
### Marker pointers on `Element`
246
296
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.
248
298
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.
250
300
251
301
The chief downside of this approach is that it requires bookkeeping similar to live `Range` objects.
0 commit comments