How to style the body of an empty iframe? - javascript

I got this problem only on IE (even on most recent versions, like 11). The thing is that I appended an iframe dinamicly to my document in which I'm writing some scripts for later execution. Those scripts must paint an image in the end, the problem is I'm getting anoying margins on IE from the body.
I can't load that using the src, it must be dynamic. So I just thought "lets get access to the iframe and write some style on the body". But when I retrieve the iframe doc like this...
var win = (iframe.contentWindow) ? iframe.contentWindow : (iframe.contentDocument.document) ? iframe.contentDocument.document : iframe.contentDocument;
... win.document.body or win.document.querySelector("body") returns null (again, in ie 11).
Does anyone know how to get to the body safely?

You can do this way:
<iframe srcdoc="" id="iframe"></iframe>
<script type="text/javascript">
var iframe = document.getElementById("iframe");
iframe.setAttribute("srcdoc", "<style>body{background:red;}</style>");
</script>
Demo: http://output.jsbin.com/kaquwilaka

I could write some css like this:
win.document.open();
win.document.write("<style>body{margin:0;}</style>");
//write other stuff
win.document.close();
This works as doesn't avoid any further writting and also because style can be in the head or in the body.

Related

Iframe manipulation [duplicate]

Is it possible to change styles of a div that resides inside an iframe on the page using CSS only?
You need JavaScript. It is the same as doing it in the parent page, except you must prefix your JavaScript command with the name of the iframe.
Remember, the same origin policy applies, so you can only do this to an iframe element which is coming from your own server.
I use the Prototype framework to make it easier:
frame1.$('mydiv').style.border = '1px solid #000000'
or
frame1.$('mydiv').addClassName('withborder')
In short no.
You can not apply CSS to HTML that is loaded in an iframe, unless you have control over the page loaded in the iframe due to cross-domain resource restrictions.
Yes. Take a look at this other thread for details:
How to apply CSS to iframe?
const cssLink = document.createElement("link");
cssLink.href = "style.css";
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
frames['frame1'].contentWindow.document.body.appendChild(cssLink);
// ^frame1 is the #id of the iframe: <iframe id="frame1">
You can retrieve the contents of an iframe first and then use jQuery selectors against them as usual.
$("#iframe-id").contents().find("img").attr("style","width:100%;height:100%")
$("#iframe-id").contents().find("img").addClass("fancy-zoom")
$("#iframe-id").contents().find("img").onclick(function(){ zoomit($(this)); });
Good Luck!
The quick answer is: No, sorry.
It's not possible using just CSS. You basically need to have control over the iframe content in order to style it. There are methods using javascript or your web language of choice (which I've read a little about, but am not to familiar with myself) to insert some needed styles dynamically, but you would need direct control over the iframe content, which it sounds like you do not have.
Use Jquery and wait till the source is loaded,
This is how I have achieved(Used angular interval, you can use javascript setInterval method):
var addCssToIframe = function() {
if ($('#myIframe').contents().find("head") != undefined) {
$('#myIframe')
.contents()
.find("head")
.append(
'<link rel="stylesheet" href="app/css/iframe.css" type="text/css" />');
$interval.cancel(addCssInterval);
}
};
var addCssInterval = $interval(addCssToIframe, 500, 0, false);
Combining the different solutions, this is what worked for me.
$(document).ready(function () {
$('iframe').on('load', function() {
$("iframe").contents().find("#back-link").css("display", "none");
});
});
Apparently it can be done via jQuery:
$('iframe').load( function() {
$('iframe').contents().find("head")
.append($("<style type='text/css'> .my-class{display:none;} </style>"));
});
https://stackoverflow.com/a/13959836/1625795
probably not the way you are thinking. the iframe would have to <link> in the css file too. AND you can't do it even with javascript if it's on a different domain.
Not possible from client side . A javascript error will be raised "Error: Permission denied to access property "document"" since the Iframe is not part of your domaine.
The only solution is to fetch the page from the server side code and change the needed CSS.
A sort of hack-ish way of doing things is like Eugene said. I ended up following his code and linking to my custom Css for the page. The problem for me was that, With a twitter timeline you have to do some sidestepping of twitter to override their code a smidgen. Now we have a rolling timeline with our css to it, I.E. Larger font, proper line height and making the scrollbar hidden for heights larger than their limits.
var c = document.createElement('link');
setTimeout(frames[0].document.body.appendChild(c),500); // Mileage varies by connection. Bump 500 a bit higher if necessary
Just add this and all works well:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
If the iframe comes from another server, you will have CORS ERRORS like:
Uncaught DOMException: Blocked a frame with origin "https://your-site.com" from accessing a cross-origin frame.
Only in the case you have control of both pages, you can use https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage to safely send messages like this:
On you main site(one that loads the iframe):
const iframe = document.querySelector('#frame-id');
iframe.contentWindow.postMessage(/*any variable or object here*/, 'https://iframe-site.example.com');
on the iframe site:
// Called sometime after postMessage is called
window.addEventListener("message", (event) => {
// Do we trust the sender of this message?
if (event.origin !== "http://your-main-site.com")
return;
...
...
});
Yes, it's possible although cumbersome. You would need to print/echo the HTML of the page into the body of your page then apply a CSS rule change function. Using the same examples given above, you would essentially be using a parsing method of finding the divs in the page, and then applying the CSS to it and then reprinting/echoing it out to the end user. I don't need this so I don't want to code that function into every item in the CSS of another webpage just to aphtply.
References:
Printing content of IFRAME
Accessing and printing HTML source code using PHP or JavaScript
http://www.w3schools.com/js/js_htmldom_html.asp
http://www.w3schools.com/js/js_htmldom_css.asp

Open <div> popup outside iFrame

Info: I was working on it for so long, I have a webpage that contains an iframe. Inside that iframe i have opened a page (application) from my own site.
Question: I'm trying to get the <div class = "ps-lightbox"> </ div> inside that iframe out of the iframe. but i cant figure it out with jQuery..
I know it sounds confusing. But I hope you understand my explanation.
Does anyone know how to fix this? You could save my day..
Screenshot of the webpage <
You can not access the elements which are not part of iframe document. But if you have iframe of your own website then window.postMessage can do the trick.
Consider below example:
mainPage.html
<html>
<head>
<script type="text/javascript">
window.addEventListener("message", function(evnet){
if(event.type === "GET_SOME_ELEMENT"){
var iframeWindow = document.getElementsById("iframe1")[0].contentWindow;
iframeWindow.postMessage("POST_SOME_ELEMENT", "TARGET_ORIGIN", {element: $(".some-element")}
}
});
<script/>
</head>
<body>
<div class="some-element"/>
<iframe id="iframe1" src="iframePage.html"/>
</body>
</html>
iframePage.html
<html>
<head>
<script type="text/javascript">
if(window.parent){
window.parent.postMessage("GET_SOME_ELEMENT", "TARGET_ORIGIN");
window.addEventListener("message", function(evnet){
if(event.type === "POST_SOME_ELEMENT"){
console.log(event.data.element);
}
});
}
<script/>
</head>
</html>
The exact question is how to do it with pure JavaScript, not with jQuery.
But I always use the solution that can be found in jQuery's source code. It's just one line of native JavaScript.
For me, it's the best, easily readable and even afaik the shortest way to get the content of the iframe.
First get your iframe
var iframe = document.getElementById('id_description_iframe');
// or
var iframe = document.querySelector('#id_description_iframe');
And then use jQuery's solution
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
It works even in the Internet Explorer which does this trick during
the contentWindow property of the iframe object. Most other browsers
use the contentDocument property and that is the reason why we proof
this property first in this OR condition. If it is not set to try
contentWindow.document.
Select elements in iframe
Then you can usually use getElementById() or even querySelectorAll() to select the DOM-Element from the iframeDocument:
if (!iframeDocument) {
throw "iframe couldn't be found in DOM.";
}
var iframeContent = iframeDocument.getElementById('frameBody');
// or
var iframeContent = iframeDocument.querySelectorAll('#frameBody');
Call functions in the iframe
Get just the window element from iframe to call some global functions, variables or whole libraries (e.g. jQuery):
var iframeWindow = iframe.contentWindow;
// you can even call jQuery or other frameworks
// if it is loaded inside the iframe
iframeContent = iframeWindow.jQuery('#frameBody');
// or
iframeContent = iframeWindow.$('#frameBody');
// or even use any other global variable
iframeWindow.myVar = window.myVar;
// or call a global function
var myVar = iframeWindow.myFunction(param1 /*, ... */);
Note
All this is possible if you observe the same-origin policy.
This might help you
var html = $(".ps-lightbox").contents().find("body").html()
And btw, you can get access to iframe's content only from the same origin due to XSS protection
Make sure your code is inside jQuery ready event.
// This won't work
$("#iframe").contents().find('.ps-lightbox');
// This will work
$(function() {
$("#iframe").contents().find('.ps-lightbox');
})

Write html string to a document and read its outer html in IE10

I need to write an html string to an element and then read the resulting outer html from that element. I need this to work in IE10, latest FF, Chrome, Safari, Android, iOS Safari but not in any older browsers. In all non-ie browsers the following simple approach works:
var html = WIUI.createElement('html');
html.innerHTML = htmlString;
console.log(html.outerHTML);
However in IE10 the above approach fails in one unacceptable way. Somehow the html element has a body tag matching that of the parent document, (NOT of the html string I give it!!! I assume this is a crazy bug in the browser itself). You can see this bug in action here: https://mod.it/iuu_1DcT, if you view that application in a browser besides IE10 the output body onload function will match the input body onload function. In IE10 it will set the output onload function to foo() no matter what the input is because foo is the onload function of the parent.
An alternative approach that does work in IE10 (and all modern browsers) is to create and iframe like so:
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.open();
doc.write(htmlString);
doc.close();
console.log(doc.documentElement.outerHTML);
However this has the unfortunate side effect that writing to the iframe actually causes the html to be executed which I do not want.
From my research something like so SHOULD work (and does in browsers that aren't IE)
var doc = document.implementation.createHTMLDocument('temp');
doc.open();
doc.write(htmlString);
doc.close();
console.log(doc.documentElement.outerHTML);
However in IE10 the doc.open line gives an "unspecified error". Can anyone give me any clue what is going on or why IE is so difficult to work with compared to other browsers for this type of task?
Try this mate:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
<textarea id="textArea" rows="4" cols="50">
Empty area
</textarea>
<script type="text/javascript">
jQuery.fn.outerHTML = function(s) {
return s
? this.before(s).remove()
: jQuery("<p>").append(this.eq(0).clone()).html();
};
function doSomething(text) {
var $wrapper = $('#textArea');
$wrapper.html('<html><head></head><body><div id="inner">' + text +'</div></body></html>');
console.log($wrapper.outerHTML());
}
doSomething('test');
</script>
</body>
</html>
This will output: <textarea id="textArea" rows="4" cols="50"><html><head></head><body><div id="inner">test</div></body></html></textarea> to the console. I have NOT tested this in IE 10 as I don't have access to it. But it Should work.
Credit to Get selected element's outer HTML for the outerhtml implementation.
Edit:
You can work around this issue in IE10 simply by doing thing following:
var doc = document.implementation.createHTMLDocument('title');
html = doc.createElement('html');
html.innerHTML = htmlString;
console.log(html.outerHTML);
For some reason creating a new document rather than using the existing one causes IE10 not to corrupt the body onload attribute.

I need to access document object of document inside an IFRAME. Is there a way to do that for IE7 and IE8?

I need to get the scrollHeight property of the document inside the <iframe>. I tried all the options which are:
contentWindow.document
contentDocument
window.frames
All these works fine for IE9,chrome and FF. But i couldnot get it to work in IE7 and IE8.
If anyone has a solution that would be great.
thanks
try out :
contentWindow.documentElement.document
Try this
<script>
var iframe_doc = "window.document.getElementById('your_iframe_id').document";
iframe_doc = eval(iframe_doc);
</script>
The above code should return you the iframe document, then get the scrollHeight attribute of the iframe document.

How can I dynamically add an <object> tag with JavaScript in IE?

I have to add either an embed tag for Firefox or an object tag for Internet Explorer with JavaScript to address the appropriate ActiveX / Plugin depending on the browser. The plugin could be missing and needs to get downloaded in this case. The dynamically added embed tag for Firefox works as expected. The dynamically added object tag for Internet Explorer seems to do nothing at all. The object tag needs the following attributes to function properly.
id ="SomeId"
classid = "CLSID:{GUID}"
codebase = "http://www.MyActicexSource.com/MyCuteActivex.CAB#Version=2,0,0,1"
Even a general working idea or method would be nice.
Thanks!
I needed to do this same thing and simply place all of the HTML needed for the OBJECT tag in a string in JavaScript and simply replace the innerHTML of a div tag with the OBJECT HTML and it works in IE just fine.
// something akin to this:
document.getElementById(myDivId).innerHTML = "<OBJECT id='foo' classid='CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95'.....etc";
That should work, it does just fine for me - I use it to embed Windows Media Player in a page.
UPDATE: You would run the above code after the page loads via an event handler that either runs on the page's load event or maybe in response to a user's click. The only thing you need to do is have an empty DIV tag or some other type of tag that would allow us to inject the HTML code via that element's innerHTML property.
UPDATE: Apparently you need more help than I thought you needed? Maybe this will help:
Have your BODY tag look like this: <body onload="loadAppropriatePlugin()">
Have somewhere in your page, where you want this thing to load, an empty DIV tag with an id attribute of something like "Foo" or whatever.
Have code like this in a <script> tag in your <head> section:
function getIEVersion() { // or something like this
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
return ((msie > 0) ? parseInt(ua.substring(msie+5, ua.indexOf(".", msie))) : 0);
}
function loadAppropriatePlugin() {
if(getIEVersion() != 0) { // this means we are in IE
document.getElementById("Foo").innerHTML = "<OBJECT id='foo' classid='CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95'.....etc";
} else {
// if you want to maybe do the same for FF and load that stuff...
}
}
Does that help?
var object = document.createelement('object')
object.setAttribute('id','name')
object.setAttribute('clssid','CLSID:{}')
And the same for other parameters.
Two ways.
1) Just do a document.write where ever you want it
<script type="text/javascript">
<!--
document.write("<object id=\"SomeId\" classid=\"CLSID:{GUID}\" codebase=\"http://www.MyActicexSource.com/MyCuteActivex.CAB#Version=2,0,0,1\"></object>");
-->
</script>
2) Edit a tag's innerHTML property.
<div id="my-div"></div>
<script type="text/javascript">
<!--
document.getElementById("my-div").innerHTML = "<object id=\"SomeId\" classid=\"CLSID:{GUID}\" codebase=\"http://www.MyActicexSource.com/MyCuteActivex.CAB#Version=2,0,0,1\"></object>";
-->
</script>
EDIT: Just a note, it is best to not use JavaScript to do this, since people with JavaScript enabled will never see the object. It would be better to just place it in your HTML.

Categories