I am receiving an error on IE 8-7 saying that Object doesn't support property or method 'addEventListener' when I used the code below. Does anyone know how I can make the code below compatible with IE8-7? thanks
document.getElementById('clear').addEventListener('click', function () {
["A1","A2","A3","A4","A5","A6", "A1_flip",
].forEach(function(id) {
document.getElementById(id).checked = false;
});
return false;
})
That's because they don't support addEventListener. See this question's answers for details.
But since you've said you're using jQuery, you can...use jQuery to get around this issue:
$('#clear').on('click', function () {
["A1","A2","A3","A4","A5","A6", "A1_flip"
].forEach(function(id) {
$("#" + id).prop("checked", false);
});
return false;
});
or actually, we can be a bit more direct:
$('#clear').on('click', function () {
$("#" + ["A1","A2","A3","A4","A5","A6", "A1_flip"].join(", #")).prop("checked", false);
return false;
});
...which works by building a selector string from the array.
I just realized I'm assuming the array's contents vary. If they don't, if you literally just want those specific elements:
$('#clear').on('click', function () {
$("#A1, #A2, #A3, #A4, #A5, #A6, #A1_flip").prop("checked", false);
return false;
});
...or better yet, give them a common class and use
$('#clear').on('click', function () {
$(".the-class").prop("checked", false);
return false;
});
If you don't use jQuery and just mis-tagged it, see the linked question above. One of the answers there is mine, providing a hookEvent function that deals with cross-browser event handling:
var hookEvent = (function() {
var div;
// The function we use on standard-compliant browsers
function standardHookEvent(element, eventName, handler) {
element.addEventListener(eventName, handler, false);
return element;
}
// The function we use on browsers with the previous Microsoft-specific mechanism
function oldIEHookEvent(element, eventName, handler) {
element.attachEvent("on" + eventName, function(e) {
e = e || window.event;
e.preventDefault = oldIEPreventDefault;
e.stopPropagation = oldIEStopPropagation;
handler.call(element, e);
});
return element;
}
// Polyfill for preventDefault on old IE
function oldIEPreventDefault() {
this.returnValue = false;
}
// Polyfill for stopPropagation on old IE
function oldIEStopPropagation() {
this.cancelBubble = true;
}
// Return the appropriate function; we don't rely on document.body
// here just in case someone wants to use this within the head
div = document.createElement('div');
if (div.addEventListener) {
div = undefined;
return standardHookEvent;
}
if (div.attachEvent) {
div = undefined;
return oldIEHookEvent;
}
throw "Neither modern event mechanism (addEventListener nor attachEvent) is supported by this browser.";
})();
Then:
hookEvent(document.getElementById('clear'), 'click', function(e) {
["A1","A2","A3","A4","A5","A6", "A1_flip"
].forEach(function(id) {
document.getElementById(id).prop("checked", false);
});
e.preventDefault();
});
Support for addEventListener() function isn't available in older versions of Internet Explorer (i.e. 7-8), so you won't be able to use it on the browsers you are attempting to target.
You could consider wiring this up using jQuery's on() function, assuming you are using a version of jQuery that is designed to target older browsers as it will generally have the necessary fallbacks to support it.
$('#clear').on('click', function () {
var elements = ["A1","A2","A3","A4","A5","A6", "A1_flip"];
elements.forEach(function(id) {
$("#" + id).prop("checked", false);
});
return false;
})
If you want a better compatibility to obsolete browsers plus not really all new features of jQuery are needed. You might consider just switch to jQuery 1.1X(currently 1.12). It will save you lots of time from handling compatible issues.
ref: jQuery - Browser support
I have the following code which when embedded within a loaded html page works successfully:
<HEAD>
<script language="javascript" type="text/javascript">
document.addEventListener('DOMContentLoaded', function ()
{
document.documentElement.addEventListener("touchstart", function (e)
{
if (['A', 'BUTTON'].indexOf(e.target.tagName) === -1)
{
e.preventDefault();
e.stopPropagation();
invokeObjectiveC("ontouchstart:");
}
else
{
e.preventDefault();
e.stopPropagation();
invokeObjectiveC(e.target);
}
}, true);
}, false);
function invokeObjectiveC(action) {
...
}
However if I take it out of the html and try to load it separatly then it is not working.
When loading it separately it looks like this:
alert('test');
function addListener()
{
alert('adding listener');
document.addEventListener('DOMContentLoaded', function ()
{
document.documentElement.addEventListener("touchstart", function (e)
{
alert('touchstart');
if (['A', 'BUTTON'].indexOf(e.target.tagName) === -1)
{
e.preventDefault();
e.stopPropagation();
invokeObjectiveC("ontouchstart:");
}
else
{
e.preventDefault();
e.stopPropagation();
invokeObjectiveC(e.target);
}
}, true);
}, false);
}
addListener();
function invokeObjectiveC(action) {
...
}
When added, a "test" and an "adding listener" alert dialog are displayed so I know this part is working.
However the code then doesn't work - its supposed to detect touches (this is on iOS) in certain parts of the screen.
With the code within the html everything works fine and it executes when the screen is touched, when its loaded separatly nothing happens when the screen is touched.
Any ideas what the problem could be?
====== UPDATE
I tried running the following during various stages of the lifecycle, including before the request to even load the page has been issued, but 'Dom content loaded' never appears:
var script = document.createElement('script');
script.type = 'text/javascript';
script.text =
var Test =
{
f: function()
{
if (!event.originalTarget.defaultView.frameElement)
{
alert('DOM content loaded');
}
}
}
function addTestListener()
{
alert('adding listener');
window.addEventListener("DOMContentLoaded", function(e) { Test.f(); }, false);
}
document.getElementsByTagName('head')[0].appendChild(script);
From your comment about the iOS function, I suspect that the document is already loaded when you try to execute your javascript. If that's the case, then the DOMContentLoaded event has already happened so you code will never be initialized. You can fix that by checking to see if the document is already loaded by changing your code to this:
function addListener() {
alert('adding listener');
function init() {
document.documentElement.addEventListener("touchstart", function (e) {
alert('touchstart');
if (['A', 'BUTTON'].indexOf(e.target.tagName) === -1) {
e.preventDefault();
e.stopPropagation();
invokeObjectiveC("ims-ontouchstart:");
} else {
e.preventDefault();
e.stopPropagation();
invokeObjectiveC(e.target);
}
}, true);
}
if (document.readyState === "complete") {
init();
} else {
document.addEventListener('DOMContentLoaded', init, false);
}
}
addListener();
function invokeObjectiveC(action) {
...
}
I changed the line
function addListener()
into
window.onload = function addListener()
and it seems to have done the trick
I have a Flash movie embedded with swfobject in a html container.
Through ExternalInterface I have registered a Javascript function to fire callback to my flash app.
ExternalInterface.addCallback("notifyClose", notifyOnClose );
The Javascript function is added as an event listener to fire onbeforeunload.
<script language="JavaScript">
function getSWF(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1){
return window[movieName];
}else { return document[movieName];}
}
var bye = function() {
getSWF('flashContainer').notifyClose('> WE ARE CLOSING APP!');
//alert('WE ARE CLOSING APP!.');
};
var hola = function(){
getSWF('flashContainer').notifyClose('> WE ARE opening APP!');
alert('WE ARE opening APP!.');
};
if(window.addEventListener) {
window.addEventListener('load', hola,false);
window.addEventListener('beforeunload', bye, false);
} else if (window.attachEvent) {
window.attachEvent('onload', hola);
window.attachEvent('onbeforeunload', bye);
}
</script>
I have tested in Firefox and IE. Firefox works as expected but not in IE.
In IE I get notified in Flash with the onload message, but not onbeforeunload.
Is it some kind of sandbox restriction? Just bad code?
The problem is the "on" in your code below in the attachEvent().
if(window.addEventListener) {
window.addEventListener('load', hola,false);
window.addEventListener('beforeunload', bye, false);
} else if (window.attachEvent) {
window.attachEvent('onload', hola);
window.attachEvent('onbeforeunload', bye);
}
Try something like the code below for your Event Listener code and see the following link for more information: http://bytes.com/topic/javascript/answers/147027-addeventlistener-function-ie
//*** This code is copyright 2003 by Gavin Kistner, !#phrogz.net
//*** It is covered under the license viewable at http://phrogz.net/JS/_ReuseLicense.txt
//*** Reuse or modification is free provided you abide by the terms of that license.
//*** (Including the first two lines above in your source code satisfies the conditions.)
//***Cross browser attach event function. For 'evt' pass a string value with the leading "on" omitted
//***e.g. AttachEvent(window,'load',MyFunctionNameWithoutParenthesis,false);
function AttachEvent(obj,evt,fnc,useCapture){
if (!useCapture) useCapture=false;
if (obj.addEventListener){
obj.addEventListener(evt,fnc,useCapture);
return true;
} else if (obj.attachEvent) return obj.attachEvent("on"+evt,fnc);
else{
MyAttachEvent(obj,evt,fnc);
obj['on'+evt]=function(){ MyFireEvent(obj,evt) };
}
}
//The following are for browsers like NS4 or IE5Mac which don't support either
//attachEvent or addEventListener
function MyAttachEvent(obj,evt,fnc){
if (!obj.myEvents) obj.myEvents={};
if (!obj.myEvents[evt]) obj.myEvents[evt]=[];
var evts = obj.myEvents[evt];
evts[evts.length]=fnc;
}
function MyFireEvent(obj,evt){
if (!obj || !obj.myEvents || !obj.myEvents[evt]) return;
var evts = obj.myEvents[evt];
for (var i=0,len=evts.length;i<len;i++) evts[i]();
}
I understand that it is not possible to tell what the user is doing inside an iframe if it is cross domain. What I would like to do is track if the user clicked at all in the iframe. I imagine a scenario where there is an invisible div on top of the iframe and the the div will just then pass the click event to the iframe.
Is something like this possible? If it is, then how would I go about it? The iframes are ads, so I have no control over the tags that are used.
This is certainly possible. This works in Chrome, Firefox, and IE 11 (and probably others).
const message = document.getElementById("message");
// main document must be focused in order for window blur to fire when the iframe is interacted with.
// There's still an issue that if user interacts outside of the page and then click iframe first without clicking page, the following logic won't run. But since the OP is only concerned about first click this shouldn't be a problem.
window.focus()
window.addEventListener("blur", () => {
setTimeout(() => {
if (document.activeElement.tagName === "IFRAME") {
message.textContent = "clicked " + Date.now();
console.log("clicked");
}
});
}, { once: true });
<div id="message"></div>
<iframe width="50%" height="300" src="//example.com"></iframe>
Caveat: This only detects the first click. As I understand, that is all you want.
This is small solution that works in all browsers even IE8:
var monitor = setInterval(function(){
var elem = document.activeElement;
if(elem && elem.tagName == 'IFRAME'){
clearInterval(monitor);
alert('clicked!');
}
}, 100);
You can test it here: http://jsfiddle.net/oqjgzsm0/
Based on Mohammed Radwan's answer I came up with the following jQuery solution. Basically what it does is keep track of what iFrame people are hovering. Then if the window blurs that most likely means the user clicked the iframe banner.
the iframe should be put in a div with an id, to make sure you know which iframe the user clicked on:
<div class='banner' bannerid='yyy'>
<iframe src='http://somedomain.com/whatever.html'></iframe>
<div>
so:
$(document).ready( function() {
var overiFrame = -1;
$('iframe').hover( function() {
overiFrame = $(this).closest('.banner').attr('bannerid');
}, function() {
overiFrame = -1
});
...
this keeps overiFrame at -1 when no iFrames are hovered, or the 'bannerid' set in the wrapping div when an iframe is hovered. All you have to do is check if 'overiFrame' is set when the window blurs, like so:
...
$(window).blur( function() {
if( overiFrame != -1 )
$.post('log.php', {id:overiFrame}); /* example, do your stats here */
});
});
Very elegant solution with a minor downside: if a user presses ALT-F4 when hovering the mouse over an iFrame it will log it as a click. This only happened in FireFox though, IE, Chrome and Safari didn't register it.
Thanks again Mohammed, very useful solution!
Is something like this possible?
No. All you can do is detect the mouse going into the iframe, and potentially (though not reliably) when it comes back out (ie. trying to work out the difference between the pointer passing over the ad on its way somewhere else versus lingering on the ad).
I imagine a scenario where there is an invisible div on top of the iframe and the the div will just then pass the click event to the iframe.
Nope, there is no way to fake a click event.
By catching the mousedown you'd prevent the original click from getting to the iframe. If you could determine when the mouse button was about to be pressed you could try to get the invisible div out of the way so that the click would go through... but there is also no event that fires just before a mousedown.
You could try to guess, for example by looking to see if the pointer has come to rest, guessing a click might be about to come. But it's totally unreliable, and if you fail you've just lost yourself a click-through.
The following code will show you if the user click/hover or move out of the iframe:-
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Detect IFrame Clicks</title>
<script type="text/javascript">
$(document).ready(function() {
var isOverIFrame = false;
function processMouseOut() {
log("IFrame mouse >> OUT << detected.");
isOverIFrame = false;
top.focus();
}
function processMouseOver() {
log("IFrame mouse >> OVER << detected.");
isOverIFrame = true;
}
function processIFrameClick() {
if(isOverIFrame) {
// replace with your function
log("IFrame >> CLICK << detected. ");
}
}
function log(message) {
var console = document.getElementById("console");
var text = console.value;
text = text + message + "\n";
console.value = text;
}
function attachOnloadEvent(func, obj) {
if(typeof window.addEventListener != 'undefined') {
window.addEventListener('load', func, false);
} else if (typeof document.addEventListener != 'undefined') {
document.addEventListener('load', func, false);
} else if (typeof window.attachEvent != 'undefined') {
window.attachEvent('onload', func);
} else {
if (typeof window.onload == 'function') {
var oldonload = onload;
window.onload = function() {
oldonload();
func();
};
} else {
window.onload = func;
}
}
}
function init() {
var element = document.getElementsByTagName("iframe");
for (var i=0; i<element.length; i++) {
element[i].onmouseover = processMouseOver;
element[i].onmouseout = processMouseOut;
}
if (typeof window.attachEvent != 'undefined') {
top.attachEvent('onblur', processIFrameClick);
}
else if (typeof window.addEventListener != 'undefined') {
top.addEventListener('blur', processIFrameClick, false);
}
}
attachOnloadEvent(init);
});
</script>
</head>
<body>
<iframe src="www.google.com" width="100%" height="1300px"></iframe>
<br></br>
<br></br>
<form name="form" id="form" action=""><textarea name="console"
id="console" style="width: 100%; height: 300px;" cols="" rows=""></textarea>
<button name="clear" id="clear" type="reset">Clear</button>
</form>
</body>
</html>
You need to replace the src in the iframe with your own link. Hope this'll help.
Regards,
Mo.
Just found this solution...
I tried it, I loved it..
Works for cross domain iframes for desktop and mobile!
Don't know if it is foolproof yet
window.focus();
window.addEventListener('blur',function(){
if(document.activeElement.id == 'CrossDomainiframeId'){
//do something :-)
}
});
Happy coding
You can achieve this by using the blur event on window element.
Here is a jQuery plugin for tracking click on iframes (it will fire a custom callback function when an iframe is clicked) :
https://github.com/finalclap/iframeTracker-jquery
Use it like this :
jQuery(document).ready(function($){
$('.iframe_wrap iframe').iframeTracker({
blurCallback: function(){
// Do something when iframe is clicked (like firing an XHR request)
}
});
});
see http://jsfiddle.net/Lcy797h2/ for my long winded solution that doesn't work reliably in IE
$(window).on('blur',function(e) {
if($(this).data('mouseIn') != 'yes')return;
$('iframe').filter(function(){
return $(this).data('mouseIn') == 'yes';
}).trigger('iframeclick');
});
$(window).mouseenter(function(){
$(this).data('mouseIn', 'yes');
}).mouseleave(function(){
$(this).data('mouseIn', 'no');
});
$('iframe').mouseenter(function(){
$(this).data('mouseIn', 'yes');
$(window).data('mouseIn', 'yes');
}).mouseleave(function(){
$(this).data('mouseIn', null);
});
$('iframe').on('iframeclick', function(){
console.log('Clicked inside iframe');
$('#result').text('Clicked inside iframe');
});
$(window).on('click', function(){
console.log('Clicked inside window');
$('#result').text('Clicked inside window');
}).blur(function(){
console.log('window blur');
});
$('<input type="text" style="position:absolute;opacity:0;height:0px;width:0px;"/>').appendTo(document.body).blur(function(){
$(window).trigger('blur');
}).focus();
http://jsfiddle.net/QcAee/406/
Just make a invisible layer over the iframe that go back when click and go up when mouseleave event will be fired !!
Need jQuery
this solution don't propagate first click inside iframe!
$("#invisible_layer").on("click",function(){
alert("click");
$("#invisible_layer").css("z-index",-11);
});
$("iframe").on("mouseleave",function(){
$("#invisible_layer").css("z-index",11);
});
iframe {
width: 500px;
height: 300px;
}
#invisible_layer{
position: absolute;
background-color:trasparent;
width: 500px;
height:300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message"></div>
<div id="invisible_layer">
</div>
<iframe id="iframe" src="//example.com"></iframe>
This works for me on all browsers (included Firefox)
https://gist.github.com/jaydson/1780598
https://jsfiddle.net/sidanmor/v6m9exsw/
var myConfObj = {
iframeMouseOver : false
}
window.addEventListener('blur',function(){
if(myConfObj.iframeMouseOver){
console.log('Wow! Iframe Click!');
}
});
document.getElementById('idanmorblog').addEventListener('mouseover',function(){
myConfObj.iframeMouseOver = true;
});
document.getElementById('idanmorblog').addEventListener('mouseout',function(){
myConfObj.iframeMouseOver = false;
});
<iframe id="idanmorblog" src="https://sidanmor.com/" style="width:400px;height:600px" ></iframe>
<iframe id="idanmorblog" src="https://sidanmor.com/" style="width:400px;height:600px" ></iframe>
Mohammed Radwan,
Your solution is elegant. To detect iframe clicks in Firefox and IE, you can use a simple method with document.activeElement and a timer, however... I have searched all over the interwebs for a method to detect clicks on an iframe in Chrome and Safari. At the brink of giving up, I find your answer. Thank you, sir!
Some tips:
I have found your solution to be more reliable when calling the init() function directly, rather than through attachOnloadEvent(). Of course to do that, you must call init() only after the iframe html. So it would look something like:
<script>
var isOverIFrame = false;
function processMouseOut() {
isOverIFrame = false;
top.focus();
}
function processMouseOver() { isOverIFrame = true; }
function processIFrameClick() {
if(isOverIFrame) {
//was clicked
}
}
function init() {
var element = document.getElementsByTagName("iframe");
for (var i=0; i<element.length; i++) {
element[i].onmouseover = processMouseOver;
element[i].onmouseout = processMouseOut;
}
if (typeof window.attachEvent != 'undefined') {
top.attachEvent('onblur', processIFrameClick);
}
else if (typeof window.addEventListener != 'undefined') {
top.addEventListener('blur', processIFrameClick, false);
}
}
</script>
<iframe src="http://google.com"></iframe>
<script>init();</script>
You can do this to bubble events to parent document:
$('iframe').load(function() {
var eventlist = 'click dblclick \
blur focus focusin focusout \
keydown keypress keyup \
mousedown mouseenter mouseleave mousemove mouseover mouseout mouseup mousemove \
touchstart touchend touchcancel touchleave touchmove';
var iframe = $('iframe').contents().find('html');
// Bubble events to parent
iframe.on(eventlist, function(event) {
$('html').trigger(event);
});
});
Just extend the eventlist for more events.
I ran into a situation where I had to track clicks on a social media button pulled in through an iframe. A new window would be opened when the button was clicked. Here was my solution:
var iframeClick = function () {
var isOverIframe = false,
windowLostBlur = function () {
if (isOverIframe === true) {
// DO STUFF
isOverIframe = false;
}
};
jQuery(window).focus();
jQuery('#iframe').mouseenter(function(){
isOverIframe = true;
console.log(isOverIframe);
});
jQuery('#iframe').mouseleave(function(){
isOverIframe = false;
console.log(isOverIframe);
});
jQuery(window).blur(function () {
windowLostBlur();
});
};
iframeClick();
Combining above answer with ability to click again and again without clicking outside iframe.
var eventListener = window.addEventListener('blur', function() {
if (document.activeElement === document.getElementById('contentIFrame')) {
toFunction(); //function you want to call on click
setTimeout(function(){ window.focus(); }, 0);
}
window.removeEventListener('blur', eventListener );
});
This definitely works if the iframe is from the same domain as your parent site. I have not tested it for cross-domain sites.
$(window.frames['YouriFrameId']).click(function(event){ /* do something here */ });
$(window.frames['YouriFrameId']).mousedown(function(event){ /* do something here */ });
$(window.frames['YouriFrameId']).mouseup(function(event){ /* do something here */ });
Without jQuery you could try something like this, but again I have not tried this.
window.frames['YouriFrameId'].onmousedown = function() { do something here }
You can even filter your results:
$(window.frames['YouriFrameId']).mousedown(function(event){
var eventId = $(event.target).attr('id');
if (eventId == 'the-id-you-want') {
// do something
}
});
We can catch all the clicks. The idea is to reset focus on an element outside the iFrame after each click:
<input type="text" style="position:fixed;top:-1000px;left:-1000px">
<div id="message"></div>
<iframe id="iframe" src="//example.com"></iframe>
<script>
focus();
addEventListener('blur', function() {
if(document.activeElement = document.getElementById('iframe')) {
message.innerHTML += 'Clicked';
setTimeout(function () {
document.querySelector("input").focus();
message.innerHTML += ' - Reset focus,';
}, 1000);
}
});
</script>
JSFiddle
Assumptions -
Your script runs outside the iframe BUT NOT in the outermost window.top window. (For outermost window, other blur solutions are good enough)
A new page is opened replacing the current page / a new page in a new tab and control is switched to new tab.
This works for both sourceful and sourceless iframes
var ifr = document.getElementById("my-iframe");
var isMouseIn;
ifr.addEventListener('mouseenter', () => {
isMouseIn = true;
});
ifr.addEventListener('mouseleave', () => {
isMouseIn = false;
});
window.document.addEventListener("visibilitychange", () => {
if (isMouseIn && document.hidden) {
console.log("Click Recorded By Visibility Change");
}
});
window.addEventListener("beforeunload", (event) => {
if (isMouseIn) {
console.log("Click Recorded By Before Unload");
}
});
If a new tab is opened / same page unloads and the mouse pointer is within the Iframe, a click is considered
Based in the answer of Paul Draper, I created a solution that work continuously when you have Iframes that open other tab in the browser. When you return the page continue to be active to detect the click over the framework, this is a very common situation:
focus();
$(window).blur(() => {
let frame = document.activeElement;
if (document.activeElement.tagName == "IFRAME") {
// Do you action.. here frame has the iframe clicked
let frameid = frame.getAttribute('id')
let frameurl = (frame.getAttribute('src'));
}
});
document.addEventListener("visibilitychange", function () {
if (document.hidden) {
} else {
focus();
}
});
The Code is simple, the blur event detect the lost of focus when the iframe is clicked, and test if the active element is the iframe (if you have several iframe you can know who was selected) this situation is frequently when you have publicity frames.
The second event trigger a focus method when you return to the page. it is used the visibility change event.
Here is solution using suggested approaches with hover+blur and active element tricks, not any libraries, just pure js. Works fine for FF/Chrome. Mostly approache is same as #Mohammed Radwan proposed, except that I use different method proposed by #zone117x to track iframe click for FF, because window.focus is not working without addition user settings:
Makes a request to bring the window to the front. It may fail due to
user settings and the window isn't guaranteed to be frontmost before
this method returns.
Here is compound method:
function () {
const state = {};
(function (setup) {
if (typeof window.addEventListener !== 'undefined') {
window.addEventListener('load', setup, false);
} else if (typeof document.addEventListener !== 'undefined') {
document.addEventListener('load', setup, false);
} else if (typeof window.attachEvent !== 'undefined') {
window.attachEvent('onload', setup);
} else {
if (typeof window.onload === 'function') {
const oldonload = onload;
window.onload = function () {
oldonload();
setup();
};
} else {
window.onload = setup;
}
}
})(function () {
state.isOverIFrame = false;
state.firstBlur = false;
state.hasFocusAcquired = false;
findIFramesAndBindListeners();
document.body.addEventListener('click', onClick);
if (typeof window.attachEvent !== 'undefined') {
top.attachEvent('onblur', function () {
state.firstBlur = true;
state.hasFocusAcquired = false;
onIFrameClick()
});
top.attachEvent('onfocus', function () {
state.hasFocusAcquired = true;
console.log('attachEvent.focus');
});
} else if (typeof window.addEventListener !== 'undefined') {
top.addEventListener('blur', function () {
state.firstBlur = true;
state.hasFocusAcquired = false;
onIFrameClick();
}, false);
top.addEventListener('focus', function () {
state.hasFocusAcquired = true;
console.log('addEventListener.focus');
});
}
setInterval(findIFramesAndBindListeners, 500);
});
function isFF() {
return navigator.userAgent.search(/firefox/i) !== -1;
}
function isActiveElementChanged() {
const prevActiveTag = document.activeElement.tagName.toUpperCase();
document.activeElement.blur();
const currActiveTag = document.activeElement.tagName.toUpperCase();
return !prevActiveTag.includes('BODY') && currActiveTag.includes('BODY');
}
function onMouseOut() {
if (!state.firstBlur && isFF() && isActiveElementChanged()) {
console.log('firefox first click');
onClick();
} else {
document.activeElement.blur();
top.focus();
}
state.isOverIFrame = false;
console.log(`onMouseOut`);
}
function onMouseOver() {
state.isOverIFrame = true;
console.log(`onMouseOver`);
}
function onIFrameClick() {
console.log(`onIFrameClick`);
if (state.isOverIFrame) {
onClick();
}
}
function onClick() {
console.log(`onClick`);
}
function findIFramesAndBindListeners() {
return Array.from(document.getElementsByTagName('iframe'))
.forEach(function (element) {
element.onmouseover = onMouseOver;
element.onmouseout = onMouseOut;
});
}
}
A colleague and I, we have a problem similar to that of Brian Trumpsett and found this thread very helpful.
Our kiosk has animations inside iframes and we need to track the page activity to set a timer.
As suggested here, rather than tracking the clicks, we now detect the focus change at each click and change it back
The following code is Okay on macOS with Safari and Chrome but does not work with FireFox (why?):
var eventListener = window.addEventListener('blur', function() {
if (document.activeElement.classList && document.activeElement.classList[0] == 'contentiFrame') {
refresh(); //function you want to call on click
setTimeout(function(){ window.focus(); }, 1);
}
window.removeEventListener('blur', eventListener );
});
The problem is that, on Windows, it works neither with Chrome nor with FireFox and thus, our kiosk is not functional.
Do you know why it is not working ?
Do you have a solution to make it work on Windows ?
As found there : Detect Click into Iframe using JavaScript
=> We can use iframeTracker-jquery :
$('.carousel-inner .item').each(function(e) {
var item = this;
var iFrame = $(item).find('iframe');
if (iFrame.length > 0) {
iFrame.iframeTracker({
blurCallback: function(){
// Do something when iFrame is clicked (like firing an XHR request)
onItemClick.bind(item)(); // calling regular click with right context
console.log('IFrameClick => OK');
}
});
console.log('IFrameTrackingRegistred => OK');
}
})
My approach was similar to that proposed by Paul Draper above. However, it didn't work in Firefox because activeElement did not update in time for the code to execute. So we wait a little bit.
This will also fire if you tab into the iframe. For my use case, it's fine, but you could filter for that keypress.
addEventListenerOnIframe() {
window.addEventListener('blur', this.onBlur);
}
onBlur = () => {
setTimeout(() => {
let activeElement = document.activeElement;
let iframeElement = document.querySelector('iframe');
if (activeElement === iframeElement) {
//execute your code here
//we only want to listen for the first time we click into the iframe
window.removeEventListener('blur', this.onBlur);
}
}, 500);
};
I believe you can do something like:
$('iframe').contents().click(function(){function to record click here });
using jQuery to accomplish this.