Skip to content

Handle className correctly for SVG nodes #1264

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

Closed
wants to merge 1 commit into from
Closed

Conversation

fforw
Copy link
Contributor

@fforw fforw commented Mar 17, 2014

Bring back the DOM mutator to check if the className we're writing
to is actually a string.

For SVG nodes, the className property is not of type string but
and SVGAnimatedString and writing to the property will cause
a "TypeError: setting a property that has only a getter"
(See http://jsfiddle.net/ca47V/ )

This first checks if the className property is indeed a string
and uses setAttribute() / removeAttribute() otherwise.

@sophiebits
Copy link
Collaborator

Thanks! Do you think you could add a couple tests and comments explaining the purpose and to make sure this works?

@fforw
Copy link
Contributor Author

fforw commented Mar 17, 2014

How would I go about to prove above code does indeed work on SVG nodes with your test system?

@sophiebits
Copy link
Collaborator

You should be able to render an SVG node then set its className and verify that the class was changed properly. See DOMPropertyOperations-test.js for our existing tests.

@fforw
Copy link
Contributor Author

fforw commented Mar 17, 2014

Ok?

@sophiebits
Copy link
Collaborator

Did you run the tests? I would think expect(svgNode.className).toBe('foo'); would fail because .className should be an object, not a string -- right?

@fforw
Copy link
Contributor Author

fforw commented Mar 17, 2014

Yes, I ran the tests :\

In a real browser, svgNode.className is of course not the string foo.

The tests seem rather superflous here. Removing the original patch, but keepin the tests executes, too :\

In short: we're testing a wrong browser emulation..

@fforw
Copy link
Contributor Author

fforw commented Mar 17, 2014

Both my firefox and my chrome agree to not do anything if I set the className property. Firefox will only give out the warning in strict mode (!).

setAttribute works in both. ( http://fforw.de/static/files/svgcls.html )

@fforw
Copy link
Contributor Author

fforw commented Mar 18, 2014

Again, the tests describe what a real browser does and your test environment obviously does not.

@sophiebits
Copy link
Collaborator

I understand. I guess it's not practical to test this in phantomjs, so I'm fine landing without tests.

@fforw
Copy link
Contributor Author

fforw commented Mar 18, 2014

So should I remove the test completely?

@sophiebits
Copy link
Collaborator

I think that's best unless you have a better idea.

@fforw
Copy link
Contributor Author

fforw commented Mar 18, 2014

Well.. I guess we could just try to file a bug against phantomjs.. I mean there's no reason they shouldn't emulate this kind of thing correctly like a browser does. The behaviour being a direct result of the SVG 1.1 specs and the integration of that into HTML.

I'm kind of surprised react doesn't already have some kind of "real browser test" setup. Is it because this is basically done indirectly by internal facebook testing resources being used?

Apart from introducing such a thing for the react project itself I see little we can do here.

@sophiebits
Copy link
Collaborator

phantomjs is actually using a really old version of webkit so I'm not that hopeful. We do have a way to run tests in real browsers via saucelabs but right now all the tests are meant to pass in phantom.

@fforw
Copy link
Contributor Author

fforw commented Mar 18, 2014

At least we can try ariya/phantomjs#12072

className: function (node, value) {
// make sure our target property is indeed string
if (typeof node.className === "string") {
node.className = value || '';
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency with our handling for other DOM properties, this should be value != null ? value : ''.

@sophiebits
Copy link
Collaborator

I think we might be best just leaving off the tests here.

@barnabyc
Copy link

barnabyc commented Apr 1, 2014

+1 for getting this into the next release if possible as I ran into the same issue on several projects this week

@fforw
Copy link
Contributor Author

fforw commented Apr 1, 2014

Rewrote PR to honor commented on style issues and removed tests again.

Test was:

diff --git a/src/browser/ui/dom/__tests__/DOMPropertyOperations-test.js b/src/browser/ui/dom/__tests__/DOMPropertyOperations-test.js
index 83e4416..62a329c 100644
--- a/src/browser/ui/dom/__tests__/DOMPropertyOperations-test.js
+++ b/src/browser/ui/dom/__tests__/DOMPropertyOperations-test.js
@@ -219,6 +219,32 @@ describe('DOMPropertyOperations', function() {
       expect(stubNode.className).toBe('');
     });

+    it('should set className properly on SVG nodes', function() {
+
+      var svgNode = document.createElement("g");
+      DOMPropertyOperations.setValueForProperty(
+        svgNode,
+        'className',
+        'foo'
+      );
+
+      expect(typeof svgNode.className).toBe('object');
+      expect(svgNode.className.baseVal).toBe('foo');
+    });
+
+    it('should set className to empty string instead of null on SVG nodes', function() {
+
+      var svgNode = document.createElement("g");
+      DOMPropertyOperations.setValueForProperty(
+        svgNode,
+        'className',
+        null
+      );
+
+      expect(typeof svgNode.className).toBe('object');
+      expect(svgNode.className.baseVal).toBe('');
+    });
+
   });

   describe('injectDOMPropertyConfig', function() {

@sophiebits
Copy link
Collaborator

Looks good to me, thanks.

@fforw
Copy link
Contributor Author

fforw commented Apr 1, 2014

Since we haven't received any reaction from the phantomjs guys in two weeks, maybe we should just give up on that for now. We can always readd the tests if either React's test-strategy or phantomjs handling of this issue change.

*/
className: function (node, value) {
// make sure our target property is indeed string
if (typeof node.className === "string") {
Copy link
Member

Choose a reason for hiding this comment

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

nit: we use single quotes for strings

Let's also add a comment explaining why we're doing this detection. And while you're doing a comment, try to do sentences as much as possible.

Bring back the DOM mutator to check if the className we're writing
to is actually a string.

For SVG nodes, the className property is not of type string but
and SVGAnimatedString and writing to the property will cause
a "TypeError: setting a property that has only a getter"
(See http://jsfiddle.net/ca47V/ )

This first checks if the className property is indeed a string
and uses setAttribute() / removeAttribute() otherwise.
@fforw
Copy link
Contributor Author

fforw commented Apr 4, 2014

Added more comment, changed to single quotes.

@fforw
Copy link
Contributor Author

fforw commented Apr 13, 2014

So.. how do we go on here?

@barnabyc
Copy link

@spicyj any chance of a merge as Travis is green? /cc @zpao

@freiksenet
Copy link

I've made a version that merges to current master:
freiksenet@bdc427a

Should I submit new pull request? Should someone merge this? This fixes important bug in SVG support, I think.

@davidaurelio
Copy link
Contributor

Please merge this.

@syranide
Copy link
Contributor

syranide commented May 8, 2014

I propose escalating #1449 as it would solve all of these SVG-issues, once and for all, if the devs agree that it's a good idea.

@zpao
Copy link
Member

zpao commented May 8, 2014

Ok, so after some more thoughts, I think what we have here is not going to be great. It touches the DOM on every update before actually doing the update. I ran a bunch of perf tests and using the attribute seems to be marginally slower for setting, faster for deleting. I think that's probably the best option, however that doesn't work in IE8, so we need to do something different there. Perhaps we can default to MUST_USE_ATTRIBUTE and if we're in IE8 change it? @yungsters, what do you think?

@yungsters
Copy link
Contributor

I pretty much agree with @syranide. Whatever solution we come up with — as long as it is not horrible — will probably be good enough to tie us over until we have per-node configurations. Then we can do whatever needs to be done for SVG (or any other unique) elements without impacting the 90% use case.

@sophiebits sophiebits added this to the 0.11 milestone May 17, 2014
@facebook-github-bot
Copy link

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@sophiebits
Copy link
Collaborator

Just put up #1590 which is an alternative approach.

@zpao
Copy link
Member

zpao commented May 28, 2014

Closing in favor of #1590. Thanks for taking a stab at this @fforw and I'm sorry we stalled on it!

@zpao zpao closed this May 28, 2014
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.