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

SL-528: Parse start_html using ::HTML to preserve expanded tags and fix App Lab rendering #50452

Merged
merged 8 commits into from Mar 1, 2023

Conversation

ebeastlake
Copy link
Contributor

@ebeastlake ebeastlake commented Feb 24, 2023

The following PR fixes several instances in which folks are seeing App Lab levels with jumbled/misplaced UI elements on sample applications (see screenshots below). The issue is that the call to Nokogiri::XML turns expanded tags in our HTML (ex. <button ...></button>) to self-enclosing tags (ex. <button ... />), and for some reason, this "breaks" the element rendering.

It turns out the config option that fixes this issue is already in place at another point in our code. Still, I did not discover that the Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS config value was used elsewhere until I finished my investigation.

I diagnosed by looking at the diff in the HTML at every step in the localized_start_html. The start_html that serves as the argument to this function renders correctly, but as soon as we call start_html_xml = Nokogiri::XML(start_html, &:noblanks), the start_html_xml reproduces the bug in an HTML renderer. Since Nokogiri can perform its operations on the self-enclosing tags, we don't need to expand the tags until before we return them from localized_start_html. This is good because the config option we need to pass to expand all HTML tags is a valid argument to start_html_xml.serialize but cannot be passed to Nokogiri::XML to keep them from getting collapsed in the first place.

NOTE: This config option will expand all tags, including any that were self-closing in our start_html. Theoretically, expanding tags meant to be self-enclosing could also cause issues, but expanding all tags seems to solve most of our problems (see screenshots below).

For posterity/documentation, sparklemotion/nokogiri#2324 describes a similar issue, but in the opposite direction (self-closing tags being converted to expanded tags), and is the issue that eventually led me to my fix.

I do not know why using self-enclosing tags instead of expanded tags would cause the issue, but given the volume of tickets we're receiving, it seems worth getting a fix out while we continue the investigation.

Links

Jira tickets:
https://codedotorg.atlassian.net/browse/SL-528
https://codedotorg.atlassian.net/browse/P20-43

Zendesk tickets:
https://codeorg.zendesk.com/agent/tickets/427471
https://codeorg.zendesk.com/agent/tickets/424893
https://codeorg.zendesk.com/agent/tickets/430408

Testing story

Before
Note: These screenshots were generated by resetting version history while the page is in Danish on studio.code.org. I have reproduced this with other languages, including Spanish and French.

https://studio.code.org/s/csp5-2022/lessons/2/levels/1
Screen Shot 2023-02-27 at 12 10 26 PM

https://studio.code.org/s/csp5-2022/lessons/10/levels/1
Screen Shot 2023-02-27 at 12 25 20 PM

https://studio.code.org/s/csp7-2022/lessons/4/levels/2
Screen Shot 2023-02-27 at 12 20 15 PM

https://studio.code.org/s/csp7-2022/lessons/3/levels/6
Screen Shot 2023-02-27 at 12 43 59 PM

After
Note: These screenshots were generated by resetting version history while the page is in Danish on localhost-studio.code.org:3000. I have reproduced this with other languages, including Spanish and French.

http://localhost-studio.code.org:3000/s/csp5-2022/lessons/2/levels/1
Screen Shot 2023-02-27 at 12 28 06 PM

http://localhost-studio.code.org:3000/s/csp5-2022/lessons/10/levels/1
Screen Shot 2023-02-27 at 12 29 14 PM

http://localhost-studio.code.org:3000/s/csp7-2022/lessons/4/levels/2
Screen Shot 2023-02-27 at 12 30 54 PM

http://localhost-studio.code.org:3000/s/csp7-2022/lessons/3/levels/6
Screen Shot 2023-02-27 at 12 45 05 PM
The screenshot above is not totally fixed because of another bug with how Nokogiri handles spaces, but it is much better than the original! I will file a follow-up ticket and link here.

Deployment strategy

Follow-up work

Privacy

Security

Caching

PR Checklist:

  • Tests provide adequate coverage
  • Privacy and Security impacts have been assessed
  • Code is well-commented
  • New features are translatable or updates will not break translations
  • Relevant documentation has been added or updated
  • User impact is well-understood and desirable
  • Pull Request is labeled appropriately
  • Follow-up work items (including potential tech debt) are tracked and linked

@ebeastlake ebeastlake marked this pull request as ready for review February 27, 2023 21:01
@ebeastlake ebeastlake requested review from mgc1194, a team, daynew and wilkie February 27, 2023 21:24
@breville
Copy link
Member

Can we add a unit test to this PR? It seems the ideal situation for one.

@ebeastlake
Copy link
Contributor Author

Yes, definitely!

:blockly,
name: 'test localized_start_html',
)
start_html = '<div><button id="leftBottomButton" style="padding: 0px; margin: 0px; border-style: solid; background-color: rgb(68, 44, 46); border-radius: 20px; border-width: 0px; border-color: rgb(255, 255, 255); color: rgb(255, 255, 255); font-family: Verdana, Geneva, sans-serif; font-size: 15px; position: absolute; left: 10px; top: 250px; background-size: contain; background-position: 50% 50%; background-repeat: no-repeat; width: 45px; height: 190px;" data-canonical-image-url="icon://fa-long-arrow-left" data-icon-color="#ffffff"></button><label style="margin: 0px; padding: 2px; line-height: 1; overflow: hidden; overflow-wrap: break-word; max-width: 320px; border-style: solid; background-color: rgb(254, 234, 230); border-width: 0px; border-color: rgb(255, 255, 255); color: rgb(68, 44, 46); font-family: Arial, Helvetica, sans-serif; position: absolute; left: 0px; top: 4.44089e-16px; border-radius: 4px; height: 40px; width: 320px; font-size: 36px; text-rendering: optimizespeed;" id="appName"> &nbsp;Outfit Picker</label></div>'
Copy link
Member

Choose a reason for hiding this comment

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

Could we reduce this to a more minimal repro case? It might be a bit easier to understand what we are verifying...

start_html_xml.serialize(save_with: XML_OPTIONS).strip
# NO_EMPTY_TAGS used because <element /> blocks fail to render correctly but
# <element></element> works, see: https://codedotorg.atlassian.net/browse/SL-528.
# TODO: Should we add UTF-8 encoding? We have it here: https://github.com/code-dot-org/code-dot-org/blob/staging/dashboard/app/models/levels/blockly.rb#L520.
Copy link
Member

Choose a reason for hiding this comment

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

nit: can we put the long URL on a new line?

Copy link
Contributor

@mgc1194 mgc1194 left a comment

Choose a reason for hiding this comment

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

We should use Nokogiri::HTML.fragment(start_html, &:noblanks) instead of Nokogiri::XML.fragment(start_html, &:noblanks).
The start_html is a well-formed html fragment that gets injected as into the level document.
It doesn't make sense to use XML here, as it is inducing undesired changes in the html tags (not only creating self-enclosing tags, but closing tags).

@ebeastlake
Copy link
Contributor Author

Yep, going to change based on our conversation. I don't think we need the argument to serialize anymore in this case, but I will confirm.

@mgc1194
Copy link
Contributor

mgc1194 commented Feb 28, 2023

Exactly.
start_html_doc.to_html(encoding: 'UTF-8') should work. We need the UTF-8 encoding as this localized html will contain characters in any language.

Copy link
Contributor

@mgc1194 mgc1194 left a comment

Choose a reason for hiding this comment

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

Awesome! This switch to HTML parsing fixes multiple issues. Thanks!

@ebeastlake
Copy link
Contributor Author

Note: The screenshots in this PR were tested with the original fix, which was replaced with an alternate approach suggested by @mgc1194 (see aa37b1a). Most of the screenshots are fixed in the same way, but Mario's approach actually leaves the Order Up! app in an even better state (see below).

Screen Shot 2023-03-01 at 8 11 30 AM

@ebeastlake ebeastlake changed the title serialize start_html_xml using expanded html tags SL-528: Parse start_html using ::HTML to preserve expanded tags and fix App Lab rendering Mar 1, 2023
@mgc1194 mgc1194 merged commit cd99135 into staging Mar 1, 2023
@mgc1194 mgc1194 deleted the task/sl-528/translation-start-over-bug branch March 1, 2023 21:14
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.

None yet

3 participants