Implementing </div> closing <span>, and friends

James C <[email protected]>
Newsgroups gmane.comp.web.dillo.devel
Message-ID <CACZ9Q6hsB3nf7q5bOHw3YEneOJuN2Jhy5=2uXii3J-fkUh5DbA@mail.gmail.com>
Hello all,

[Sorry if this is a dup; gmail may be playing tricks on me.]

This page displays, with distortions, in dillo 3.0.4, but the image
does not display after commit 317f010:
https://medium.com/@verynicetweets/getting-out-of-the-house-is-so-hard-these-days-68d6c36b5f44

A partially cleaned-up and stripped version is attached, where the
comment block shows a suppression of the problem.  The page is
illegal: two unclosed <span>s interfere with a </div> and the
following <div>.

There is code around html.cc:1355, which is intended to implement
heuristics to close unclosed tags but, in the cases where it is
triggered, no tags are closed.

Here is a patch which I think implements the intent of the heuristics:
-----------------
$ hg diff
diff -r 26378f85c4ea src/html.cc
--- a/src/html.cc	Sun Sep 14 09:56:22 2014 +0000
+++ b/src/html.cc	Mon Sep 15 18:13:21 2014 +1200
@@ -1355,7 +1355,9 @@
               i_SELECT = a_Html_tag_index("select"),
               i_TEXTAREA = a_Html_tag_index("textarea");
    int w3c_mode = !prefs.w3c_plus_heuristics;
-   int stack_idx, tag_idx, matched = 0, expected = 0;
+   // TODO: If there was a clean way of never having a tag index zero,
+   // (it's currently <a>), then expected_idx could be prettier.
+   int stack_idx, tag_idx, matched = 0, expected_idx = -1, skipped = 0;
    TagInfo new_tag = Tags[new_idx];

    /* Look for the candidate tag to close */
@@ -1368,26 +1370,42 @@
          break;
       } else if (Tags[tag_idx].EndTag == 'O') {
          /* skip an optional tag */
+         ++skipped;
          continue;
       } else if ((new_idx == i_BUTTON && html->InFlags & IN_BUTTON) ||
                  (new_idx == i_SELECT && html->InFlags & IN_SELECT) ||
                  (new_idx == i_TEXTAREA && html->InFlags & IN_TEXTAREA)) {
          /* let these elements close tags inside them */
+         ++skipped;
          continue;
       } else if (w3c_mode || Tags[tag_idx].TagLevel >= new_tag.TagLevel) {
          /* this is the tag that should have been closed */
-         expected = 1;
-         break;
+         /* skip it as if it were optional, but complain */
+         ++skipped;
+         if (-1 == expected_idx) {
+            // ie this is the first thing we're unwinding
+            expected_idx = tag_idx;
+         }
+         continue;
       }
    }

+   // Either or both matched and expected_idx could now be set
+
+   // TODO: decide whether to carry line numbers in the parser state stack,
+   // in order to report them here.
+
    if (matched) {
+      if (-1 != expected_idx) {
+         BUG_MSG("Unexpected closing tag: </%s> -- expected </%s>",
+                 new_tag.name, Tags[expected_idx].name);
+      }
+
       Html_tag_cleanup_to_idx(html, stack_idx);
-   } else if (expected) {
-      BUG_MSG("Unexpected closing tag: </%s> -- expected </%s>.",
-              new_tag.name, Tags[tag_idx].name);
    } else {
-      BUG_MSG("Unexpected closing tag: </%s>.", new_tag.name);
+      BUG_MSG("Unexpected closing tag: </%s>"
+              " -- explored %d layer(s) and not closed.",
+              new_tag.name, skipped);
    }
 }

-----------------

Closing tags that match no opening tag (I used </area>, which is
illegal) do not cause catastrophic failure.  So far, it has not broken
on my usual workload.  Gmail is noisy, so I wonder if something's
going wrong there, but it looks fairly normal.

I have no good idea what a general test suite for this code looks
like.  If someone wants to point me toward related tests, then I will
think about extending them.

Regards,
James.

_______________________________________________
Dillo-dev mailing list
[email protected]
http://lists.dillo.org/cgi-bin/mailman/listinfo/dillo-dev
getting-out-11.html (text/html, 7.1 KB)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://dnqgz544uhbo8.cloudfront.net/_/fp/css/main-base.UmSC9IyQiUkQl7ATxs7Vzw.css">
</head>
<body itemscope itemtype="http://schema.org/Article" class="template-flex-article os- js-loading ">
<div class="site-main" id="container">
<div class="surface">
<div id="prerendered" class="screenContent">
<div class="metabar u-clearfix metabar--top is-onImagelessCoverPost metabar--postArticle ">

<div class="metabar-block u-alignLeft">
<span class="postMetaInline postMetaInline--authorDateline">
<span class="postMetaInline postMetaInline--date"> on 
</div>

<!-- this combination makes the image appear
</span></span>
</div>
-->

<div class="metabar-block u-alignRight">
</div>
</div>
<div class="logo-container">
</div>
<div class="editorSidebar">
<div class="editorSidebar-controls">
<ul class="tabs">
<li class="tabs-item tabs-item--info is-active">
<button class="button button--chromeless" title="Info" data-action="show-tab" data-action-value="info">Info
</button>
</li>
<li class="tabs-item tabs-item--history">
<button class="button button--chromeless" title="History" data-action="show-tab" data-action-value="history">History
</button>
</li>
</ul>
<div class="button-set u-alignRight">
<button class="button button--circle" title="Show more actions" data-action="show-post-actions-popover">
<span class="icon icon--arrowDownThin">
</span>
</button>
<button class="button button--publish button--primary" title="Publish"data-action="publish">Publish
</button>
</div>
</div>
<div class="editorSidebar-content">
<div class="postMetaBlock">
<div class="postMetaBlock-title">
</div>
<div class="postMetaBlock-titleErrorMessage u-danger">
</div>
<div class="postMetaBlock-subtitle">
</div>
<div class="postMetaBlock-description">Change the title or subtitle to customize how your story is presented across Medium.
</div>
<div class="postMetaBlock-help">
<p class="postMetaBlock-label">Welcome to the new, more flexible Medium editor
</p>
<a class="button button--primary button--link" title="Learn about the new editor features" href="//medium.com/the-story/new-editor-features-title-images-and-more-5588495ec3c0" target="_blank">Learn about the new editor features
</a>
</div>
<div class="postMetaBlock-draftLink u-hide">
<p class="postMetaBlock-label">Don’t write alone
</p>
<p class="postMetaBlock-description">Copy and send this draft link to anyone. They’ll be able to leave you notes before you publish.
</p>
<input class="textInput textInput--chromeless u-fillWidth js-draftUrl">
</div>
<div class="postMetaBlock-submitDraft">
</div>
<div class="js-postMetaBlock-featured postMetaBlock-featured u-hide">
<button class="button button--circle button--small button--toggle" id="postMetaBlock-featuredInput" title="Set as featured in collection" data-action="toggle-post-featured">
<span class="icon icon--check">
</span>
</button>
<label class="label postMetaBlock-label" for="postMetaBlock-featuredInput">Set as featured in collection
</label>
</div>
</div>
<div class="postHistory">
</div>
</div>
</div>
<article class="postArticle  is-languageTier1" data-allow-notes="true">
<section class="postWrapper postWrapper--contain">
<div class="postWrapper-inner">
<div class="postContent">
<div class="postContent-inner">
<div class="notesSource">
<div class="postField postField--body">
<section name="fa9a" class=" section--first section--last">
<div class="section-divider layoutSingleColumn">
<hr class="section-divider">
</div>
<div class="section-content">
<div class="section-inner layoutSingleColumn">
<h3 name="379b" class="graf--h3 graf--first">
<a id="379b">
</a>Getting Out of the House is So Hard, These Days. (comic)
</h3>
<p name="0d3a" class="graf--p">
<a id="0d3a">
</a>A caffeinated old man struggles to move on.
</p>
</div>
<div class="section-inner sectionLayout--outsetColumn">
<figure name="49ba" class="graf--figure postField--outsetCenterImage graf--last">
<a id="49ba">
</a>
<div class="aspectRatioPlaceholder is-locked" style="max-width: 1020px; max-height: 4246px;">
<div class="aspect-ratio-fill" style="padding-bottom: 416.3%;">
</div>
<img class="graf-image" data-image-id="1*PEJ-J0l-yZlu9bVRMGikzQ.jpeg" data-width="1024" data-height="4263" data-action="zoom" data-action-value="1*PEJ-J0l-yZlu9bVRMGikzQ.jpeg" src="https://d262ilb51hltx0.cloudfront.net/max/1200/1*PEJ-J0l-yZlu9bVRMGikzQ.jpeg">
</div>
</figure>
</div>
</div>
</section>
</div>
</div>
<div class="postFooter-actions supplementalPostContent layoutSingleColumn">
<div class="button-set">
<button class="button button--large button--toggle button--primary button--suffix button--recommend js-recommendButton u-noUserSelect "data-action="sign-in-prompt"data-requires-token="true"data-popover-type="sign-in"data-redirect="/_/vote/p/68d6c36b5f44"data-popover="Sign in to recommend" data-popover-position="bottom" data-popover-signin-type="recommend"title="Recommend this post">
<span class="icon icon--heart">
</span>
<span class="button-label recommendButton-label" data-suffix="ed">Recommend
</span>
</button>
<div class="postfooter-secondaryActions">
<a class="button button--chromeless" title="Share this post on Twitter" data-action="share-on-twitter" data-action-value="68d6c36b5f44">
<i class="icon icon--twitter">
</i>
</a>
<a class="button button--chromeless" title="Share this post on Facebook" data-action="share-on-facebook" data-action-value="68d6c36b5f44">
<i class="icon icon--facebook">
</i>
</a>
</div>
</div>
</div>
<div class="postFollowUps supplementalPostContent layoutSingleColumn">
</div>
<div class="postFooter-cards supplementalPostContent layoutSingleColumn">
<div >
<h4 class="cards-heading">Written by
</h4>
<ul class="cards">
<li class="card card-user">
<div class="card-imageWrapper ">
<a href="/@verynicetweets" class="avatar avatar--medium" title="Go to the profile of Hot Dogs &amp; Crystal Balls">
<img src="https://d262ilb51hltx0.cloudfront.net/fit/c/80/80/1*39vzf6qq66tTWJP8LGNz7Q.png" class="avatar-image avatar-image--medium" title="Hot Dogs &amp; Crystal Balls">
</a>
</div>
<div class="card-content">
<h3 class="card-name">
<a href="/@verynicetweets" data-id="89ecb6dd28ee" title="Go to the profile of Hot Dogs &amp; Crystal Balls" rel="author" class="link link--primary">Hot Dogs &amp; Crystal Balls
</a>
</h3>
<p class="card-description">Observations &amp; Anticipations. Comics, Stories, Poetry, Internets.
</p>
<div class="button-set">
<button class="button button--small button--follow button--toggle button--suffix button--primary u-noUserSelect "data-action="sign-in-prompt"data-requires-token="true"data-popover-type="sign-in"data-redirect="/_/subscribe/user/89ecb6dd28ee"data-popover="Sign in to follow this user" data-popover-position="bottom" data-popover-signin-type="">
<span class="button-label follow-label" data-suffix="ing">Follow
</span>
<span class="button-label button-count">597
</span>
</button>
</div>
</div>
</li>
</ul>
</div>
</div>
<div class="js-responses responses--wrapper supplementalPostContent layoutSingleColumn">
</div>
</div>
</div>
</div>
</section>
<footer class="post-footer supplementalPostContent">
</footer>
</article>
</div>
</div>
</div>
<div class="loadingBar">
</div>
</body>
</html>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.