Edit: New title.
What I'm looking for is a document.querySelector for elements inside an iframe.
I've done quite a bit of Googling for an answer and finally I'm stumped.
I'm trying to query inside an iframe. I'm building string selectors to be used in Selenium and usually I just inspect the element with Firebug, and use document.querySelectorAll("theStringIBuid");
But it doesn't work with elements inside iframes. I've tried all of the below to get an element "radiobutton1" inside the "page-iframe" iframe.
var elem1 = ".page-iframe";
console.log(elem1);
var elem2 = ".radiobutton1";
console.log(elem2);
document.querySelectorAll(elem1+elem2+"");
document.querySelectorAll('.page-iframe').contentWindow.document.body.querySelectorAll('.radiobutton1')
document.getElementById('.page-iframe').contentWindow.document.body.innerHTML;
[].forEach.call( document.querySelectorAll('.page-iframe'),
function fn(elem){
console.log(elem.contentWindow.document.body.querySelectorAll('.radiobutton1')); });
var contentWindow = document.getElementById('.page-iframe').contentWindow
var contentWindow = document.querySelectorAll('.page-iframe')
var contentWindow = document.querySelectorAll('.page-iframe')[0].contentWindow
Thanks-
simple es6 adapted from h3manth:
document.querySelectorAll('iframe').forEach( item =>
console.log(item.contentWindow.document.body.querySelectorAll('a'))
)
if the original page's url isn't at the same domain with the iframe content, the javascript will treat the iframe as a black box, meaning it will not see anything inside it.
You can do this:
document.querySelector("iframe").contentWindow.document.querySelector("button")
https://m.youtube.com/watch?v=-mNp3-UX9Qc
You can simply use
document.querySelector("iframe").contentDocument.body.querySelector("#btn")
First query selector is to select the iframe. Then we can access ifram dom using content document and use the 2nd query selector to select the element inside iframe.
Here's a snippet for diving into same-origin frames (ie-compatible ES5):
function findInFramesRec(selector, doc) {
var hit = doc.querySelector(selector);
if (hit) return hit;
var frames = Array.prototype.slice.call(doc.frames);
for(var i = 0; (i < frames.length) && !hit ; i++) {
try {
if (!frames[i] || !frames[i].document) continue;
hit = findInFramesRec(selector, frames[i].document);
} catch(e) {}
}
return hit;
}
This dives into both frameset frames and iframes alike. It may even survive (though not enter) cross origin frames.
Related
A simple task in JavaScript is to open a new window and writing inside. But I need to write in a dom element, a div with an ID.
var novoForm = window.open("somform.html", "wFormx", "width=800,height=600,location=no,menubar=no,status=no,titilebar=no,resizable=no,");
Than I try something...
var w = novoForm.innerWidth;
var h = novoForm.innerHeight;
novoForm.document.getElementById("monitor").innerHTML = 'Janela: '+w+' x '+h;
I did it to see if the object "novoForm" is valid. But nothing is written in "monitor" div. I also try using onload event with no success. I'm wondering if it's some security restriction or am I missing something...
You've done it right, but you do need to be sure to use onload (or poll), because it takes a moment for the page to get loaded in the new window.
Here's a full working example: Live Copy | Source
(function() {
document.getElementById("theButton").onclick = function() {
var novoForm = window.open("http://jsbin.com/ugucot/1", "wFormx", "width=800,height=600,location=no,menubar=no,status=no,titilebar=no,resizable=no,");
novoForm.onload = function() {
var w = novoForm.innerWidth;
var h = novoForm.innerHeight;
novoForm.document.getElementById("monitor").innerHTML = 'Janela: '+w+' x '+h;
};
};
})();
I'm wondering if it's some security restriction or am I missing something...
Not in your example as shown, no, because the page is clearly being loaded from the same origin. If the URL were from a different origin, then yes, you'd be running into the Same Origin Policy, which prohibits cross-origin scripting. You can relax that via the document.domain property, having both the window containing the code above and the window being loaded setting document.domain to the same value. From the link above:
If two windows (or frames) contain scripts that set domain to the same value, the same-origin policy is relaxed for these two windows, and each window can interact with the other. For example, cooperating scripts in documents loaded from orders.example.com and catalog.example.com might set their document.domain properties to “example.com”, thereby making the documents appear to have the same origin and enabling each document to read properties of the other.
More about document.domain can be found on MDN. Note that it only works where both documents share a common parent domain, e.g., so it works for app1.example.com and app2.example.com if they both set to example.com, but not for example1.com and example2.com because they have not common value they can set.
Alternatively, this is a solution:
var novoForm = window.open("somform.html", "wFormx", "width=800,height=600,location=no,menubar=no,status=no,titilebar=no,resizable=no,");
var teste = function(){
var mon = novoForm.document.getElementById("monitor");
if(typeof(mon)!="undefined"){
//novoForm.alert("Achei!");
var h = novoForm.innerHeight;
var strh = String(h - 40 - 30)+'px';
novoForm.document.getElementById("pagina").style.height = strh;
novoForm.document.getElementById("monitor").innerHTML = '<p class="legenda">© NetArts | gustavopi</p>';
clearInterval(id);
}
}
var id = setInterval(teste, 100);
This will do the job. Not a "pretty" solution to me, but it works!
Depends on what url you try to load into the new window. #T.J is right on that. Also note that if you just want to load a blank document you can load "about:blank" into the url. The only difference is that you would use outerWidth since you haven't loaded an actual document.
var novoForm = window.open("about:blank", "wFormx", "width=800,height=600,location=no,menubar=no,status=no,titilebar=no,resizable=no,");
var w = novoForm.outerWidth;
var h = novoForm.outerHeight;
novoForm.document.body.innerHTML = 'Janela: '+w+' x '+h;
I need to find out if html document inside iframe contains some occurance of word wysiwyg (purpose: to check if it is wysiwyg editor).
What I have tried:
iframes = $('iframe').filter(
function () {
var result = this.id.match(/wysiwyg/i);
if (!result)
result = this.className.match(/wysiwyg/i);
if (!result)
{
var success = this.innerHTML.match(/wysiwyg/i);
if ( success && success.length )
return this;
}
return result;
});
using JQuery.
The problem here is that innerHTML is empty. I thought, contentDocument could contain innerhtml, but this is not the case. I try to do case insensitive search, where the word wysiwyg can be in the middle of any element. Originally I tried to find a tag with href value or img tag with src value but I found that is too much complicated and the word could be used in other parts of the html document and I would miss it. I don't know where the word could be, it can be anywhere in the iframe -> html document.
Your suggestion?
Note:
Permissions here are not problem, they are granted by Firefox webextentions API - which is not subject of the question.
If permissions are not the problem, you should be able to access the iframe HTML by doing the following:
$('#specificIframe').contents().find('#thingToFind');
jQuery .contents()
You may use .contents() and jQuery( ":contains(text)" ) plus the load event to check if the iframe contains the string.
In order to test if the id contains the string you may refer to attributeContains selector.
$(function () {
$('iframe[id*="wysiwyg"]').on('load', function (e) {
var iframes = $(this).contents().find(':contains("wysiwyg")');
});
});
As guest271314 has mentioned, you are not currently using .contentDocument in your code.
You could change your code as follows:
iframes = $('iframe').filter(function() {
var result = this.id.match(/wysiwyg/i);
if (!result){
result = this.className.match(/wysiwyg/i);
}
if (!result) {
var success = this.contentDocument.querySelector('html').innerHTML.match(/wysiwyg/i);
if ( success && success.length ){
return this;
}
}
return result;
});
From MDN's <iframe> page:
From the DOM iframe element, scripts can get access to the window object of the included HTML page via the contentWindow property. The contentDocument property refers to the document element inside the iframe (this is equivalent to contentWindow.document), but is not supported by Internet Explorer versions before IE8.
However, if this is the same issue you were asking about in a prior, now deleted, question, this will, not solve your actual problem. The actual problem appeared to be that your (nearly identical) code was executing prior to the <iframe> you are looking for being inserted into the DOM by other JavaScript on the page. Your code, of course, can not find it when it is not, yet, in the DOM. Your code in that question was verified to find the <iframe> desired if it existed in the DOM in the state that the DOM was once the page scripts finished setting up the DOM. Prior to that code, ckeditor_new/ckeditor.js, executing, what exists on the page is:
<script src="ckeditor_new/ckeditor.js"></script>
<textarea id="FCKeditor1" name="FCKeditor1" rows="8" cols="60"></textarea>
<script>CKEDITOR.replace( 'FCKeditor1', {customConfig: '/ckeditor_new/config.js'});</script>
The page script hides that <textarea> and inserts a <div> containing the <iframe> in which you are interested (about 15kB of inserted HTML).
You will need to delay looking for the existence of that <iframe> until after that other JavaScript inserts it into the DOM.
While there may be better ways to perform this delay (e.g. watching for the insert, etc.), it could be something as simple as:
setTimeout(findIframeAndDoAllTasksNeedingIt,150);
If still not found, you could retry looking for the <iframe> a limited number of times after additional delays.
I thought this could be solution:
iframes = $('iframe').filter(
function () {
var result = this.id.match(/wysiwyg/i);
if (!result)
result = this.className.match(/wysiwyg/i);
if (!result)
{
if (!this.contentDocument)
return null;
var success = this.contentDocument.head.innerHTML.match(/wysiwyg|editor|editable/i);
if ( success && success.length )
return this;
success = this.contentDocument.body.innerHTML.match(/wysiwyg|editor|editable/i);
if ( success && success.length )
return this;
}
return result;
});
edit: bugfix
I tried improvement which enables to use this code for almost all WYSIWYG editors, except TINYMCE which is kind of strange behaviour. There are found some frames with different id than that one containing "mce". Maybe we will find solution later.
iframes = $('iframe').filter(
function () {
var result = this.id.match(/wysiwyg/i);
if (!result)
result = this.className.match(/editable|wysiwyg|editor/i);
if (!result)
result = this.id.match(/mce/i);
if (!result)
{
if (!this.contentDocument)
return null;
var success = this.contentDocument.head.innerHTML.match(/editable|wysiwyg|editor|tinymce/i);
if ( success && success.length )
return this;
success = this.contentDocument.body.innerHTML.match(/editable|wysiwyg|editor|tinymce/i);
if ( success && success.length )
return this;
}
return result;
});
I love this code (I use it in my program which adds css styles to WYSIWYG editors - quite usable).
Well, I have an IFrame, which calls a same domain page.
My problem is that I want to access some information from this parent Iframe from this called page (from JavaScript). How can I access this Iframe?
Details: There are several Iframes just like this one, that can have the same page loaded, because I am programming a Windows environment. I intend to close this Iframe, that's why I need to know which I should close from inside him. I have an array keeping references to these Iframes.
EDIT: There iframes are generated dynamically
Also you can set name and ID to equal values
<iframe id="frame1" name="frame1" src="any.html"></iframe>
so you will be able to use next code inside child page
parent.document.getElementById(window.name);
Simply call window.frameElement from your framed page.
If the page is not in a frame then frameElement will be null.
The other way (getting the window element inside a frame is less trivial) but for sake of completeness:
/**
* #param f, iframe or frame element
* #return Window object inside the given frame
* #effect will append f to document.body if f not yet part of the DOM
* #see Window.frameElement
* #usage myFrame.document = getFramedWindow(myFrame).document;
*/
function getFramedWindow(f)
{
if(f.parentNode == null)
f = document.body.appendChild(f);
var w = (f.contentWindow || f.contentDocument);
if(w && w.nodeType && w.nodeType==9)
w = (w.defaultView || w.parentWindow);
return w;
}
I would recommend using the postMessage API.
In your iframe, call:
window.parent.postMessage({message: 'Hello world'}, 'http://localhost/');
In the page you're including the iframe you can listen for events like this:
window.addEventListener('message', function(event) {
if(event.origin === 'http://localhost/')
{
alert('Received message: ' + event.data.message);
}
else
{
alert('Origin not allowed!');
}
}, false);
By the way, it is also possible to do calls to other windows, and not only iframes.
Read more about the postMessage API on John Resigs blog here
Old question, but I just had this same issue and found a way to get the iframe. It's simply a matter of iterating through the parent window's frames[] array and testing each frame's contentWindow against the window in which your code is running. Example:
var arrFrames = parent.document.getElementsByTagName("IFRAME");
for (var i = 0; i < arrFrames.length; i++) {
if (arrFrames[i].contentWindow === window) alert("yay!");
}
Or, using jQuery:
parent.$("iframe").each(function(iel, el) {
if(el.contentWindow === window) alert("got it");
});
This method saves assigning an ID to each iframe, which is good in your case as they are dynamically created. I couldn't find a more direct way, since you can't get the iframe element using window.parent - it goes straight to the parent window element (skipping the iframe). So looping through them seems the only way, unless you want to use IDs.
you can use parent to access the parent page. So to access a function it would be:
var obj = parent.getElementById('foo');
Once id of iframe is set, you can access iframe from inner document as shown below.
var iframe = parent.document.getElementById(frameElement.id);
Works well in IE, Chrome and FF.
Maybe just use
window.parent
into your iframe to get the calling frame / windows. If you had multiple calling frame, you can use
window.top
Try this, in your parent frame set up you IFRAMEs like this:
<iframe id="frame1" src="inner.html#frame1"></iframe>
<iframe id="frame2" src="inner.html#frame2"></iframe>
<iframe id="frame3" src="inner.html#frame3"></iframe>
Note that the id of each frame is passed as an anchor in the src.
then in your inner html you can access the id of the frame it is loaded in via location.hash:
<button onclick="alert('I am frame: ' + location.hash.substr(1))">Who Am I?</button>
then you can access parent.document.getElementById() to access the iframe tag from inside the iframe
// just in case some one is searching for a solution
function get_parent_frame_dom_element(win)
{
win = (win || window);
var parentJQuery = window.parent.jQuery;
var ifrms = parentJQuery("iframe.upload_iframe");
for (var i = 0; i < ifrms.length; i++)
{
if (ifrms[i].contentDocument === win.document)
return ifrms[i];
}
return null;
}
I have a popup window that needs to access the parent dom to generate a print page. The structure of the print page is significantly different then the structure of the parent so a print css would not solve the problem. I basically want to popup a window and then have that window grab some data from the parent of even access the dom from the popup and generate the print page without having to go to the server again. Any ideas how i can achieve this?
Im using the standard
window.open()
to pop up a window. I need this solution to not be a hack and be cross browser compatible with all major browsers.
Thanks in advance!
Sajjan's answer is a start, but better make sure your objects are available before you try to access them:
var opener = window.opener;
if(opener) {
var oDom = opener.document;
var elem = oDom.getElementById("your element");
if (elem) {
var val = elem.value;
}
}
Otherwise, you do run the risk that the opener doesn't respond to your initial call, and that you can't get the element from it.
As jQuery, I think (based on an answer, here: how to access parent window object using jquery?):
var opener = window.opener;
if(opener) {
var elem = opener.$("#elementId");
if (elem) {
var val = elem.val(); // I forgot we're dealing with a jQuery obj at this point
}
}
window.opener.document.getElementById("your element").value
According to MDN, window.open() will return you a handle to the new window.
var popUpHandle = window.open();
With this handle you should be able to access the DOM of the PopUp. It is possible vice-versa using the already mentioned window.opener. Refer again to MDN:
var originalWindow = window.opener;
Still, your favorite search engine will provide you more details, as this is topic is fairly old and your approach has already been done a million times or more.
parent.document helped in my case.
var elem = parent.document.getElementById("overlay_modal");
if (elem) {
alert('setting attribute');
elem.setAttribute("onclick", "Windows.close('2', event);");
}
I have an iframe and I want to set it's border to zero.
But I want to do this from inside the iframe, using javascript or jQuery.
How to do this? Many thanks in advance,
If the parent is on a different origin, you can't do it, because access to the parent's content is forbidden by the Same Origin Policy.
If the parent document is on the same origin, this should do it:
(function() {
var frames = window.parent.document.getElementsByTagName("iframe"),
index,
frame;
for (index = 0; index < frames.length; ++index) {
frame = frames[index];
if (frame.contentWindow == window) {
frame.frameBorder = "none";
}
}
})();
Live example | source of parent | source of frame
Note that it's important to use == rather than === when comparing the window properties (unusually, window is special).
You can do it by $(parent.document).find('#myIframe').css('border', 'xxxx'); - But as pointed out by the comment above, both the pages (main one as well as the one shown in the iframe) should be in the same domain - otherwise you'll end up with a security exception because of same origin policy.
Alternatively you can use parent.$
parent.$("iframe").prop("frameborder", 0); // This will change all iframes
parent.$("#IframeID").prop("frameborder", 0); // This will change single iframe