Changeset 58677
- Timestamp:
- 07/05/2024 12:50:19 AM (9 months ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/html-api/class-wp-html-open-elements.php
r58676 r58677 190 190 * Returns whether an element is in a specific scope. 191 191 * 192 * ## HTML Support193 *194 * This function skips checking for the termination list because there195 * are no supported elements which appear in the termination list.196 *197 192 * @since 6.4.0 198 193 * … … 312 307 * Returns whether a particular element is in select scope. 313 308 * 314 * @since 6.4.0 309 * This test differs from the others like it, in that its rules are inverted. 310 * Instead of arriving at a match when one of any tag in a termination group 311 * is reached, this one terminates if any other tag is reached. 312 * 313 * > The stack of open elements is said to have a particular element in select scope when it has 314 * > that element in the specific scope consisting of all element types except the following: 315 * > - optgroup in the HTML namespace 316 * > - option in the HTML namespace 317 * 318 * @since 6.4.0 Stub implementation (throws). 319 * @since 6.7.0 Full implementation. 315 320 * 316 321 * @see https://html.spec.whatwg.org/#has-an-element-in-select-scope 317 322 * 318 * @throws WP_HTML_Unsupported_Exception Always until this function is implemented.319 *320 323 * @param string $tag_name Name of tag to check. 321 * @return bool Whether given element is inscope.324 * @return bool Whether the given element is in SELECT scope. 322 325 */ 323 326 public function has_element_in_select_scope( $tag_name ) { 324 throw new WP_HTML_Unsupported_Exception( 'Cannot process elements depending on select scope.' ); 325 326 return false; // The linter requires this unreachable code until the function is implemented and can return. 327 foreach ( $this->walk_up() as $node ) { 328 if ( $node->node_name === $tag_name ) { 329 return true; 330 } 331 332 if ( 333 'OPTION' !== $node->node_name && 334 'OPTGROUP' !== $node->node_name 335 ) { 336 return false; 337 } 338 } 339 340 return false; 327 341 } 328 342 -
trunk/src/wp-includes/html-api/class-wp-html-processor.php
r58676 r58677 102 102 * - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY. 103 103 * - Custom elements: All custom elements are supported. :) 104 * - Form elements: BUTTON, DATALIST, FIELDSET, INPUT, LABEL, LEGEND, METER, PROGRESS, SEARCH.104 * - Form elements: BUTTON, DATALIST, FIELDSET, INPUT, LABEL, LEGEND, METER, OPTGROUP, OPTION, PROGRESS, SEARCH, SELECT. 105 105 * - Formatting elements: B, BIG, CODE, EM, FONT, I, PRE, SMALL, STRIKE, STRONG, TT, U, WBR. 106 106 * - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP. … … 757 757 case WP_HTML_Processor_State::INSERTION_MODE_IN_BODY: 758 758 return $this->step_in_body(); 759 760 case WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD: 761 return $this->step_in_head(); 762 763 case WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT: 764 return $this->step_in_select(); 759 765 760 766 default: … … 1335 1341 case '+SOURCE': 1336 1342 case '+TRACK': 1343 $this->insert_html_element( $this->state->current_token ); 1344 return true; 1345 1346 /* 1347 * > A start tag whose tag name is "select" 1348 */ 1349 case '+SELECT': 1350 $this->reconstruct_active_formatting_elements(); 1351 $this->insert_html_element( $this->state->current_token ); 1352 $this->state->frameset_ok = false; 1353 1354 switch ( $this->state->insertion_mode ) { 1355 /* 1356 * > If the insertion mode is one of "in table", "in caption", "in table body", "in row", 1357 * > or "in cell", then switch the insertion mode to "in select in table". 1358 */ 1359 case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE: 1360 case WP_HTML_Processor_State::INSERTION_MODE_IN_CAPTION: 1361 case WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY: 1362 case WP_HTML_Processor_State::INSERTION_MODE_IN_ROW: 1363 case WP_HTML_Processor_State::INSERTION_MODE_IN_CELL: 1364 $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT_IN_TABLE; 1365 break; 1366 1367 /* 1368 * > Otherwise, switch the insertion mode to "in select". 1369 */ 1370 default: 1371 $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT; 1372 break; 1373 } 1374 return true; 1375 1376 /* 1377 * > A start tag whose tag name is one of: "optgroup", "option" 1378 */ 1379 case '+OPTGROUP': 1380 case '+OPTION': 1381 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) { 1382 $this->state->stack_of_open_elements->pop(); 1383 } 1384 $this->reconstruct_active_formatting_elements(); 1337 1385 $this->insert_html_element( $this->state->current_token ); 1338 1386 return true; … … 1379 1427 case 'NOSCRIPT': 1380 1428 case 'OBJECT': 1381 case 'OPTGROUP':1382 case 'OPTION':1383 1429 case 'PLAINTEXT': 1384 1430 case 'RB': … … 1388 1434 case 'SARCASM': 1389 1435 case 'SCRIPT': 1390 case 'SELECT':1391 1436 case 'STYLE': 1392 1437 case 'SVG': … … 1447 1492 } 1448 1493 } 1494 } 1495 1496 /** 1497 * Parses next element in the 'in head' insertion mode. 1498 * 1499 * This internal function performs the 'in head' insertion mode 1500 * logic for the generalized WP_HTML_Processor::step() function. 1501 * 1502 * @since 6.7.0 Stub implementation. 1503 * 1504 * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. 1505 * 1506 * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead 1507 * @see WP_HTML_Processor::step 1508 * 1509 * @return bool Whether an element was found. 1510 */ 1511 private function step_in_head() { 1512 $this->last_error = self::ERROR_UNSUPPORTED; 1513 throw new WP_HTML_Unsupported_Exception( "No support for parsing in the '{$this->state->insertion_mode}' state." ); 1514 } 1515 1516 /** 1517 * Parses next element in the 'in select' insertion mode. 1518 * 1519 * This internal function performs the 'in select' insertion mode 1520 * logic for the generalized WP_HTML_Processor::step() function. 1521 * 1522 * @since 6.7.0 1523 * 1524 * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. 1525 * 1526 * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inselect 1527 * @see WP_HTML_Processor::step 1528 * 1529 * @return bool Whether an element was found. 1530 */ 1531 private function step_in_select() { 1532 $token_name = $this->get_token_name(); 1533 $token_type = $this->get_token_type(); 1534 $op_sigil = '#tag' === $token_type ? ( parent::is_tag_closer() ? '-' : '+' ) : ''; 1535 $op = "{$op_sigil}{$token_name}"; 1536 1537 switch ( $op ) { 1538 /* 1539 * > Any other character token 1540 */ 1541 case '#text': 1542 $current_token = $this->bookmarks[ $this->state->current_token->bookmark_name ]; 1543 1544 /* 1545 * > A character token that is U+0000 NULL 1546 * 1547 * If a text node only comprises null bytes then it should be 1548 * entirely ignored and should not return to calling code. 1549 */ 1550 if ( 1551 1 <= $current_token->length && 1552 "\x00" === $this->html[ $current_token->start ] && 1553 strspn( $this->html, "\x00", $current_token->start, $current_token->length ) === $current_token->length 1554 ) { 1555 // Parse error: ignore the token. 1556 return $this->step(); 1557 } 1558 1559 $this->insert_html_element( $this->state->current_token ); 1560 return true; 1561 1562 /* 1563 * > A comment token 1564 */ 1565 case '#comment': 1566 case '#funky-comment': 1567 case '#presumptuous-tag': 1568 $this->insert_html_element( $this->state->current_token ); 1569 return true; 1570 1571 /* 1572 * > A DOCTYPE token 1573 */ 1574 case 'html': 1575 // Parse error: ignore the token. 1576 return $this->step(); 1577 1578 /* 1579 * > A start tag whose tag name is "html" 1580 */ 1581 case '+HTML': 1582 return $this->step_in_body(); 1583 1584 /* 1585 * > A start tag whose tag name is "option" 1586 */ 1587 case '+OPTION': 1588 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) { 1589 $this->state->stack_of_open_elements->pop(); 1590 } 1591 $this->insert_html_element( $this->state->current_token ); 1592 return true; 1593 1594 /* 1595 * > A start tag whose tag name is "optgroup" 1596 * > A start tag whose tag name is "hr" 1597 * 1598 * These rules are identical except for the treatment of the self-closing flag and 1599 * the subsequent pop of the HR void element, all of which is handled elsewhere in the processor. 1600 */ 1601 case '+OPTGROUP': 1602 case '+HR': 1603 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) { 1604 $this->state->stack_of_open_elements->pop(); 1605 } 1606 1607 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTGROUP' ) ) { 1608 $this->state->stack_of_open_elements->pop(); 1609 } 1610 1611 $this->insert_html_element( $this->state->current_token ); 1612 return true; 1613 1614 /* 1615 * > An end tag whose tag name is "optgroup" 1616 */ 1617 case '-OPTGROUP': 1618 $current_node = $this->state->stack_of_open_elements->current_node(); 1619 if ( $current_node && 'OPTION' === $current_node->node_name ) { 1620 foreach ( $this->state->stack_of_open_elements->walk_up( $current_node ) as $parent ) { 1621 break; 1622 } 1623 if ( $parent && 'OPTGROUP' === $parent->node_name ) { 1624 $this->state->stack_of_open_elements->pop(); 1625 } 1626 } 1627 1628 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTGROUP' ) ) { 1629 $this->state->stack_of_open_elements->pop(); 1630 return true; 1631 } 1632 1633 // Parse error: ignore the token. 1634 return $this->step(); 1635 1636 /* 1637 * > An end tag whose tag name is "option" 1638 */ 1639 case '-OPTION': 1640 if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) { 1641 $this->state->stack_of_open_elements->pop(); 1642 return true; 1643 } 1644 1645 // Parse error: ignore the token. 1646 return $this->step(); 1647 1648 /* 1649 * > An end tag whose tag name is "select" 1650 * > A start tag whose tag name is "select" 1651 * 1652 * > It just gets treated like an end tag. 1653 */ 1654 case '-SELECT': 1655 case '+SELECT': 1656 if ( ! $this->state->stack_of_open_elements->has_element_in_select_scope( 'SELECT' ) ) { 1657 // Parse error: ignore the token. 1658 return $this->step(); 1659 } 1660 $this->state->stack_of_open_elements->pop_until( 'SELECT' ); 1661 $this->reset_insertion_mode(); 1662 return true; 1663 1664 /* 1665 * > A start tag whose tag name is one of: "input", "keygen", "textarea" 1666 * 1667 * All three of these tags are considered a parse error when found in this insertion mode. 1668 */ 1669 case '+INPUT': 1670 case '+KEYGEN': 1671 case '+TEXTAREA': 1672 if ( ! $this->state->stack_of_open_elements->has_element_in_select_scope( 'SELECT' ) ) { 1673 // Ignore the token. 1674 return $this->step(); 1675 } 1676 $this->state->stack_of_open_elements->pop_until( 'SELECT' ); 1677 $this->reset_insertion_mode(); 1678 return $this->step( self::REPROCESS_CURRENT_NODE ); 1679 1680 /* 1681 * > A start tag whose tag name is one of: "script", "template" 1682 * > An end tag whose tag name is "template" 1683 */ 1684 case '+SCRIPT': 1685 case '+TEMPLATE': 1686 case '-TEMPLATE': 1687 return $this->step_in_head(); 1688 } 1689 1690 /* 1691 * > Anything else 1692 * > Parse error: ignore the token. 1693 */ 1694 return $this->step(); 1449 1695 } 1450 1696 … … 2037 2283 * 2038 2284 * @since 6.4.0 2285 * @since 6.7.0 Full spec support. 2039 2286 * 2040 2287 * @see https://html.spec.whatwg.org/#generate-implied-end-tags … … 2047 2294 'DT', 2048 2295 'LI', 2296 'OPTGROUP', 2297 'OPTION', 2049 2298 'P', 2299 'RB', 2300 'RP', 2301 'RT', 2302 'RTC', 2050 2303 ); 2051 2304 2052 $current_node = $this->state->stack_of_open_elements->current_node(); 2305 $no_exclusions = ! isset( $except_for_this_element ); 2306 2053 2307 while ( 2054 $current_node && $current_node->node_name !== $except_for_this_element&&2308 ( $no_exclusions || ! $this->state->stack_of_open_elements->current_node_is( $except_for_this_element ) ) && 2055 2309 in_array( $this->state->stack_of_open_elements->current_node(), $elements_with_implied_end_tags, true ) 2056 2310 ) { … … 2066 2320 * 2067 2321 * @since 6.4.0 2322 * @since 6.7.0 Full spec support. 2068 2323 * 2069 2324 * @see WP_HTML_Processor::generate_implied_end_tags … … 2072 2327 private function generate_implied_end_tags_thoroughly() { 2073 2328 $elements_with_implied_end_tags = array( 2329 'CAPTION', 2330 'COLGROUP', 2074 2331 'DD', 2075 2332 'DT', 2076 2333 'LI', 2334 'OPTGROUP', 2335 'OPTION', 2077 2336 'P', 2337 'RB', 2338 'RP', 2339 'RT', 2340 'RTC', 2341 'TBODY', 2342 'TD', 2343 'TFOOT', 2344 'TH', 2345 'THEAD', 2346 'TR', 2078 2347 ); 2079 2348 -
trunk/tests/phpunit/tests/html-api/wpHtmlProcessor.php
r58363 r58677 407 407 'NOSCRIPT' => array( 'NOSCRIPT' ), 408 408 'OBJECT' => array( 'OBJECT' ), 409 'OPTGROUP' => array( 'OPTGROUP' ),410 'OPTION' => array( 'OPTION' ),411 409 'PLAINTEXT' => array( 'PLAINTEXT' ), 412 410 'RB' => array( 'RB' ), … … 416 414 'SARCASM' => array( 'SARCASM' ), 417 415 'SCRIPT' => array( 'SCRIPT' ), 418 'SELECT' => array( 'SELECT' ),419 416 'STYLE' => array( 'STYLE' ), 420 417 'SVG' => array( 'SVG' ), -
trunk/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php
r58592 r58677 190 190 'NOSCRIPT', 191 191 'OBJECT', 192 'OPTGROUP',193 'OPTION',194 192 'PLAINTEXT', // Neutralized. 195 193 'RB', // Neutralized. … … 198 196 'RTC', // Neutralized. 199 197 'SCRIPT', 200 'SELECT',201 198 'STYLE', 202 199 'SVG', -
trunk/tests/phpunit/tests/html-api/wpHtmlSupportRequiredHtmlProcessor.php
r57508 r58677 59 59 */ 60 60 public function test_generate_implied_end_tags_needs_support() { 61 $this->ensure_support_is_added_everywhere( 'OPTGROUP' );62 $this->ensure_support_is_added_everywhere( 'OPTION' );63 61 $this->ensure_support_is_added_everywhere( 'RB' ); 64 62 $this->ensure_support_is_added_everywhere( 'RP' ); … … 80 78 $this->ensure_support_is_added_everywhere( 'CAPTION' ); 81 79 $this->ensure_support_is_added_everywhere( 'COLGROUP' ); 82 $this->ensure_support_is_added_everywhere( 'OPTGROUP' );83 $this->ensure_support_is_added_everywhere( 'OPTION' );84 80 $this->ensure_support_is_added_everywhere( 'RB' ); 85 81 $this->ensure_support_is_added_everywhere( 'RP' ); -
trunk/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php
r57508 r58677 309 309 */ 310 310 $this->ensure_support_is_added_everywhere( 'SVG' ); 311 312 // These elements are specific to SELECT scope.313 $this->ensure_support_is_added_everywhere( 'OPTGROUP' );314 $this->ensure_support_is_added_everywhere( 'OPTION' );315 311 } 316 312 }
Note: See TracChangeset
for help on using the changeset viewer.