IE7/8 get parentNode of an VML node



  • This is a long shot, but nothing ventured, nothing gained:

    Does anybody here know how to get the parentNode of a VML node in IE7/8?

    I installed a handler on a link, which was working fine until a few days ago when the client switch to a font library named Cufon. Cufon uses VML objects to draw text onto the page, which is fine, except when the user clicks on the link, the VML object becomes the e.srcElement and it's (apparently) impossible to traverse the DOM to find its parent link. (The parentNode of the VML object is set to null.)

    This is driving me nuts. Normally I'm pretty defensive about IE as a browser, but in this case they really, really half-assed VML support.



  • @blakeyrat said:

    This is a long shot, but nothing ventured, nothing gained:

    Does anybody here know how to get the parentNode of a VML node in IE7/8?

    I installed a handler on a link, which was working fine until a few days ago when the client switch to a font library named Cufon. Cufon uses VML objects to draw text onto the page, which is fine, except when the user clicks on the link, the VML object becomes the e.srcElement and it's (apparently) impossible to traverse the DOM to find its parent link. (The parentNode of the VML object is set to null.)

    This is driving me nuts. Normally I'm pretty defensive about IE as a browser, but in this case they really, really half-assed VML support.

    Have you filled this at their connect site?

    http://www.microsoft.com/windowsxp/expertzone/chats/transcripts/08_0417_ez_ie8.mspx



  • Thanks for searching, but that doesn't really address the matter. Sure, VML works the same as in IE7... but how did you find the parentNode of a VML node in IE7?

    I get the distinct impression that Microsoft lost interest about 1/3rd of the way through implementing VML, because the more I look into it, the more broken I find out it is.



  •  A VML object doesn't have a dom-type thing of its own? 

    Alternatively, it's possible that, since the VML is rendered in an object, its structure is lost or otherwise completely invisible to javascript.



  • @blakeyrat said:

    I get the distinct impression that Microsoft lost interest about 1/3rd of the way through implementing VML...

     

    I'm no expert, but from what I've heard, that's basically what happened. Because halfway in the implementation, another equivalent technology had turned out to win the battle - something called "SVG"...

    So good luck coding away on the web graphics equivalent of HD DVD. My toughts are with you :)

     

    As for the problem, I know it's kind of WTF-ish but can you attach custom JS properties to the VML objects? Then you could once at the start traverse the VML DOM tree from root to leaves and set the parent pointers yourself.



  • @PSWorx said:

    another equivalent technology had turned out to win the battle - something called "SVG"...
     

    So, Cufon uses both.

    That smells slightly WTFish to me.

     



  • @dhromed said:

     A VML object doesn't have a dom-type thing of its own? 

    Alternatively, it's possible that, since the VML is rendered in an object, its structure is lost or otherwise completely invisible to javascript.

    As far as I can work out, and IE8's developer tools are telling me, the VML objects are in the DOM. But while I have a nice little diagram of exactly where in the DOM they are, their parentNode property is set to null.

    @PSWorx said:

    As for the problem, I know it's kind of WTF-ish but can you attach custom JS properties to the VML objects? Then you could once at the start traverse the VML DOM tree from root to leaves and set the parent pointers yourself.

    As far as I can tell, the instant you touch anything in a VML object other than a VML property, it becomes invalid and any further accesses of that object raise an exception that simply says "Failed". No message, no line number, just... "Failed".

    One blog I read suggested removing the VML objects from the DOM, at which point you could (apparently) do whatever you wanted to them without the "Failed" exception, but I can't remove the VML objects from the DOM without being able to find their parentNode first, so that's a dead-end.

    As a sidenote, I find it extremely annoying that most guides/help/tutorials/etc on things like this assume you have control over the page source.

    @dhromed said:

    So, Cufon uses both.

    That smells slightly WTFish to me.

    Cufon is a piece. of. shit. They've managed the impossible: to make SIFR look good.

    Of course the real question is, since both IE and Firefox support font embedding, why the holy shit hell fuck are web developers using these shitty libraries that don't fucking work to get custom fonts!!!! Jesus shit. Let's ignore the fact that the browser has built-in support for it, which fucking works right, and use this horrible hack some 16-year-old basement dwelling Linux fan shat out in 3 weeks and never bothered to actually fucking test.

    (BTW: it uses VML in IE and SVG in Firefox. So what they're doing makes a tiny bit of sense if you ignore the fact that it's a horrible hack to give browsers a feature they already have.)

    Anyway, I came up with a new idea that I'm going to try today when I get a chance. See if adding a custom JS function call to the A tag's "onclick" handler (the old fashioned way), and embed the 'clue' I need to find out what link was clicked in the function call. (Something like:

    theLink.onclick = 'MyTrackingFunction("this is link 1"); return false;';

    If that doesn't work, then fuck everything I give up.


  • 🚽 Regular

    @blakeyrat said:

    As a sidenote, I find it extremely annoying that most guides/help/tutorials/etc on things like this assume you have control over the page source.
     

    Well, it sounds as though there isn't any solution for this if you don't have control over the page source. Are you building this JS file solely for this client? If so, then what's wrong with asking the client to do minor changes to the DOM that might make this whole thing a helluvalot easier for you?

    This is a long shot, but have you looked into possibly traversing the DOM, looking at all elements' children and, if an VML element is found, simply return that element as the parent? Obviously if a VML has a null parentNode property, chances are this won't work, but it's worth a check.

    @blakeyrat said:

    Jesus shit. Let's ignore the fact that the browser has built-in support for it, which fucking works right

    To be a little fair, there's one thing that annoys me about embedding fonts. In FF anyway, while the page is loading, the text is in a default sans-serif or serif font, and the actual font does not get applied until the page is fully loaded (or perhaps until the font file is downloaded). I did some web-dev work for someone who wanted embedded fonts, and when the client saw the finished product and saw this issue, it was a dealbreaker and we instead used regular fonts.



  • @RHuckster said:

    Well, it sounds as though there isn't any solution for this if you don't have control over the page source. Are you building this JS file solely for this client? If so, then what's wrong with asking the client to do minor changes to the DOM that might make this whole thing a helluvalot easier for you?

    We have clients I'd do that with. This isn't one of those clients. But since they changed the page to add this font library without consulting us, or letting us see the staging server (something they agreed to do), which caused those nice little "Failed" exceptions all over the place (since our code wasn't even slightly VML-compliant) and put us into panic mode, they can wait a few days for the fix. My guess is some business-y person said, "it's not like we changed the page! We just added fonts."

    (Thankfully virtually zero IE users have JS error reporting turned on, and their QA people caught it quickly.)

    @RHuckster said:

    This is a long shot, but have you looked into possibly traversing the DOM, looking at all elements' children and, if an VML element is found, simply return that element as the parent? Obviously if a VML has a null parentNode property, chances are this won't work, but it's worth a check.

    That could potentially work if the VML node I had access to was right next to the normal nodes. Unfortunately, it's inside other VML nodes.

    The links I'm interested in already have Omniture link tracking installed (in the dumbest possible way, but hey it works), so I'm just going to steal their handlers and hook the Omniture function to add my own code.

    @RHuckster said:

    In FF anyway, while the page is loading, the text is in a default sans-serif or serif font, and the actual font does not get applied until the page is fully loaded (or perhaps until the font file is downloaded).

    Well, fair enough, but since Cufon and SIFR do that also... so...



  • @RHuckster said:

    In FF anyway, while the page is loading, the text is in a default sans-serif or serif font, and the actual font does not get applied until the page is fully loaded
     

    Does FF use the secondary specified font until it can render your pretty primary font?

    As in,

    h1 {
       font-family: 'Berthold Baskerville Book', Georgia;
    }


  • 🚽 Regular

    @dhromed said:

    Does FF use the secondary specified font until it can render your pretty primary font?

    I'm 99% sure that is the case, but that would have been no use to me in the aforementioned situation because the font was so different from any "ubiquitous" font, it wouldn't have made a difference.



  • @RHuckster said:

    the font was so different from any "ubiquitous" font, it wouldn't have made a difference.
     

    I see your point, but any chosen font would be better than Times New Roman, I think.



  • Oh, I guess I should report back in case anybody reads this.

    I found two things:
    1) Setting the handler with linkObj.onclick = new Function( "DoStuff();" ) worked
    2) But the easier solution was to hook into the client's existing Omniture reporting, since that did all the links at once without having to identify them by destination URL. (Seriously, there was nothing-- no classes, no IDs, no nothing except destination URLs.)



  • @blakeyrat said:

    1) Setting the handler with linkObj.onclick = new Function( "DoStuff();" ) worked
     

    Er, that's 100% equivalent to linkObj.onclick = function () { DoStuff(); };

    But perhaps you've tried that already, and they're different through some some idiotic quirk.

     



  • @dhromed said:

    @blakeyrat said:

    1) Setting the handler with linkObj.onclick = new Function( "DoStuff();" ) worked
     

    Er, that's 100% equivalent to linkObj.onclick = function () { DoStuff(); };

    But perhaps you've tried that already, and they're different through some some idiotic quirk.

     

    Eh, it's probably the exact same. I always write new Function() and use its constructor to create functions-- habit I guess.

    I do find it interesting that you assume I *should* be using "function() {DoStuff();}" to the extent where you assume I must have tried that and rejected it for some reason... explain?



  • Because using new Function() is archaic, completely obsolete syntax, and uses eval() when you pass it a string. And you always pass it a string, because if you passed it a function ref, you'd use the function ref in the first place, making new Function redundant code. Additionally, the function body is a string. What do you do when the function you add to the onclick has more than 1 line? That becomes unmaintainable quicklike. 

    i.o.w. there's no reason to pick new Function() over function (), unless you're hacking shit together to make it work.

    But, if this is your standard way of adding a single function call to an event, then use .onclick = DoStuff; instead. I'm sure you see the readability benefits there.



  • @dhromed said:

    Because using new Function() is archaic, completely obsolete syntax, and uses eval() when you pass it a string. And you always pass it a string, because if you passed it a function ref, you'd use the function ref in the first place, making new Function redundant code. Additionally, the function body is a string. What do you do when the function you add to the onclick has more than 1 line? That becomes unmaintainable quicklike. 

    It's not completely obsolete, because I have to use that syntax for overloading other people's functions, like the Omniture function I overloaded to "steal" their tracking events. You can't do that without creating a function from a string, and you can't create a function from a string using your syntax. (Unless you bury it in a significantly more confusing eval();.) I do that pretty often, so... yeah.

    @dhromed said:

    there's no reason to pick new Function() over function (), unless you're hacking shit together to make it work.

    1. I just gave a reason.

      2) "hacking shit together to make it work" is pretty much all I ever do.

    @dhromed said:

    But, if this is your standard way of adding a single function call to an event, then use .onclick = DoStuff; instead. I'm sure you see the readability benefits there.

    Of course it's not my standard way. Are you brand new to this thread? Believe me, our code is extremely WTF-free and works in all browsers, on virtually all sites, by default. It just has never encountered VML before.

    (In any case, I tried ".onclick = DoStuff;" and it didn't work. It would work if I had access to the source of the page, and could insert it directly into the tag, but setting it from JS later on doesn't, not sure why.)

    Your post is making me feel like a dinosaur and grumpy.


  • 🚽 Regular

    @blakeyrat said:

    Eh, it's probably the exact same. I always write new Function() and use its constructor to create functions-- habit I guess.

    ...

    @blakeyrat said:

    Of course it's not my *standard* way. Are you brand new to this thread?

    I hate to break it to you, but if you think new Function("eval code"); makes your code "extremely WTF-free" you're patently wrong. 

    Btw, chances are the reason .onClick = DoStuff doesn't work is because the event passes an event object to DoStuff, which it probably doesn't expect if it normally wouldn't handle a click event. Ergo,

    .onclick = function() { DoStuff(); } 

    should most definitely work. Obviously, I don't know how more complicated your real code is, but *anything* in Javascript can definitely be at least broken down into anonymous function closures. I can probably count on one Simpson-hand the number of times I've resorted to using eval code in JavaScript and I've done some pretty complicated JS code.



  • @blakeyrat said:

    I have to use that syntax for overloading other people's functions, like the Omniture function I overloaded to "steal" their tracking events. You can't do that without creating a function from a string
     

    I don't see why new Function() would work where function () would fail. That's rather weird.



  • Congratulations, I now regret sharing my solution to the problem.

    I'm going to leave the thread now, but by all means, continue to pile-on.



  • Aw, c'mon, don't be a sourpuss. I was just wondering why one would work while the equivalent would not, and why you commonly use a way that is decidedly less maintainable than another.



  • Welcome to another installment of "useless javascript facts"! How nice that you have tuned in again!

    I'm normally a firm member of the eval() = evil() community but I think I can understand blakey in this situation. Based on the original problem I guess his event handler isn't actually onclick = new Function("doStuff()") but rather something like onclick = new Function("doStuff('" + someID + "')"). And unfortunately that sort of thing really can bite you in the back if you do it with closures:

    Try out the following two code snippets: (replace console.info() with alert() if you don't have firebug.)

     for (var i = 0; i < 5; i++) {
    setTimeout(function(){console.info("without eval: " + i)}, 500);
    }

    for (var i = 0; i < 5; i++) {
    setTimeout(new Function("console.info('with eval: " + i + "');"), 500);
    }

    Notice something? Yup, the "eval" callbacks seem to work just fine, but the "without eval" ones all print "5". Solution: Because of the stupid way JS closures work, the callbacks in the first snippet don't actually capture the value of i, they capture the variable i. And because i is set to 5 after the loop, they will all print out that value.

    The "correct" solution is to use a "proxy function":

     function makeHandler(x) {
    return function() {console.info("without eval: " + x)};
    }

    for (var i = 0; i < 5; i++) {
    setTimeout(makeHandler(i), 500);
    }

    You can also make that into an inline function which is slightly shorter and works but looks completely cryptic:

     for (var i = 0; i < 5; i++) {
    setTimeout(function(x){return function(){console.info("without eval: " + x)}}(i), 500);
    }

    However, I can't see blakey using either of those solutions in his lifetime. So yes, I guess if you have your "ID" value under control this is one of the rare occurances where the "eval" version is really the most easy to understand. That you're constantly teetering on the edge of a giant XSS hole is of course another thing.



  • @PSWorx said:

    Welcome
     

    I agree.



  • @blakeyrat said:

    Of course the real question is, since both IE and Firefox support font embedding, why the holy shit hell fuck are web developers using these shitty libraries that don't fucking work to get custom fonts!!!! Jesus shit. Let's ignore the fact that the browser has built-in support for it, which fucking works right, and use this horrible hack some 16-year-old basement dwelling Linux fan shat out in 3 weeks and never bothered to actually fucking test.




    I asked the same thing at my company and the answer was that we are not allowed to store these fonts on our server so they are accessible to everyone. apparently you have to pay a lot more to do so (some copyright shit, i lost interest halfway through the explanation).

    on the other hand, sIFR and cufon seem to be perfectly legal way to embed fonts in the webpage (as an alternative, you can render headlines with imagemagic and serve them as gifs; been there, done that, would not recommend, my ass still hurts) .

    there is a service called Typekit which pays for this shit and hosts the fonts on their servers, they offer subscription plans, so you can point the browser to download fonts from them (haven't tried them yet, have no idea how that works).

    there is google font directory as well, however the designers seem to despise these fonts



  • @Nelle said:

    we are not allowed to store these fonts on our server so they are accessible to everyone. [...] on the other hand, sIFR and cufon seem to be perfectly legal way to embed fonts in the webpage
     

    I've no experience at all with those frameworks, but from a superficial glance it doesn't look extremely hard to transform cufon's JS tables back into an OpenType font - or at least get rid of the domain restriction. So isn't this basically security through obscurity? Or actually, even "DRM through obscurity"?



  • @PSWorx said:

    @Nelle said:
    we are not allowed to store these fonts on our server so they are accessible to everyone. [...] on the other hand, sIFR and cufon seem to be perfectly legal way to embed fonts in the webpage
     

    I've no experience at all with those frameworks, but from a superficial glance it doesn't look extremely hard to transform cufon's JS tables back into an OpenType font - or at least get rid of the domain restriction. So isn't this basically security through obscurity? Or actually, even "DRM through obscurity"?




    you are right... then i really have no idea what cufon is really about ...

    they even have a checkbox on their page: "The EULAs of these fonts allow Web Embedding (without Adobe Flash)"



  • Technically, in the United States, fonts are not copyrightable.  There is an exception to this for SCALABLE fonts, to the extent that the copyright holder holds the copyright to the program or algorythm which scales the fonts.  Don't really know how this applies to anything you may be doing. ymmv.  another random only partially on topic post.


  • 🚽 Regular

    @Medezark said:

    Technically, in the United States, fonts are not copyrightable.  There is an exception to this for SCALABLE fonts, to the extent that the copyright holder holds the copyright to the program or algorythm which scales the fonts.  Don't really know how this applies to anything you may be doing. ymmv.  another random only partially on topic post.
     

    Hmm... maybe I'm thinking of another intellectual property concept like trademarks or patents, but I'm pretty sure there are fonts commercially available which they require you to pay royalties or a license for. I'm not a lawyer, though, and I could be completely wrong.


Log in to reply