I am binding event to an element.
How to prevent new JavaScript event to be bound to it?
I want to prevent unknown scripts to play with my elements.
You cannot block an unknown script from attaching an event listener to your object. The browser does not offer that feature. The browser does block scripts that are running from other domains (other windows, tab, or frames) from messing with your DOM, but if a script is in the same domain or even in the same page, it is free to do whatever it wants to the DOM in that page.
If you have problems with unknown scripts doing bad things, then you're probably better off backing way, way up and describing what you're really trying to protect against because trying to block an event listener is like trying to keep someone out of one drawer when they're already roaming free through your house. You probably need to secure things at a much higher level.
If you want to get into the realm of "hacking" to try to block specific types of code, there are some options. These aren't foolproof if the 3rd party code wants to get around them. In other words, these would be more useful if you can see what the 3rd party code does and it won't adapt itself to try to get around you:
Firstly, you can replace elem.addEventListener() after you've installed your event handler which will prevent other code from using elem.addEventListener() on that object again.
var item = document.getElementById("test");
item.addEventListener("click", function() {
log("original event handler");
});
// install "do nothing" override method
item.oldAddEventListener = item.addEventListener;
item.addEventListener = function() {};
// this one will do nothing because addEventListener has been replaced
item.addEventListener("click", function() {
log("2nd event handler");
});
Demo: http://jsfiddle.net/jfriend00/C5rzN/
This isn't foolproof as there are other ways to still install an event handler calling the method directly from the prototype or using the onclick property.
Related
TLDR Below
JS Fiddle To Demo
I've been really involved in recreating the tools that are foundations of premiere JS Libraries to better improve my skills. Currently I'm working on functional data-binding a la Angular.
The idea of data-binding is to take data and bind it to elements so that if manipulated all elements subscribed will change accordingly. I've gotten it to work but one thing I hadn't considered going into it was the issue with innerHTML vs value. Depending on the element you need to change one or the other( in the demo above you'll see that I needed to specifically single out the button element in a conditional statement because it has both, but that's kind of a fringe case )
The issue is that in order to capture a SPAN tag update I needed to trigger an event to happen, and the easiest one to manipulate for Text Boxes/Textareas was 'keyup'.
In my function then, if you pass in an element with no value property we assume you're going to be updating innerHTML, and we setup an observer to determine if the element ever mutates, and if it ever does, the observer will emit a 'keyup' event.
if (watchee.value == void(0)) {
var keyUpEvent = new Event('keyup');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
watchee.dispatchEvent(keyUpEvent);
});
});
observer.observe(watchee, {
childList: true
});
}
Now it may just be my paranoia, but it seems like I might be tunneling into a can of worms by faking 'keyup' on an element that doesn't natively have that support.
TLDR:
I'm curious if there's an alternative way to make, a.e. a span tag reactive other than faking a 'keyup'/'keydown'/'change' event? For instance, is there a way that I can make my own pure event(by pure I mean not reliant on other events) that checks if innerHTML or value has changed and then performs a function? I know that this is probably possible with a timer, but I feel like that might hinder performance.
EDIT: just an aside. In the demo the function called hookFrom works by taking a DOM node and returning a function that will take the receiving dom node and continues to return a function that will take additional receiving dom nodes. :
hookFrom(sender)(receiver);
hookFrom(sender)(receiver)(receiver2);
hookFrom(sender)(receiver)(receiver2)(receiver3)(receiver4)...(receiver999)...etc
JS Fiddle To Demo (same as above)
There is nothing inherently wrong with creating a similar event on a DOM node that doesn't natively have that functionality. In fact this happens in a lot of cases when trying to polyfill functionality for separate browsers and platforms.
The only issue with doing this sort of DOM magic is that it can cause redundancy in other events. For instance the example given in this article: https://davidwalsh.name/dont-trigger-real-event-names shows how a newly minted event using the same event name can cause problems.
The advice is useful, but negligible in this specific case. The code adds the same functionality between text boxes, divs, spans, etc... and they are all intentionally handled the same way, and if the event would bubble up to another event, it would be intentional and planned.
In short: There is a can of worms that one can tunnel into while faking already explicitly defined event names, but in this case, the code is fine!
I'm customizing an existing ASP.NET 3.5 AJAX web application that I can't modify the source code to (it's SharePoint 2010).
I need to add a click event handler as the first event on a Close button. However, I'd like to check what the existing event handlers already registered on this button do first, so I don't mess anything up.
I'm still learning ASP.NET AJAX and can see the Sys.UI.DomEvent class has methods to add and remove event handlers, but not enumerate them. I know jQuery and am familiar with JavaScript debugging in Chrome.
How can I see which events are registered and insert a custom event handler at a particular position?
There is a technique that will at least allow you to be the first in line (unless another script employs the same trick - unlikely).
What you have to do is hijack the click event. This related question demonstrates the technique: Hijacking onchange event without interfering with original function
All we do is redefine the click function to be one of our own choosing, e.g.
var myButton = document.getElementById('button1')
var oldClick = myButton.click;
myButton.click = function(evt) {
//do whatever you want. When done, call the default click function:
if (oldClick) oldClick(evt);
}
(the syntax in the linked question is superior, but the above code is easier to read).
I am making mouse click events and I'm trying to dispatch it to some node several times in a row. For that I am using the same MouseEvent object and for some reason this approach does not work. Yet, when I create event manually each time, system works. Does anybody know what is the reason for this behavior?
I've tried to change the timeStamp, but problem still occurs. I can solve the problem like I mentioned before, but I am interested in how this MouseEvent and corresponding dispatching and handling subsystems really work. MouseEvent specification that I've found on MDC pages seems to lack a lot of information.
Tnx for the help!
This is actually a security mechanism, dispatching an event that has been dispatched before isn't allowed. An event always has additional data associated with it, for example whether it comes from a trusted source (user's keyboard rather than JavaScript code). Some attacks (mostly against MSIE because it had mutable event objects) were using this - they caught a trusted event, changed it and dispatched it again elsewhere (changing might not always be required, dispatching it at a different element is enough for some attacks). In the end disallowing redispatching of events turned out to be the best solution. After all, this functionality isn't really required: creating a new event object with identical properties (minus hidden data) isn't exactly hard.
Pretty much all the security issues in this area were related to the file input control. Some time ago Firefox decided to change the file input UI radically and disallow entering the file name directly. I wonder whether this change made redispatching of events a non-issue. I doubt that anybody will be willing to risk opening this can of worms again however.
I think the reason you can't reuse the same MouseEvent object is because the event system maintains some internal state in the event objects so they can implement things like bubbling and cancelling. You may just have to stick with creating distinct event objects.
Reading Document Object Model Events may give you a better understanding of how the DOM event system works.
Without knowing what you have now ill just go under assumption.
Make an event function:
function clickEvent(event) {
//do something
}
Attach it:
obj.onclick = clickHandler;
And you can do this multiple times to multiple objects.
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.
I'm developing a touchscreen application that, aside from everything else, records the amount of times the screen is used so that the user can be reminded to clean the screen after a predefined number of clicks.
I've got the click functions written nicely, all I need now is make sure the function is called on a click.
I imagine $('*').click(function() { //do something }); would accomplish my goal, but is that the best way? Also, would that overwrite other click functions assigned to the elements?
It would add, not override, but a better solution would be this:
$(document).click(function() {
//do something
});
Since clicks bubble, just listen up at the document level with one event instead of creating events on every element beneath. For the override part...you can add as many handlers as you want, they will just execute in the order they were bound.
The best way is to assign the event handler to document itself. The events bubble and document can catch them all, while still retaining the origin of the event.