I am currently building a browser extension that injects javascript/jquery into certain pages, and i am having a weird issue, where forcing .click() events are not working from my injected code. The strange bit is that it works completely fine if i make the call from my console js console.
I dont really understand what the problem is. It seems that all of my other calls are working fine. I can bind to click events using .click(function(){...}) (so clearly my jquery has been loaded properly), and call methods when things are clicked (so clearly my jquery has been loaded properly), but the second that i try to force a click, the call just does not go through.
Can anybody explain what is happening, or a way that i can get around it?
(i can not recreate this issue, because the problem clearly has to do with injecting the js in an extension)
this is the best i can do for recreation:
//I have tried all of these separately
console.log($("#this_is_an_id")) //This returns the correct element
$("#this_is_an_id").click() //This does not work at all
$("#this_is_an_id").trigger("click") //I have also tried this without success
$("#this_is_an_id").click(function(){ console.log("stuff") }) //This works fine.
Really, at this point, i am assuming it is not my fault, but something that is wrong with the browser's method of injecting script. I am sorta looking for really hackey ways to fix this, i also tried eval('$("#this_is_an_id").trigger("click")'). Does anybody have any other suggestions?
I finally found a very excellent answer/work around to this issue here:
Trigger events from Firefox browser extension?
From user cms:
First of all, for click events, you need to create an event object with type MouseEvents, not HTMLEvents, and use event.initMouseEvent instead of event.initEvent.
To access the document of the current tab of Firefox from a XUL overlay, you can use the content.document property, but since you already have access to the DOM element you want to click, you can use the Node.ownerDocument property, which will refer to the top-level document object for this node.
I have made a simple function to simulate MouseEvents:
function triggerMouseEvent(element, eventName, userOptions) {
var options = { // defaults
clientX: 0, clientY: 0, button: 0,
ctrlKey: false, altKey: false, shiftKey: false,
metaKey: false, bubbles: true, cancelable: true
// create event object:
}, event = element.ownerDocument.createEvent("MouseEvents");
if (!/^(?:click|mouse(?:down|up|over|move|out))$/.test(eventName)) {
throw new Error("Only MouseEvents supported");
}
if (typeof userOptions != 'undefined'){ // set the userOptions
for (var prop in userOptions) {
if (userOptions.hasOwnProperty(prop))
options[prop] = userOptions[prop];
}
}
// initialize the event object
event.initMouseEvent(eventName, options.bubbles, options.cancelable,
element.ownerDocument.defaultView, options.button,
options.clientX, options.clientY, options.clientX,
options.clientY, options.ctrlKey, options.altKey,
options.shiftKey, options.metaKey, options.button,
element);
// dispatch!
element.dispatchEvent(event);
}
Usage:
triggerMouseEvent(element, 'click');
Check a test usage here.
You can pass also an object as the third argument, if you want to change the values of the event object properties.
Thank you so much for this answer. O_O
Related
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
Before starting this question, i have to say I really searched everywhere to find the answer but nothing found. Also tried manythings like dispatchevent, postmessage, ... but nothing worked.
Here is the case.
I have a main windows, where I have 4 simple buttons, like downarrow, uparrow, left and right arrow. I want to create a simulation of events pass to the iframe which is in this main window.
In that iframe is a page loaded where is an Eventhandler and react on the arrows.
I tried following but did not worked
var event = document.createEvent('KeyboardEvent'); // create a key event define the event
event.initKeyboardEvent("keypress", // typeArg,
true, // canBubbleArg,
true, // cancelableArg,
null, // viewArg, Specifies UIEvent.view. This value may be null.
false, // ctrlKeyArg,
false, // altKeyArg,
false, // shiftKeyArg,
false, // metaKeyArg,
39, // keyCodeArg (39 is the right arrow key ),
0); // charCodeArg);
document.getElementById('vid').dispatchEvent(event);
Is there anybody who has an idea how I can solve this issue?
Use postMessage. It works perfectly.
document.getElementById('vid').contentWindow.postMessage(event);
Finally I have sorted out the issue. I have used parent.document on my iframe to catch the events from the parnet side and create them again on iframe and it works great!
you want something like this:
var iframe = document.getElementById('something');
var iframeEvent = new Event('iframe-keypress');
document.addEventListener('keypress', function (e) {
iframe.dispatchEvent(iframeEvent);
});
iframe.addEventListener('iframe-keypress', function (e) {
console.log(e);
});
listen for the event on the document then pass down a custom event to the iframe.
jsfiddle - http://jsfiddle.net/rfkqe64j/
This works, but with jQuery.
window.addEventListener("keydown", (evt) => {
const {type, key} = evt;
parent.$("body").trigger(parent.$.Event(type, {key}));
})
Interestingly, parent.$.Event(evt) directly doesn't work.
I think this jquery forum thread should help
https://forum.jquery.com/topic/how-to-pass-mouse-events-to-an-iframe
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I have a form. It contains some hyperlinks. I can click on them and get another page in browsers like Google Chrome and Mozila Firefox but instead, I am unable to open them in IE9, IE10,..
What might be the problem? and whats the solution? help me.
In dev-tool(console), I am getting
un-terminated string constant error
.
Apart from any coding this could be the reason:
A previously installed browser or add-in might be interfering with ie browser on your computer.
or it might be a result of bad DCOM.
If bad DCOM is the problem you can get solution here:- http://www.techsupportall.com/links-are-not-working/
Jay,
This might happen due to incorrect concatenations or omission of the semicolon(;) at the end of statement.
Or may be any server variable that is not being populated. Like:
var var1 ='<% = someServerVariable %>'
someCode
It is possible that some someServerVariable is not being populated and the browser compiler would read the code as
var1 = someCode
Please look into your code and find out if there is any similar issue with your code. Or the best is to share your code snippet to point out the exact issue.
I ran into this same exact problem. For me, whenever I was embedding links in an ul / li list format, it just wouldn't let me click the first link (happens a lot navigation menus).It would only let me click the embedded ones. My work around for this was using java-script to create a force the click and pass.
Put this script in your head
<script>
function fakeClick(event, anchorObj) {
if (anchorObj.click) {
anchorObj.click()
} else if(document.createEvent) {
if(event.target !== anchorObj) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
var allowDefault = anchorObj.dispatchEvent(evt);
// you can check allowDefault for false to see if
// any handler called evt.preventDefault().
// Firefox will *not* redirect to anchorObj.href
// for you. However every other browser will.
}
}
}
</script>
And then in the body you can use this convention for any link you need to be forced clicked.
<a id="link" href="#YourDestinationLinkHere" onclick="fakeClick((event.target || event.srcElement).innerHTML)">Destination</a>
Still a little "gunshy" about jQuery. Does this simple popup window script look okay? Is my jQuery logic right?
I have a few questions in the code comments that I'm curious about.
$( document ).ready( function()
{
$( "a[target='popup']" ).click( function( event )
{
var $href = $( this ).attr( 'href' ); // should I use "this.href"?
var $name = $( this ).attr( 'target' ); // does the window name matter?
var $config = 'width=590, height=590, top=20, left=60, scrollbars=1';
var $popup = window.open( $href, $name, $config );
if ( window.focus ) // is this even necessary?
// any other conditions I should check instead?
{
$popup.focus();
}
event.preventDefault(); // should this be above $popup.focus()?
});
});
It seems to work, but since this script will be important for acquiring RSS subscribers on my site, I thought I'd make sure.
// should I use "this.href"?
No, use the jquery selector - if you're going to use $(this) a lot, put it into a variable at the start so you don't have the overhead of creating the jquery object each time (you do it twice, so you're creating a jquery object twice).
// does the window name matter?
If you want to do anything with the window later, like close it or change it's location, you'll need the name. It's just a handle to the window.
// is this even necessary?
This just makes sure you can do what you're about to try - it's a feature test to ensure you don't generate an error where the focus() method isn't available.
// any other conditions I should check instead?
Nope - test for the function you will call (you call it when you focus the popup).
// should this be above $popup.focus()?
No. It's better to leave this until last as this is where another developer would look for it. Do all the stuff you want to do first, then pop this in to stop the event from bubbling up.
Finally, what's with the $ prefix on your variable names? You might want to save that practice for PHP as the $ is now a handle on jquery.
$(document).ready( function() {
$("a[target='popup']").click( function(event) {
var myObject = $(this);
var href = myObject.attr("href");
var name = myObject.attr("target");
var config = "width=590, height=590, top=20, left=60, scrollbars=1";
var popup = window.open(href, name, config);
if ( window.focus ) {
popup.focus();
}
event.preventDefault();
});
});
Your javascript function is correct. Here is an explanation for each question:
1) Should I use this.href?
No you shouldn't because thats not the jquery way to do things. Javascript implementations can vary from browser to browser, and this jQuery function will make sure the call returns the correct value in every browser it is intended to support. While this.href might work, there is no guarantee it will, but the jQuery will work (in the browsers it is intended to support).
2) Does the window name matter?
Yes. The point of using this jQuery script is to control the window that comes up, however, the link should work (targeting the named window) even if the user has javascript disabled. This javascript is intended to let you control what the window looks like.
3) Is this necessary?
Yes, this goes back to you not being guaranteed to support certain javascript features. The call to window.focus is just checking if the focus function exists for this element in this browser. If it does exist, it will try to set the focus to that element, and if it does not exist, it will not show as a script error (bad user experience) in the browser.
4) should this be above $popup.focus()?
This is letting the browser know that you successfully created and popped up the window yourself and that the event should stop working (thus canceling the browsers default event of opening the new window).
window.focus
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.
event.preventDefault()
Cancels the event if it is cancelable,
without stopping further propagation
of the event.
I don't think there will be any difference if you give this above the focus method.