How to create click event across MULTIPLE iframes (same domain)? - javascript

I have a main (parent) page that hosts 3 iframes that are under the same domain. The iframe's src attribute is added on a click event, so the iframe's aren't loaded until needed.
What I want is when I click a certain div on my main page, it will trigger a click on a specific div that's located inside all 3 iframes at the same time.
I have tried the following code in my parent page:
function myFunction() {
var iframe = document.getElementById("iframe1");
var elmnt = iframe.contentWindow.document.getElementById("btn").click()
}
and repeated it twice more for iframe's #iframe2 and #iframe3. However, it didn't work unless I loaded the iframes in order that they're written on my page. (i.e the click event on #iframe2 didn't execute until after #iframe1's event). This is a problem as I'm unable to control what iframe visitors will load first. I tried giving them separate function() names, but the same thing occurred - only one iframe was effected at a time. Note, this worked fine when I tested it out with the iframe's already having their src's like normal, just not when they're added manually.
I also tried adding this in the iframe pages:
parent.document.getElementById('btn').onclick = function(){
document.getElementById('btn').click();
}
However, this only works on the first iframe that is loaded (i.e if #iframe2 is loaded first, then the iframe1's and iframe3's event wont execute)
Is there any other solutions I could try? My purpose is creating a day and night toggle with classList.toggle, and I want all the iframes css to be toggled at the same time, with the toggle button
being on the main page.
(I prefer vanilla javascript for my main page, but am fine with jQuery on the iframe pages)

You are dynamically loading iframe's src suppose user loads <iframe3> but your code is written such a way that it tries to do something with <div> inside <iframe1> (which isn't loaded yet) what will happen? It will throw error and break the execution that's why it's not working for you what you need is to first look whether they are currently there
Also you are using var iframe = document.getElementById("iframe1"); but I don't see any id on the fiddle you posted
Try this
<body>
<style>
body {
background:#fff;
color:#000
}
body.toggled
{
background:#000;
color:#fff
}
</style>
<div id="btn">click here to toggle css</div>
<p>page content</p>
add src to iframe one<br>
add src to iframe two<br>
add src to iframe three
<p>iframe 1:</p>
<iframe src="about:blank" id="iframe1" name="iframe1"></iframe>
<p>iframe 2:</p>
<iframe src="about:blank" id="iframe2" name="iframe2"></iframe>
<p>iframe 3:</p>
<iframe src="about:blank" id="iframe3" name="iframe3"></iframe>
</body>
<script>
document.querySelector('#btn').addEventListener('click', function(e) {
[].map.call(document.querySelectorAll('body,a'), function(el) {
el.classList.toggle('toggled');
});
var iframe1 = document.getElementById("iframe1");
var iframe1btn = iframe1.contentWindow.document.getElementById("btn");
if(iframe1btn) //<-- check if that element really exists within <iframe>
iframe1.contentWindow.document.getElementById("btn").click()
// you could've also used <iframe>'s loaded event but this is better way
var iframe2 = document.getElementById("iframe2");
var iframe2btn = iframe2.contentWindow.document.getElementById("btn");
if(iframe2btn)
iframe2.contentWindow.document.getElementById("btn").click()
var iframe3 = document.getElementById("iframe3");
var iframe3btn = iframe3.contentWindow.document.getElementById("btn");
if(iframe3btn)
iframe3.contentWindow.document.getElementById("btn").click()
});
</script>

I am not particularly sure what you got wrong on, but I think I understand what you want to do. To reproduce this example, please create a HTML file (with name index.html) in your local PC and run this file on your browser:
<!DOCTYPE html>
<html>
<head>
<style>
body {
background: #fff;
color: #000;
}
body.toggled {
background: #000;
color: #fff;
}
</style>
</head>
<body>
<div id="btn">click here to toggle css</div>
<p>page content</p>
add src to iframe one<br>
add src to iframe two<br>
add src to iframe three
<p>iframe 1:</p>
<iframe src="about:blank" name="iframe1"></iframe>
<p>iframe 2:</p>
<iframe src="about:blank" name="iframe2"></iframe>
<p>iframe 3:</p>
<iframe src="about:blank" name="iframe3"></iframe>
<script>
let outerBody = document.querySelector('body')
let toggleButton = document.querySelector('#btn')
let iframes = document.querySelectorAll('iframe')
let anchors = document.querySelectorAll('a')
toggleButton.addEventListener('click', () => {
let body = document.querySelector('body')
body.classList.toggle('toggled')
Array.from(iframes).forEach(iframe => {
toggleIframe(iframe)
})
})
Array.from(iframes).forEach(iframe => {
iframe.addEventListener('load', e => {
toggleIframe(iframe)
})
})
Array.from(anchors).forEach(anchor => {
anchor.addEventListener('click', e => {
let targetedIframe = document.querySelector(`iframe[name=${anchor.target}]`)
targetedIframe.src = './index.html'
})
})
function toggleIframe(iframe) {
let iframeBody = iframe.contentWindow.document.querySelector('body')
let iframeToggleButton = iframe.contentWindow.document.querySelector('#btn')
let isOuterBodyToggled = outerBody.classList.contains('toggled')
let isIframeBodyToggled = iframeBody.classList.contains('toggled')
if (isOuterBodyToggled && iframeToggleButton && !isIframeBodyToggled)
iframeToggleButton.click()
else if (!isOuterBodyToggled && iframeToggleButton && isIframeBodyToggled)
iframeToggleButton.click()
}
</script>
</body>
</html>
I changed your a's href to empty (#). I also changed your JS file. Basically, I specified the as to change the source of its associated iframe when it's clicked with addEventListener('click'). Also, each time I click on the outerBody's (parent browsing context) button, I will also toggle its containing iframes' body by performing a click on the iframes' buttons. That already works. However, your problem was that you don't know when the iframes will be loaded. There's a function for that, addEventListener('load') on your iframes. When an iframe is loaded (an iframe will be loaded again when its source is changed), I will use that event listener to check if its parent browsing context's body is toggled. If it is, then simply toggle the iframe's body too by performing click.
Voila, it works. As mentioned, please try pasting the code above to your local file in your PC and run it in a browser.

Related

prevent iframe from scrolling parent document when calling focus

I have an iframe that calls someElement.focus. When this happens the parent scrolls to show the iframe. How can I prevent the parent from scrolling? Effectively I want the iframe itself to scroll so within the iframe the correct element is scrolled into space of the iframe itself but the parent page should be unaffected.
const lines = new Array(100).fill(0).map((e,i) => i).join('\n')
const script = 'script';
const frameContent = `
<style>
pre { font-size: 60pt; }
</style>
<body>
<pre>${lines}</pre>
<input type="text" id="target">
</body>
<${script}>
document.querySelector('#target').focus();
</${script}>
`;
document.querySelector('pre').textContent = lines;
const iframe = document.querySelector('iframe');
iframe.src = URL.createObjectURL(new Blob([frameContent], {type: 'text/html'}));
<style>
pre { font-size: 60pt; }
}
</style>
<div>you should see this element</div>
<pre></pre>
<iframe></iframe>
<div>you should NOT be scrolled to see this element</div>
It makes sense to me that calling focus would move the input area on to the screen, but at the same time, it makes no sense to me that any random iframe can get the parent page to jump to it on demand by calling focus.
Is it possible to prevent the iframe from affecting the parent?
You can try passing options when setting focus:
document.querySelector('#target').focus({preventScroll: true});
The preventScroll option is described in the MDN docs on HTMLElement.focus().
Note that this will likely only work for same-origin iframes.
Browsers apply restrictions that might prevent the preventScroll option being respected inside cross-origin/third-party iframes.

Q: How i can append attach on <div> iframe with src adress?

How i can append attach on iframe with src adress?
How i can manipulate div attaching on it iframe object with content?!
(Included into Wordpress page) by using brackets for testing....
I want to make custom js included into wordpress page without use jquery
(if u have any ideas cause i read the wordpress does support jquery libraries) could be good. I accept and jquery too as idea. I choose to do not use jquery cause i think wordpress does not support it.
javascript
<script async="" type="text/javascript">
var Divfrm = document.getElementById('#frame');
var ifrm = document.createElement('iframe');
function evtTrigger(){
document.addEventListener('click',function(e){
e.preventDefault();
Divfrm = document.appendChild(ifrm);
ifrm.setAttribute('src','http://google.com');
});
function close(){
ifrm = document.Detach(Divfrm);
};
return DivFrm = document.InnerHTML = ('');
</script>
html
<!--I'din't know why worpress cover field "script" tag?!-->
<h1 style="color: aqua; text-align: left;">Magic fountain mod example script</h1>
<p style="color: aqua; text-align: left; margin-left: 20px;">Can you ever saw glow fountain?, that was is available now</p>
<div id="frame" style="outline-color: mediumturquoise; background: rgba(0,128,128,0.2); overflow-y: scroll; height: 400px; margin-top: 20px; margin-bottom: 30px; color: mediumaquamarine;">
<!--here div was as role dialog ^^^>
<p>Explanation about code here text</p>
</div>
<div>
<button onclick="evtTrigger()">Show video</button>
<button onclick="close()">Hide this</button>
</div>
When the user clicks Show Video, it will call evtTrigger() -- but all that function does is attach the click listener to the document, it doesn't run that handler function. In fact, after clicking Show Video, after that every click on the page will run your handler function.
You're also appending the iframe to the entire document, not just your div (hence you're using document.appendChild instead of Divfrm.appendChild) -- that's probably not what you want.
So remove your addEventListener code, put the iframe appending code directly in the evtTrigger function, and change Divfrm = document.appendChild(ifrm) to just Divfrm.appendChild(ifrm). Then it should work.
Question is really unclear. I assume you want to add the ifrm inside Divfrm on clicking somewhere which fires the evtTrigger function. And then remove the ifrm when calling close()
If this is your goal, try this
var Divfrm = document.getElementById('#frame');
var ifrm = document.createElement('iframe');
function evtTrigger(){
Divfrm.appendChild(ifrm);
ifrm.setAttribute('src', 'http://google.com');
};
function close(){
Divfrm.removeChild(ifrm);
};
By the way, you can't load google.com inside your iframe because browser won't allow it. If this is just as an example, then it's fine.

How do I execute javascript only relative to that frame and not the whole window?

I have the following iFrame:
<div id="sandbox-inner">
<iframe sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts" frameborder="0" name="Output " id="output" src="JavaScript:''"></iframe>
</div>
And when the user clicks to run their code, it injects the javascript successfully within this iframe. However, it actually runs it across the whole window, not just the iframe. So basically if I add a class "test" to an element outside the iframe, and one inside, and then inject the following inside the head of the iframe...
$(function() {
$('.test').css({ background: "blue" });
});
It effects my element outside the iframe too, which I really dont want. I need the iFrame to be a completely seperate environment. This is how I am currently injecting the javascript:
$('#runGuestCode').on("click", function () {
var js = $('#js-input').val(),
iframe = $("#output"),
iframeHead = iframe.contents().find("head").first(),
frame = document.getElementById("output"),
scriptTag = '<script>' + js + '<\/script>';
$('#output').contents().find("head").append(scriptTag);
});
Many thanks
UPDATE #1
The javascript is taken from textarea #js-input, which is whatever the user has typed. This is then appended to the head of the iframe, but currently runs relative to the parent document, not the iframe document.
You can do it following way, it will not effect you current page elements will apply to iframe element only:-
var iframe = $('iframe');
$(element, iframe.contents()).css({'background':'blue'});
Working Fiddle
Showcase the javascript code put by user in iframe:
$('#submit1').click(function (e) {
e.preventDefault();
var myIframe = document.getElementById("resultFrame");
var s = document.createElement("script");
s.type = "text/javascript";
s.innerHTML = $("#textarea1").val();
myIframe.contentWindow.document.head.appendChild(s);
});
Working Fiddle with Javascript Output in iframe

Change iframe source from another iframe

Ok, I have 2 iframes inside a parent page (for whatever reason).
I have a navigation menu on parent page, which changes the source of iframe #1...
iFrame #1's job, is to display ANOTHER navigation menu... Like a subnavigation menu...
Now, how can I upon clicking an li inside iFrame #1, change the source of iframe #2? They're both on the same parent page...
Aside from failing miserably, I also get a warning from Chrome's Dev tools -
Unsafe JavaScript attempt to access frame with URL file:///C:/website/index.html from frame with URL file:///C:/website/news/navigator.html. Domains, protocols and ports must match.
Here's some code to make things slightly clearer:
The HTML
<!-- HTML for the parent page itself -->
<iframe id="frameone" src=""></iframe>
<iframe id="frametwo" src=""></iframe>
<button onclick="onenav('test.html')">Change 1st frame</button>
<!-- The following is the HTML that is loaded inside "frameone" -->
<button onclick="twonav('test2.html')">Change 2nd frame</button>
// Javascript
var one = document.getElementById('frameone');
var two = document.getElementById('frametwo');
function onenav(x){
one.src = x;
}
function twonav(y){
two.src = y;
}
To me, this makes sense, since this is all being executed on the parent page... On loading, I query the dev tools and I can see that both, 'one' and 'two' have frame elements... The first button works, the second one, doesn't...
Works for me when using parent.twonav
DEMO
var links = [
'javascript:\'<button onclick="parent.twonav(1)">Change 2nd frame</button>\'',
'javascript:\'Hello\''
];
var one, two;
window.onload=function() {
one = document.getElementById('frameone');
two = document.getElementById('frametwo');
}
function onenav(idx) {
one.src=links[idx];
}
function twonav(idx) {
two.src=links[idx];
}
How did you try to change the iframe source?
parent.document.getElementById('2').src = "the new url";
Did you try something like this? I assumed from your message that the id of the 2nd iframe is 2.

get iframe page title from javascript using jquery

How to get iframe src page title and then set main page title
If you want to do it using jQuery:
var title = $("#frame_id").contents().find("title").html();
$(document).find("title").html(title);
You can do it only when pages are on the same domain, otherwise it's useless.
Granting that iframes src and the parent document src are the same domain:
Parent document:
<html>
<head><title>Parent</title>
<body>
<iframe id="f" src="someurl.html"></iframe>
<script>
//if the parent should set the title, here it is
document.title = document.getElementById('f').contentWindow.document.title;
</script>
</body>
</html>
someurl.html:
<html>
<head><title>Child</title>
<body>
<script>
//if the child wants to set the parent title, here it is
parent.document.title = document.title;
//or top.document.title = document.title;
</script>
</body>
</html>
Unless the webpage is in the iframe is from the same domain as the containing page, it is impossible.
If they do have the same domain, then try the following:
document.title = document.getElementById("iframe").documentElement.title;
One way you can share title and location:
document.write('<iframe src="http://www.yourwebsite.com/home.html?title='+document.title+'&url='+window.location+'" frameborder="0" scrolling="no"></iframe>');
and then you can read the parameters on home.html page.
This can be done using event listeners on the page. It's not particularly elegant, but the browsers I have tried it with support it (so IE9+, Firefox, Chrome).
In your main site page add the following javascript:
function setPageTitle(event) {
var newPageTitle = event.data
// your code for setting the page title and anything else you're doing
}
addEventListener('message', setPageTitle, false);
In the iFrame, you'll then need to have the following script:
var targetOrigin = "http://your.domain.com"; // needed to let the browser think the message came from your actual domain
parent.postMessage("New page title", targetOrigin); // this will trigger the message listener in the parent window

Categories