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

Escaped characters inside <noscript> on Safari #107

Closed
hacknug opened this issue Feb 7, 2019 · 6 comments
Closed

Escaped characters inside <noscript> on Safari #107

hacknug opened this issue Feb 7, 2019 · 6 comments

Comments

@hacknug
Copy link

hacknug commented Feb 7, 2019

I've encountered a weird issue on Safari where special characters inside a <noscript> tag get escaped when using swup (first load works fine).

The issue seems to be related to how .innerHTML works and I was able to work around it using .innerText instead (.textContent seems to work too). This is most probably the line causing the issue: https://github.com/gmrchk/swup/blob/master/src/modules/getDataFromHtml.js#L6

I was trying to do some custom layout with elements inside this <noscript> when JavaScript is available, which will fallback to a simple flexbox-wrapped grid layout.

Here's the code I wrote that solves the issue. Note the use of a helper function named decodeHTML that helps getting those escaped characters unescaped again.

var getMasonryItems = function (container, selector) {
  var parser = new DOMParser()
  var parsedHtml = parser.parseFromString(decodeHTML(container.innerText), 'text/html')
  // Both .innerText and .textContent seem to work. Don't use .innerHTML !!!

  return parsedHtml.querySelectorAll(selector)
}
var decodeHTML = function (html) {
  var textarea = document.createElement('textarea')
  textarea.innerHTML = html
  return textarea.value
}

var items = getMasonryItems(document.querySelector('noscript'), '[data-item]')
@gmrchk
Copy link
Member

gmrchk commented Feb 18, 2019

Hi, thanks for reporting!

I've encountered a similar issue in no longer used IE versions but didn't know Safari suffers a similar problem.

noscript tags serve as a fallback for disabled JavaScript, but that means swup won't work in that case as well (and can't replace the content of noscript tags incorrectly)... so just to make sure I understand the problem in your use case:
Are you using the contents of the noscript tags in your JS? Are the characters escaped in the noscript tags the tag brackets (< and >)?

@hacknug
Copy link
Author

hacknug commented Feb 18, 2019

Yeah, I'm using <noscript> as a fallback layout for when JS is disabled, and yes, it looks like the characters being escaped are < and >.

In case JS is enabled, I'm parsing the contents of the <noscript> element using DOMParser() and building the custom layout I need on my pages given the elements in there (italics because since JS is enabled, the contents are not nodes of the DOM but just text).

Here's a screenshot showing the contents of .innerHTML, .innerText, and .textContent, on first load and after the first swup transition (where the & ends up being escaped).

captura de pantalla 2019-02-18 a las 14 03 46

@gmrchk
Copy link
Member

gmrchk commented Feb 18, 2019

I see. Thanks for the explanation!

I would maybe consider avoiding the possibly unnecessary processing of noscript tag and just have the elements rendered in a fallback state by default. When the JS kicks in, masonry could just use elements already available on the page. I haven't used masonry in while, so maybe there is some good reason why you rather create the elements from noscript with JS.

It seems like a really specific issue (only Safari when processing noscript tag, which I don't think is a common thing to do), and I would like to avoid adding some more processing to the swup content replacement flow. Right now it simply replaces the whole block of HTML, and we would need to search for each noscript tag and process any unnecessary escaping as well.

How about we "don't fix" this issue and add the issue into the Common Issues for future reference?

@hacknug
Copy link
Author

hacknug commented Feb 19, 2019

It's actually a custom masonry plugin I wrote that handles layout in a different way than any other implementation (no absolute positioning and resize watching). The reason I use <noscript> is to avoid showing any of the items before any logic's run.

Sound good to me. Do you want me to open a PR with the notes?

@gmrchk
Copy link
Member

gmrchk commented Feb 21, 2019

That's pretty cool! Would love to see the outcome if you have an example somewhere. I always hated that long list of elements with absolute positions...

How about this?

@gmrchk gmrchk closed this as completed Feb 21, 2019
@hacknug
Copy link
Author

hacknug commented Feb 22, 2019

Looks good to me!

Here's a gist where I dumped the different pieces that make it work: https://gist.github.com/hacknug/4b0461240054a9cdcad28e427a3014a8

I also just discovered there a react/vue component that does pretty much the same:

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

No branches or pull requests

2 participants