Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When parsing, jQuery ignores anything that isn't a table and document removes the table tag

Not sure if this is a bug or a feature. When parsing html with table elements outside a table, jQuery ignores non-table elements.

<tr><td>table data</td></tr>
<div>div after will be ignored</div>

passed into $(html) becomes

<tr><td>table data</td></tr>

When passing the same html into plain javascript element.innerHTML = html becomes

table data
<div>div after will be ignored</div>

Here it is in action https://codepen.io/addbrick/pen/mprBgP

EDIT: Right after posting this I realized jQuery is removing the table elements because of the opposite behavior in the dom.

like image 503
Addison Brickey Avatar asked Dec 22 '17 07:12

Addison Brickey


1 Answers

To start with, that’s not a valid HTML.

Yes. The Jquery parser cleanup that.

If you have a close look at source code jquery, html function uses parseHTML before it actually sets the innerHTML.

And the parseHTML is calling a buildFragment and removing all the spurious elements inside the string.

Below is a part of source code of buildFragment function

// Add nodes directly
            if ( jQuery.type( elem ) === "object" ) {
                jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );

            // Convert non-html into a text node
            } else if ( !rhtml.test( elem ) ) {
                nodes.push( context.createTextNode( elem ) );

            // Convert html into DOM nodes
            } else {
                tmp = tmp || safe.appendChild( context.createElement( "div" ) );

                // Deserialize a standard representation
                tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
                wrap = wrapMap[ tag ] || wrapMap._default;

                tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

                // Descend through wrappers to the right content
                j = wrap[ 0 ];
                while ( j-- ) {
                    tmp = tmp.lastChild;
                }



// Manually add leading whitespace removed by IE
            if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
                nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[ 0 ] ) );
            }

            // Remove IE's autoinserted <tbody> from table fragments
            if ( !support.tbody ) {

                // String was a <table>, *may* have spurious <tbody>
                elem = tag === "table" && !rtbody.test( elem ) ?
                    tmp.firstChild :

                    // String was a bare <thead> or <tfoot>
                    wrap[ 1 ] === "<table>" && !rtbody.test( elem ) ?
                        tmp :
                        0;

Yes, that is where you actual passed string gets evaluated and creating DOM nodes.

And finally, div should not be used a a element inside a table directly. Can be wrapped inside a td and tr.

So why exactly jquery ignored it ? because that is not real and valid html. If you look close at html specification of Table, you can only have the given tags. In a table tag,

<!ELEMENT TABLE - -
     (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>
<!ATTLIST TABLE                        -- table element --
  %attrs;                              -- %coreattrs, %i18n, %events --
  summary     %Text;         #IMPLIED  -- purpose/structure for speech output--
  width       %Length;       #IMPLIED  -- table width --
  border      %Pixels;       #IMPLIED  -- controls frame width around table --
  frame       %TFrame;       #IMPLIED  -- which parts of frame to render --
  rules       %TRules;       #IMPLIED  -- rulings between rows and cols --
  cellspacing %Length;       #IMPLIED  -- spacing between cells --
  cellpadding %Length;       #IMPLIED  -- spacing within cells --
  >

And inside a each tag

<!ELEMENT THEAD    - O (TR)+           -- table header -->
<!ELEMENT TFOOT    - O (TR)+           -- table footer --> 

As you can see, there is no div tag directly allowed.

However in case of vanilla javascript innerHTML, no such parsing happens and browser directly interprets the string provided to dom nodes and add's them to the document.

Removes all of element's children, parses the content string and assigns the resulting nodes as children of the element.

like image 107
Suresh Atta Avatar answered Oct 21 '22 09:10

Suresh Atta