105105 * - Formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
106106 * - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP.
107107 * - Links: A.
108- * - Lists: DL .
108+ * - Lists: DD, DL, DT, LI, OL, LI .
109109 * - Media elements: AUDIO, CANVAS, FIGCAPTION, FIGURE, IMG, MAP, PICTURE, VIDEO.
110110 * - Paragraph: P.
111111 * - Phrasing elements: ABBR, BDI, BDO, CITE, DATA, DEL, DFN, INS, MARK, OUTPUT, Q, SAMP, SUB, SUP, TIME, VAR.
@@ -648,10 +648,12 @@ private function step_in_body() {
648648 case '+MAIN ' :
649649 case '+MENU ' :
650650 case '+NAV ' :
651+ case '+OL ' :
651652 case '+P ' :
652653 case '+SEARCH ' :
653654 case '+SECTION ' :
654655 case '+SUMMARY ' :
656+ case '+UL ' :
655657 if ( $ this ->state ->stack_of_open_elements ->has_p_in_button_scope () ) {
656658 $ this ->close_a_p_element ();
657659 }
@@ -685,9 +687,11 @@ private function step_in_body() {
685687 case '-MAIN ' :
686688 case '-MENU ' :
687689 case '-NAV ' :
690+ case '-OL ' :
688691 case '-SEARCH ' :
689692 case '-SECTION ' :
690693 case '-SUMMARY ' :
694+ case '-UL ' :
691695 if ( ! $ this ->state ->stack_of_open_elements ->has_element_in_scope ( $ tag_name ) ) {
692696 // @todo Report parse error.
693697 // Ignore the token.
@@ -755,6 +759,109 @@ private function step_in_body() {
755759 $ this ->state ->stack_of_open_elements ->pop_until ( '(internal: H1 through H6 - do not use) ' );
756760 return true ;
757761
762+ /*
763+ * > A start tag whose tag name is "li"
764+ * > A start tag whose tag name is one of: "dd", "dt"
765+ */
766+ case '+DD ' :
767+ case '+DT ' :
768+ case '+LI ' :
769+ $ this ->state ->frameset_ok = false ;
770+ $ node = $ this ->state ->stack_of_open_elements ->current_node ();
771+ $ is_li = 'LI ' === $ tag_name ;
772+
773+ in_body_list_loop:
774+ /*
775+ * The logic for LI and DT/DD is the same except for one point: LI elements _only_
776+ * close other LI elements, but a DT or DD element closes _any_ open DT or DD element.
777+ */
778+ if ( $ is_li ? 'LI ' === $ node ->node_name : ( 'DD ' === $ node ->node_name || 'DT ' === $ node ->node_name ) ) {
779+ $ node_name = $ is_li ? 'LI ' : $ node ->node_name ;
780+ $ this ->generate_implied_end_tags ( $ node_name );
781+ if ( $ node_name !== $ this ->state ->stack_of_open_elements ->current_node ()->node_name ) {
782+ // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
783+ }
784+
785+ $ this ->state ->stack_of_open_elements ->pop_until ( $ node_name );
786+ goto in_body_list_done;
787+ }
788+
789+ if (
790+ 'ADDRESS ' !== $ node ->node_name &&
791+ 'DIV ' !== $ node ->node_name &&
792+ 'P ' !== $ node ->node_name &&
793+ $ this ->is_special ( $ node ->node_name )
794+ ) {
795+ /*
796+ * > If node is in the special category, but is not an address, div,
797+ * > or p element, then jump to the step labeled done below.
798+ */
799+ goto in_body_list_done;
800+ } else {
801+ /*
802+ * > Otherwise, set node to the previous entry in the stack of open elements
803+ * > and return to the step labeled loop.
804+ */
805+ foreach ( $ this ->state ->stack_of_open_elements ->walk_up ( $ node ) as $ item ) {
806+ $ node = $ item ;
807+ break ;
808+ }
809+ goto in_body_list_loop;
810+ }
811+
812+ in_body_list_done:
813+ if ( $ this ->state ->stack_of_open_elements ->has_p_in_button_scope () ) {
814+ $ this ->close_a_p_element ();
815+ }
816+
817+ $ this ->insert_html_element ( $ this ->state ->current_token );
818+ return true ;
819+
820+ /*
821+ * > An end tag whose tag name is "li"
822+ * > An end tag whose tag name is one of: "dd", "dt"
823+ */
824+ case '-DD ' :
825+ case '-DT ' :
826+ case '-LI ' :
827+ if (
828+ /*
829+ * An end tag whose tag name is "li":
830+ * If the stack of open elements does not have an li element in list item scope,
831+ * then this is a parse error; ignore the token.
832+ */
833+ (
834+ 'LI ' === $ tag_name &&
835+ ! $ this ->state ->stack_of_open_elements ->has_element_in_list_item_scope ( 'LI ' )
836+ ) ||
837+ /*
838+ * An end tag whose tag name is one of: "dd", "dt":
839+ * If the stack of open elements does not have an element in scope that is an
840+ * HTML element with the same tag name as that of the token, then this is a
841+ * parse error; ignore the token.
842+ */
843+ (
844+ 'LI ' !== $ tag_name &&
845+ ! $ this ->state ->stack_of_open_elements ->has_element_in_scope ( $ tag_name )
846+ )
847+ ) {
848+ /*
849+ * This is a parse error, ignore the token.
850+ *
851+ * @todo Indicate a parse error once it's possible.
852+ */
853+ return $ this ->step ();
854+ }
855+
856+ $ this ->generate_implied_end_tags ( $ tag_name );
857+
858+ if ( $ tag_name !== $ this ->state ->stack_of_open_elements ->current_node ()->node_name ) {
859+ // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
860+ }
861+
862+ $ this ->state ->stack_of_open_elements ->pop_until ( $ tag_name );
863+ return true ;
864+
758865 /*
759866 * > An end tag whose tag name is "p"
760867 */
@@ -1223,6 +1330,9 @@ private function close_a_p_element() {
12231330 */
12241331 private function generate_implied_end_tags ( $ except_for_this_element = null ) {
12251332 $ elements_with_implied_end_tags = array (
1333+ 'DD ' ,
1334+ 'DT ' ,
1335+ 'LI ' ,
12261336 'P ' ,
12271337 );
12281338
@@ -1248,6 +1358,9 @@ private function generate_implied_end_tags( $except_for_this_element = null ) {
12481358 */
12491359 private function generate_implied_end_tags_thoroughly () {
12501360 $ elements_with_implied_end_tags = array (
1361+ 'DD ' ,
1362+ 'DT ' ,
1363+ 'LI ' ,
12511364 'P ' ,
12521365 );
12531366
0 commit comments