I am trying to write a userscript which creates a text input on a website, however in the website's javascript code, a function called on keypress or something else calls e.preventDefault() which prevents text input. I do not have access and cannot change that function. Is there any way to bypass that?
We have to register an event listener to be able to call preventDefault or stopPropagation. If the methods are called, I believe there's no way negating the effect after the default was prevented or the propagation stopped.
The only chance would be: register you own listener before the website has a chance to register it's own. Which probably happens in a script and if you can find that, you can inject your own script before that. Then your handler would be called first and that could work for you. (you could call stopPropagation and the other listener wouldn't be called anymore)
Related
In the following code (JSFiddle here):
<form>
<button>ok</button>
</form>
$(function(){
$('form').submit(false) ;
$('button').click(function(){ $('form').remove() }) ;
}) ;
When you click the button in Google Chrome 48, it triggers a form submission.
If you do it in Firefox 43, however, there is no form submission.
It seems to me that the Firefox behavior should be the correct one, but since I don't have such a deep knowledge of the standard, I don't really know.
Is either behavior wrong or buggy?
Follow up:
I just found out that the same test case but without using jQuery doesn't trigger a form submission in neither browser.
<form onsubmit="return false">
<button onclick="form.remove()">ok</button>
</form>
This could not be a timing issue because there's no thread concurrency in Javascript. Event threads will always run in sequence, so the button event handler must finish before the form event handler starts.
I'm blind here. jQuery must be doing some weird cumbersome stuff for this to happen in Chrome.
Follow up 2:
It's not a jQuery problem. At the jQuery bug tracker I was told that inline event handlers don't follow the same specification as those attached with addEventListener, so a true functionally equivalent code should be like this:
<form>
<button>ok</button>
</form>
<script>
document.querySelector('form').addEventListener('submit',function(){ return false }) ;
document.querySelector('button').addEventListener('click',function(evt){ evt.target.form.remove() }) ;
</script>
And this does behave like the jQuery version.
Your first code adds a returnFalse jQuery event listener:
$('form').submit(false);
In a jQuery event listener, return false is equivalent to
event.stopPropagation();
event.preventDefault();
The later should prevent the submission of the form.
However, before the submit event is fired, you use $.fn.remove. This not only removes the form from the document, it also cleans its jQuery data, including the event listener.
Therefore, when the browser fires the submit event to the form, it is not canceled.
Then browsers behave differently (demo):
Firefox doesn't submit removed forms
Chrome doesn't care whether the form has been removed and submits it anyway
If you don't want to remove jQuery data, you should remove the form using vanilla-js methods instead of $.fn.remove.
In your second code, you cancel the event in a vanilla-js event handler.
Since it's not jQuery data, $.fn.remove does not remove it, so the submit event is canceled and the form is not submitted.
In your third code, you you remove the form using vanilla-js methods, so its jQuery data is not cleaned.
This does not matter because the submit event listener is added with vanilla-js too.
However, the event is not canceled. That's because, unlike vanilla-js event handlers and jQuery event listeners, the value returned in a vanilla-js event listener is completely ignored.
So at the end the result is the same than in the first code, but they are not equivalent.
If you want to cancel an event using a vanilla-js event listener, you should use
event.preventDefault();
This would make it behave like the second code.
I think that it is implementation dependent and not guarantee identical behaviour
Both Chromium and Firefox does not call form.onsubmit handler installed by $('form').submit(...) when $('form').remove() called. So this mean that form is checked as destroyed (or realy destroyed) before to call onsubmit in both Chromium and Firefox.
I think that Chromium does not check that form marked as destroyed when process default submit action emitted by button pressing. But Chromium do checking preventDefault flag where default action of button is form submit. So it is possible to add event.preventDefault() before or after $('form').remove().
In opposite Firefox ignore preventDefault of button pressing event and pass control to form.onsubmit.
So behaviour of this two browsers concerning preventDefault and onsubmit is exactly opposite.
As far as fact of form submiting when form is marked as destroyed it is possible to imagine software design where object actually deleted after communication is finished and not before. But seems to me that it is bug. Need to know what developers think. Does they know about it and is this bug or feature.
is there any universal way to instrument javascript event handler firing using javascript?
for example, I want to do something before the event handler firing, so when to fire an event, I would like to execute my code first then the event handler code.
The problem is that there are multiple ways to register event handlers, I would like to handle all of them: html, javascript
No, there's not.
You can hook addEventListener and removeEventListener, which would allow you to intercept both the registration and invocation of event listeners by JS code. However, this will not capture event listeners set in ways such as elt.onclick. Nor of course will it catch listeners set up via the old IE attachEvent API. Most importantly, it will not help with you that events that are generated and listened for internally, such as a mouse click on a check box.
You might be tempted to hook createEvent and dispatchEvent in similar fashion, but that will capture only events that are explicitly created or dispatched in the JS code.
In short
Is there a way in which, when listening to a native event, I can detect if the event was somehow used by CKEditor before it propagated to my listener, or prevent it from propagating at all?
Use case
I'm listening to the keyup event using jQuery, to detect when escape is pressed. When it is, the user is prompted if they want to discard changes, and the CKEditor instance is destroyed and its element removed from the DOM.
$('body').on('keyup', function(e){
if(e.which==27){
CKEDITOR.instances.myDiv.destroy();
$('#myDiv').remove();
}
});
The problem here is that CKEditor allows the user to interact with certain UI elements using the escape key. For instance to close a dialog window or drop-down list.
So my event should only execute its code if CKEditor did not already use the event to close a UI element of its own.
Attempt
I tried to listen to the dialogShow and dialogHide events to detect if a dialog window is open, and my action should thus be ignored. This didn't work for two reasons:
CKEditor handles the event first, so by the time the event propagates to my listener, no dialog windows are open and my code is executed.
Even if it would work, it wouldn't for drop-down lists as they do not trigger the dialog* events.
Ideas
I don't know enough about the workings of CKEditor to come up with a solution, but I think I'm looking for something along the lines of:
A setting in CKEditor to prevent event propagation: CKEDITOR.instances[0].noEventPropagation = true
An indication in the original event object: if(event.CKEditorWasHere){/*do nothing*/}
A plugin providing functionality that I can use.
Worst case scenario: A setTimeout in the dialogHide event which I'll use to suppress my own events for a short time.
So
Maybe I'm completely overlooking something. This seems to me like a common problem which should have a simple solution.
Thanks for your time.
I have a page which has two different event listeners picking up click events from inside the page. One listener is generic to the site, the other is specific to the page. Recently, a link was added which runs through the first handler, which processes it, opens the url in a new window and then stops the event. The problem is, the second handler then executes, stops the event again and somehow the event continues and executes.
I have stopPropagation, and cancelBubble both executing on this event. When it arrives at the second handler, it has a prevented field which is set to true, but still it carries on. The only way to stop it is to put a check in the second handler which skips its code if the event arrives with prevented set to true.
My question is, why would this happen at all? Why is stopPropagation not working? This happens in all browsers, BTW.
I suppose you try to stop event from firing on the same element. Have you tried to use stopImmediatePropagation method?
As Samuel Liew correctly commented, adding return false; to the end of your first event handler might do the trick. This is because some browsers ignore the .stopPropagation() (However, others will ignore the return)
I have a facebook connect button on this site here is the code
<fb:login-button onlogin="javascript:jfbc.login.login_button_click();"
perms="email,publish_stream,user_about_me,user_hometown,user_location,user_birthday,user_religion_politics,user_interests,user_activities,user_website"
size="medium" v="2"><a class="fb_button fb_button_medium">
<span class="fb_button_text"\>Login With Facebook</span></a></fb:login-button>
and i want to trigger this button with a javascript call and doing research i found this jquery that seems that it would do the trick (havent tested though) and i was wondering if there is an equivelent javascript or mootool because jquery is not installed. I can install it if i cant find a solution. Or if anyone has another idea on how to trigger this facebook button
$("fb\:login-button").trigger("click");
There are two ways to "trigger" a listener:
call it directly (e.g. element.onclick())
dispatch an event into the DOM that the listener will respond to
The trouble with the first method is that it doesn't replicate a bubbling event so the listener may not work as intended (e.g. there is no associated event object or bubbling, the listener's this keyword may not be correctly set).
The trouble with the second is that some browsers will not allow programatically dispatched events to do certain things (click on links for example). Also, in some browsers you have to use the W3C dispatchEvent and in others the Microsoft fireEvent.
So unless the listener has been designed specifically to work with one method or the other and is called appropriately, your chances of triggering the listener successfully are quite low.
PS. Some libraries provide their own event system, with custom events and bubbling of otherwise non-bubbling events, but in that case you have to set and trigger the listener using that library, otherwise it will probably not respond to either of the above methods.
You should be able to just invoke the same code that is invoked inline:
jfbc.login.login_button_click();
I suppose it would be something like
document.getElementsByTagName("fb\:login-button")[0].click();
I'm sure that would work very well with a "normal" DOM element that handles the click event; however, I'm not entirely sure it will work in all browsers with the fb:login-button element shimmed into HTML. You'll have to let me know.
Looks like you should be able to do:
document.body.getElementsByTagName("fb\:login-button")[0].click();
It looks like you want a namespaced element selector, so you should use:
document.getElementsByTagNameNS('fb', 'login-button')[0].click();
The : is the namespace separator.
I ran into this tonight, absolutely positioned a new button image over the iframe, and was planning on using pointer-events:none to pass through and click the iframe, but I was looking for a cross-browser solution, here you go.
jQuery('.button_fb_connect').live('click', function(){ FB.login() })
Your simply running the js function FB.login() after clicking your new element, obviously you can use whatever event you want.
Thats in jQuery of course, but thats the function you want, not just a simple click event trigger.