Accessing SVG inside object with JS in Internet Explorer - javascript

I have a test page: http://benfrain.com/playground/svg-test/
On it I have inserted the same SVG a number of ways (img, object, inline, and background image)
I have also implemented the use method of re-using defs from within the SVG (only for the object insertion method and the 'inline' insertion method).
In the console you will see I am also attempting to access the SVG contents from each insertion method (I know img and background image should not be accessible via script - I'm just proving the point).
However, on any version of Internet Explorer (IE9+) the object insertion method fails to load the external CSS (as noted in the comments, IE requires the alternative linking mechanism) referenced from within (via xlink, you would see a 6px wide stroke if it was working) and it is not reachable via JavaScript (works in all the other evergreen browsers) (my mistake).
Can anyone clarify why? I've had a look through the spec: http://www.w3.org/TR/html5/embedded-content-0.html#the-object-element but I must confess some of the technicalities are beyond my comprehension.
Update:
Further to Robert's comments below I made some tweaks to the test page above.
Firstly, the object is accessible with script (rookie mistake). However, oddities still abound:
If the SVG has a link in this format: <?xml-stylesheet href="styles.css" type="text/css"?> then IE11 applies the styles within that stylesheet to the SVG whether it is inserted in the page via img, background-image, inline or object (Safari/Firefox/Chrome only apply the styles if the SVG is inserted inline or via object).

There is a w3c testsuite page for external <use>: http://www.w3.org/Graphics/SVG/Test/20110816/svg/struct-use-05-b.svg
The implementation matrix suggests that IE9 doesn't support external <use> I'm not sure why Firefox is listed as failing as I think even at that time it should have passed that particular test.
For the <object> issue, you need to run the script in the onload event of the <object> tag. I guess you just get lucky with the other UAs as you basically have a race condition.
Presumably IE doesn't support including stylesheets using html syntax. Try XML syntax instead: <?xml-stylesheet href="mystyle.css" type="text/css"?>
Allowing images to use external files is a privacy leak which is why Firefox, Chrome and Safari disallow it. If you converted the CSS to a data URL you could use a link element.

Related

Is there a way to execute javascript from inside a css file ?

I have access ONLY to a css file which I can modify. I have a lot of modifications to do and I want to know if there is a way to execute a javascript code from inside a CSS file.
I did find an old vulnerability that is not supported in up-to-date browsers any more.
http://dougrathbone.com/blog/2013/10/30/executing-javascript-inside-css-another-reason-to-whitelist-and-encode-user-input
As you can see the vulnerability was exploited by calling an arbitrary code from another url like this
body {
behavior:url(/user/uploadedfiles/evil-uploaded-component.htc);
}
Now, I want to know if there's any alternative way to do that ?
IE and Firefox both contain ways to execute JavaScript from CSS. As Paolo mentions, one way in IE is the expression technique, but there's also the more obscure HTC behaviour, in which a separate XML that contains your script is loaded via CSS. A similar technique for Firefox exists, using XBL. These techniques don't execute JavaScript from CSS directly, but the effect is the same.
HTC with IE
Use a CSS rule like so:
body {
behavior:url(script.htc);
}
and within that script.htc file have something like:
<PUBLIC:COMPONENT TAGNAME="xss">
<PUBLIC:ATTACH EVENT="ondocumentready" ONEVENT="main()" LITERALCONTENT="false"/>
</PUBLIC:COMPONENT>
<SCRIPT>
function main()
{
alert("HTC script executed.");
}
</SCRIPT>
The HTC file executes the main() function on the event ondocumentready (referring to the HTC document's readiness.)
XBL with Firefox
Firefox supports a similar XML-script-executing hack, using XBL.
Use a CSS rule like so:
body {
-moz-binding: url(script.xml#mycode);
}
and within your script.xml:
<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="mycode">
<implementation>
<constructor>
alert("XBL script executed.");
</constructor>
</implementation>
</binding>
</bindings>
All of the code within the constructor tag will be executed (a good idea to wrap code in a CDATA section.)
In both techniques, the code doesn't execute unless the CSS selector matches an element within the document. By using something like body, it will execute immediately on page load.

Javascript onclick with base tag in ie with subfolder

Try this: create a folder test in your website, and put this html file (test.html) in it:
<html><head>
<base href="http://www.site.com/" />
</head><body>
<span onclick="window.location.href='test/test.html?done!';return false;">click me</span>
</body></html>
Click the link in your favourite browser. What's the URL?
Click the link in IE. What's the URL?
EDIT: IE takes you to: http://www.site.com/test/test/test.html?done!
Any way to fix this, that isn't (1) removing base tag, (2) changing onclick to use a function that appends the proper base? Is there a way to override the window.location.href function in IE?
This is apparently still an issue in IE11. I ran into it just now. What I've done is this:
onclick="window.location=document.getElementsByTagName('base')[0].href+'your_url_destination';"
It requires modifying the onclick line, but it doesn't require a separate function. It should work in all browsers, and has so far for me.
After moving my test.htm into a subdirectory called test (final relative path: test/test.htm), I am able to confirm the bug (I initially misunderstood what you were asking about). Googling it also confirms that it is a bug, or at the very least a non-Standard implementation of the <base> tag (this may merely be yet another case of Microsoft not following implementations according to specification).
IE will honor the <base> tag for any defined anchors.
<a href="test/test.html">Click me</span>
will go to http://www.site.com/test/test.html (provided the <base> tag is either not closed, or not self-closed for older versions of IE), but IE (all versions) will only honor the base tag for anchors, not for JavaScript.
The reason IE prepends the additional test/ to your URL is actually standards-compliant behavior. As IE is ignoring the <base> tag, your link of test/test.html indicates that there is a subdirectory called test with a test.html file relative to the current directory (test) and IE correctly navigates to `test/test/test.html'.
As far as how to fix it...
Removing the <base> tag will not help.
Changing the onclick to a function that returns the correct base URL would work, but you've stated this is not acceptable.
window.location.href is a String, not a function, so "overriding" it is a non-starter.
Changing onclick to use an absolute URL would also work.
Removing all embedded onclick attributes and assigning them via JavaScript (attachEvent or addEventListener) would be more effective in the long run (separation of content/behavior) and allow you to easily attach the correct base URL (and the method I would probably choose, although I don't know your specific circumstance).
You could use a DOM manipulation library, like jQuery/Dojo/Prototype to loop through any onclick attributes and update the URL to an absolute URL.

IE7 and IE8 randomly not able to load external script

I am dynamically adding <link> elements to the head once the DOM is ready. However, I'm getting inconsistent results in IE8 and IE7 (all other browsers are fine).
Every few times the page is loaded (cached or uncached), IE 7/8 will drop a handful of CSS rules in the stylesheets. 1 or 2 of my dynamic stylesheets will not load. It's always the same 1 or 2 stylesheets that IE tends to ignore - even though the Developer Toolbar shows them as added to the head!.
The stylesheets themselves show up as <link> elements in the final DOM, but some of their rules are not applied (although every few reloads they are applied, without any issue).
In my position, I do not have the luxury of writing code from the <head> (CMS restriction) - I can only dynamically insert from the body, which may be the issue.
UPDATED: This is the code I am using (located within the <body>) to insert stylesheets:
document.observe('dom:loaded', function() { // Using Prototype.js
// Add stylesheets
// addStylesheet('cite.css', 'head'); // Contains no webfont/#font-face rules
// addStylesheet('type.css', 'head'); // Contains webfont family name references*
// addStylesheet('flex.css', 'head'); // Responsive rules with #media queries
// addStylesheet('anm8.css', 'head'); // Some minor positional CSS for home page
// addStylesheet('gothic-cite.css', 'head'); // *Contains #font-face config
// addStylesheet('stag-cite.css', 'head'); // *Contains #font-face config
addStylesheet('all.css', 'head'); // Contains ALL content from above in 1 file
function addStylesheet(cssname, pos2)
{
var th2 = document.getElementsByTagName(pos2)[0];
var s2 = document.createElement('link');
s2.setAttribute('type', 'text/css');
s2.setAttribute('href', cssname);
s2.setAttribute('media', 'screen');
s2.setAttribute('rel', 'stylesheet');
th2.appendChild(s2);
}
});
As suggested, even when I combined all rules into one stylesheet (which I hate doing), IE 7/8 continues to flip-flop as described with some rules, and the page appears differently.
As a further check, I also removed all #font-face and referenced font-family: "webfont-name" rules from the stylesheets, and the same behavior continued. Therefore, we can rule out webfonts being the issue.
You can see the anomalies by visiting the following with IE8 and refreshing/clicking the nav several times. It seems completely random as to when IE8 is dropping those styles. However, in the natively-built control page, all styles load correctly, every time.
Live Page (with problems)
https://www.eiseverywhere.com/ehome/index.php?eventid=31648&tabid=50283
PHP-based CMS prints out XHTML on page load (template content mixed w/user content)
Prototype.js is loaded and initialized by default on page load
CMS proprietary scripts.js file is parsed on page load
My scripts run when DOM is loaded, essentially replacing body.innerHTML CMS fluff-HTML with just the HTML I want, then adds stylesheets to <head>.
For lte IE 8, CSS extension plugins (selectivizr.js, html5.js, and ie-media-queries.js) are loaded within the <body> via conditional comments. Not sure if they wait for DOM:loaded...
The CMS WYSIWYG editor converts all carriage-returns to empty <p> tags, resulting in elements like <section> being contained inside broken <p> tags, and extra <p></p> tags being created where whitespace is expected. Only lt IE 8 seems to choke on this, however, so I added the following CSS rules to remedy this:
:not(.ie7) p { display: none; }
.ie7 p { display: inline; }
article p { display: block !important; }
I should note that the external stylesheets here are being pulled from the same domain, but each time they are re-uploaded, a new MD5-based URL is generated for the file. I'm not sure if previous revisions to the file (or previous files) are still available by their previous URLs. This isn't likely to be the problem though, since the newly created all.css stylesheet is still dropping rules that have been in the file from the start.
Control Page (works flawlessly)
http://client.clevelanddesign.com/CD/IDG/CITE/home.html
Pure XHTML document - no PHP.
jQuery is used, rather than Prototype, for IE8 and below.
All resources (stylesheets) are present in <head> at page load - no dynamic insertion
For lte IE 8, CSS extension plugins (selectivizr.js, html5.js, and ie-media-queries.js) are initialized natively.
Rephrased question:
Which of these differences do you think may be causing IE 7/8 to flip-flop on styles when loaded on the Live page? I personally suspect either a race-condition issue, or that Prototype.js and the other CMS scripts are mucking things up (unfortunately no way to purge those from the page though).
PS: I've already tried using IE's createStylsheet() function, to no avail.
UPDATE - Screenshots of working/not working in IE8
IE8: DOM code when loaded correctly:
IE8: DOM code when NOT loaded correctly:
I've nailed down exactly what is happening, but still do not know the cause of flip-flop:
selectivizr.js is not loading correctly every few page loads.
All of the rules that use CSS3 selectors need that script to be applied in IE 7/8. Therefore when IE 7/8 does not load selectivizr.js correctly, those rules are ignored. Those rules certainly include the webfont references, as well as the errant <p> display properties.
To remind you all, these helper JS scripts are being loaded normally (from within the <body>) with the initial page load, before my script replaces the <body> contents (including that script reference). Therefore, there's a chance it's initializing twice (can anyone confirm this?)
The trouble is, on the control website, selectivizr.js always loads correctly in IE 7/8. There are also no known incompatibilities between the CSS3 helper js and the Media Query help js files (when initialized correctly).
I removed selectivizr.js from the page and the page loaded exactly the same way after 20+ refreshes. Good to get consistency back, bad that I've lost my CSS3 rules in IE 7/8.
Apparently this is how the js plugin in question works:
In accordance with the W3C specs, a web browser should discard style
rules it doesn’t understand. This presents a problem — we need access
to the CSS3 selectors in the style sheet but IE throws them away. To
avoid this issue each style sheet is downloaded using a
XMLHttpRequest. This allows the script to bypass the browsers internal
CSS parser and gain access to the raw CSS file.
Source: http://www.css3.info/css3-pseudo-selectors-emulation-in-internet-explorer/
I can try any suggested CSS3-selector plugins that you all may have; maybe one will load more reliable, or have less overhead and thus less room for lag-related issues. Any alternatives?
Or, perhaps I should add it after the DOM is ready the second time (after my script replaces the body contents) to the <head> or elsewhere in the <body>. None of these options worked - they had the same if not worse outcome.
First off let me say I have worked on multiple initiatives where the teams have started down the path of dynamically generating the DOM via Javascript, including remote-loading of scripts through CORS.
After many months of effort on 3 different projects (and different approaches used in each), we finally had to face the fact that IE7 and IE8 are incapable of properly or consistently dynamically loading and processing external scripts or CSS.
My recommendation is to consolidate / combine any scripts on the PHP / server side and serve up as a single file that can be cached on the client side.
As an additional note, IE is not completely to blame. There are huge complexities involved with downloading, processing, and rendering scripts / css in the correct orders and programming this process such that it works well in every environment (webkit + mozilla + IE9+) requires near-expert-level knowledge and very thorough testing.
In your case, one example of bad "flow" is the fact that when I viewed your page specifically, it briefly shows the non-CSS-applied page (yucky!) before the screen "updates" and CSS gets pulled in and applied. Bad bad bad.
Other issues I noticed are the large number of httprequests in general. Each requires a DNS lookup, cache / expires check (and other stuff dictated by headers), and subsequent download of response. On desktops this is not all that noticable, but on mobile devices, tablets and even some slower / bogged-down PC's it is especially noticable.
If you're building a web app in today's browsing environment and have only a small team, it's probably best to either:
Serve up CSS as a single, cacheable file from a CDN, and pages in pre-parsed, pre-iterated, pre-rendered HTML chunks, minimizing the client-side JS processing (only binding elements post-load), or
Go with a pre-existing client-side framework such as Sencha, SproutCore, YUI etc. - they have built out the framework for you and fixed all the bugs already.
Two things have to happen before I change my view: IE8 has to disappear from general use (drops below 10%), and the "average" mobile device needs to have 2 physical processor cores. Right now only the expensive / high-end models have dual-core processors.
Also of note, the fastest mobile processors even with JIT JS compilers are still 10x slower than a typical desktop in JS performance - which when compared directly to a desktop, would compete head-to-head with a Pentium 4 or old AMD Athlon 64.

Differences in using <iframe> and <embed> for displaying SVG and scripting

I'm trying to create Dynamic SVG graphics, it is my understanding that the only way to create dynamic SVG is to use a scripting language, so I have a few questions, basically I'd like to load or embed the SVG to a HTML web page and control the graphics using Inputs in the web page, rather than hardcoding the ECMAscript in the SVG file. I'm not entirely sure if I should use the embed tag or an iframe for displaying the SVG here are my doubts regarding SVG and scripting:
Whats the difference (in terms of scripting) in using an <iframe> or and <embed> tag for accessing the SVG elements?, maybe someone can include simple examples.
Can SVG evaluate math expressions in element attributes(just to be sure)?
Don't use either <iframe> or <embed>. Instead, embed your SVG directly in XHTML like so:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
With that, you have full access to the SVG DOM as part of your document. As shown in that example, you simply need to be certain to create SVG elements (but not attributes) using the SVG namespace. You must also ensure that your web host is sending the content type for xhtml as application/xhtml+xml or text/xml, not text/html.
phrogz$ curl --silent -I http://phrogz.net/svg/svg_in_xhtml5.xhtml | grep "Type"
Content-Type: application/xhtml+xml
For more examples of JavaScript manipulating SVG mixed with HTML, see the various .xhtml files in that same directory. A particularly compelling example is this one, which dynamically creates hundreds of small SVG files as inline elements flowing like text.
And to your question:
Can SVG evaluate math expressions in element attributes(just to be sure)?
Not in general, no. However, the usage of SMIL Animation does allow you to specify various interpolation methods of properties over time.
Finally, note that you don't have to put SVG in HTML to make it dynamic. You can script SVG with JavaScript directly. For example, see this test file (press the green button to start simulation):
http://phrogz.net/svg/SpringzTest.svg
Whats the difference (in terms of scripting) in using an or and tag for accessing the SVG elements?, maybe someone can include simple examples.
<iframe>:
Scripts trying to access a frame's content are subject to the same-origin policy, and cannot access most of the properties in the other window object if it was loaded from a different domain. This also applies to a script inside a frame trying to access its parent window. Cross-domain communication can still be achieved with window.postMessage.
Source: https://developer.mozilla.org/en/HTML/Element/iframe#Scripting
We access iframe content by iframe_element.contentWindow method:
<html>
<body>
<iframe id="SVG_frame" src="image.svg"></iframe>
</body>
<script>
var SVG_frame = document.getElementById ( "SVG_frame" );
var SVG_content = null;
function getContent ()
{
SVG_content = SVG_frame.contentWindow;
SVG_content ? alert ( "YAY!" ) : alert ( "BOO!" );
}
SVG_frame.onload = getContent;
</script>
</html>
<embed>:
Example (view source): https://jwatt.org/svg/demos/scripting-across-embed.html
(both methods fail at least in Chromium)
<object>
Example (view source): https://jwatt.org/svg/demos/scripting-across-object.html
Can SVG evaluate math expressions in
element attributes(just to be sure)?
like <element attribute="48/2*(9+3)"/>?
I did't find a word about it in SVG spec.
EDIT
Personally, I recommend to use <object> + Data URI Scheme and/or object_element.contentDocument. I've tested both in Chromium and Firefox.
AHA! <object> has similar security behavior to <iframe>: domain, protocol must be same for site and SVG file.
EDIT2
If You are interested how to get markup vector graphics to work in Internet Explorer(s) without plug-in(s), then Vector Markup Language is the way.
Well, it depends on what you mean with dynamic. In most cases yes, you'll probably want scripts. There's no difference if you put your script in the HTML or the SVG file, both will be executed by the same engine.
You can create interactive/animated svg content with the declarative animation elements (aka SMIL). You can also do simple hover effects with CSS :hover rules, or transitions with CSS3 Transitions.
XSLT can also be used to make somewhat dynamic svg content, since it can transform your input to something else. It doesn't cover the interaction aspect though.
You can access the svg elements from the HTML file that includes it with either of:
theEmbeddingElement.contentDocument (preferred, but doesn't work on <embed>)
or alternatively theEmbeddingElement.getSVGDocument().

styling XML (not HTML) with javascript & css after rendering in browser

I'm using a webkit browser (safari), so this question is specific to webkit.
I have safari rendering an XML document (it's not HTML). In order to style certain sections of the document, I've attached a stylesheet (see below) to the document. In the case below, the text within the first "thing" element is displayed in magenta.
This works reasonably well. But I would also like to dynamically modify the style of various elements (I assume by using javascript) after the document has been rendered.
I can use javascript to capture the first "thing" element using document.getElementsByName("a").item(0); but I'm not sure how to set the style (or if this is possible at all). this does not work => document.getElementsByName("a").item(0).style.display = "none";
Any thoughts on how to change the style of an xml element in a browser after it's been rendered?
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="simple.css" type="text/css"?>
<document xmlns:ab="adfadfafadf">
<thing name="a">stuff</thing>
<thing name="b">stuff2</thing>
</document>
_
//simple.css________________________________
document {margin: 1em; font-family: sans-serif; font-size: 14px;}
thing[name="a"] {color: magenta;}
I can use javascript to capture the first "thing" element using document.getElementsByName("a").item(0)
You shouldn't even be able to do that, and you can't on non-WebKit browsers. getElementsByName is a DOM Level 1 HTML method that shouldn't be available on XML documents, which have no notion of name attributes having special significance. (This is slightly different to the situation with attributes of schema type ID.)
Can you legitimately expect a style property to exist on Elements in arbitrary XML documents? The DOM Level 2 Style spec has this to say about the ElementCSSInlineStyle interface:
The expectation is that an instance of the ElementCSSInlineStyle interface can be obtained by using binding-specific casting methods on an instance of the Element interface when the element supports inline CSS style informations.
I'd argue that an arbitrary XML document's elements do not support inline CSS style information, as there is no style or other attribute that could be used to introduce CSS, unlike with [X]HTML. Mozilla and Opera agree with WebKit here in not providing it.
However, DOM Level 2 Style's document.styleSheets interface should work (in any of those browser bases). For example you can remove the thing[name="a"] rule by saying:
document.styleSheets[0].deleteRule(1);
and add a replacement by saying:
document.styleSheets[0].insertRule('thing[name="a"] {display: none;}', 1);
It doesn't look good, but I would try clicking on the links in the W3C spec to see if WebKit supports the styling you want to do. If it doesn't, you could dynamically request a stylesheet from the server after you've looked at the data. That might be the only work around.

Categories