javascript in iframe document.write overwrites parents document - javascript

I want to load HTML as string into an iframe via Javascript.
like this:
$('#iframe1').contents().find('html').html("<h1>This is an iframe</h1>");
this worked great until I found out, that inside this HTML upcomming Javascript like document.write are writing to the wrong document -> the parent!
Here is a Plunker to show it:
http://plnkr.co/edit/YQAqqSDCVKnP3uhLj4lF?p=preview
if I load the same HTML to the iframe via src as external document, the document.write goes to the iframe (and not to the parent), which is what i was expecting.
Are there some insights out there?
How can I tell the browser to correctly create the iframes document scope before it executes its Javascript?
PS: Its meant to be for preview purposes, so i inject HTML-Code of a (trusted!) source, but within that code, document.write is allowed.

Ok. srcdoc is helpfull here.
$('#iframe1').attr({srcdoc:intrusiveHTML});
I updated the Plunker.
With srcdoc, Javascript won't slip up with the document scope.
It won't work in IE (http://caniuse.com/#feat=iframe-srcdoc), so it might help to use Polyfill additionally:
https://github.com/jugglinmike/srcdoc-polyfill
But I did not test that yet.

Instead of using document.write, use document.getElementById('iframe1').contentWindow.document.write.
Because when you point document it will take main window document, so we need to indicate which iframe doument need to be used.

Related

How to reload script tag

I'm dynamically changing a script tag's src attribute using JavaScript.
Problem is, that I'd like to "undo" the previous JavaScript before re-executing it.
Any way to do this?
Thanks,
g3
I can describe a method I used to achieve a partial undo in a project. Ugly, but might be useful. First, you may need to refactor your script to work from within an iframe, and/or wrap it in a with statement to give it easy access to some objects in the parent (don't even think of with(opener); you'll want something more precise like with({someObject: opener.someObject}).
When your script runs, it can use the iframe's global scope and DOM freely. Then, instead of reloading the <script> tag, you overwrite the whole iframe, which will reset everything your script did inside the iframe.

Non-invasive Javascript HTML injection

I'm looking for a non-invasive javascript HTML/CSS/JS injection into page.
I'm ideally looking to use document.write, but keep the original contents that were on the page. So doing the following:
javascript:document.write("blablabla"); - this removes all the content on page, I don't want to use innerHTML += to append the data.
Any suggestions?
If document.write is called after the onload event for the document it needs to re-open the document - effectively truncating it. While you can explicitly call document.write() inline (either with javascript directly embedded in the page or with a tag which does not use defer/async) this is considered bad practice as it blocks all the other processing of the page.
You can inject elements by constructing them in Javascript personally I prefer to set the innerHTML of an existing placeholder to an HTML fragment:
<div id='placeholder/></div>
...
document.getElementById('placeholder').innerHTML="<h2>hello world!</h2>";
(using createElement becomes messy and slow when creating/injecting complex HTML)
document.write will always overwrite the whole page as far I know. One option is to append/prepend your code to a div or to the bottom of your body.
$(elementObj).append(contents);
//or
$(elementObj).prepend(contents);
You can createElement() then use one of the methods above to inject your code into the newly created element.

jQuery: How to replace the whole DOM with another HTML using .load

I have a problem.
We are doing a Captive Portal.
Go to any site, for example www.php.net
Then in Chrome's console, use this:
$("html").load( "https://www.ccc.co.il/Suspend.aspx" );
You will notice, the DOM is replaced, but not quite the way it should be:
The wrapper elements of the loaded webpage (title, body for example) are missing!
This causes problems of course on the injected page.
How do I replace the entire initial DOM?
And please dont suggest to me using a link, or normal redirect.
Those are the restrictions, I need to replace the entire DOM tree please.
Thanks!
This is fundamentally a feature of browsers.
Here's a snip from the jQuery docs for .load():
jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as <html>, <title>, or <head> elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser.
While I don't recommend what you're suggesting at all, I will attempt to answer your question:
Using a server-side language (like PHP, for example), return documents as parsed json:
{
"head": [head string],
"body": [body string]
}
Then your JavaScript can individually replace each element.
You'll need to switch from .load() to something more configurable, like .ajax()
I think you would have to use an iframe in this case as I don't think that you can replace an entire DOM with another.
$('body').html("<iframe height=100% width=100% frameBorder=0 src='https://www.ccc.co.il/Suspend.aspx'></iframe>");
http://jsfiddle.net/c7EbY/
$.get("https://www.ccc.co.il/Suspend.aspx", function(html){$("html").html(html)});
I'm using a regular AJAX function here because it shouldn't strip anything.
Sorry about those 4 htmls in a row. :P

When should one use .innerHTML and when document.write in JavaScript

Is there a general rule, when one should use document.write to change the website content and when to use .innerHTML?
So far my rules were:
1) Use document.write when adding new content
2) Use .innerHTML when changing existing content
But I got confused, since someone told me that on the one hand .innerHTML is a strange Microsoft standard, but on the other hand I read that document.write is not allowed in XHTML.
Which structures should I use to manipulate my source code with JavaScript?
innerHTML can be used to change the contents of the DOM by string munging. So if you wanted to add a paragraph with some text at the end of a selected element you could so something like
document.getElementById( 'some-id' ).innerHTML += '<p>here is some text</p>'
Though I'd suggest using as much DOM manipulation specific API as possible (e.g. document.createElement, document.createDocumentFragment, <element>.appendChild, etc.). But that's just my preference.
The only time I've seen applicable use of document.write is in the HTML5 Boilerplate (look at how it checks if jQuery was loaded properly). Other than that, I would stay away from it.
innerHTML and document.write are not really comparable methods to dynamically change/insert content, since their usage is different and for different purposes.
document.write should be tied to specific use cases. When a page has been loaded and the DOM is ready you cannot use that method anymore. That's why is generally most used in conditional statements in which you can use it to syncronously load external javascript file (javascript libraries), including <script> blocks (e.g. when you load jQuery from the CDN in HTML5 Boilerplate).
What you read about this method and XHTML is true when the page is served along with the application/xhtml+xml mime type: From w3.org
document.write (like document.writeln) does not work in XHTML documents (you'll get a "Operation is not supported" (NS_ERROR_DOM_NOT_SUPPORTED_ERR) error on the error console). This is the case if opening a local file with a .xhtml file extension or for any document served with an application/xhtml+xml MIME type
Another difference between these approaches is related on insertion node: when you use .innerHTML method you can choose where to append the content, while using document.write the insertion node is always the part of document in which this method was used.
1) document.write() puts the contents directly to the browser where the user can see it.
this method writes HTML expressions or JavaScript code to a document.
The below example will just print ‘Hello World’ into the document
<html>
<body>
<script>
document.write("Hello World!");
</script>
</body>
</html>
2) document.innerHTML changes the inner content of an element
It changes the existing content of an element
The below code will change the content of p tag
<html>
<body>
<p id="test" onclick="myFun()">Click me to change my HTML content or my inner HTML</p>
<script>
function myFun() {
document.getElementById("test").innerHTML = "I'm replaced by exiesting element";
}
</script>
</body>
</html>
you could use document.write() without any connected HTML, but if you already have HTML that you want to change, then document.innerHTML would be the obvious choice.
I agree with the above comments. Basically:
document.write can be useful while the page is loading, to output new HTML tags or content while the browser is building the document object model. That content is output precisely where the JavaScript statement is embedded.
.innerHTML is useful at any time to insert new HTML tags/content as a string, and can be more easily directed to specific elements in the DOM regardless of when/where the JavaScript is run.
A couple of additional notes...
When document.write is called from a script outside of the body element, its output will be appended to the body element if called while the page is loading; but once the page is loaded, that same document.write will overwrite the entire document object model, effectively erasing your page. It all depends on the timing of document.write with the page load.
If you are using document.write to append new content to the end of the body element, you may be better off using this:
document.body.innerHTML += "A string of new content!";
It's a bit safer.

Included JS in iframe has context of top frame window

$('<script/>', {
src: '/path/to/javascript.js',
type: 'text/javascript'
}).appendTo($('#iframe').contents().find('body'));
Correct me if I'm wrong, but I think that should load the JS into the iframe. I've also tried appending to head.
The problem
javascript.js is executed, but console.debug(this) in that script returns the top frame window. I've tried to verify that the script is actually included in the iframe, but don't really know how.
Additionally, running $('a') from javascript.js returns all links in the top frame, not every link in the iframe which I'd like.
Thanks for your time!
Update: I've put together an isolated test case which you also can download. Check the console and note that this is the top frame (can be verified by the variable _TOP).
This is kind of a grey area. For this specific action using jQuery, under the hood you're using importNode or adoptNode depending on the browser. However, IE won't support either (since I last researched it).
You might want to get a reference to the document, and write the script. If memory serves me right:
$('<iframe/>')[0].contentDocument.document.write('script');
I was able to make something in the same domain iframe update:
http://jsfiddle.net/maniator/DX6bg/1/
Make sure that the two URLs are in the same domain.
(including if there is a www in from or not)
UPDATE
You can test it like this:
$(function(){
var iframe = $('#iframe').contents();
$('body', iframe).append($('<div>', {text: 'this is a test'}));
});
now if you see the text this is a test in the iframe you know it is working

Categories