@@ -341,23 +341,31 @@ static xmlNodePtr dom_xml_fragment_parsing_algorithm(dom_object *obj, const xmlN
341
341
return NULL ;
342
342
}
343
343
344
- /* https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin
345
- * and https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm */
346
- zend_result dom_element_inner_html_write (dom_object * obj , zval * newval )
344
+ /* https://w3c.github.io/DOM-Parsing/#dfn-fragment-parsing-algorithm */
345
+ static xmlNodePtr dom_parse_fragment (dom_object * obj , xmlNodePtr context_node , const zend_string * input )
347
346
{
348
- DOM_PROP_NODE (xmlNodePtr , context_node , obj );
349
-
350
- xmlNodePtr fragment ;
351
347
if (context_node -> doc -> type == XML_DOCUMENT_NODE ) {
352
- fragment = dom_xml_fragment_parsing_algorithm (obj , context_node , Z_STR_P ( newval ) );
348
+ return dom_xml_fragment_parsing_algorithm (obj , context_node , input );
353
349
} else {
354
- fragment = dom_html_fragment_parsing_algorithm (obj , context_node , Z_STR_P ( newval ) , obj -> document -> quirks_mode );
350
+ return dom_html_fragment_parsing_algorithm (obj , context_node , input , obj -> document -> quirks_mode );
355
351
}
352
+ }
353
+
354
+ /* https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin */
355
+ zend_result dom_element_inner_html_write (dom_object * obj , zval * newval )
356
+ {
357
+ /* 1. We don't do injection sinks, skip. */
358
+
359
+ /* 2. Let context be this. */
360
+ DOM_PROP_NODE (xmlNodePtr , context_node , obj );
356
361
362
+ /* 3. Let fragment be the result of invoking the fragment parsing algorithm steps with context and compliantString. */
363
+ xmlNodePtr fragment = dom_parse_fragment (obj , context_node , Z_STR_P (newval ));
357
364
if (fragment == NULL ) {
358
365
return FAILURE ;
359
366
}
360
367
368
+ /* 4. If context is a template element, then set context to the template element's template contents (a DocumentFragment). */
361
369
if (php_dom_ns_is_fast (context_node , php_dom_ns_is_html_magic_token ) && xmlStrEqual (context_node -> name , BAD_CAST "template" )) {
362
370
context_node = php_dom_ensure_templated_content (php_dom_get_private_data (obj ), context_node );
363
371
if (context_node == NULL ) {
@@ -366,6 +374,7 @@ zend_result dom_element_inner_html_write(dom_object *obj, zval *newval)
366
374
}
367
375
}
368
376
377
+ /* 5. Replace all with fragment within context. */
369
378
dom_remove_all_children (context_node );
370
379
return php_dom_pre_insert (obj -> document , fragment , context_node , NULL ) ? SUCCESS : FAILURE ;
371
380
}
@@ -397,4 +406,62 @@ zend_result dom_element_outer_html_read(dom_object *obj, zval *retval)
397
406
return SUCCESS ;
398
407
}
399
408
409
+ /* https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#the-outerhtml-property */
410
+ zend_result dom_element_outer_html_write (dom_object * obj , zval * newval )
411
+ {
412
+ /* 1. We don't do injection sinks, skip. */
413
+
414
+ /* 2. Let parent be this's parent. */
415
+ DOM_PROP_NODE (xmlNodePtr , this , obj );
416
+ xmlNodePtr parent = this -> parent ;
417
+ bool created_parent = false;
418
+
419
+ /* 3. If parent is null, return. */
420
+ if (parent == NULL ) {
421
+ return SUCCESS ;
422
+ }
423
+
424
+ /* 4. If parent is a Document, throw. */
425
+ if (parent -> type == XML_DOCUMENT_NODE || parent -> type == XML_HTML_DOCUMENT_NODE ) {
426
+ php_dom_throw_error (INVALID_MODIFICATION_ERR , true);
427
+ return FAILURE ;
428
+ }
429
+
430
+ /* 5. If parent is a DocumentFragment, set parent to the result of creating an element given this's node document, body, and the HTML namespace. */
431
+ if (parent -> type == XML_DOCUMENT_FRAG_NODE ) {
432
+ xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns (php_dom_get_ns_mapper (obj ));
433
+
434
+ parent = xmlNewDocNode (parent -> doc , html_ns , BAD_CAST "body" , NULL );
435
+ created_parent = true;
436
+ if (UNEXPECTED (parent == NULL )) {
437
+ php_dom_throw_error (INVALID_STATE_ERR , true);
438
+ return FAILURE ;
439
+ }
440
+ }
441
+
442
+ /* 6. Let fragment be the result of invoking the fragment parsing algorithm steps given parent and compliantString. */
443
+ xmlNodePtr fragment = dom_parse_fragment (obj , parent , Z_STR_P (newval ));
444
+ if (fragment == NULL ) {
445
+ if (created_parent ) {
446
+ xmlFreeNode (parent );
447
+ }
448
+ return FAILURE ;
449
+ }
450
+
451
+ /* 7. Replace this with fragment within this's parent. */
452
+ if (!php_dom_pre_insert (obj -> document , fragment , this -> parent , this )) {
453
+ xmlFreeNode (fragment );
454
+ if (created_parent ) {
455
+ xmlFreeNode (parent );
456
+ }
457
+ return FAILURE ;
458
+ }
459
+ xmlUnlinkNode (this );
460
+ if (created_parent ) {
461
+ ZEND_ASSERT (parent -> children == NULL );
462
+ xmlFreeNode (parent );
463
+ }
464
+ return SUCCESS ;
465
+ }
466
+
400
467
#endif
0 commit comments