Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use self closing tags so sharif works with XHTML/XML mode #234

Closed
wants to merge 2 commits into from
Closed

Use self closing tags so sharif works with XHTML/XML mode #234

wants to merge 2 commits into from

Conversation

theseer
Copy link
Contributor

@theseer theseer commented Jun 10, 2017

This PR adjusts the way the elements are created to support XHTML/XHTML5.

The strings past in $('<foo>') are applied to the innerHTML property and thus, when the browser is in XML mode, likely because the content has been served as application/xhtml+xml or due to the XML header, must be parse-able as XML:

XML Parsing Error: mismatched tag. Expected: </ul>.  
SyntaxError: An invalid or illegal string was specified  shariff.min.js:29

The change by this PR is simply closing all elements directly. This works fine as all other changes following are going to be added as children or attributes referencing the newly created node.

Tested in Firefox 52+53 (Linux) and Chrome 57 (Linux).

@theseer
Copy link
Contributor Author

theseer commented Jun 10, 2017

From #213, comment by @sehkunde

Hey, before you start this anew could you please elaborate as to why self closing tags in JS strings are necessary? Self closing <a /> or <span /> don't seem more valid to me.

The string is applied as innerHTML to an element and thus parsed by the Browser. If the Browser is in XML compliance mode, this string must be XML compliant. On the other hand, the Browser doesn't have any issues with XML-style self-closed tags in HTML mode.

Additionally I'm not aware of a use-case for XHTML to be parsed as XML in a web browser user-agent if delivered with content-type application/xhtml+xml (the <?xml> prefix doesn't trigger the xml parser in any browser or does it?)

If content is served as application/xhtml+xml the browser is set into XML compliant parsing mode - or at least should be. Technically, the actual content is supposed to start with the XML decl. header as well, but that is not a requirement.

@compeak compeak requested a review from sehkunde June 12, 2017 06:37
Copy link
Member

@sehkunde sehkunde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, we will merge this - I would prefer closing tags to self closing, but that's just my preference :)

I know about XML mode in browsers, but would still be interested in your use-case.

And because this piqued my interest: my reading of the jQuery documentation and some googling on Stack Overflow says:

When the parameter has a single tag (with optional closing tag or quick-closing) — $( "&lt;img /&gt;" ) or $( "<img>" ), $( "&lt;a&gt;&lt;/a&gt;" ) or $( "<a>" ) — jQuery creates the element using the native JavaScript .createElement() function.

which your error message about the <ul> line contradicts ... somethings going on there.

@compeak compeak self-assigned this Jun 19, 2017
@theseer
Copy link
Contributor Author

theseer commented Jun 19, 2017

Interesting. And Confusing.

If what you said would be what is actually implemented, my change shouldn't have helped at all since both should have triggered the use of createElement.

Which actually by itself might be a problem if the HTML comes with the default namespace xmlns="http://www.w3.org/1999/xhtml". Then createElementNS should have been used. Which, at least when grep'ing over the jQuery source is not used at all in their code base. While creating the nodes technically would work, they are in the wrong namespace. I have no idea what the browser would do with that when in strict mode..

But it seems like what you found is wrong - or at least no longer how it's implemented. If I didn't misinterpret the code, jQuery uses innerHTML. I only quickly glanced over it though, so maybe I missed something.

The dom.js-Implementation shipping now also does not use createElement but innerHTML.

@sehkunde
Copy link
Member

It's in the current documentation http://api.jquery.com/jQuery/#jQuery2, but I won't dig any further - the dom.js-Implementation is relevant and should guide what we implement here.

@glaszig
Copy link
Contributor

glaszig commented Jul 12, 2017

jquery does indeed use innerHTML to leverage browser-parsing of markup. but they also employ a lot of checks and balances to be most compatible with whatever you throw at it.

even though, jquery recommends using valid markup:

To ensure cross-platform compatibility, the snippet must be well-formed. Tags that can contain other elements should be paired with a closing tag
-- http://api.jquery.com/jQuery/#jQuery2

i think @theseer's approach is the way to go. since shariff only handles the limited scope of putting buttons on a page we'd be doing well to use the most compatible markup and thereby being compatible with xhtml, jquery and our native DOMQuery.
doing all the crazy compatibility acrobatics which jquery does is outside the scope of our native DOMQuery.

regarding details of the matter, @scottschiller did a quite insightful article in 2004.

@craiq
Copy link
Contributor

craiq commented Jul 12, 2017

This approach looks not very clean to me :/
what about:
var $shareText = $("<span/>", { class: "share_text", text: self.getLocalized(service, 'shareText') });
Didn't test it. Just came to my mind, when I saw this really easy approach to add the closed tag with the content as one text line...
Docs

@glaszig
Copy link
Contributor

glaszig commented Jul 12, 2017

@craiq DOMQuery does not support this syntax because it only implements functions which are actually needed by shariff.

@craiq
Copy link
Contributor

craiq commented Jul 12, 2017

forgot you changed to this ...
then another way:
var $shareText = dom("<span/>").addClass("share_text").html(self.getLocalized(service, 'shareText'));

Edit:
should be more exact: (but it's not in the documentation of domquery, just in the code)
var $shareText = dom("<span/>").addClass("share_text").text(self.getLocalized(service, 'shareText'));

@theseer
Copy link
Contributor Author

theseer commented Jul 12, 2017

While that indeed looks like a clean(er) approach, it would modify how the HTML is constructed rather than just fixing the XHTML/XHTML5 issue.

Maybe it's a good additional PR?

@theseer
Copy link
Contributor Author

theseer commented Jul 12, 2017

You probably would like to also address the $shareLink.prepend('<span class="fa ' + service.faName + '" />'); in that case.

pmb0 added a commit that referenced this pull request Jul 14, 2017
@pmb0
Copy link
Member

pmb0 commented Jul 14, 2017

This issue should now be solved, see b230e46.

@pmb0 pmb0 closed this Jul 14, 2017
@craiq
Copy link
Contributor

craiq commented Jul 14, 2017

@pmb0 that's how it looks good :D
one little thing:
on line 166 you erased a &nbsp;
thought it was there for a reason

@pmb0
Copy link
Member

pmb0 commented Jul 14, 2017

Yes, i know -- good that it's gone. :)

@theseer theseer deleted the xhtml branch July 14, 2017 18:28
pmb0 added a commit that referenced this pull request Jul 28, 2017
Changelog:

* Added `npm run dev` command.
* Added tests for the DOM library. (glaszig)
* Added list of supported sharing services to READMEs.
* Added `{url}` placeholder to `data-mail-body` option. (stephankellermayr)
* Fixed Shariff to use `data-title` in favor of `meta[name=DC.title]` if present. ([#143](#143))
* Fixed Twitter popup opening twice when a tweet is embedded on a page. (Nebel54)
* Improved service initialization code. ([#188](#188))
* Made DOM element creation consistent. ([#234](#234))

* tag '1.26.0':
  release 1.26.0
  format changelog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants