SVG embed not loaded or unaccessible via contentDocument - javascript

I've been struggling for... hours on a simple problem even though it seems to have been described here :How to access SVG elements with Javascript
I can't access elements of an external svg file loaded in a embed tag, even if I wait for the div or the whole window to load (I've tried several "load listeners")
I've simplified my html file into those fewlines to show you the issue :
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Desperate demo</title>
</head>
<body>
<div id="content">
<embed class="emb" id="maptest" type="image/svg+xml" src="star.svg">
</div>
<script type='text/javascript'>
window.onload = initAll;
function initAll(){
var mySVG = document.getElementById("maptest");
var svgDoc = mySVG.contentDocument;
console.log(svgDoc);
}
</script>
</body>
</html>
Basically, the log returns "null" or "undefined" on contentDocument property call, as if there was no svg at all loaded in the DOM.
Can you see what did I miss ? It doesn't work either if I write the whole svg tag in my html instead of calling an extern file...

Try getSVGDocument() and see if it helps you:
window.onload = initAll;
function initAll(){
var mySVG = document.getElementById("maptest");
console.log(mySVG);
var svgDoc = mySVG.getSVGDocument();
console.log(svgDoc);
}

Related

How do I make the querySelector look in a specific included document only?

On my index page I have a number of includes.
<section><?php include('content/content1.php') ?></section>
<section><?php include('content/content2.php') ?></section>
<section><?php include('content/content3.php') ?></section>
In each of them I have a unique script (and some other things which is not shown here).
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Content1</title>
<link rel="stylesheet" href="content/sketch.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"></script>
</head>
<body>
<div class="frame">
<canvas></canvas>
</div>
<script src="content/content1.js"></script>
</body>
The <canvas> tag is what the querySelector in the javascript calls to.
var canvas = document.querySelector('canvas');
This works, but only for the first content file. It seems the querySelector looks at the whole loaded page, instead of just inside the body of the document where the script is placed. Google console says: "Indentifier 'canvas' has already been declared".
I have tried setting an id on the canvas-element:
<canvas id="canvas1"></canvas>
var canvas = document.querySelector('#canvas1');
But it's not working. How do I get around this?
You can use document.currentScript to get the tag of the currently running script tag. From there, you can navigate to its containing section, and from there, get to the canvas descendant.
You should also put everything into an IIFE to avoid global variable collisions.
(() => {
const canvas = document.currentScript.closest('section').querySelector('canvas');
// ...
})();

How to read values from particular class of an Iframe using javascript/jquery?

In my web page, I have imported an Iframe I want to read the values present in the class cell-hover of that iframe.
If the iframe page is on your domain, add an ID to that iframe, then use contentWindow property to access it (after iframe is loaded); like in the code from this example:
<iframe src='http://localhost/test.htm' id='ifrm1'></iframe>
<script>
var ifrm1 = document.getElementById('ifrm1');
//called after iframe is loaded
function testIfrm(){
// Apply the property "contentWindow" to ifrm1 object
//get array with all '.cell-hover' elements in iframe
var cell_h = ifrm1.contentWindow.document.querySelectorAll('.cell-hover');
alert(cell_h[0].innerHTML); // Displays an Alert with content of 1st .cell-hover
}
//calls testIfrm() on ifrm1 load
ifrm1.addEventListener('load', testIfrm);
</script>
And test.htm:
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Title</title>
</head>
<body>
<div class="cell-hover">one.</div>
<div class="cell-hover">two..</div>
</body>
</html>
I tested it before posting, it works.
Source: http://coursesweb.net/javascript/get-modify-content-iframe_t

IE executes inline scripts before external in dynamic iframe content

within a website I'm writing the content of a dynamically added iframe with JavaScript. After adding the content to the iframe the JavaScript in the iframe will be executed. Unfortunately there are differences in IE. IE (8-11) will execute inline JavaScript first, before executing external scripts even if they are before the internal scripts. This is very strange since the normal process is, that JavaScript will be loaded synchronously step by step.
Example:
My webpage:
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=8" />
<meta charset="UTF-8">
<title>
TEST
</title>
</head>
<body>
<iframe name="testFrame" frameborder="0"></iframe>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var $iframe = $("iframe");
// Data
var data = "<!doctype html><html><head>";
data += '<scrip'+'t type="text/javascript" src="test1.js"><'+'/script>';
data += '<scrip'+'t type="text/javascript">console.log("Inline");<'+'/script>';
data += "</head><body>TEST</body></html>";
// Write in frame
var dstFrame = $iframe[0];
var dstDoc = dstFrame.contentDocument || dstFrame.contentWindow.document;
dstDoc.write(data);
dstDoc.close();
});
</script>
</body>
</html>
test1.js will just log a example status to see what kind of log will be executed firstly:
console.log("EXTERNAL");
In Firefox the console will be:
"EXTERNAL" test1.js:1
"Inline" test.html:1
"EXTERNAL" test1.js:1
"Inline" test.html:1
In IE the console will be:
EXTERNAL
Inline
Inline
EXTERNAL
As you can see the inline content will be executed before the external even if the external was added to the iframe before!
Can somebody tell me why and how to avoid it?
Notice: You can ignore the first two console logs since the parser will log the JavaScript even if it is inside a string (in my example it is inside the string).

How to add a javascript function inside the body of iframe

i have a html file with iframe and button in it, Is there a way to add a javascript function inside the body of iframe after I click the button?. Here is my code. Thanks
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script>
function callMe() {
var frame = $('iframe'),
contents = frame.contents(),
body = contents.find('body');
var script2 = document.createElement("script");
script2.type = "text/javascript";
script2.text = " function setEmployeeId(){var employeeId = 0;};"
$(body).append(script2);
};
</script>
<title>sample</title>
</head>
<body>
<iframe src="page2.html">
</iframe>
<button onClick="callMe();">click</button>
</body>
</html>
The result I want is to be like this.
<html>
<head>
<title>sample</title>
</head>
<body>
<iframe>
<html>
<head>
<title></title>
</head>
<body>
<script>
function setemployeeId() {
var employeeId = 0;
};
</script>
</body>
</html>
</iframe>
</body>
</html>
Hopefully you can clarify a few things for me as we go, but I think I have some bad news for you.
Any content that is loaded in an iframe cannot truly edited unless you own the page that is being loaded, in that case you can just bake in whatever you need into the loaded page.
HOWEVER!
You can still access elements in the iframe by using the contentWindow attribute. That is all laid out for you here: How to pick element inside iframe using document.getElementById
Once you've got the element you want to work with, you can create a function in the parent window and then add a call to the parent window's function using window.parent. That's outlined here: Calling a parent window function from an iframe
So if you wanted to make a button in an iframe alter the contents of the iframe you could use
var elem = document.getElementById('myframe1').contentWindow.document.getElementById('myButton')
and then create a function in your parent window
function changeIt(){
document.getElementById('thingToChangeInIframe_ItsIDintheIframe').property = 'value';
}
and append it to the button with the code
elem.setAttribute('onclick', 'changeIt();');
If you have any clarifications to what you need just comment and we'll work those out. I'm sorry this doesn't use much jQuery but that's not really my forte, but I think the pure javascript is relatively self explanatory.
EDIT: I should clarify that if the iframe is on another domain then your options are pretty much all eliminated. For security reasons you can't mess with the settings on other people's pages when you load them in an iframe.

how to distinguish from dynamic loaded script and normal src scripts

How can I distinguish from dynamic loaded script and normal script included using src property? For example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script src="static.js" type="text/javascript"></script>
<script type="text/javascript">
document.getElementsByTagName('head')[0].appendChild(document.createElement('script').src = 'dynamic.js');
</script>
</head>
<body>
<script type="text/javascript">
// I want to distinguish dynamic.js and static.js script tags
</script>
</body>
</html>
Add a specific HTML5 data-* attribute to the dynamic scripts:
var script = document.createElement("script");
script.setAttribute("data-is-dynamic", "true");
script.id = "script1";
script.src = "dynamic.js";
document.getElementsByTagName('head')[0].appendChild(script);
An option for getting the <head> element is to use document.head, although it's not supported in older browsers. Here's the MDN docs - https://developer.mozilla.org/en-US/docs/DOM/document.head
Then to distinguish later, use:
var someScript = document.getElementById("script1"); // or any script tag you want to analyze
if (someScript.getAttribute("data-is-dynamic") === "true") {
// is dynamic
} else {
// is static
}
Of course, at the same time, you can set an attribute on static script tags, like data-is-static, and then check for that in the opposite manner.
This allows you to validly set a "flag" on a script tag that you can retrieve later.

Categories