This is a result of a little background project I've been working on since July. This PR teaches our HTML parser to simplify the document structure and remove most spacing-related quirks that plague HTML. It also implements support for display:none attribute and unbreakable spaces ( ), seen in a number of Living Atlas maps.
New code walks the node tree, skips empty/useless nodes, and merges as many single-child nodes as possible. It then finds groups of inline nodes that flow together, and adjusts trailing/leading whitespace among and around these nodes.
Although this adds some complexity to our HTML parser, it benefits all supported platforms in terms of fidelity (more accurate rendering) and performance (much fewer UI element needed to render a popup). Here are some concrete examples:
This is a result of a little background project I've been working on since July. This PR teaches our HTML parser to simplify the document structure and remove most spacing-related quirks that plague HTML. It also implements support for
display:none
attribute and unbreakable spaces (
), seen in a number of Living Atlas maps.New code walks the node tree, skips empty/useless nodes, and merges as many single-child nodes as possible. It then finds groups of inline nodes that flow together, and adjusts trailing/leading whitespace among and around these nodes.
Although this adds some complexity to our HTML parser, it benefits all supported platforms in terms of fidelity (more accurate rendering) and performance (much fewer UI element needed to render a popup). Here are some concrete examples:
Example 1: Social Vulnerability Index
https://www.arcgis.com/apps/mapviewer/index.html?webmap=2c8fdc6267e4439e968837020e7618f3 This popup has a number of empty paragraphs, which were getting collapsed by browsers, but wasted a lot of space in PopupViewer.
Popup HTML
```html2018 Overall SVI Score:
0.82
Possible scores range from 0 (lowest vulnerability) to 1 (highest vulnerability).
A score of 0.82 indicates high vulnerability.
Data Dictionary
Original document tree
``` Document { children=1 } Block { children=9 } Block { children=1 } Span { children=1 } Span { size=1 children=1 } Text { text="2018 Overall SVI Score:" } Block { children=1 } Span { bold=True children=1 } Span { size=1.5 children=1 } Text { text="0.82" } Block { children=1 } Span { size=1 children=1 } Span { } Block { children=1 } Span { size=1 children=5 } Span { children=1 } Text { text="Possible scores range from " } Span { bold=True children=1 } Text { text="0 " } Span { children=1 } Text { text="(lowest vulnerability) to " } Span { bold=True children=1 } Text { text="1" } Span { children=1 } Text { text=" (highest vulnerability)." } Block { children=1 } Span { size=1 children=1 } Span { } Block { children=1 } Span { size=1 children=5 } Span { children=1 } Text { text="A score of " } Span { bold=True children=1 } Text { text="0.82 " } Span { children=1 } Text { text="indicates " } Span { bold=True children=1 } Text { text="high " } Span { children=1 } Text { text="vulnerability." } Block { children=1 } Span { size=1 children=1 } Span { } Block { children=1 } Link { color=Color [A=255, R=109, G=109, B=109] text="https://svi.cdc.gov/Documents/Data/2018_SVI_Data/SVI2018Documentation.pdf" children=1 } Span { children=1 } Span { size=1 children=1 } Text { text="Data Dictionary " } Block { children=1 } Span { } ```Simplified document tree
``` Document { children=1 } Block { children=5 } Block { children=1 } Text { size=1 text="2018 Overall SVI Score:" } Block { children=1 } Text { bold=True size=1.5 text="0.82" } Block { size=1 children=5 } Text { text="Possible scores range from " } Text { bold=True text="0 " } Text { text="(lowest vulnerability) to " } Text { bold=True text="1" } Text { text=" (highest vulnerability)." } Block { size=1 children=5 } Text { text="A score of " } Text { bold=True text="0.82 " } Text { text="indicates " } Text { bold=True text="high " } Text { text="vulnerability." } Block { children=1 } Link { color=Color [A=255, R=109, G=109, B=109] text="https://svi.cdc.gov/Documents/Data/2018_SVI_Data/SVI2018Documentation.pdf" children=1 } Text { size=1 text="Data Dictionary" } ```Example 2: NWS Wind Speed forecast
https://www.arcgis.com/apps/mapviewer/index.html?webmap=a7b007939f02406ca2b8559a821c08ab These popups have many ignorable line break and extra spaces/newlines between paragraphs, which caused bad spacing and bloated the visual tree.
Popup HTML
```htmlWind Speed Forecast
Fresh Breeze (18-24mph, 29-38km/h)
From
10/12/2023 02:00 PM
Until
10/12/2023 04:58 PM
Source: The National Digital Forecast Database produced by the National Weather Service
Data updated every 3 hours
```Original document tree
``` Document { children=17 } Block { align=Center children=4 } Span { bold=True children=1 } Span { size=1.5 children=1 } Text { text="Wind Speed Forecast" } Span { size=0.75 children=2 } Break { } Text { text=" " } Span { size=0.8333333333333334 children=1 } Text { text=" " } Span { size=0.75 } Text { text=" " } Block { align=Center children=2 } Span { bold=True children=1 } Span { size=1.125 children=1 } Span { color=Color [A=255, R=0, G=0, B=255] children=1 } Text { text="Fresh Breeze (18-24mph, 29-38km/h)" } Span { size=0.75 } Text { text=" " } Block { children=1 } Span { size=1 children=1 } Text { text=" " } Text { text=" " } Block { align=Center children=2 } Span { size=1.125 children=1 } Text { text="From" } Span { size=0.75 } Text { text=" " } Block { align=Center children=2 } Span { bold=True children=1 } Span { size=0.75 children=3 } Text { text="10/12/2023 02:00 PM" } Break { } Text { text=" " } Span { size=0.75 } Text { text=" " } Block { align=Center children=2 } Span { size=1.125 children=1 } Text { text="Until" } Span { size=0.75 } Text { text=" " } Block { align=Center children=2 } Span { bold=True children=1 } Span { size=0.75 children=1 } Text { text="10/12/2023 04:58 PM" } Span { italic=True children=1 } Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] } Text { text=" " } Block { children=1 } Span { italic=True children=1 } Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] children=3 } Text { text="Source: The National Digital Forecast Database produced by the National Weather Service" } Break { } Text { text=" " } Text { text=" " } Block { children=1 } Span { italic=True children=1 } Span { size=0.75 color=Color [A=255, R=105, G=105, B=105] children=1 } Text { text="Data updated every 3 hours" } ```Simplified document tree
``` Document { children=8 } Block { align=Center children=1 } Text { bold=True size=1.5 text="Wind Speed Forecast" } Block { align=Center children=1 } Text { bold=True size=1.125 color=Color [A=255, R=0, G=0, B=255] text="Fresh Breeze (18-24mph, 29-38km/h)" } Block { align=Center children=1 } Text { size=1.125 text="From" } Block { bold=True size=0.75 align=Center children=1 } Text { text="10/12/2023 02:00 PM" } Block { align=Center children=1 } Text { size=1.125 text="Until" } Block { align=Center children=1 } Text { bold=True size=0.75 text="10/12/2023 04:58 PM" } Block { italic=True size=0.75 color=Color [A=255, R=105, G=105, B=105] children=1 } Text { text="Source: The National Digital Forecast Database produced by the National Weather Service" } Block { children=1 } Text { italic=True size=0.75 color=Color [A=255, R=105, G=105, B=105] text="Data updated every 3 hours" } ```Example 3: Energielabels (Netherlands Enterprise Agency)
https://www.arcgis.com/apps/mapviewer/index.html?webmap=22f951f0951f4922b800021b0ba98539 These popups have many collapsible table rows/cells and hidden elements, which caused Runtime to render completely differently from the browser.
Popup HTML
```html Er is 1 energielabel geregistreerd in dit pand met bouwjaar 1888Dit pand bevat in totaal 9 verblijfsobject(en), met de volgende gebruiksfunctie(s):
Original document tree
``` Document { children=14 } Text { text="Er is 1 energielabel geregistreerd in dit pand met bouwjaar 1888" } Break { } Break { } Text { text=" " } Table { children=5 } TableRow { children=2 } TableCell { children=3 } Text { text=" " } Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" } Text { text=" " } TableCell { children=2 } Text { text=" " } Block { } TableRow { children=2 } TableCell { children=2 } Text { text=" " } Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" } TableCell { children=2 } Text { text=" Meest zuinig " } Block { } TableRow { } TableRow { children=2 } TableCell { children=2 } Text { text=" " } Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" } TableCell { children=1 } Text { text=" Minst zuinig" } TableRow { children=2 } TableCell { children=2 } Text { text=" " } Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" } TableCell { children=2 } Text { text=" " } Block { } Break { } Text { text="Dit pand bevat in totaal " } Span { bold=True children=1 } Text { text="9" } Text { text=" verblijfsobject(en), met de volgende gebruiksfunctie(s):" } Break { } Text { text=" " } Break { } Text { text=" " } Table { children=11 } TableRow { children=1 } TableCell { children=2 } Text { text="• Winkelfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Woonfunctie: 8" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Kantoorfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Bijeenkomstfunctie: 1" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Gezondheidszorgfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Industriefunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Logiesfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Celfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Onderwijsfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=2 } Text { text="• Sportfunctie: 0" } Break { } TableRow { children=1 } TableCell { children=1 } Text { text="• Overige gebruiksfuncties: 0" } ```Simplified document tree
``` Document { children=10 } Text { text="Er is 1 energielabel geregistreerd in dit pand met bouwjaar 1888" } Break { } Table { children=2 } TableRow { } TableRow { children=2 } TableCell { children=1 } Image { text="https://arcgis.com/sharing/rest/content/items/f179492056fe42318fa0948a9c38d138/data" } TableCell { } Break { } Text { text="Dit pand bevat in totaal " } Text { bold=True text="9" } Text { text=" verblijfsobject(en), met de volgende gebruiksfunctie(s):" } Break { } Text { text=" " } Table { children=2 } TableRow { children=1 } TableCell { children=1 } Text { text="• Woonfunctie: 8" } TableRow { children=1 } TableCell { children=1 } Text { text="• Bijeenkomstfunctie: 1" } ```