Allow truncating SVG in AppNodeText#945
Conversation
✅ Deploy Preview for monarch-app ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #945 +/- ##
=======================================
Coverage 73.51% 73.51%
=======================================
Files 95 95
Lines 3417 3417
=======================================
Hits 2512 2512
Misses 905 905 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
877ffa1 to
b7cc485
Compare
Additionally, use AppNodeText for SVG labels
b7cc485 to
a7982af
Compare
|
I am going to add several test cases before continuing |
This commit does two main things. First, it almost completely dials back the difference between rendering HTML and SVG. Instead of recreating HTML elements (<b>, <i>, <sup>) with styled <tspan> elements in SVG, it just includes those elements as HTML in a <foreignObject> tag. Part of the reason I did this is that there were strange cross-browser differences in how superscripted text was being truncated. For some reason, the code for detecting character positions (see the code that was removed with `getStartPositionOfChar` and `getCharNumAtPosition`) stopped working when `dy` was set on a tspan in some browsers. There was also the issue that the SVG equivalents to the HTML elements were always sliiightly different. --- Second, and following from that, I was able to get rid of a lot of the complexities that went with treating rendering SVG and HTML differently. The new logic is much more simple: the text of the label is retrieved via `innerHtml`, then a whitelist of tags is escaped (i.e. replacing `<` with `<` and `>` with `>`). The only SVG specific logic (besides wrapping the container in a <foreignObject>) is replacing <sup> tags with <span> tags styled as superscript. (Again, because of cross-browser rendering issues, which are commented in the code).
4fe5bd2 to
9813cf2
Compare
amc-corey-cox
left a comment
There was a problem hiding this comment.
This is a great change! This makes it much simpler and we don't have to rely as much on our own internal logic. This both solves the bug and makes the whole thing easier to understand and maintain.
|
Waiting to merge until you make that last small fix. |
|
@ptgolden this is going to have conflicts now with all the updates @varun-divya has done. If it still needs to happen, please work with her to get the conflicts resolved. Thanks! |
✅ Deploy Preview for monarch-app ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
PR Review: Allow truncating SVG in AppNodeTextOverviewThis PR refactors the ✅ Strengths1. Simplified ArchitectureThe new approach is significantly cleaner:
2. Correct Truncation LogicThe core problem is properly solved:
3. Excellent Test CoverageAdded comprehensive unit tests (AppNodeText.test.ts) covering:
4. Better Browser CompatibilityAddressed WebKit-specific positioning issues inside with an elegant workaround (lines 81-102). 🔍 Issues & Concerns1. Security: Potential XSS Vulnerability
|
Since a0f2eef, label text is passed to <AppNodeText> as HTML, rather than text. This reintroduces the HTML injection that was eliminated in #908. Setting v-html was done to support rendering highlighted text, but it also makes it so that any HTML in labels is also passed straight through as HTML. It also probably introduces some bugs in rendering genotypes that have "<...>" strings in them. I'm doing this now because we really need to get the SVG rendering fixed.
Code ReviewThanks for working on this PR! The refactoring from custom DOM manipulation to CSS-based truncation is a solid improvement. Here's my detailed review: ✅ Strengths
🔍 Potential Issues1. Security Concern - Potential XSS Vulnerability (Medium Priority)In <span
v-else
ref="container"
v-bind="$attrs"
:class="{ 'highlight-text': highlight }"
v-html="text"
/>This renders Example attack vector: text = 'Hello <img src=x onerror="alert(1)">'This would trigger the onerror handler before buildDOM processes it. Recommendation: Use Note from test file (line 55-57): There's a FIXME comment acknowledging this was done for highlighting support. Consider alternative approaches like:
2. foreignObject May Not Work in All Contexts (Low-Medium Priority)Using
Recommendation:
3. Unused Function in dom.ts (Low Priority)
Recommendation: Remove 4. Browser Compatibility for CSS Truncation (Low Priority)The CSS truncation approach (lines 104-111) relies on:
This is well-supported but doesn't truncate styled text predictably when markup is involved. For example: <span style="max-width: 50px">Hello <b>world</b></span>The truncation will work, but if "world" is bolded and bold text is wider, the ellipsis position might be unexpected. Recommendation: Test with the actual phenogrid labels to ensure truncation looks good with the expected markup combinations. 🎯 Code Quality
🧪 Testing Recommendations
test("Prevents XSS attacks", async () => {
const props = { text: 'Node <img src=x onerror="alert(1)">' };
const htmlEl = mount(AppNodeText, { props });
// Should not render img tag, should escape it
expect(htmlEl.html()).not.toContain('<img');
});
📊 PerformanceThe new approach should be more performant:
🔒 Security SummaryPriority fix needed: Change Overall AssessmentThis is a good refactoring that simplifies the codebase significantly. The main concern is the XSS vulnerability from using Recommendation: Address the Great work on the simplification and thorough testing! 🎉 |
I'm aware of this concern and it was introduced elsewhere. I'm going to make a new issue about it, but it will take some work to fix that is outside the scope of this PR.
Unfortunately, reliably rendering superscripted text with SVG has inescapable cross-browser inconsistencies. See my commit message in 48457da. This approach should be much better browser-compatibility wise. I take the accessbility comment, but when this component is rendered in SVG, it's going to be in the case of a data visualization component, which would not be fit for a screen reader anyway. |
Labels in the phenogrid were previously rendered as
<text>SVG elements, rather than<AppNodeText>Vue elements which whitelist certain markup. This replaces thosetextelements withAppNodeTextelements.An issue, though, is that labels were previously truncated based on their bare text length. So the string
'label<b>with bolded</b>'might be truncated to'label<b'or'label<b>with bo'rather than'label with bo'(where "with bo" would be bolded).This PR fixes that bug by truncating text according to its length as it appears in rendered SVG.
Fixes the bug mentioned in #943 (comment).