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 & Crystal Balls"> <img src="https://d262ilb51hltx0.cloudfront.net/fit/c/80/80/1*39vzf6qq66tTWJP8LGNz7Q.png" class="avatar-image avatar-image--medium" title="Hot Dogs & 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 & Crystal Balls" rel="author" class="link link--primary">Hot Dogs & Crystal Balls </a> </h3> <p class="card-description">Observations & 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>