What alternatives are there to document.write? - javascript

I'm trying to load a zoom.it script dynamically, but I can't seem to do so without document.write. The problem with document.write is that it replaces everything on my page, which I don't want. What other alternatives are there?
This is document.write in action: http://jsfiddle.net/JyT9B/6/ (notice the element that gets removed).
Also, putting the <script> tag straight into the body works: http://jsfiddle.net/gTcRw/5/, but I need it to be dynamically placed.
I've also tried the methods in Ways to add javascript files dynamically in a page, and How to add and remove js files dynamically, but seem to get the error Cannot set property 'innerHTML' of null, which is probably a zoom.it specific thing. I wouldn't mind knowing why this is the case.
The jsfiddle examples of using the other approaches:
$('body').append
$.getScript
document.createElement as per google analytics
document.createElement in a function
Also tried this in vain: .innerHTML - it gets added to the dom but isn't run.

I think the combination of createElement and appendChild should work, in something like this:
http://jsfiddle.net/kbDny/3/
$(function() {
getScript("http://www.zoom.it/aaa.js");
});
function getScript(src) {
var scr = document.createElement("script");
scr.type = "text/javascript";
scr.src = src;
var head = document.getElementsByTagName("head")[0];
head.appendChild(scr);
}
But there's no reason to not use $.getScript - just pass the url as the first argument, like:
$.getScript(url, function (data, textStatus, jqxhr) {
// Script loaded successfully
});

Ended up using an iframe to contain a html page with an embedded script tag.
The benefit of an iframe is that I can show/remove it at will, without having to worry about cleaning up the current page document when removing the script.
ie,
HTML
<body>
<div id="container">
<a id="show" href="#">show</a>
<a id="close" href="#">close</a>
<div id="placeholder"></div>
</div>
</body>​
JavaScript
function appendFrame(elem) {
var iframe = document.createElement("iframe");
iframe.id = "iframe";
iframe.setAttribute("src", "about:blank");
iframe.style.width = "200px";
iframe.style.height = "200px";
$(elem).append(iframe);
}
function loadIFrame() {
appendFrame($("#placeholder"));
var doc = document.getElementById('iframe').contentWindow.document;
doc.open();
doc.write("<html><head><title></title></head><body><script src='http://zoom.it/aaa.js'><\/script><\/body><\/html>");
doc.close();
};
$("#show").click(function() {
loadIFrame();
});
$("#close").click(function() {
$("#iframe").remove();
});​
JSFiddle solution here: http://jsfiddle.net/7KRcG/2/

Related

Jquery not loading inside iFrame that includes jquery

I have to dynamically create an Iframe and fill it with content, so I am doing the following:
var ifrm = document.createElement("iframe");
ifrm.id = 'myIframe';
document.getElementById('myIframe').contentWindow.document.write(myIframeContent);
The issue is that the iframe content relies on jquery. Jquery is included in the head of myIframeContent like so:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
However using jquery selectors (e.g. $('#myDiv')) in the iframe results in the variable being undefined. I assume because there is a problem loading jquery, but I'm not sure why. Is it due to how the iframe is being created? Other scripts included in the iframe content are working correctly.
Perhaps you just need to escape the <script><\/script>
SO cannot run this due to security errors
var ifrm = document.createElement("iframe");
ifrm.id = 'myIframe';
const myIframeContent = `<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"><\/script>
<div id="myDiv">Hello</div>
<script>$("#myDiv").html("Hello there")<\/script>`;
document.getElementById("content").appendChild(ifrm);
document.getElementById("myIframe").contentWindow.document.write(myIframeContent);
<div id="content"></div>

Reload iFrame (same-domain) without changing `src=`

I am dynamically creating iframe , which just contains content (no src attribute).
var iframe = document.createElement('iframe');
iframe.contentWindow.document.body.innerHTML= my_page_content;
....
however, JS scripts (<script src="....." inside my_page_content) are not being loaded and I have to re-load scripts.
these methods wont help me to reload frame:
//this one emptyfies the iframe at all
iframeElement.src = iframeElement.src
//this one is not possible, because the `<script>` links are embedded in the content already.
var script = doc.createElement('script'); script.src = "jquery.min.js";
framebody.appendChild(script);
what are the solutions to force the iframe to load the included scripts in its html content? maybe I am attaching the content in a wrong way?
The only way I've solved this was to write the body inside iframe using write() command:
var ifr = iframeElement.contentWindow.document;
ifr.open(); ifr.write("<body>"+ my_page_content +"</body>"); ifr.close();
neither appendChild() nor .innerHTML helped me.

Run custom javascript from dynamicaly loaded innerHTML context

I have an HTML document
...
<div id="test"></div>
...
Then i dynamicaly load some context to #test div.
function change()
{
ws = document.getElementById(id);
str = '<script>function ttest(){window.alert("Yahoo!!!")}</script><select><option onclick="ttest();">1</option><option >2</option></select>';
ws.innerHTML = str;
}
window.onload = change();
When the page is loaded a custom script
<script>function ttest(){window.alert("Yahoo!!!")}</script>
doesnt work.
It works perfect when its put static without any innerHTML.
Also it works when its not a custom function.
How can i make my custom function work, when it was loaded dynamically using innerHTML or/and AJAX+innerHTML ?
Add your script to the document.head via createElement. So something like this:
var script = document.createElement("script");
script.innerHTML = "function ttest() { alert('Yahoo'); }";
document.head.appendChild(script)

Does anyone know a way to print the loaded page HTML after DOM is completed?

I'm looking for a way to read the source code of a page after it finished loading and inspect the code to see if it contains a specific text.
I found this reference but this only returns the text visible in the page and not the whole HTML code.
For instance, if the html source code is:
<html>
<header>
<header>
<body>
<p> This is a paragraph</a>
<body>
</html>
I want the script to print exactly the same thing.
Your help is appreciated.
I think you are over-complicating this problem. You don't need to "print" the page's HTML or "inspect the code".
In a comment, you said:
Check if page contains an iframe [and] Display a message if the iframe is found
You can just use DOM traversal functions to examine the DOM.
Try something like this:
window.addEventListener('load', function() {
if(document.getElementsByTagName('iframe').length){
console.log('Found an iframe');
}
});
Or with jQuery:
$(function() {
if($('iframe').length){
console.log('Found an iframe');
}
});
That's so simple, you can use this method to run a script after a page is fully loaded window.onload
function load(){
console.log(document.getElementsByTagName('html')[0].innerHTML);
}
window.onload = load;
For further explanations, check this post
Do like this, call this function on load
Fiddle Demo
function printBody() {
// store oiginal content
var originalContents = document.body.innerHTML;
// get the outer html of the document element
document.body.innerText = document.documentElement.outerHTML;
// call window.print if you want it on paper
window.print();
// or put it into an iframe
// var ifr = document.createElement('iframe');
// ifr.src = 'data:text/plain;charset=utf-8,' + encodeURI(document.documentElement.outerHTML);
// document.body.appendChild(iframe);
// a small delay is needed so window.print does not get the original
setTimeout(function(){
document.body.innerHTML = originalContents;
}, 2000);
}
Src: Print <div id=printarea></div> only?
Assuming that by 'print' you don't actually mean to transfer it to a paper copy, you can add some script like:
window.addEventListener('load', function() {
var content = document.documentElement.innerHTML,
pre = document.createElement('pre'),
body = document.body;
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
});
What this does, step by step is:
window.addEventListener('load', function() > Wait for the page to be fully loaded and then execute the function
content = document.documentElement.innerHTML > store the actual page source in the content variable (document.documentElement refers to the 'root'-node, usually <html> in html documents
pre = document.createElement('pre') > create a new <pre>-element
body = document.body > create a reference to the <body> element
pre.innerText = content > assign the HTML-structure we've stored earlier as text to the <pre>-element
body.insertBefore(pre, body.firstChild) > put the <pre>-element (now with contents) before any other element in the body (usually on top of the page).
This leaves you with the entire source (as it was before creating the <pre>-element containing the source) on top of you page.
Edit: Added <iframe> workflow
It was not clear to me you actually wanted to target an <iframe>, so here's how to do that (using a naive approach, more on that further on):
window.addEventListener('load', function() {
var iframeList = document.getElementsByTagName('iframe'),
body = document.body,
content, pre, i;
for (i = 0; i < iframeList.length; ++i) {
content = iframeList[i].documentElement.innerHTML;
pre = document.createElement('pre');
pre.innerText = content;
body.insertBefore(pre, body.firstChild);
}
});
why is this approach naive?
There is a thing called Same-Origin-Policy in javascript, which prevents you from accessing <iframe>-content which if the contents do not originate from the same domain as the page containing the <iframe>.
There are several ways to take this into consideration, you could wrap the inside of the for-loop in try/catch-blocks, though I prefer to use a more subtle approach by not even considering <iframes> which do not match the Same-Origin-Policy.
In order to do this, you can swap the getElementsByTagName method with the querySelectorAll method (please note the compatibility table at the bottom of that page, see if it matches your requirements).
The querySelectorAll accepts a valid CSS selector and will return a NodeList containing all matching elements.
A simple selector to use would be
'iframe[src]:not([src^="//"]):not(src^="http")' which selects all iframe with a src attribute which does not start with either // or http
Disclaimer: I never use a <base>-tag (which changes all relative paths within the HTML) or refer to the current website using a path containing the domain, so the example CSS-selector does not consider these aberrations.
Can you use :not()
IE9 or better
Can you use document.querySelector(All)
IE8 or better (in order to use with :not(), IE9 or better)
hover/click the boxes above to show the spoiler

Load jQuery in an iframe

I'm writing a script which requires some stuff to be carried out in an iframe. It's a userscript for a site which I do not own, so because of cross-domain issues, I cannot just set the src of the iframe to a page with my own code. Instead, I am dynamically building the iframe.
To do this, I have
function childScripts(){
//Stuff that must be injected into the iframe.
//Needs jQuery
}
//because I'm lazy:
var iframeWin=$('#my-iframe')[0].contentWindow;
//Load jQuery:
var script = iframeWin.document.createElement("script");
script.type = "text/javascript";
script.src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
iframeWin.document.head.appendChild(script);
//Inject script
var script = iframeWin.document.createElement("script");
script.type = "text/javascript";
script.textContent="("+childScripts.toString()+")()";
iframeWin.document.body.appendChild(script);
Now, the injected script needs jQuery, but for some reason, jQuery isn't loaded when the injected script runs--even though jQuery is in <head> and the injected script is in <body>.
I've tried other workarounds--making the injected script run onload. I don't like the idea of setting a timeout and checking for the existence of jQuery, I'd prefer a more elegant solution.
I've also tried copying the $ object to iframeWin.$, but of course that doesn't work, since it just backreferences to the parent $ and manipulates the parent document.
It's easier to manipulate iframes using jQuery. Please try:
$('<iframe id="my-iframe"/>').load(function(){
$('#my-iframe').contents().find('body').append('asd').end()
.find('body').append('<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"><\/script>').end()
.find('body').append('<script>$(function() {alert("hello from jquery");console.log("hello from jquery"); })<\/script>');
}).appendTo("body");
Placement:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
$('<iframe id="my-iframe"/>').load(function(){.....
</script>
</body>
</html>

Categories

Resources