@@ -94,6 +94,40 @@ private function convertDataValueToString( $value ) {
94
94
return json_encode ( $ value );
95
95
}
96
96
97
+ private function safeModifyChildren ( DOMNode $ parent , DOMNode $ oldNode , array $ newNodes , bool $ insert = false ) {
98
+ // TODO To work around the double-free, we detach all the children of the parent node and
99
+ // re-attach them in the correct sequence, replacing the target node with our newly-imported
100
+ // node. Once `mwcli` has moved off this outdated version of PHP (T388411) we should be able
101
+ // to remove this workaround. T398821
102
+ $ children = [];
103
+ foreach ( iterator_to_array ( $ parent ->childNodes ) as $ child ) {
104
+ if ( $ child === $ oldNode ) {
105
+ $ children = array_merge ( $ children , $ newNodes );
106
+ }
107
+ if ( $ insert || $ child !== $ oldNode ) {
108
+ $ children [] = $ child ;
109
+ }
110
+ $ child ->remove ();
111
+ }
112
+
113
+ foreach ( $ children as $ child ) {
114
+ $ parent ->appendChild ( $ child );
115
+ }
116
+ }
117
+
118
+ private function safeReplaceNode ( DOMNode $ parent , DOMNode $ oldNode , array $ newNodes ) {
119
+ $ this ->safeModifyChildren ( $ parent , $ oldNode , $ newNodes , false );
120
+ }
121
+
122
+ private function safeInsertBefore ( DOMNode $ parent , DOMNode $ oldNode , array $ newNodes ) {
123
+ $ this ->safeModifyChildren ( $ parent , $ oldNode , $ newNodes , true );
124
+ }
125
+
126
+ private function replaceNodeWithChildren ( DOMNode $ node ) {
127
+ $ children = iterator_to_array ( $ node ->childNodes );
128
+ $ this ->safeReplaceNode ( $ node ->parentNode , $ node , $ children );
129
+ }
130
+
97
131
/**
98
132
* @param DOMNode $node
99
133
* @param array $data
@@ -145,24 +179,7 @@ private function handleComponent( DOMElement $node, array $data ): bool {
145
179
if ( $ node != $ importNode ) {
146
180
$ node ->replaceWith ( $ importNode );
147
181
} else {
148
- // TODO To work around the double-free, we detach all the children of the parent node and
149
- // re-attach them in the correct sequence, replacing the target node with our newly-imported
150
- // node. Once `mwcli` has moved off this outdated version of PHP (T388411) we should be able
151
- // to remove this workaround. T398821
152
- $ parent = $ node ->parentNode ;
153
- $ children = [];
154
- foreach ( iterator_to_array ( $ parent ->childNodes ) as $ child ) {
155
- if ( $ child !== $ node ) {
156
- $ children [] = $ child ;
157
- } else {
158
- $ children [] = $ importNode ;
159
- }
160
- $ child ->remove ();
161
- }
162
-
163
- foreach ( $ children as $ child ) {
164
- $ parent ->appendChild ( $ child );
165
- }
182
+ $ this ->safeReplaceNode ( $ node ->parentNode , $ node , [ $ importNode ] );
166
183
}
167
184
return true ;
168
185
}
@@ -286,14 +303,18 @@ private function handleFor( DOMNode $node, array $data ) {
286
303
287
304
/** @var DOMElement $node */
288
305
if ( $ node ->hasAttribute ( 'v-for ' ) ) {
306
+ $ parentNode = $ node ->parentNode ;
289
307
list ( $ itemName , $ listName ) = explode ( ' in ' , $ node ->getAttribute ( 'v-for ' ) );
290
308
$ node ->removeAttribute ( 'v-for ' );
291
309
$ node ->removeAttribute ( ':key ' );
292
310
293
311
foreach ( $ this ->app ->evaluateExpression ( $ listName , $ data ) as $ item ) {
294
312
$ newNode = $ node ->cloneNode ( true );
295
- $ node -> parentNode -> insertBefore ( $ newNode , $ node );
313
+ $ this -> safeInsertBefore ( $ parentNode , $ node, [ $ newNode ] );
296
314
$ this ->handleNode ( $ newNode , array_merge ( $ data , [ $ itemName => $ item ] ) );
315
+ if ( $ newNode ->tagName === 'template ' ) {
316
+ $ this ->replaceNodeWithChildren ( $ newNode );
317
+ }
297
318
}
298
319
299
320
$ this ->removeNode ( $ node );
@@ -324,7 +345,9 @@ private function handleRawHtml( DOMNode $node, array $data ) {
324
345
}
325
346
326
347
private function removeNode ( DOMElement $ node ) {
327
- $ node ->parentNode ->removeChild ( $ node );
348
+ if ( $ node ->parentNode ) {
349
+ $ node ->parentNode ->removeChild ( $ node );
350
+ }
328
351
}
329
352
330
353
/**
0 commit comments