Resizing Iframe issue in Chrome only - javascript

Okay, here goes. Stack Overflow virgin here but hopefully you guys will be able to help me.
I have been playing around with resizing the height of an iframe based on it's content. The content varies as a user will progress through a series of forms, this means that each submit will result in a new form of which there are 3 forms.
The code below is called when the iframe loads,
function checkHeight() {
var frame=document.getElementById('frame');
var doc=frame.contentWindow.document;
var data=doc.getElementById('data');
alert(data);
var data_height=data.offsetHeight;
if(data_height) {
frame.style.height=data_height + 'px';
alert('height has been set');
}
}
This is working fine on both mac and pc versions of Mozilla, IE and Safari but I am having a massive issue with chrome. It is not returning a document within the frame. Is this a permissions error or what?!
I have also tried contentDocument but to no avail.
All the documents reside on my server and are all within the same folder.
Thanks in advance.

Edit:
I've re-read your question - would it be simpler to just calculate the height inside the iframe's document and call the parent resizing function since they are in the same security sandbox (i.e. on the same domain)?
Original:
Since a somewhat similar thing happens when the iframes are embedded from a different domain (cannot access iframe..document) I'd speculate this approach would work:
First: calculate the document height in the document itself (i.e. inside the iframe).
Pass the values to the parent using window.postMessage/hash polling for older browsers. There is a neat library that takes care of compatibility for you.
Receive the value in the parent and resize the iframe accordingly.
Again, this may be overkill, but given that the solution has been tested to do exactly what you're after between different security sandboxes, this should also be the case for a simpler scenario if iframes are on the same domain.
That being said, if they are on the same domain (as opposed to widgets/non-mashable third party content) is there really need for an iframe? Sounds like it's just a matter of setting up jQuery to make ajax requests and populate container(s) with new data.

this seems like a fairly straight forward question so i'm not sure why such strange answers, so maybe i missed the boat entirely on this one, but here are my solutions, one is x-domain and the other isn't (note: the open/write/close, is just there to simulate server interaction to make it more obvious what's going on...)
first x-domain style:
// METHOD #1: postMessage() x-domain (chrome, ff, ie8+, safari, etc)
var d = document,
iframe = d.createElement('iframe');
iframe.height = 0;
d.getElementsByTagName('body')[0].appendChild(iframe);
window.onmessage = function(msg) {
iframe.height = parseInt(msg.data, 10);
};
var fd = iframe.contentDocument || iframe.contentWindow.document;
fd.open();
fd.write('<!DOCTYPE ht' + 'ml><ht' + 'ml><he' +
'ad><scri' + 'pt>' +
'window.onload = function(){' +
'var db = document.body,' +
'de = document.documentElement;' +
'window.parent.postMessage(' +
'Math.max(db.scrollHeight, de.scrollHeight, db.offsetHeight, de.offsetHeight, db.clientHeight, de.clientHeight),' +
'"*"' +
');' +
'};</scr' + 'ipt></he' + 'ad><bo' +
'dy style="background:#afa"><div style="border:s' +
'olid 1px black;padding:50px;line-height:50px">method #1: x-domain<b' +
'r />test<br />test</div></bo' + 'dy></ht' +
'ml>');
fd.close();
next more compatible same domain version:
// METHOD #2: manually same-domain (all browsers? [with tweaks] )
var iframe2 = d.createElement('iframe');
iframe2.height = 0;
iframe2.onload = function() {
var xfd = iframe2.contentDocument || iframe2.contentWindow.document,
db = xfd.body,
de = xfd.documentElement;
iframe2.height = Math.max(db.scrollHeight, de.scrollHeight, db.offsetHeight, de.offsetHeight, db.clientHeight, de.clientHeight);
};
d.getElementsByTagName('body')[0].appendChild(iframe2);
fd = iframe2.contentDocument || iframe2.contentWindow.document;
fd.open();
fd.write('<!DOCTYPE ht' + 'ml><ht' + 'ml><he' +
'ad></he' + 'ad><bo' +
'dy style="background:#aaf"><div style="padding:50px;line-height:50px;border:s' +
'olid 1px black;">method #2: same domain<b' +
'r />test2<br />test2</div></bo' + 'dy></ht' +
'ml>');
fd.close();
you can see it in action here: http://jsbin.com/ifevad
i hope this helps -ck

This very same example worked for me, in Chrome 17, on Windows, with the given html files:
index.html:
<html>
<head>
</head>
<body>
<iframe src="index2.html" id="test">
</iframe>
</body>
</html>
index2.html
<html>
<head>
</head>
<body>
<div id="test_div">
Ohai
</div>
</body>
</html>
Then I used this in the chrome developer window:
i = document.getElementById('test')
doc = i.contentWindow.document
data=doc.getElementById('test_div');
i.style.height = data.offsetHeight + 'px'
The only catch was that it didn't work when opening the .html files directly - I had to start a web server.
I used this (it's the default Python server):
server.py
import SimpleHTTPServer
import SocketServer
PORT = 8080
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()

Related

Get the height of a same domain iframe when that iframe is inside a different domain iframe?

I have a site which has a media player embedded inside an iframe. The media player and the site are on the same domain, preventing cross-origin issues. Each page, the main page as well as the media player page, have a bit of code which finds the height and width of any parent iframe:
var height = $(parent.window).height();
var width = $(parent.window).width();
No problems so far....until:
A client wants to embed my site inside an iframe on his own site. His site is on a different domain. Now, my iframe is inside another iframe and my code is throwing cross-origin errors.
The following does not throw errors:
var test1 = parent.window; // returns my site
var test2 = window.top; // returns client site
The following does throw cross-origin errors:
var test3 = parent.window.document;
var test4 = $(parent.window);
var test5 = window.top.document;
var test6 = $(window.top);
How do I get the height of the iframe on my domain without the cross-origin errors? I'm hoping for a pure javascript/jQuery solution.
Options which will not work for my solution are:
Using document.domain to white list the site.
Modifying the web.config to white list the site.
Like in Inception, I must go deeper. Please help.
You will need to use Javascript's messager. First, you need to define a function like this:
function myReceiver(event) {
//Do something
}
Then you need an event listener:
window.addEventListener("message", myReceiver);
You will need something like this on both sides. Now, you can send a message like this to the iframe:
innerWindow.contentWindow.postMessage({ message: {ResponseKey: "your response key", info1: "something1", info2: "something2"}}, innerWindow.src)
and this is how you can send a message to the parent:
window.parent.postMessage({ message: {ResponseKey: "your response key", info1: "something1", info2: "something2"}}, myorigin);
The only missing item in the puzzle is myorigin. You will be able to find it out in your iframe using event.origin || event.originalEvent.origin in the message receiver event.
However, the pages using your site in their pages inside an iframe will have to include a Javascript library which will handle the communication you need. I know how painful is this research, I have spent days when I have done it before to find out the answer.
Your code is running from the iframe in the middle of the parent and the child window. So, anytime you call
window.parent
and your site is embedded inside an iframe and the parent is a different domain (Same origin policy), an error will be thrown. I would recommend first checking if the parent is the same origin. You need to wrap this check in a try catch.
NOTE: Most browsers, but not Edge, will not throw an error if the parent is http://localhost:xxx and the iframe is http://localhost:zzz where xxx is a different port number than zzz. So, you also need to manually check the origins match by comparing the protocol, domain, and port.
var isEmbeddedInCrossOriginIframe = false;
try {
var originSelf = (window.self.location.protocol + '//' +
window.self.location.hostname +
(window.self.location.port ? ':' +
window.self.location.port : '')).toLowerCase();
var originParentOrSelf = (window.parent.location.protocol + '//' +
window.parent.location.hostname +
(window.parent.location.port ? ':' +
window.parent.location.port : '')).toLowerCase();
isEmbeddedInCrossOriginIframe = originSelf != originParentOrSelf;
}
catch(err) {
isEmbeddedInCrossOriginIframe = true;
//console.log(err);
}
Your solution will then be:
var height = $(isEmbeddedInCrossOriginIframe ? window : parent.window)
.height();
var width = $(isEmbeddedInCrossOriginIframe ? window : parent.window)
.width();

JavaScript Behavior difference: IE11/Edge vrs Chrome/Firefox

function displayInfo(nKey) {
var i, xdata, xfilm, xprop;
if(!nKey) return false;
var objFilm;
var imgRef;
//iterate through all object properties; display their attributes
var jqxhr = $.getJSON('dbMovies.json', function(data) {
$.each(data.disc, function(i, xdata) {
if(xdata.key == nKey) {
objFilm = xdata.film;
imgRef = xdata.img;
if(xdata.doc) bkDoc = true;
return false;
}
}); // $.each
})
.done(function() {
// objFilm has either a single film object or else an array of film objects
var arInfo = [];
if(!$.isArray(objFilm)) {
var arProps = Object.keys(objFilm);....//absolutely
arProps.forEach(function(item) {
if(item != "ref") {
arInfo.push(item + ": " + objFilm[item] + "<br>");
} else {
arInfo.push(item + ": <a href=" + objFilm[item] + " target=_blank>Wikipedia</a>");
}
});
var w = window.open('', '', 'width = 650, height = 500, resizable');
$(w.document.body).html(arInfo.join(""));
}) // .done
I have what we'll call a kiosk app that contains the contents of my film library as stored in a JSON file. One can access the contents in several ways, but each yields a display of all relevant titles. For example, searching for films with Sophia Loren, one would see this result:
All browsers work to this point.
You can see that each film has a link that leads to certain information about the film.
Although one browser (Mac Safari) reportedly does not display the Wikipedia link, all other browsers do. But only the Microsoft browsers (Edge, IE11) show the associated thumbnail. Therefore(?), only the Microsoft browsers respond to a click by invoking my display engine on the full version of the image. All browsers respond well and equally on more direct invocations of the display engine. For example, see [http://www.michaelbroschat.com/LongviewChristmas/LongviewChristmas.html].
The information window is created dynamically upon clicking the index number link shown in the first illustration.
All browsers successfully create the new window and most of the information data items. In fact, Chrome and Firefox appear to create the image display code but don't act upon it.
The entire app can be seen at http://www.michaelbroschat.com/film/disccatalog.html
I would love to know why Chrome and Firefox don't allow what the Microsoft browsers allow.
You left out of your question a critical part of the code, that being the code that creates the <a> tag around the image reference.
The problem you're having is that you're stuffing the assembled HTML for the list of films into that popup window, which is opened with no URL reference. Your <img> tags are built with relative URLs (like "liners/i0001.jpg"), but since there's no base URL for the browser to reference the image can't be loaded.
Internet Explorer may be making some inference that the popup window has the same base URL as the parent, but other browsers apparently don't do that.
I have some theories on this portion of your code:
............arProps.forEach(function(item) {
................if(item != "ref") {
....................arInfo.push(item + ": " + objFilm[item] + "<br>");
................} else {
....................arInfo.push(item + ": <a href=" + objFilm[item] + " target=_blank>Wikipedia</a>");
................}
............});
ONE: Be sure the anchor tag is using single quotes or double quotes depending on your preference when you output the source such as:
Wikipedia
My guess is that being only your version of safari is having an issue with the Wikipedia link it is sensitive to the quotes.
As far as the image goes, where is the img tag to output an image path?

IE does not display Response in new pop-up window

In my application, I pop-up a new window then set the Response display on it.
It worked in all of browser versions in my development and testing environments (IE10, IE9, IE11).
But in my customer's browsers using the same IE version as mine, it does not work.
They said they updated some security patches from Microsoft. I tried to run on Chrome, and it worked. I tried some ways to simulate that issue in my PC, but the browser still can show the response.
Is there any configurations to solve it on browser? Below is my code.
var etc = "channelmode=0,dependent=0,directories=0,fullscreen=0,location=0,menubar=0,resizable=1,scrollbars=1,status=1,toolbar=0" + ",scrollbars=no,left = 0 , top = 0 , height=" + screen.availHeight + " , width=" + screen.availWidth ;
var newWindow = window.open('', "MyWindow123", etc );
newWindow.focus();
document.forms[0].target="MyWindow123";
d.action="POST";
d.submit();
You have some issues
in your paste, "d" is not set
d.action is set to "POST" but you meant d.method or d.action="someurl"
you could very likely have a security issue. It could also be a timing issue. Well known in IE
show what is calling the statements you posted. If it is a link, you need to cancel the click
Try this where I also removed all illegal spaces in the parms and removed unnecessary ones:
function myPost() {
var etc = "resizable,scrollbars,status,left=0,top=0,height="+screen.availHeight+",width="+ screen.availWidth;
var newWindow = window.open('', "MyWindow123", etc );
if (newWindow) {
newWindow.focus();
var d = document.forms[0];
d.target="MyWindow123";
d.method="POST"; // NOT action!!!
setTimeout(function() {document.forms[0].submit();},300);
}
else {
alert("Sorry your browser does not allow popups");
}
return false; // cancel the event
}
assuming (inline here, unobtrusive is better)
<a href="pleaseenablejavascript.html"
onclick="return myPost()">Submit</a>
or
<form action="someurl" onsubmit="return myPost()">...

Is it possible to control Firefox's DNS requests in an addon?

I was wondering if it was possible to intercept and control/redirect DNS requests made by Firefox?
The intention is to set an independent DNS server in Firefox (not the system's DNS server)
No, not really. The DNS resolver is made available via the nsIDNSService interface. That interface is not fully scriptable, so you cannot just replace the built-in implementation with your own Javascript implementation.
But could you perhaps just override the DNS server?
The built-in implementation goes from nsDNSService to nsHostResolver to PR_GetAddrByName (nspr) and ends up in getaddrinfo/gethostbyname. And that uses whatever the the system (or the library implementing it) has configured.
Any other alternatives?
Not really. You could install a proxy and let it resolve domain names (requires some kind of proxy server of course). But that is a very much a hack and nothing I'd recommend (and what if the user already has a real, non-resolving proxy configured; would need to handle that as well).
You can detect the "problem loading page" and then probably use redirectTo method on it.
Basically they all load about:neterror url with a bunch of info after it. IE:
about:neterror?e=dnsNotFound&u=http%3A//www.cu.reporterror%28%27afew/&c=UTF-8&d=Firefox%20can%27t%20find%20the%20server%20at%20www.cu.reporterror%28%27afew.
about:neterror?e=malformedURI&u=about%3Abalk&c=&d=The%20URL%20is%20not%20valid%20and%20cannot%
But this info is held in the docuri. So you have to do that. Here's example code that will detect problem loading pages:
var listenToPageLoad_IfProblemLoadingPage = function(event) {
var win = event.originalTarget.defaultView;
var docuri = window.gBrowser.webNavigation.document.documentURI; //this is bad practice, it returns the documentUri of the currently focused tab, need to make it get the linkedBrowser for the tab by going through the event. so use like event.originalTarget.linkedBrowser.webNavigation.document.documentURI <<i didnt test this linkedBrowser theory but its gotta be something like that
var location = win.location + ''; //I add a " + ''" at the end so it makes it a string so we can use string functions like location.indexOf etc
if (win.frameElement) {
// Frame within a tab was loaded. win should be the top window of
// the frameset. If you don't want do anything when frames/iframes
// are loaded in this web page, uncomment the following line:
// return;
// Find the root document:
//win = win.top;
if (docuri.indexOf('about:neterror') == 0) {
Components.utils.reportError('IN FRAME - PROBLEM LOADING PAGE LOADED docuri = "' + docuri + '"');
}
} else {
if (docuri.indexOf('about:neterror') == 0) {
Components.utils.reportError('IN TAB - PROBLEM LOADING PAGE LOADED docuri = "' + docuri + '"');
}
}
}
window.gBrowser.addEventListener('DOMContentLoaded', listenToPageLoad_IfProblemLoadingPage, true);

Opening a new window/ document in PhoneGap

With the following code, I am able to open a new window on a Desktop browser:
var thisWin = window;
var oauthWin = thisWin.open(data, 'twitter-oauth-window', 'location=0,status=0,width=800,height=400');
var lastUrl = oauthWin.location.href;
var meh = true;
var oauthInt = thisWin.setInterval(
function()
{
if (meh)
{
alert(
'\noauthWin.closed: ' + oauthWin.closed +
'\noauthWin.location: ' + oauthWin.location +
'\nthisWin.closed: ' + thisWin.closed +
'\nthisWin.location: ' + thisWin.location +
'\noauthWin===thisWin: ' + (oauthWin === thisWin));
meh = false;
}
// do more stuff here
}
);
In the debug output within the alert:
oauthWin===thisWin: false
Which is what it should be. However, when the same code is run within PhoneGap, I get the following:
oauthWin===thisWin: true
Which indicates that PhoneGap has opened the new URL in the same window, replacing the current HTML document.
I wish to open the new URL separately, and to be able to close it upon a certain condition being met, and revert to the old one.
Can this be achieved in PhoneGap, and how?
Thanks!
Now with PhoneGap 2.3+, I was unable to get URLs to open in Mobile Safari in any way. Using _blank didn't work, and I tried window.open(url, '_blank'), but this now opens the URL using the InAppBrowser plugin (which pretty much sucks). I thought it was interesting that that one used a plugin though, so I decided to write a plugin to open URLs using the standard method of opening URLs in iOS apps. You can see/grab the code on this gist here: https://gist.github.com/typeoneerror/5097118.
It's simple enough. In my example, I wired up links that have a class called "_blank" with jQuery and opened those URLs with the plugin call:
// execute the plugin called OpenUrl, signature:
// exec(successCallback, errorCallback, pluginName, pluginMethod, params)
cordova.exec(success, error, "OpenUrl", "openUrl", [url]);
I'm sure you could rewrite the plugin easily for each platform you require it on. This one is iOS-specific.

Categories

Resources