I'm using jQuery in an app which registers user clicks to perform a given action through the .click() binding, and I want this functionality to be available only through a user mousedown. One of my friends pointed out today that it's possible to run $(element).click() from a javascript terminal in Firebug (or something similar), and achieve the same functionality as clicking on the element -- something I'd like to prevent. Any ideas on how to go about doing this? Thanks for your input.
Short answer: No, you can't really prevent it.
Long answer: Any event like a click event is bound to such called Event handlers. Those handlers are functions which are executed when a given event occurs. So if you click on an element, your browser checks if any event handlers are bound to it, if so it fires them. If not, the browser will try to bubble up the event to the parent elements, again checks if there are any event handlers bound for that kind of event .. and so forth.
jQuerys .trigger() method (which is what you actually call if calling .click() for instance) just does the same thing. It calls the event handlers which are bound to a specific element, for a specific event.
EDIT
There might some simple ways to somekind of soft detect a real click, for instance you might check for the toElement property within an event object. That property is not set when triggered. But then again, you can easily fake that aswell with .trigger(). Example:
$(document).ready(function() {
$('#invalid2').bind('click', function(e){
alert('click\nevent.target: ' + e.toElement.id);
console.log(e);
});
$('#invalid1').bind('click', function(){
$('#invalid2').trigger({
type: 'click',
toElement: {id: 'Fake'}
});
});
});
Working example: http://www.jsfiddle.net/v4wkv/1/
If you would just call $('#invalid2').trigger('click') the toElement property would not be there and therefore fail. But as you can see, you can add like anything into the event object.
What are you trying to prevent? Someone messing with your client side script? You can do things like obfuscate your code but not much other than that. But even doing this is just making it more hassle than it's worth in my opinion.
If you don't want people doing certain things move the functionality to the server.
Sorry to be bearer of bad news.
You cannot really do anything against it, it would also be possible to write the complete function and then fire it.
But why is this a problem? If somebody is changing something client side it only affects him. Or are you trying to check some data? This MUST always be done in the backend, because you can never be sure what is really sent to it.
You can check event object (which is passed as first argument to handler) originalEvent.
It will be undefined if event is simulated by .click()
But it's completely useless. You cannot use javascript for security - client has full control over it (and firebug console is just most obvious tool). Client-side security checks should be only hint for user and protection against errors, malicious input can be stopped on server-side only.
Related
Using HTMX, I have an element rigged up with hx-get and hx-trigger, and it works fine. But under certain circumstances, I want the GET request to trigger from some vanilla JavaScript logic (which is not based on user input).
I've looked through the JavaScript API, and I'm just not seeing it. There's an htmx.trigger(), but it seems to just trigger the standard HTML events, not an element-based event.
I can do this all manually in JavaScript, of course, but I feel like there has to be a way to get HTMX to do it.
I got it.
You can do this in the hx-trigger element:
<input hx-trigger="[all your other triggers], doSearch from:body" ...
The trigger will now work in the all the other ways defined, and it will also listen for an event called doSearch from the BODY element..
You raise that event like this:
// Do a bunch of logic here, then...
document.body.dispatchEvent(new Event('doSearch'));
I want a generic (cross browser) way to get the browser to execute the default action for an object for a specified event preferably without getting any attached listeners to fire.
This kind of question has been asked before but in the context of already being in an event, &/or strictly talking about synchronously holding off the default action before letting it happen later.
Basically, let's say you have an DOM element (you don't know which) variable, and you want to invoke a click, such that if it were an anchor, it'd follow its href, if it were an input[type="submit"] it would submit the form.
But without firing that element's listeners for the click event (which may be prone preventDefault()s in the listeners).
For those that need a reason to answer questions; you may want to do it if you're implementing something like dispatchEvent() for browsers that only have fireEvent().
Both functions return true if the default wasn't 'prevented', but only dispatchEvent() actually follows through and invokes the default.
As a side question, jQuery's trigger() is meant to do this (although after firing the listeners) and be cross-browser, maybe the solution is there? As nice as jQuery is I'd like to know the vanilla methods it is calling (if it [this particular feature] indeed works on things like IE8).
It appears that, at least for the click event, you can call .click() on the element in these browsers.
This will have the element enact the default (as well as calling all listeners and the .onclick value, if defined).
I don't know of any other defaults on DOM elements, would scroll need to be accounted for? Keypress? Maybe those exist as functions too, but I haven't tested.
When I did test .click(), I noticed it obeyed any of the listeners returning false and did not fire the default, and the event did bubble (a listener I had on document fired too!).
There may be no other alternative (I.e. calling the default directly, avoiding the listeners). And as for passing it an event object, the browser in question has the single global event thing going on, so maybe you can manipulate that and it wont have changed when executing .click().
Adding as I find more information in my travels :)
Furthermore, there is an doScroll() function, but I think it would be really hard to translate a given event into the string accepted by this method
Other javascript is changing the value of an input and I was wondering if there was a way to detect the change.
This question has nothing to do with Keyup or Change. This is not being typed in by the user it is being changed by other javascript though various actions of the user.
When changing an event programatically, you can trigger a change event to make sure event handlers that are attached to the element are fired. jQuery has a trigger() method to do this:
$('#elementID').on('change', function() {
alert( this.value );
});
$('#elementID').val('some new value').trigger('change');
The quick run-down of what I am going to say is: there is no way other than to modify the third-party scripts to output stuff, or to use setInterval (costly).
The bottom line of this issue is a simple one, that does not appear to be so at first: How can you get your scrips to communicate with each other?
When a script modifies the value of an input through JS methods (i.e. not user input), they have to go through specific hoops to get the "change" event to fire (they can fire it manually by calling it, which most devs never do and is easily forgotten when writing code). In practice, people tend to rely on the observation events (user-defined ones) to track code changes. This is very similar to DOM events - you bind callbacks to your script, which allow you to tap callbacks in that will fire whenever your scripts do something interesting (like modifying inputs. This is just one example). You then teach your scripts and developers to fire events on useful stuff using the callbacks to notify other scripts.
A great library for this is Postal, which is originally a Node library. jQuery also has an event system you can tap into. However, if you want to roll your own, all you have to read into is the Observer design pattern. It is trivial: you bind a function to your object to pick up callbacks, and another to fire them. Whenever you change the thing, you fire the callback. Simples.
Failure to do so means setInterval. Sucks, but there you go :-(
I'll try and explain the best I can...
I have a page, we'll call it pageA. When a button is clicked on that page, an ajax request is sent out and the return data is eval()'d. That data obviously contains javascript code. This code could possibly contain event listeners that are added to pageA when it is eval'd. Something like jquery $('body').click() for example.
When the button on pageA is clicked again, is there a function or something to remove any and all event listeners and data added on that eval.
I am capturing all the data returned from the ajax call into a variable before I eval the data, so is there a way to just do $(data).remove() and have all the event listeners and data magically disappear?
With eval data, it's not really added to the page per se where I could just do a text remove on the page and have all my problems go away, but the event listeners certainly do stay around.
Any ideas?
I will forgo the lecture on the evils of eval and recommend that you try namespacing your events in jQuery.
http://docs.jquery.com/Namespaced_Events
For example, have can the code in data add all new events with a namespace:
$(node).bind("click.myNameSpace", fn);
And when you want to remove it, you just do $(node).unbind("click.myNameSpace"), of course, that's assuming you know what elements they were added to. If you don't know the type of event that was added you can also do $(node).unbind(".myNameSpace") and it will remove all events under your namespace.
It may be easier to just copy all the currently attached event handlers on the particular button before you eval the javascript that's returned. Then unbind all the events (to which eval could have added extra handlers) and re-bind what was there before.
EDIT: Looks like someone's already had a similar question: jQuery: Unbind event handlers to bind them again later (though that uses jQuery).
I can't help but ask though, don't you have control over the JS that gets returned? Because if you do, it would be better to make sure malicious content is never sent in the first place.
in javascript, when I receive a focus event, how can I work out which element has lost focus? I'm trying to avoid having to put an onblur event handler on all elements within my web page.
#pbrodka: the target/srcElement property would refer to the element with focus for onfocus events
offhand I can't see a way to get this short of onblur, or if the set of objects you care about all have focus methods you could store a reference to that object instead. It's also possible event bubbling could get you out of jail
this all feels like a bit of a code smell though - perhaps you need to describe the problem in more detail
Difficult this. You cannot use event delegation to find out which control last produced a blur as focus/blur do not bubble up. There have been some attempts to 'fix' this but they are buggy and not resiliant cross browser.
Could I ask you why do you need this information as maybe there is an alternative solution.
Unfortunately, the onblur event doesn't bubble, otherwise you could have handled it at the window level to always know when an element lost focus.
As things are, I do believe it will be hard to do without, as you say, adding an onblur event handler to all elements (a truly nasty solution ;-).
It is possible to delegate the focus and blur events, if you follow PPK's advice, here:
http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
The most simple solution is to write a function that walks all forms and then all elements within the form and installs an onblur handler for each (which will probably call some global function). This handler will get an event and this event will contain the info you seek.
This way, you just have to call this method once in body.onload and it will work no matter how complex your document is.
The only drawback is that you will need to call it if you dynamically add forms to your current document. In this case, you must make sure not to install the handler again (or you will get spurious duplicate events).