How can I capture a click or mousedown event on a div surrounding an iframe. I've tried attaching the function to click event on the div but since the iframe never bubbles the event up to the surrounding div the function is never called. Is there a way I can capture the event on the div and then propagate it to the iframe for default action?
If the click is in the iframe area, the iframe context handles the click event, it does not bubble up to the iframe parent. So the div will never register the click event at all if it happened in the iframe area.
Furthermore, if the iframe contains a page that does not belong to the same domain as the iframe parent, any interaction is prohibited (re. same origin policy).
When the same origin policy is met, there are a few things you can do, you could call a method in the iframe parent context:
top.parentFunction();
So in the iframe you add an event listener that delegates to the iframe parent (accessible with the top reference.
Propagating events is a lot more complicated, so I'm simply going to refer to Diego Perini's NWEvents library. I believe his event system to be one of the better ones out there and he's particular on iframe interaction.
I certainly would not start writing your own code to achieve this, this can easily be a year long project if you want to do it properly and even then will be inferior to Diego's work.
There's no "good" way to do it, but if you really need to detect a click on an Iframe, you can kind-of do it in the latest browsers.
<iframe src="http://mtw-ed.com/" id="iframe" style=""></iframe>
<script type="text/javascript">
var inIframe = false;
function checkClick() {
if (document.activeElement
&& document.activeElement === document.getElementById("iframe")) {
if (inIframe == false) {
alert("iframe click");
inIframe = true;
}
} else
inIframe = false;
}
setInterval(checkClick, 200);
</script>
This script will check every 200ms whether the user is in the Iframe. Of course, they may not have clicked on the Iframe to get there, but I'm afraid this is the best you can do without #BGerrissen's solution.
It will detect the first 'click' only, unless you click out again. It only works in really modern browsers.
You can use a library like porthole to pass messages between parent and iframe, even across domains. Using this wouldn't exactly propagate the event (you won't be able to get the event object), but you can create your own event in the form of a simple message, and then handle it in the parent as a click.
Here's their example
However, I've used Brendon's answer as it's simpler works for my current need.
If you land here because you need to track a click on a PayPal button (like me), and you have access to the JavaScript SDK, you can listen to the click by adding the onClick callback in the initialization.
Example:
paypal.Buttons({
onClick() {
// here you can track the click
}
}).render('#paypal-container');
Link to the docs: https://developer.paypal.com/sdk/js/reference/#link-oninitonclick.
Related
I run into this problem quite often when I decide to try tinkering with a 3rd party site for a browser plugin, let's say I want to make a simple auto-play plugin for a video site that doesn't have an autoplay feature. There's a UI element that I know triggers their internal function for playing the video, but I dont know how to identify that function by inspecting the element in the console.
What tricks / methods can I use to be able to trigger that function manually without the user actually clicking the element?
In Chrome dev tools I think you can add a breakpoint for when an event is fired which might allow you to find the function that the 3rd party calls or you could simulate the click event using this code from MDN:
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
For more information see MDN.
If you know that clicking a button or an element somewhere results in the video playing, often it'll be simple enough to just call .click() on that button.
With the mouse hovered over the element with the functionality, right click and Inspect at that point, and the Elements panel of the developer console should bring you to the element the mouse is over. Figure out a selector or a process to uniquely identify the element, and then .click() it, eg
document.querySelector('.video-container .play-button').click();
You also may need to wait for the video container / play button to be created in the DOM first, in which case you can use MutationObserver or a setInterval to wait for the site to be ready.
An alternative, trickier method is to, when inspecting the element, go to the Event Listeners panel, and look for listeners attached to click / mousedown (etc) events. Sometimes, these functions are callable from the global scope, in which case you can call those functions directly instead of clicking the element.
If the function isn't callable from the global scope, a hacky method to get a reference to it anyway is to monkeypatch addEventListener before the page loads, listen for when the listener you want gets attached, and then call the function passed. (But the earlier methods are much simpler and preferable when possible)
I have requirement where I need to detect inactivity of web page and if user is inactive for more than 15 min then user should be logged out.For this purpose I am trying to detect inactivity of user by attaching click/keypress events to whole whole page and also for the main iframe.
The problem here is I am able to detect keypress / click event on the main page (main iframe) but wherever showDialoge(another iframe), I am not able to detect this event. Even though this events are being added to body of main iframe and also to whole web page, somehow i am not able to detect the same.Please help.
I am using OpenText Cordys framework XFORMs / JavaScript.
No jquery as of now but if required I can used.
If your files are on same server, you can call parent window's function from child iframe like
parent.html
<script>
window.whichKey = function(keycode) {
console.log("I'm called from child frame, you pressed " + keycode);
}
</script>
child.html
<script>
window.onkeypress = function(event) {
window.parent.window.whichKey(event.keyCode);
}
</script>
The other possible solution for your case is passing a variable in the url of parent from your child iframe. For example window.top.location.href = "parent.html?inactive=true"; and in the parent window you can check for this variable and perform required action.
This is how you can bind an event from parent to child frame's body for listening keypress using jQuery
$("#child-frame").bind("load", function(){
$(this).contents().find("body").on('keypress', function(e) {
console.log(e.keyCode);
});
});
If I understand your issue it has to do with event propagation. I'll admit though that I am less familiar with iframes. See this other post.
What is event bubbling and capturing?
Aside from your question, ideally you should manage this via sessions. Expire the session after 15min. If the user is not authorized, aka not logged in, send them to the main page.
system.windows will return you the window objects of the opened applications. You can attach the event handler to all windows and do it.
I need to capture certain user events (i.e. double-click) but let the rest pass to the iframe below. Some of these events may be enabled/disabled over time. I also don't want to block the iframe from receiving simple events like click or scroll. It seems, however, that iframe gets dibs on both bubble events (makes sense) and capture (this doesn't make sense, as it violates the order of propagation).
It seems like the only way to prevent the iframe from stealing all events is by putting an invisible div above it. In that case, however, I'd need to write handlers for all events to create a fake fall-through to the iframe, because even the events the div doesn't capture will no longer hit the iframe.
I see the following potential problems with this approach:
I may not be able to pass-through/simulate a click event into a foreign iframe (most iframes would be generated via srcdoc, so they'd be local, but some may reference foreign location via src)
I will need to write handlers for just about every mouse event to simulate a pass-through
It may be problematic to send the event to iframe itself and let it resolve the coordinates rather than detecting which element inside the iframe should receive the event
I may be wrong about my assumptions, so feel free to correct me.
Another approach I played around with involves detecting when iframe gets focus:
function clickListener() {
var monitor = setInterval(function(){
var elem = document.activeElement;
if(elem && elem.tagName == 'IFRAME'){
message.innerHTML = 'Clicked';
setInterval(function() {
message.innerHTML = '';
}, 100);
clearInterval(monitor);
elem.blur();
clickListener();
}
}, 100);
}
clickListener();
iframe {
width: 500px;
height: 300px;
}
<iframe id="iframe" src="//example.com"></iframe>
<div id="message"></div>
Problems with this approach:
the 100ms loop isn't ideal when I have 20+ elements on the page doing this
it ignores hover events and lumps all click-like events into a click
These two problems (especially the 2nd) are actually pretty severe show-stoppers, as I want to be able to detect double-click and drag events as well.
Does anyone have suggestions for how to tackle this?
You can check for the click coordinates on the fly and see if they match to your iframe. If they do, then its a double click on iframe, else, let other elements handle the event.
document.addEventListener("dblclick", check);
function check(event) {
if(document.elementFromPoint(event.clientX, event.clientY).id == "message") {
alert('iframe clicked');
} else {
alert('something else dude');
}
}
And obviously, stop iframe from receiving any clicks:
iframe {
pointer-events: none;
}
Here's a fiddle: https://jsfiddle.net/rg59yaau/1/
I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.
Is it possible, with Javascript or some other technology to determine which hyperlink a user has clicked on, without changing the hyperlink source code.
For example:
Can you click on a 'tag' button, then click on a hyperlink hosted in a different iframe, and be able to calculate which hyperlink the user clicked on, without changing any of the source code in that iframe?
Using jQuery, you are able to set the context of your selection. i.e.
$('a', $('#iframe-id')).click(function() {...});
You can then implement an event handler that will handle the iFrame hyperlink clicks. The "this" property within the handler will allow you to interrogate the hyperlink and obtain properties such as innerText etc.
you need to put an event on each a link ,
and then you will get all the information about the specific click.
this will work only in the some document,
so if you try to do a test between the link inside an iframe and a link in your page you will not get an event for the iframe link.
in order to attach the event for all link you need to run on all the links in the page ,
the best way to do that is by jQuery selector. or other js framework like YUI
$("a").click(function () {
alert('')
});
getElementsByTagName("a") - will give you all the links in the page.
I just thought of a solution, would this work, or are there other options?
The solution would be to proxy the content of the iframe soruce page, replacing href's with code to call a javascript function which would identify which href was clicked on.
This could then be used in conjunction with the tag'ing click to accurately tag a link.
This would also mean the original source, doesn't need to change at all.
What do you need ?-)
If you got an iframe, you use as a target for links, you must do some server-side processing or add something to the url of the links, that you can read when the page loads ...
But detecting time of page-load requires a script in the page, that is inside the iframe, or a function which tests the availability of the elements in the page in the iframe in short intervals ...
-- but you can only succeed if the page comes from the same domain as the main-page, as cross-domain scripting is illegal and thus impossible !-)
I think it should be possible. The contents of an IFrame is accessible from the outer document (the page in which the iframe is embedded) so you should be able to add event handlers (see other answers) on those elements after the iframe has loaded.
See also Wikipedia on Iframe which gives some examples and frameworks which actually work on content within an IFrame.
You can inject code into an iframe, but only if that iframe is on the same domain as the page you're injecting from, for obvious security reasons.
<iframe id="framedpage" src="framedpage.html"></iframe>
<button type="button" id="tagbutton">Tag</button>
<script type="text/javascript">
function framedclicks_bind() {
var f= document.getElementById('framedpage');
var fdoc= f.contentDocument;
if (!fdoc) fdoc= f.contentWindow.document; // for IE
if (fdoc)
for (var i= fdoc.links.length; i-->0;)
fdoc.links[i].onclick= framedclicks_click; // bind to all links
}
function framedclicks_click() {
alert('You clicked on '+this.href);
return false; // don't follow link
}
document.getElementById('tagbutton').onclick= framedclicks_bind;
</script>
Might want to cleaning-up depending on application needs (eg. to ensure the frame is always loaded before trying to bind, or that unbinding can happen, or that any onclicks from the original links are remembered), but that'd be the general shape of things.
Good solution to find out which element was clicked is to use event delegation. If you attach event listener to each element using a loop (over document.links or document.getElementsByTagName), you have two problems:
- browser has many listeners to maintain
- events are attached only to elements that were in the DOM when you called the loop; any element dynamically added later doesn't have an event listener.
A simple example of event delegation:
document.onclick = function(e){
e = e || window.event;
var t = e.target || e.srcElement;
if(t.nodeName=='A'){
alert( t.href );
}
}
If you want to find clicked link inside an iframe just use iframe's contentDocument instead of document.