Entries tagged ‘javascript’
Firefox 3, or, technically, Gecko 1.9, comes with support for full page zoom. It works by scaling CSS pixels when the page is rendered – from the perspective of JavaScript or CSS there is no difference between a page zoomed to 200%, 50% or 100%.
I’ve found two ways of detecting the zoom level. One way to detect zoom level changes relies on the fact that percentage values are not zoomed. A percentage value is relative to the viewport width, and thus unaffected by page zoom. If you insert two elements, one with a position in percentages, and one with the same position in pixels, they’ll move apart when the page is zoomed. Find the ratio between the positions of both elements and you’ve got the zoom level. See test case.
The problem with this solution is that it does not detect the zoom level when the page is first loaded.
Another solution I found relies on Flash. Not so much a problem for sIFR, for which I started this little investigation, but not the best solution either. Flash can be configured not to scale with its container page by setting Stage.scaleMode = "noscale";. The Stage.height value gives the height of the Flash movie as its actually rendered by the browser. In other words, this value is not affected by page zoom. The height assigned to the Flash movie <object>, as it exists in the DOM, however, is affected by the zoom level. Simply dividing Stage.height by <object>.height gives the zoom level, even on page load. See test case.
Of course, these two methods are hacks. It would be great if the browser can be queried for the zoom level.
Addendum: I just tested both approaches in Opera and IE 7. The percentages trick works in Opera, but not in IE. IE’s page zoom is quite a hack anyway, so that’s to be expected. The Flash solution works in all browsers, and is far more precise than the percentages approach. Definitely the way forward I’d say!
The discussion on document load detection is more than two years old. The accepted solution for IE looks pretty much like this:
document.write('<scr'+'ipt defer src="//:" '
+ 'onreadystatechange="if(this.readyState==\'complete\'){dojo._loadInit();}">'
+ '</scr'+'ipt>'
(As you can see I took this from Dojo)
Unfortunately this solution is broken. It relies on the defer attribute, which causes the script to change its readyState to complete after the document has finished loading. defer, however, doesn’t always work correctly. If the innerHTML of a descendant of the body element is changed by an inline script, the script may not be deferred properly. This bug cannot always be reproduced – I’ve seen it occur only a few times while others report it happening on every second page load. However, I did find a way to force its appearance. The bug can be triggered by alert()ing right after changing the innerHTML. See also a test case.
So, without the defer trick, what else can we use to detect DOM load in IE? Diego Perini found a pretty cool solution. If you call document.documentElement.doScroll('left'); before the document has loaded, an exception is thrown. Call it every couple of milliseconds until there’s no exception, and you know the document is ready. Diego has also done a superb job of testing his solution, ensuring that it works as expected.
With IE covered, let’s have a look at document load in other browsers. Mozilla 0.9.4 introduced a DOMContentLoaded event for the document object. Opera 9 also supports this event. Since about two months WebKit supports it as well, but only in the nightly builds. Konqueror is in the same situation, and will support it starting with version 4.0. For WebKit and Konqueror, which do not yet support the DOMContentLoaded event, you can poll the readyState of the document, as explained by Dean Edwards.
We can say that document load is covered (again). However, it isn’t sufficient if your script relies on the CSS being applied. Opera, WebKit and Konqueror load CSS and JavaScript in parallel (all CSS is loaded before being applied, however). This means that the document may have finished loading, and your JavaScript may have executed, before the CSS is fully loaded and applied. sIFR relies on CSS, which means that document load may be too early. Preferably there’d be a CSSApplied event, but in lieu of that, we can detect CSS application ourselves.
The trick is to insert an empty element into the body, which has a style property set in the external style sheet. If you insert this element on document load, and poll every couple of milliseconds until the style property can be retrieved using the computed style, you know that the external style sheet has been applied.
I’ve implemented the hacks discussed in this post in sIFR r339. See also hacks.pageLoad under sifr.js:
function checkStyle() {
dummy = dom.create("div");
dummy.className = CSS_DUMMY;
dom.getBody().appendChild(dummy);
pollStyle();
};
function pollStyle() {
if(dom.getComputedStyle(dummy, 'marginLeft') == '42px') afterStyle();
else setTimeout(pollStyle, 10);
};
function afterStyle() {
if(dummy && dummy.parentNode) dummy.parentNode.removeChild(dummy);
dummy = null;
fire(null, true);
};
And the CSS:
.sIFR-dummy {
width: 0px;
height: 0px;
margin-left: 42px;
z-index: 0;
}
Over at the Xopus blog, I’m discussing what I spent my summer on: a DHTML caret! Go read it and see the demo!
I had to write a depth-first tree iterator recently – at Xopus of course – and I wondered about the call stack size. Here is the test, and the results:
- Safari 2.04: 100
- Firefox 2.0.0.6: 1001
- Internet Explorer 7: 1789
- Opera 9.22: 3340
Safari surprises me, it’s just 10% of Firefox! Opera stands out quite clearly as well.
At Xopus we develop a pretty big (~50k lines) JavaScript application to edit XML documents through a WYSIWYG interface. With such a large application there’s a large risk of memory leaks. Indeed, this is what we’ve been experiencing in Internet Explorer 6. We’ve also seen a decrease in performance as memory usage increased. These leaks, however, do not occur in Internet Explorer 7. And, as of just 10 days ago, they no longer occur in IE6 on Windows XP.
On June 12th, Microsoft released security update MS07-033. Included in this update is the following:
General distribution release (GDR) fixes
A memory leak occurs in Internet Explorer 6 when you view a Web page that uses JScript scripting on a Windows XP-based computer (KB929874)
And indeed, IE 6 on Windows XP no longer leaks memory, nor performance. This is great news for all JavaScript hackers, there’s no need to worry about memory leaks anymore!
The one cave-at is that this fix is only available for Windows XP. For Xopus this means we’ll still have to fix the leaks, since some of our clients are still running Windows 2000. Users who haven’t installed the latest security updates will also experience memory leaks in IE 6. In the end though, Microsoft fixed the memory leak issues in Internet Explorer, and I’m thankful for that.
From time to time I’ll be posting about what’s going on in the sIFR nightlies. Today is such a time, with a lot of interesting changes! I won’t go into too much detail as it’s all documented on the wiki, so here’s the list:
- Support for pixel fonts through the
pixelFontargument. See JavaScript Methods: replace. - A way to stop the page jumps by specifying the
ratiosargument. (More about ratios). See JavaScript Methods: replace. - Support for fixed font sizes and sizes relative to the main size, see
font-sizein Styling. - Simplification in the API, you can now pre-fetch by passing the movies to
activate()instead ofprefetch(). See the How to use. - Improved pre-fetch code for Internet Explorer.
- Laid groundwork to communicate with the Flash movies. Test it!.
Ain’t that cool? You can find r209 under the nightlies.
A Word About That Pre-Fetching Improvement
There were a few reports about sIFR overwriting the class name on the body element in Internet Explorer, but only on the first load. This has been fixed in this revision, and here’s the background for the bug:
It only happened on initial load because the issue was caused by the pre-fetch code, which only runs once per browser session. Pre-fetching was done by document.write()ing an embed element to the document. As it turns out this forced Internet Explorer to create a body element. (It behaves the same for any other element which should be in the body).
Results of this are breaking the *:first-child+html IE 7 CSS hack and overwriting class names on the body. After sIFR sets the class name IE won’t use the class names from the real body element anymore.
The solution is to write a script tag, which does not have the effect of IE creating the body element. Other software, such as Mint suffers from the same problem. I’ve already reported this to Shaun Inman, but in case you keep seeing the problem even with this revision make sure the Mint JavaScript is loaded after sIFR has been activated.
Over the past few weeks I’ve been exchanging e-mails with Bobby van der Sluis, discussing sIFR and UFO. Among the things discussed was DOMContentReady, or more specifically my implementation for Internet Explorer, which was based on the Dojo implementation. Dojo uses the following code:
if(dojo.render.html.ie && dojo.render.os.win){
document.attachEvent("onreadystatechange", function(e){
if(document.readyState == "complete"){
dj_load_init();
}
});
}
Whereas the “official” code is as follows:
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
init(); // call the onload handler
}
};
/*@end @*/
The difference may seem minor (readyState on a script instead of the document), but Dean Edwards mentioned in a comment on his site that document.readyState wouldn’t work properly. So, time for some test cases! First of all, domcontentloaded.html logs the following:
- Safari: changes to
document.readyState - Mozilla/Opera: firing of the
DOMContentLoadedevent - Internet Explorer: both techniques covered above
- All browsers: the loading of an image and
window.onload
Additionally, an external CSS file is loaded which gives the document a red background color. When the DOMContentLoaded event (or browser specific equivalent) fires, some CSS is written to the page which changes the background color to green. More on this later. The CSS file waits 5 seconds before returning data to the browser, the image waits 10 seconds.
It turns out that in Internet Explorer document.readyState fires after the loading of the image, and right before window.onload. In effect, it’s useless. The “official,” script.readyState variant does fire before the image loads, and is indeed the correct version. In the other browsers the official techniques work properly as well, and the background color of the page is green.
Safari & Style at the Opera
Now, what are we using that background color for? For sIFR it is incredibly important that all CSS has been loaded and applied before kicking into gear. It relies completely on the specified styles for the to-be-replaced elements, without it just won’t function properly. As said before, the first test case showed no surprises with the background color: it appears as if the stylesheets are applied in the correct order. In Safari and Opera, however, this turns out to be false. Enter readstyle-domcontentloaded.html. This test case is virtually the same as the one used before, however on the DOMContentLoaded event it logs the computed background color.
In Internet Explorer and Mozilla it reads out a red background color, in Safari however it reads rgba(0, 0, 0, 0) or transparent. There is also a Flash Of Unstyled Content. In Opera 9 the background color also reads as transparent, but without a FOUC. Webkit.org has an article by Dave Hyatt explaining the issue (as well as the FOUC):
(WebKit) will continue parsing a page even after a stylesheet directive has been encountered so that stylesheet and script loads can be parallelized (compared to waiting for the stylesheet to load – Mark Wubben). That way everything can be ready for display much earlier. (…) when a script attempts to access a property that involves having accurate layout/style information(, shipping Safari’s) will go ahead and lay out what it’s got even though it doesn’t have the stylesheet yet. It will also display it. This means you see FOUC whenever a script tries to access properties like scrollHeight or offsetWidth before the stylesheet has loaded. (…) we will (…) give back information that the page might consider to be incorrect, since the stylesheet that supplies the up-to-date information hasn’t loaded yet.
The article also discusses ways of solving this issue in WebKit itself. The suggested method is stalling the JavaScript execution when it tries to access a style dependent property. Unfortunately as of nightly r17760 this has not yet been implemented. This behaviour also highlights a need for something like a FinishedRendering event that would fire when the stylesheets referred to in the HTML have loaded and been applied. Right now the DOMContentLoaded movement relies quite heavily on this specific browser behaviour, if things change in Mozilla or Internet Explorer without implementing either a FinishedRendering event or stalling JavaScript execution — for backwards compatibility probably the better solution — many modern sites and applications will break.
In the mean time, no more DOMContentLoaded in sIFR for Safari and Opera.
I was looking at a bug report for sIFR today. It discussed how sIFR 3 crashed Firefox 1.0.0 on Windows. After the better part of the evening, here’s what I found: if you create a non-anonymous method, declare a variable inside it and set a property on the function object with the same name as the variable (and whatever value, I used null), Firefox 1.0.0 will crash after about ten seconds after loading the page. If it doesn’t, close the window and it should crash right away. It seems to be an issue in the JavaScript parser.
Here’s the code, adjusted for readability, but you bet this fits in one line!
(function nonAnonymousMethod() {
var aProperty;
}).aProperty = null;
In the case of sIFR, the parseSelector code contained a similar construct. Fixed now in r130.
Full testing details: Firefox 1.0.0 and Firefox 1.0.1 on Windows XP SP2 with the latest updates as of Sept 8, 2006. Firefox 1.0.0 crashes, Firefox 1.0.1 doesn’t. I therefore assume the problem will not occur in any versions later than 1.0.0. Download old Firefox versions.
JavaScript runs in a single thread, which is why a lot of things, including XHR, work with callbacks. But sometimes, sometimes you need to escape the thread [1] and run you code in a new one. One example is event based code, where your stuff should not run while the event is still being propagated. The easiest way to accomplish this is by using setTimeout():
setTimeout(myCode, 0);
Since JavaScript is single-threaded, and the timeout 0 milliseconds, the timer will fire when there is no JavaScript being executed. In theory it’s still possible for other threads to be started, blocking the timer, but this shouldn’t lead to any practical problems.
Happy coding!
[1]: For sake of argument. Technically it’s all the same thread, and execution would depend on queues and callstacks, but I find it easier to think of this as in different threads.
Here’s something that came up at Jot last week. Which event will be fired continuously, if you hold down a key: onkeydown or onkeypress?
The answer is that it depends on both platform and browser. In general, Windows-based browsers fire only onkeydown, except for Firefox/Win which also fires onkeypress. On the Mac and on Linux, only onkeypress is fired, and onkeydown is not fired on the Firefox browser for these platforms. Something to keep in mind when you bind the “iterate over items while holding arrow up or down key” behaviour to your application. See the testcase.
Yesterday I was hunting down an Internet Explorer memory leak at the office. I started with disabling all events which might leak, and then began to check them one by one. With a stroke of luck the first event I checked caused the biggest leak, which was several megabytes on each page load. The event wasn’t to blame, though.
In fact the real bug was something much harder to grasp than the closure-induced leak. And, since I couldn’t find it described elsewhere, I’ve decided to coin it the Externally Declared Global Variable Leak. It has been confirmed in IE6 and IE7.
Here’s the problem in a nutshell:
- When you create circular references between
windowobjects - And declare global variables (
someWindow.globalVariable) onwindowobject A, fromwindowobject B (or vice versa) - These variables will leak
- Even if they are not referenced
There are a number of possible solutions:
- Prevent or clear the circular references
- Declare the global variables inside the
windowobject - Use
eval()to declare the variables from another window - Remove the variables
I’ve created three testcases, one leaking, another one leaking, and a non leaking one. For fun I’ve added a ~ 20 MB object to the tests, so the leaking will be rather obvious.
As you can see in the tests the leak occurs if the global variable is declared in the main window. Declaring the circular reference variable – which is global as well – in the iframe window has no effect. This leads me to believe the JScript engine thinks the leaking variables are still referenced, because they were declared by another window object.
So, yet another thing to look out for when developing for IE. Happy leak hunting!
Christian Heilmann of the DOM Scripting Task Force published a long article called From DHTML to DOM Scripting today. In it, he claims that DHTML is awful and outdated and generally very bad, and that DOM Scripting is the second coming of Zarquon.
Okay, that was slightly exaggerated. Yet this line of thinking annoys me. DHTML is, like HTML before it, painted in a bad light, whereas XHTML and DOM Scripting are purportedly the best (and therefore only) way ahead. When you look more closely at the practices so easily associated with XHTML and DOM Scripting you see a different picture. Quoting from the weblog post:
DOM scripting assets:
- Progressive Enhancement – check if things are available, then apply those dependent on them
- Ease of maintenance – keep the maintenance as easy as possible via dynamic CSS classes and properties at the beginning of the script
- Separation of Presentation and Behaviour – add dynamic classes instead of changing the style collection
- Separation of Structure and Behaviour – use dynamic event handlers and generated elements instead of onclick and NOSCRIPT
- Using modern event handling – more than one onload please
- Avoiding clashes with other scripts – avoid global variables and encapsulate functions as methods in an object
That sounds quite reasonable. In fact, I’d say these are all very good programming practices, regardless of being used in “DHTML” or “DOM Scripting” scripts. The problem is that DHTML, and all of it, is being blamed for blatantly ignoring these practices. I consider myself to be a DHTML programmer – heck, I learned most of my stuff at the now dead DHTMLCentral – and yet I grew up to these practices. While I am aware of the type of DHTML hinted at by the DOM Scripters, virtually all of the provided scripts on DHTMLCentral fit the description, it’s not the DHTML I, and many others, know and write.
Seeing DHTML portrayed as evil pains me. It does not deserve to be used as a straw-man for good practices. I believe good practices should stand on their own merit, and the ones the DOM Scripting Task Force attempts to spread are perfectly capable of doing that.
Sometimes QuickTime may take over handling Flash content. As QuickTime is only compatible with Flash 5, this can pose major problems. Here’s some code which detects if QuickTime is handling Flash:
var qtFlash = false; // Is QuickTime rendering Flash?
var flashPlugin = navigator.plugins['Shockwave Flash'];
for(var i = 0; i < navigator.mimeTypes.length; i++) {
var mime = navigator.mimeTypes[i];
if(mime.type == 'application/x-shockwave-flash'
&& mime.enabledPlugin != flashPlugin) {
qtFlash = true;
break;
}
}
[Update April 28, 2006] If there are multiple Flash versions installed this test won’t work. Instead try this:
var qtFlash = false; // Is QuickTime rendering Flash?
var flashVersion = 7; // Stub for real detection code
for(var i = 0; i < navigator.mimeTypes.length; i++) {
var mime = navigator.mimeTypes[i];
if(mime.type == 'application/x-shockwave-flash'
&& !new RegExp('.*Shockwave\\sFlash\\s' + flashVersion
+ '.*').exec(mime.enabledPlugin.description)) {
qtFlash = true;
break;
}
}
If you want to test this see these Mozilla guidelines and apply them in reverse order.
This workaround doesn’t work in IE, though, which leaves me wondering how to detect QuickTime for that browser. Here’s the Flash detection code for IE in sIFR:
if(this.ieWin) {
try {
this.flashVersion = parseFloat(
new ActiveXObject('ShockwaveFlash.ShockwaveFlash.7')
.GetVariable('$version').match(/([\d,?]+)/)[1].replace(/,/g, '.')
);
} catch(e) {}
}
I haven’t been able to get IE to use QuickTime, so the question is: will IE be able to create a Shockwave Flash object if QuickTime is handling Flash? If not, problem solved. If so, any ideas on detecting QuickTime?
The most powerful thing about the JavaScript programming language are it’s scoping rules. In programming languages, scope is what makes the world go round. It defines the context in which the code executes. The context contains objects which are available to the code. To draw a real-world analogy: Say you’re in your living room, and you want to watch some television. You can, because the television is in your living room. But what if you’re in the kitchen?
Scopes can be chained to each other. This means that if some portion of the code is not available in the current scope, you’ll be able to find it somewhere else. If you’re in the kitchen, and it is chained to the living room via a door (as in my place), you can simply walk to the living room to watch television.
In JavaScript there is a variable scope chain. All objects are stored inside variables (and in JavaScript everything is an object). New scopes can only be created when you define a new function. The newly created scope will be chained to the scope it was created in. And for good measure there is a global scope, available right from the start. In most JavaScript implementations (read: browsers), this is the window object.
As I said, in JavaScript everything is an object. You could view the scope as an object as well: the variables you use are simply properties on this object. Normally you can’t access this scope object, it is implied by the language and everything is handled by the interpreter. There is, however, one exception to this rule. The window object acts as a public scope object. Let’s have a look:
var foo = 'bar';
window.baz = 'thud';
alert(window.foo); // alerts 'bar'
alert(baz); // alerts 'thud'
As you can see the foo variable is accessible by window.foo, just as the window.baz property is accessible by baz.
So how do we find the variables on the scope chain? First the JavaScript interpreter checks if the variable has been declared in the current scope (or: if the property exists on the hidden scope object). If not, it’ll check the chained scope. This process continues until the variable has been found, or until the window object has been reached and the variable hasn’t been declared even on that object. In this latter case an exception will be thrown.
This process makes it possible to use the same variable name in different scopes, effectively masking the other variables. There is one caveat in JavaScript though: unless you declare the variable with the var keyword it will be created in global scope.
By now it’s time for some examples:
var foo = 'bar'; // variable declared in global scope
function a() { // creates a new scope, chained to the global scope
alert(foo);
}
a(); // alerts 'bar'
function b() { // creates a new scope, chained to the global scope
foo = 'the quick brown fox'; // in which scope does the `foo` variable exist?
}
alert(foo); // alerts 'bar'
b();
alert(foo); // alerts 'the quick brown fox'
function c() {
var foo = 'thud';
alert(foo);
}
alert(foo); // alerts 'the quick brown fox'
c(); // alerts 'thud'
alert(foo); // still alerts 'the quick brown fox'
Of course we can chain more than two scopes together:
function d() { // what scope is this function chained to?
var foo = 'thud';
function e() { // creates a new scope, chained to the scope of `d()`
alert(foo);
}
e();
}
d(); // alerts 'thud'
Function e() has access to the scope of function d(). This is called a closure. As I said this is one of the most powerful things of JavaScript. This lets you do some really cool things. Ever wanted to create private methods in JavaScript? Now you can!
function A() {
function hidden() {
alert("I'm a private method!");
}
this.visible() {
alert("I'm a public method. I can also invoke `hidden()`.");
hidden();
}
}
var a = new A;
a.visible();
Up to you to figure out why this works.
This also lets us create Singleton objects:
var b = new function() {
this.hello = function() {
alert('Hello world!');
}
}
b.hello();
Or functions which have private methods in their scope:
var c = (function() {
function hidden() {
alert("I'm a private method!");
}
return function() {
alert("I'm a public method. I can also invoke `hidden()`.");
hidden();
}
})();
c();
This latter technique is referred to as Block Scope.
One thing to watch out for with these techniques are memory leaks. You can find more info about those by reading my Event Cache article. In any case, let that not be a discouragement! Closures are cool. Use them.
When optimizing, you have to make sure it actually helps. In this case, not really. You’re lucky to see a one millisecond difference on a thousand function calls (in Firefox 1.5 on Mac, at least).
Update (a few minutes after the fact): I realized that Deans function checks for the existence of a property on a node. This lookup could cost more time, so I updated the test case to make sure the if/else clause looked up two properties on the document node. Differences now are 10 – 20 ms (still not very much as we are talking about a thousand invocations).
Update (December 13th, 11 pm): Updated test with Sjoerds suggestions. More interesting results in the comments.
One of the few things I like about Java is how methods are identified not by their identifier (language collision here, it’d seem) but by their signature. In code:
public static void foo (String bar) {
// do things
}
public static void foo (String[] bar) {
// do things
}
These foo() methods are different in that they accept different types of parameters. In dynamic languages this is not possible, but of course you aren’t limited to one type of parameter.
And yet, I was wondering if there was an elegant way to implement someting comparable in JavaScript. Let’s take the following code, and try to make it more elegant:
function say (value) {
value = value || "";
if (typeof (value) != "string") {
if (value.constructor == Array)
value = value.join("\n");
else {
var result = "";
for(var prop in value)
result += prop + ": " + value[prop] + "\n";
return result;
}
}
alert(value);
}
Hmm, some conditions and specific code in their bodies. It’d almost look like a switch statement, but in JavaScript you can only compare values, not use your own conditions. However, Ruby has a switch mechanism which lets you evaluate conditions:
case
when 1 + 1 == 2
puts "1 + 1 is indeed 2"
when 1 * 1 == 1
puts "1 * 1 is indeed 1"
else
puts "Somebody must have disproved mathematics"
end
Quite elegant. Let’s consider this example:
function say (value) {
value = value || "";
alert (Function.$case (
typeof value == "string", // when
value, // expression
value.constructor == Array, // when
function () { // expression
return value.join("\n");
},
function () { // else
var result = "";
for(var prop in value)
result += prop + ": " + value[prop] + "\n";
return result;
}
));
}
The even attributes (counting from 0) are the conditions. The odd attributes are the expressions, and the last even attribute is the “or else” expression.
I’d say this is (in theory) more elegant, but it looks confusing and requires more code — sounds a bit like Java, actually. And this is what Function.$case() looks like:
Function.$case = function () {
var condition;
for (var i = 0, expr = null; i < arguments.length; i+=2, expr = null) {
condition = arguments[i];
if (i == arguments.length - 1)
expr = condition;
else if (condition === true)
expr = arguments[i + 1];
else if (typeof (condition) == "function" && condition () === true)
expr = arguments[i + 1];
if (typeof (expr) == "function")
return expr ();
else if (expr != null) // To obviate the need for superfluous functions, you can also use a value instead of a function
return expr;
}
}
Peter-Paul Koch recently launched the adddEvent() recoding contest. Of course, I couldn’t say no to such a challenge, so here’s my article explaining my entry. You might want to write the short terminology overview I wrote a while back before diving into this article.
First off, let’s look at the requirements for the event code:
- must work in all modern major browsers: Mozilla, Opera, Safari and Internet Explorer.
- must follow DOM standards (which also means adding the same listener only once)
- must not leak memory
- must respect the
thiskeyword (scoping must work correctly)
Then there are some niceties we might want:
- allowing you to set the scope
- providing a way to modify the event object
With that in mind, I started writing. After three iterations of simplifying, I came to the current solution. Let’s look through it piece by piece.
Oh blimey, that looks like code!
var __DomEvents__ = new function()
I’m creating the necessary functions inside __DomEvents__. I’m using the underscores because the actual addEvent() and removeEvent() functions are exported into the window object and I want a nice little namespace of my own. Also note the new function() part: the methods for the script are defined in an anonymous class, which is immediately instantiated. JavaScript’s solution for Singletons.
var registry = {};
function registryKey(id, type, fn)
{
return id + "#" + type + "#" + fn;
}
function isInRegistry(key)
{
return registry[key] != null;
}
This is the code which keeps track of all event listeners. registry is a hash table in which the listeners are stored. registryKey() takes care of creating a unique key to store the listener with. It does this by combining the ID of the event target, the event type, and the string representation of the listener. Finally isInRegistry() is a utility method we can use to see if a key has already been registered.
function invoke(key, evt)
{
if(!isInRegistry(key))
return null;
_evt = __DomEvents__.alterEventObject(evt);
// If the alteration method returned an object, use that as the event
// object.
if(typeof _evt == "object")
evt = _evt;
var handler = registry[key];
var scope = handler.scope;
// Evade Function#apply()
scope.__DomEvents_listener__ = handler.listener;
scope.__DomEvents_listener__(evt);
scope.__DomEvents_listener__ = null;
}
invoke() will make sure the listener is invoked in the right scope. First — of course — it makes sure the listener is still in the registry. It then calls alterEventObject(), which allows us to modify the event object before it’s sent to the listeners. And at last it’ll invoke the listener!
The next part is a bit tricky. We first load the handler, a small object stored in the registry which contains a reference to the listener and the scope. Then it sets a property, __DomEvents_listener__ (now if that isn’t unique, what else is???), which references the listener. This means that when the listener is invoked via the property its scope will be scope. That’s exactly what we want so we invoke the listener via the property and then set the property back to null. We ain’t leaving no traces, are we now?
var targetIdCount = 0;
function targetId(target)
{
if(target == document)
return "__DomEvents_ID_document";
if(target == window)
return "__DomEvents_ID_window";
var id = target.getAttribute("id") || target.uniqueID;
if(id == null){
id = "__DomEvents_ID_" + targetIdCount++;
target.setAttribute("id", id);
}
return id;
}
Remember how registryKey() uses the ID of the event target? We need a way to find this ID. For the document and window objects, we’ll use a static ID, for HTML elements we’ll try to derive the ID from the element. Our first attempt is the id attribute. If it doesn’t exist we check for uniqueID. The latter is a property in Internet Explorer which contains a unique id (you didn’t expect that, did you?) which you can use to reference the element (through document.getElementById()). If we still don’t have an ID, we’ll have to set it ourselves. IDs generated by this code are prefixed with __DomEvents_ID_. targetIdCount is used to make sure we assign unique IDs — with each assignment the count is updated. And finally we return the ID.
window.addEvent = function(target, type, listener, scope)
{
var key = registryKey(targetId(target), type, listener);
scope = scope || target;
// Check if the listener hasn't been registered already.
if(isInRegistry(key))
return false;
// Hey, it's a new listener!
handler = {
listener: listener,
scope: scope,
invoker: function(evt)
{
invoke(key, evt);
}
}
registry[key] = handler;
if(target.addEventListener){
target.addEventListener(type, handler.invoker, false);
} else if(target.attachEvent){
target.attachEvent("on" + type, handler.invoker);
} else {
return false;
}
// Reset variables:
target = listener = scope = null;
return true;
}
Yes! That’s the code you’ve been waiting for, right? Let’s go through this step by step. First we create the key for this listener. We also check if it’s already been registered. Since isInRegistry() takes a key as parameter, listeners are distinguished by their function, not the scope. Talking about which, the line scope = scope || target; means that the scope will be scope, unless it hasn’t been specified, in which case it’ll be target (and the this keyword refers to the event target the listener was added to, great!).
You can also see how the handler object is created. The invoker property holds the method which will be added as the DOM event listener — it’s just a wrapper for the listener you specify. The handler object is added to the registry and the invoker method is added as the event listener.
There are some key things in this code with regards to memory leaks. By storing the listener and scope in an object separate from the event target,
we can prevent circular references between the target and the listener and the target. And even though the invoker method is a closure, by setting the values of target, listener and scope to null we make sure IE won’t be taking a leak.
By now we are almost finished with the code. We only have to look at a way to remove the listeners:
window.removeEvent = function(target, type, listener, scope)
{
var key = registryKey(targetId(target), type, listener);
if(!isInRegistry(key))
return false;
var invoker = registry[key].invoker;
registry[key] = null;
if(target.removeEventListener){
target.removeEventListener(type, invoker, false);
} else if(target.detachEvent) {
target.detachEvent("on" + type, invoker);
} else {
return false;
}
return true;
}
Actually I think you are perfectly capable of understanding this method. Onwards to the final cleaning up:
this.alterEventObject = function(){};
The alterEventObject() method is a dummy method for invoke(). Note how it’s set as __DomEvents__.alterEventObject().
Documentation for the public methods
addEvent()
Adds the listener.
Parameters:
target: the element to which the listener will be added.
documentandwindoware supported as well.string >> type: the type of the event, without the “on” prefix.
function >> listener: the listener you want to add.
object >> scope: the scope this listener should be invoked in. Default:
el.Returns:
boolean: whether the listener has successfully been added or not.
removeEvent()
Removes the listener.
Parameters:
target: the element to which the listener will be added.
documentandwindoware supported as well.string >> type: the type of the event, without the “on” prefix.
function >> listener: the listener you want to remove.
[object >> scope]: the scope this listener should be invoked in. Default:
el.Returns:
boolean: whether the listener has successfully been removed or not.
alterEventObject()
A function which can alter the event object. Override this to use your own.
Parameters:
evt: Event object to alter.
Returns:
[object]: the modified event object. You can also modify
evtdirectly.
And… that’s it!
Wow, I just explained the entire code! You can see the required example page and also the source (littered with custom-style documentation, that’ll have to be extracted in the near future). Like most of my other work the code is licensed under the CC-GNU LGPL.
Also I’d like to thank Michaël van Ouwerkerk for testing the script on Windows, and Lief van der Baan for checking the article for spelling and grammar mistakes. Thanks guys!
I hope you enjoyed the article. If you have any questions, you are welcome to contact me.
Dear DSTF,
I applaud your effort to bring JavaScript into a better light, and teach people how to write scripts following best practices. However, I am worried that your focus on unobtrusiveness and best practices will result in less attention for code quality.
A recent example of this is your post about Image Previews. While the script you link to is certainly unobtrusive, I don’t think it’s a good example of code quality, or for that matter, DOM scripting.
I won’t complain about the coding style of the JavaScript, that’s entirely personal. (Although some more whitespace can’t hurt.) No, one of the problems is that the script, written by one of your members, even, does not use DOM events. For a script linked to from your weblog I find that disturbing. Another, and perhaps worse, issue is that the script leaks memory.
Things like memory leakage can be hard to grasp, but it’s fundamental that DOM scripters understand these problems and work around them. Promoting a script which does not use DOM events is giving the wrong example. By all means, link to a great unobtrusive script, but in that same post also point out what could be improved. Please check the code quality of the scripts you link to: people will try to learn from the code and it’s important they learn it correctly.
If all goes well, you’ll be a huge influence to many new developers. Let’s get the max out of that influence.
Kind regards,
- Mark Wubben
P.S. I realized during writing this letter that the script in question was written by and about by Christian Heilmann, one of your members. Please understand that this post is not meant as an attack on Christian, but as an expression of my worries. Again, I applaud you for your efforts.
Finally, here’s a short follow-up to the original Event Cache article. Let’s start with the best news: the script is now known to work in Internet Explorer, Safari and Mozilla.
Implementing
Something which had to be read through the lines in the original article was how to actually implement the script. Therefore, a little tutorial.
First we take Scott Andrew LePera’s addEvent code. The addEvent function [1] is as follows:
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
return false;
}
}
This doesn’t take care of IE/Mac and other legacy browsers, so you might want to use this method by Simon Willison to get around that.
Anyway, onwards with adding the event to the cache! Here’s the modified version of Scott Andrew’s code which does exactly that:
function addEvent(obj, evType, fn, useCapture){
var result;
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
result = true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
result = r;
} else {
return false;
}
EventCache.add(obj, evType, fn, useCapture);
return result;
}
We also need to register the onunload handler so we can flush the cache:
addEvent(window, "unload", EventCache.flush);
And that’s it!
Sam Schillace pointed out that the code above was wrong… the method would return before Event Cache kicked in. Big Oops! Thanks for pointing that out, Sam!
(Edited June 3, 2005).
Event Cache, but without the cache
Ramon Leon pointed out to me the other day that it’d be easier to add an unload event which removes the event handler for each event, instead of caching the event and setting an unload event to flush the cache.
Well, yeah, that approach sounds good to me. It doesn’t mean, however, that you’re no longer using a cache: the unload event still contains references to the characteristics of the original event, you just can’t access those references. It’s a minor difference though, I’d say choose which method suits your needs best.
Footnotes
[1]: The original code has an alert to warn you that the event wasn’t set. I figured it’d be more useful if the function would simply return false, so it wouldn’t scare off visitors
Two things:
- Hardcore DHTML hackers hate it
- Everybody else loves it
- Some people confuse it with soccer (Thanks, Anne!)
Why? Because we hardcore DHTML hackers have been doing this stuff for years, but it never caught on. Combine that with a lot of hype, and you get negative reactions to the term. Until Google put the principle to good use in Gmail. That is, the hardcore DHTML hackers it hired finally got to design a system which used it.
The attention which has been given to Ajax in the past months has largely affected… designers. UI designers, such as Duntan Orchard and Derek Powazek. But also in the back end: Ajax got included in RubyOnRails a month after the original Adaptive Parth article. These are people who haven’t been hanging around in the DHTML communities of yore [1].
The question is, why? I don’t really know [2], but I have the feeling it’s because the DHTML hackers never got to design the systems, and as such couldn’t show their knowledge and ideas. XMLHttpRequest has been here since IE 5.0, after all.
Footnotes
[1]: Bold claim, I know.
[2]: Hey, I was eleven back in 1998!
Mark, I’ve got a challenge for you! Try to make some JavaScript that emulates the behavior of the :target psuedo-class in IE.
No, I’m not trying to be rude, this would honestly be something very cool, and to be honest (still), my JavaScript skills are not that good.
That’s the challenge I recieved this morning from The Wolf (not The Real Wolf though). Well, I thought it was doable, so I accepted:
That should be possible… challenge accepted!
And indeed, after about 30 minutes of hacking it’s done: Emulate the CSS :target Pseudo-Class in IE. The demo only works in Internet Explorer, you can view source there to see the code.
I hope you can use it!
Oh, one more thing:
Great to hear it! If you can do it, everyone owes you a beer or something…
![]()
You all owe me one!
When I wrote my short tutorial on how to use the DOM for :hover I tried to point out something else. It was between the lines, and the post was written in a hurry, so I suppose it didn’t caught much attention.
Basically what the JavaScript did was look for events so it could set a different class on the elements. Effectively, mouseover set the state of the element to “hover”, while mouseout set it to “none”. In other words: I wrote code to manage the state of the element, and the style of the element in that specific state is controlled via it’s class.
Thus, a.hover becomes the equivalent of a:hover.
This turns out to be key in understanding why CSS doesn’t define behaviour. The pseudo-classes are a special kind of classes, which aren’t set by some JavaScript code, but by hidden, low-level code in the browser. The browser manages state, detects you have placed the mouse pointer over the element, and styles the element following the rules in the applied pseudo-class [1].
Unfortunately Internet Explorer doesn’t support this behaviour for elements other than a. We need to write high level JavaScript code to manage the state. And since we can’t use :hover to style these elements, we need to use our own class.
This doesn’t mean, however, that CSS is behavioural. Nor does it mean that we should shy away from using :hover, because there are browsers out there which aren’t capable of managing the state of elements internally [2].
Footnotes
[1]: Of course this not only applies to :hover, but also to :active, :link, :visited and :focus.
[2]: Or, more likely, aren’t capable of exposing this state.
Via Jeffry Zeldman’s alter ego Apartness’ blog come the following practices from Tanya Rabourn regarding web standards (emphasize mine):
In order to anticipate future browser compatibility we require conformance to the following W3C standards:
HTML
Validate to either the W3C’s XHTML 1.0 transitional or strict doctype http://www.w3.org/TR/xhtml1/
CSS
Validate to the W3C’s CSS 2.1 or 1.0 http://www.w3.org/TR/CSS21/ http://www.w3.org/TR/CSS1
Javascript
Javascript will never use browser detect but instead object detection to test for browser support of properties, arrays and methods
I think we all know that things aren’t black and white, just how it is in this case. Object detection surely is a good idea: if you want to fetch an element which has a certain ID, you need document.getElementById, so you might as well want to make sure that method is supported before you run your script. Unfortunately browsers have other bugs than “simply” not supporting DOM methods.
Take Safari, for instance. It won’t repaint the document if you append a new node to it. To work around this you need to use a hack which adds an empty string to the innerHTML of the node you just appended to. Quite obviously you don’t want to use this hack in other browsers: you need to use browser detection to determine if the hack is necessary. And to add to the confusion: this bug has been solved in Safari 1.3, so you might as well want to make sure not to use this hack in that browser.
By the way, did I mention innerHTML is not supposed to work in XHTML documents? You need to find a way to detect that as well…
To conclude: it’s a good idea to use object detection, but sometimes it just won’t cut it. And you don’t want to leave out awesome scripts because it uses browser detection, do you?
Yup, Jeremy Keith is completely right when he says that :hover is behavioural. That’s why I’m going to explain here how you should do :hover via the DOM. That’s right… I’m going to tell you!
Okay, so first we grab all the links on the page. We’ll do this on onload. I’m actually going to cheat a bit with the events, but I hope you’ll forgive me:
window.onload = function(){
var links = document.getElementsByTagName("a");
for(var i = 0; i < links.length; i++){
links[i].onmouseover = function(){
this.className += "hover"; // sorry, no support for multiple classNames here
};
links[i].onmouseout = function(){
this.className = this.className.replace(/\bhover\b/, "");
};
};
links = null; // look how I evaded memory leaks here!
};
And the CSS:
a.hover {
text-decoration: none;
font-weight: bold;
}
Ahhh.. that’s so much better. Now we have seperated style and behaviour completely. Time for some well deserved rest now.
You didn’t think I was serious about this, did you?
This is an introductory tutorial to the sIFR Explained series, covering basic JavaScript (and programming) concepts — some knowledge of JavaScript, like knowing how to define functions, is required though. It’ll be updated from time to time when more background information is necessary. Here we go.
Anonymous Functions
An anonymous function is a function without a name. This is an anonymous function [1]:
function(msg){ alert(msg); }("hello world");
What is happening here is that the function is defined: function(msg){ alert(msg); } and executed immediately: ("hello world").
This isn’t an anonymous function:
function foo(msg){ alert(msg); };
foo("hello world");
Nor is this:
var foo = function(msg){ alert(msg); };
foo("hello world");
In general anonymous functions are used to execute code which only needs to be executed once. This is the way it is used in sIFR. A side effect which occurs in the sIFR code is the creation of closures.
Scope, the scope chain and closures
But before we get into closures, something about scope. Every JavaScript expression is surrounded in a scope. The scope contains what is available to the expression. When you define a new function, the body of this function exists in a new scope. For example:
function foo(){
var msg = "hello world";
alert(msg);
};
foo();
Here alert(msg); works, because msg is defined in the same scope as in which alert is called.
Deep down in the JavaScript interpreter the scope is represented as a call object. This object contains all the variables which have been defined in the scope that the call object represents. When a new scope is created, it’s call object is linked to the call object of the scope it was created in. This creates a scope chain.
This phenomenon is best explained through an example. In JavaScript the window object is the global scope. This is the highest scope in the scope chain. If we create a new function in the global scope the scope of this function will be chained to the window object:
var msg = "hello world";
function foo(){
alert(msg);
};
foo();
Now, if you call foo, it’ll alert hello world
! But how does it know the value of msg, which wasn’t defined in the function body foo? It turns out that if the JavaScript interpreter can’t find a variable in it’s current scope, it’ll go up the scope chain and searches the parent scope until it finds the variable. In our case it finds msg in global scope.
You can also create a scope chain by nesting functions:
function foo(){
var msg = "hello world";
function bar(){
alert(msg);
};
bar();
};
foo();
Now, if you call foo, it’ll define bar and execute it immediately afterwards. And as expected it’ll alert hello world
.
When a nested function has access to the scope of it’s parent function, it is called a closure. sIFR relies quite heavily on closures.
At ths point you might want to read Variable scoping gotchas from Scott Andrew for more information about defining variables in JavaScript.
Footnotes
[1]: I’m not really sure why you’d want to write an anonymous function to alert `”hello world”`, but it’s just an example!
This is a series about how the JavaScript code in sIFR works. What tricks were used, what are the powerful concepts, and what are the browser hacks. It’s an interesting read, in which you’ll dive into some complicated JavaScript code.
Before we get started though, you might want to read the terminology tutorial which will give you insight in the wonders of closures, scopes and all that fancy stuff.
Enjoy!
Event Cache is a small script which can store the events you have set on a page and remove them on unload. This way it can prevent memory leakage. Please read DHTML leaks like a sieve by Joel Webber for more information. Also, here’s a quote Jim Ley, who explains:
The Internet Explorer web browser [...] has a fault in its garbage collection system that prevents it from garbage collecting ECMAScript and some host objects if those host objects form part of a “circular” reference. The host objects in question are any DOM Nodes (including the document object and its descendants) and ActiveX objects. If a circular reference is formed including one or more of them, then none of the objects involved will be freed until the browser is closed down, and the memory that they consume will be unavailable to the system until that happens.
So, how can we solve this? If we make sure no references are left when the page unloads, there won’t be a problem. In the comments of Joel Webber’s article Dylan Schiemann mentioned that Alex Russell of NetWindows had written a solution for this problem. So I dived into the NetWindows code to look for it.
It turns out that what the NetWindows code does is caching all events set for the affected browsers and detaching the events on unload. Based on this principle I wrote EventCache.
Please also read the follow-up article.
Usage
The idea is that you hook EventCache into your normal event code. You simply add the information you need to set the event to the EventCache using the add method.
EventCache has the following properties and methods:
listEvents-
An
arraywhose items are arrays which contain the information in the following order:node,sEventName,fHandler,bCapture. Seeaddfor more information. add(node, sEventName, fHandler, bCapture)-
Add new information to
listEvents.node- A reference to the node on which the event has been set.
sEventName-
The name of the event.
Please note: this name must not be prefixed with
on
for any browser but Internet Explorer. The actual event you use must be prefixed withon
. For example, if your event isonclick,sEventNamemust beclick. If you use a custom event you can’t usefoo, but you have to useonfoo. Of coursesEventNamemust befoo. fHandler- A reference to the
functionwhich handles the event. bCapture- A
booleanwhich determines whether the event is triggered in capture mode or not. Does not apply to Internet Explorer.
flush()- Remove all cached events.
Please note: You have to make sure that EventCache.flush is fired on unload!
Examples
I’ve made two testcases. One with memory leaking, and one which uses Event Cache. You can also try the Event Cache testcase with feedback
As you can see these examples don’t use browser detection to see if cleaning the references is really necessary. That’s something for your own implementation.
Other Methods
There are some other ways to solve this problem. One would be to never keep references at all, but closures are too handy to do this. Another solution is to iterate over all elements in a document and remove specific events. This is the solution that Aaron Boodman proposed.
The downside with this method though is that it only works for events which use the so-called DOM 0 event model: element.onclick = function(){};. If you use element.attachEvent() or element.addEventListener() you need to remember the specific values you used to set the event, which means you have to cache it.
Considerations
The cache keeps references to the element on which you’ve set an event and the event handler. This means that it consumes memory itself. It also takes time to remove the events on unload.
Download and Licensing
EventCache is released under the CC-GNU LGPL. You can download version 1.0.
And Finally
If you have any questions about this article or the code, please contact me.
A Greasemonkey extension which ensures Gmail uses the secure connection.
September 16th: Due to a bug in Deer Park beta 1, the script no longer worked. Aaron Boodman of Youngpup fame fixed it… and I’m pretty excited about that (hey, the guy behind Greasemonkey fixes my one-line script, by adding two lines, great!). Anyway, hit the download link below to catch the latest version.
June 23th: Updated script because Gmail has changed it’s domain.
For sIFR RC3 I wrote a handy little piece of code which allows users to use named arguments in their JavaScript code. For example, if you have a function foo which takes five arguments, and you only need to set the first and the last, this can be quite cumbersome:
function foo(one, two, three, four, five){
// do something
};
// let's call foo() with only the first and last argument
foo("hello", null, null, null, "world");
sIFR takes thirtheen arguments, a lot of which are optional. As you can hopefully understand using named arguments is lots easier.
Interlude – For the True JavaScript Hacker
If you’re really interested in how all this all works, and how you can implement it in your own scripts… please be patient. I still have to write about the inner workings of my named arguments implementation. Sorry!
Syntax & Placement
In order for named arguments to work you need to pass a special construct to the function. The syntax of this construct is like this:
named({
name : value,
name : value
})
named({ is the beginning of the construct. name : value, is the syntax you need for each argument. name is the name of the argument and value is of course the value. You end the construct with }).
Due to a bug in Internet Explorer and Opera you have to be careful not to end the last argument with a comma. There will be a JavaScript error and the code will break.
By convention you pass this construct to the function as the last argument.
Example
Let’s look at the function foo from earlier in this article. Using named arguments the function call will look like this:
foo(named({one : "hello", five : "world"}));
Much easier, eh?
Here’s an example where we pass some other arguments to the function before the construct:
foo("the", "ocean", named({three : "breathes", five : "salty"}));
Here we passed on the arguments one, two, three and five to the function.
Applying it to sIFR
sIFR takes the following arguments (in this order): sSelector, sFlashSrc, sColor, sLinkColor, sHoverColor, sBgColor, nPaddingTop, nPaddingRight, nPaddingBottom, nPaddingLeft, sFlashVars, sCase, sWmode
You can find out what these arguments do in the readme.txt in the download. The names of the arguments above are the same as those which you use in the named arguments construct. For example:
sIFR.replaceElement("h1", "./vandenkeere.swf", named({sColor : "#000", sCase : "upper"}));
Here we passed on the arguments sSelector, sFlashSrc, sColor and sCase to the sIFR.replaceElement function.
Usage Ideas
There are more ways named arguments can simplify your (sIFR) life. You could also store the construct in a variable and use it as a template:
if(typeof sIFR == "function"){
var template = named({sFlashSrc : "./vandenkeere.swf", sColor : "#000", sCase : "upper"});
sIFR.replaceElement("h1", template);
sIFR.replaceElement("h2", template);
};
No doubt more things are possible, but I’m leaving that to your imagination.
Download and Licensing
Just as sIFR the named arguments code is licensed under the CC-GNU LGPL. You can also download the source.
And Finally
If you have any questions about this article or the code, please contact me.
For now, please see the explanation for sIFR users.
Version Update – Konqueror Crazyness
As of today (Jan. 4, 2005) Named Arguments is at version 1.0.1. A bug was discovered where browsers based on an old Apple WebKit / Konqueror version (WebKit v85) would throw a JavaScript error:
Anonymous function hack: eating identifier named_Arguments
Anonymous function hack: eating identifier named_extract
This was caused by naming an anonymous function:
named.Arguments = function named_Arguments(oArgs){
Removing the name and the script worked again:
named.Arguments = function(oArgs){
I searched for the error message in Google and found what looks like the source code for the Konqueror JavaScript engine… and I quote:
00524 // Lookup for keyword failed, means this is an identifier
00525 // Apply anonymous-function hack below (eat the identifier)
00526 if (eatNextIdentifier) {
00527 eatNextIdentifier = false;
00528 #ifdef KJS_VERBOSE
00529 UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii());
00530 #endif
Also note that I had to apply a workaround earlier because the Konqueror JavaScript engine doesn’t deal very well with constructors for classes:
named.Arguments.prototype.constructor = named.Arguments;
Things like this make we want to throw the computer out of the window – luckily Mike found the bug, so I had no reason to throw my computer out of the window
