For some reason when fired through C# code by using the IHTMLElement2.focus() method call, an onfocus event will not set window.event (which will become null), instead some other object window.Event will get set with the event information. Is there a reason for this? I am using ShDocVw interface for InternetExplorer and this is the first time I have seen this issue.
Sounds like a typical microsoft bug. They often have a problem with case sensitivity since it has been onverlooked as a distinction since day one of the OS.
I would suggest maybe looking into this kb article http://msdn.microsoft.com/en-us/library/aa703985(v=vs.85).aspx specifically the tabindex hooha which sounds like a joke, but what else would you expect.
Then I would suggest trying the 4th variant form of IHTMLElement particularly the onfocusin event as an alternative to onfocus.
But ultimately since you control the environment via the shdocvw object - I'd just map the window.Event object to the window.event object in your onfocus handler - one line of code never hurt no one - except for when that one line of code hurts someone with a stack overflow, buffer overrun or Out of Memory exception of course :D
Related
I need an efficient mechanism for detecting changes to the DOM. Preferably cross-browser, but if there's any efficient means which are not cross browser, I can implement these with a fail-safe cross browser method.
In particular, I need to detect changes that would affect the text on a page, so any new, removed or modified elements, or changes to inner text (innerHTML) would be required.
I don't have control over the changes being made (they could be due to 3rd party javascript includes, etc), so it can't be approached from this angle - I need to "monitor" for changes somehow.
Currently I've implemented a "quick'n'dirty" method which checks body.innerHTML.length at intervals. This won't of course detect changes which result in the same length being returned, but in this case is "good enough" - the chances of this happening are extremely slim, and in this project, failing to detect a change won't result in lost data.
The problem with body.innerHTML.length is that it's expensive. It can take between 1 and 5 milliseconds on a fast browser, and this can bog things down a lot - I'm also dealing with a large-ish number of iframes and it all adds up. I'm pretty sure the expensiveness of doing this is because the innerHTML text is not stored statically by browsers, and needs to be calculated from the DOM every time it is read.
The types of answers I am looking for are anything from the "precise" (for example event) to the "good enough" - perhaps something as "quick'n'dirty" as the innerHTML.length method, but that executes faster.
EDIT:
I should also point out that whilst it would be "nice" to detect the precise element that has been modified, it is not an absolute necessity - just the fact that there has been any change would be good enough. Hopefully this broadens people's responses. I'm going to investigate Mutation Events, but I still need a fallback for IE support, so any whacky, creative, outside-of-the-square ideas would be very welcome.
To bring this up to date, the DOM4 standard does away with Mutation Events and replaces them with Mutation Observers: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
http://www.quirksmode.org/js/events/DOMtree.html
jQuery now supports a way to attach events to existing and future elements corresponding to a selector: http://docs.jquery.com/Events/live#typefn
Another interesting find - http://james.padolsey.com/javascript/monitoring-dom-properties/
Mutation events are the W3 recommendation of what you are looking for..
Not sure if they are supported all around.. (IE will most likely not support them..)
You could try using the DOMNodeInserted and DOMNodeRemoved events. Acording to Quirksmode, they kind of work in most browsers, with the notable exception of IE...
http://www.quirksmode.org/dom/events/index.html
I have recently written a plugin that does exactly that - jquery.initialize
You use it the same way as .each function
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
The difference from .each is - it takes your selector, in this case .some-element and wait for new elements with this selector in the future, if such element will be added, it will be initialized too.
In our case initialize function just change element color to blue. So if we'll add new element (no matter if with ajax or even F12 inspector or anything) like:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Plugin will init it instantly. Also plugin makes sure one element is initialized only once. So if you add element, then .deatch() it from body and then add it again, it will not be initialized again.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Plugin is based on MutationObserver - it will work on IE9 and 10 with dependencies as detailed on the readme page.
jQuery Mutate does this too, by default it supports like height, width, scrollHeight etc... but it also can be extended with a little bit of extra code to add new events like see if text has changed etc...
http://www.jqui.net/jquery-projects/jquery-mutate-official/
Hope it helps
One benefit of calling functions directly from markup is that it is easier to track what's being called. I would like to know if there is an browser addon or something that supports a "Goto javascript source function" for each of the events attached (bound) to an element. Ideally this would take me to the original location it got bound.
You can use FireQuery add on with Firefox browser. It will show you all the events attached to a dom element.
https://addons.mozilla.org/en-US/firefox/addon/firequery/
The built-in Chrome 12 debugger will show you any Event Listeners for any object in the DOM. It can be quite useful, especially to find your way around a larger project. It shows you what event and where the code is.
What is the straight JavaScript syntax to replace the jQuery's keydown event?
Lint is complaining so much that it's hard to read my Firebug console.
Since I'm developing a proof-of-concept for me only, I'm not worried about any cross browser problems - it only has to work in Firefox at the moment.
That's because charCode is indeed meaningless in the keydown event. Change the keydown event to a keypress event if you need to know the charCode.
According to DOM level2 Events:
The DOM Level 2 Event specification
does not provide a key event module.
An event module designed for use with
keyboard input devices will be
included in a later version of the DOM
specification.
So there is no standard concerning the key events. Currently all the browsers do as they see fit. If you are using a JS framework it should give a consistent value in all browsers (that would be the main point of the framework after all).
First, the others explained quite well the roots of your problem.
But for the record, answering your original question, what you need is addEventListener. This is a non-obtrusive, nice and modern way to attach events in Javascript. Works in every modern browser (so not under IE9, for those IEs you need attachEvent).
So for example, using addEventListener, you assign events like:
var elem = document.getElementById("fos");
elem.addEventListener("keydown", whateverFunction, false);
You can also use the simple way (elem.onkeydown=whateverFunction;), but I discourage you to do it. With addEventListener, you can assign several handlers to the same event, and you cannot accidentally overwrite another event you or a library/3rd party script assigned.
Change
$(document).keydown(function(myEvent) {
to
document.onkeydown=function(myEvent){
we're currently developing an application that makes extensive use of popup windows(*) and have run into an issue on IE (this has been reported before but I couldn't find any solution).
The problem is this: our main window M opens a popup window P and keeps a reference to it. P then registers an event handler on an object in M. When the event fires, IE8 bombs out with the following error message:
JScript object expected
ext-all-debug.js (Line 1735, Char 17)
Code: 0
which is the fire-function in EXTUTIL.Event.prototype. The code works fine in Firefox, Opera and Chrome.
I've provided a minimal example that produces this behaviour.
Any help is appreciated.
(*) Yes, there's a good reason for that. And no, Ext.Window is not an option.
Well, at least I got the tumbleweed badge. :-)
As it turns out, you can not use ExtJS to fire events across browser windows in IE. Condor from the ExtJS Community Support Team said:
Ext is NOT safe to be used across windows. Each window should have it's own Ext instance and communication between the two windows should only be done using primitive datatypes (String, Number, Boolean, Date).
This means that you can't register an event handler in a different window, because that would mean passing objects to the other window.
As it turns out, this is not entirely accurate (at least in IE7 and above). You can reference objects across browser windows. What you can't do is use the Ext event system.
The workaround I used is, instead of registering event handlers in P, to have M call methods in P that then fire the events "locally". It is, of course, not quite es elegant or flexible, but it does work nicely in all browsers. Besides, I think it is good practice to keep cross-window-communication simple and well defined. If you use event handlers you have to carefully keep track of what happens where, for instance you need to make sure you unregister all event handlers before the window is closed.
Is there a way to debug or trace every JavaScript event in Internet Explorer 7?
I have a bug that prevents scrolling after text-selecting, and I have no idea which event or action creates the bug. I really want to see which events are being triggered when I move the mouse for example.
It's too much work to rewire the source and I kind of hoped there was something like a sniffer which shows me all the events that are triggered.
Loop through all elements on the page which have an onXYZ function defined and then add the trace to them:
var allElements = document.all; // Is this right? Anyway, you get the idea.
for (var i in allElements) {
if (typeof allElements[i].onblur == "function") {
var oldFunc = allElements[i].onblur;
allElements[i].onblur = function() {
alert("onblur called");
oldFunc();
};
}
}
You might want to try Visual Studio 2008 and its feature to debug JavaScript code.
If the problem is not specific to Internet Explorer 7 but also occurs in Firefox, then another good way to debug JavaScript code is Firefox and the Firebug add-on which has a JavaScript debugger. Then you can also put console.log statements in the JavaScript code which you can then see the output of in the Console Window in Firebug, instead of using alerts which sometimes mess up the event chain.
#[nickf] - I'm pretty sure document.all is an Internet Explorer specific extension.
You need to attach an event handler, there's no way to just 'watch' the events. A framework like jQuery of the Microsoft Ajax library will easily give you methods to add the event handlers. jQuery is nice because of its selector framework.
Then I use Firebug (Firefox extension) and put in a breakpoint. I find Firebug is a lot easier to set up and tear down than Visual Studio 2008.
Borkdude said:
You might want to try Visual Studio 2008 and its feature to debug JavaScript code.
I've been hacking around event handling multiple times, and in my opinion, although classical stepping debuggers are useful to track long code runs, they're not good in tracking events. Imagine listening to mouse move events and breaking into another application on each event... So in this case, I'd strongly advise logging.
If the problem is not specific to Internet Explorer 7 but also occurs in Firefox, then another good way to debug JavaScript code is Firefox and the Firebug add-on which has a JavaScript debugger.
And there's also Firebug Lite for Internet Explorer. I didn't have a chance to use it, but it exists. :-) The downside of it is that it doesn't a fully-fledged debugger, but it has a window.console object, which is exactly what you need.
It's basic, but you could stick alerts or document.write calls in when you trigger something.
The obvious way would be to set up some alerts for various events something like:
element.onclick = function () { alert('Click event'); }
Otherwise you have a less intrusive option of inserting your alerts into the dom somewhere.
But, seriously consider using a library like jQuery to implement your functionality. Lots of the cross-browser issues are solved problems and you don't need to solve them again. I am not sure exactly of the functionality you are trying to achieve but there are most probably plenty of scrolling and selecting plugins for jQuery you could use.
I am not sure on the exact code (it has been a while since I wrote complex JavaScript code), but you could enumerate through all of the controls on the form and attach an event that outputs something when the event is triggered.
You could even use anonymous functions to wrap the necessary information for identifying which event was triggering.
One thing I like to do is create a bind function in JavaScript (like what you can find in the Prototype library) specifically for events, so that it passes the "event" object along to the bound function. Now, if you were to do this, you could simply throw in a trace call that will be invoked for every handler that uses it. And then remove it when it's not needed. One place. Easy.
However, regardless of how you get the trace statement to be called, you still want to see it. The best strategy is to have a separate pane or window handing the trace calls. Dojo Toolkit has a built-in console that runs in Internet Explorer, and there are other similar things out there. The classic way of doing it is to create a new window and document.write to it.
I recommend attaching a date-time to each trace. Helped me considerably in the past.
Debugging and alerts usually won't help you, because it interrupts the normal event flow.
Matt Berseth has something that may be the kind of thing you're looking for in Debugging ASP.NET AJAX Applications with the Trace Console AjaxControlToolkit Control.
It's based on the Yahoo YUI logger, YUI 2: Logger.
My suggestion is, use FireFox together with FireBug and use the built-in Debug/Trace objects. They are a charm.