Javascript
Safari Textarea bug
by bhartsock on Jun.01, 2007, under Javascript
Well, I came across another Safari bug dealing with forms today. Unfortunately, I discovered this problem months ago and compeltely forgot it. So I figured I should document the issue so when it arises again, I won’t waste any time searching for the solution.
Basically, like most other issues with forms on IE and Safari, this issue deals with setting values of elements before they are on the document. Before today, I thought that checkboxes and radios in IE were the main problem, but textareas also have issues.
Here is the hack I did to solve the problem:
1 2 3 4 5 6 7 8 9 10 | //While populating the form var form = Element.createHtml('<form><textarea name="some_textarea"/></form>'); form.some_textarea.value = form.some_textarea._value = 'Hello world'; //When appending the form to the document document.body.appendChild(form); //Safari fix form.some_textarea.value = form.some_textarea._value; |
If I am feeling chipper, I may even search through WebKit’s huge list of bugs to see if it needs to be reported. Hope this helps someone out there.
Dynamic form issues in IE and Safari
by bhartsock on Apr.27, 2007, under Javascript
In the world of rich web applications, browser bugs and incompatibilities are the number one killer of productivity, next to YouTube, Facebook, and Myspace. Like most web developers, I have come to realize most of those issues arise from IE and Safari. Today I stumbled upon another interesting problem when trying to implement some dynamic forms.
Take for instance the following code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //Create form elements var form1 = Element.create('form', {name: 'test_form'}); var input1 = Element.create('input', {type: 'text'}); var input2 = Element.create('input', {type: 'text', name: 'input2'}); //Append inputs to form form1.appendChild(input1); form1.appendChild(input2); //Append form to document document.body.appendChild(form1); //Set input1's name input1.name = "input1"; //Check if form picked up on name change alert(form1.input1); alert(form1.input2); |
If you aren’t familiar with Prototype, this may be a bit hard to understand, but here is what is going on. I am creating a form with two inputs. Both inputs’ names are set in Javascript, but one is set before the form is appended to the document body, and the other is set after.
This code works fine in Firefox, but IE and Safari fail to note the name change, and don’t add the element’s property to the form element.
I created a workaround for a different Safari issue a few months ago, but it works well for this issue as well. The only requirement is your application must be using Prototype.
1 2 3 4 5 6 7 8 9 | Form.prepare = function(form){ var elements = Form.getElements(form); for(var i=0, ii=elements.length; i++){ var elm = elements[i]; if(elm.name && !form[elm.name]){ form[elm.name] = elm; } } } |
In the above example, this would be called before we wished to access the form elements, alert(form1.input1).
Prototype and speed
by bhartsock on Apr.12, 2007, under Javascript
Since Mike doesn’t really blog anymore, I figured I would steal his thunder and discuss some of his findings the past week.
For those of you that haven’t used Prototype before, it is a Javascript library which we use fairly heavily at webmail. It has served us well for a while now …..
But version 1.5 is becoming too slow to be used in webmail. Being a very large web application, we don’t always have the luxury of elegant code, especially in javascript. Sometimes, we just have to do what works fastest and looks the ugliest. This past week Mike made some interesting findings, singling out some of the major performance culprits in Prototype.
Enumerable.each()
We have known this function is slow and have tried to avoid using it, but Prototype itself uses it on some very common functions such as:
- Element.addClassName()
- Element.removeClassName()
- Enumerable.* (Basically all of them use each() somewhere)
Mike overrode the first two functions to use a regular loop instead of each() and saw a 200ms login improvement! That is a pretty large improvement, nearly 14% of the total javascript rendering time on login.
Element.update()
For a long time, I thought Element.update() just abstracted element.innerHTML. I was wrong. It calls stripScripts() and evalScripts(). Since we never pass in text containing script tags, we overwrote this function to just use element.innerHTML. Again, another huge performance enhancement.
Unnecessary abstractions
Prototype has added some great functionality to javascript, but sometimes they take it a little too far with their abstractions. Some functions serve very little purpose other than to add an extra function call.
- Element.update() – Since we have taken out the stripScripts()/evalScripts(), there is really no reason to use this function
- Element.setStyle() – As long as you don’t set opacity or float styles, don’t use this function.
- Element.addClassName() – If you know an element doesn’t have the class name already, just call element.className += ‘ foobar’.
A better web framework – Part 1
by bhartsock on Apr.09, 2007, under CSS, Design Patterns, Javascript, PHP, Programming
As I have mentioned before, design patterns are one of my favorite areas of computer science. Well, design patterns have a close association with web frameworks, so web frameworks are definitely another favorite area of mine. They both help speed up the development process by providing a structure for applications. Since Ruby on Rails took off a couple years ago, other web frameworks have sprung up in many other languages. None of these have met my needs at Webmail.us.
The webmail application I work on is very different than many other Web 2.0 applications, which is why most of the existing frameworks don’t work for us.
- There are no page refreshes and therefore:
- Most drawing is done by Javascript
- All data transfered is JSON encoded
- Email, Calendar, Tasks, Contacts, Settings are all combined into 1 application which means:
- Large memory footprint
- Javascript performance very important
- On the fly loading of HTML, Javascript, and CSS is a must
For the past few months, I have been thinking about what I really need in a web framework. Just like Rails, an MVC framework would need to be the base. In Part 1, I will just talk about the MVC foundation for this framework.
Model
An ActiveRecord type object would provide the MySQL data abstraction. I have mentioned that I have been working on my own implementation for a while, so I won’t go into too much detail on this. Basically, for a complicated web application, most existing model abstractions don’t work very well. With complicated JOIN’s, WHERE’s, and subquerys, something different must be used.
View
A templating mechanism must exist to have a complete web framework. Current view abstractions won’t work in webmail. Since webmail never refreshes, going to the server every time we need to populate a template is troublesome. The templating mechanism in the better web framework would allow a template to be used in PHP or in Javascript.
If a template is used in Javascript, once it is downloaded once, it wouldn’t have to be downloaded again. The hard part about a Javascript template is the inability to have loops and the need for slow regular expression parsing.
If a template request in Javascript has to make a server request every time a template needs to be populated, speed becomes an issue. This is fine for large templates, but what about small widget templates? Making a server request for a small element increases 1. latency and 2. server load which in turn increases latency even more.
Controller
Controllers are the backbone of a web framework. I like how Rail works with a controller class where each data request is mapped to a function call. This seems effective to me and needs little modification.
Conclusion
I know what you must be thinking: Your MVC design isn’t that much different than Rails. Well, that’s true, but remember this is part 1. The MVC design is just the foundation of a better web framework. Rails is popular because it is useful, so it is definitely a good starting point for developing a new framework.
Shout out to Mike for his work on Javascript templates.
Breaking instanceof in Javascript
by bhartsock on Mar.08, 2007, under Javascript
That’s right, this afternoon I figured out how to break instanceof in Javascript. Since I don’t use it often, I figured it worked just like it does in PHP. Basically it does, with one major caveat. Mozilla’s javascript reference gives this definition of the instanceof operator:
Use instanceof when you need to confirm the type of an object at runtime. For example, when catching exceptions, you can branch to different exception-handling code depending on the type of exception thrown.
Earlier today, I was trying to pass data from a child window to its parent window. From there, the parent window used JSON to encode the data ….. but it never got encoded. Upon further investigation, I saw that JSON used the instanceof operator to determine if an object was an Array. I created these test pages to confirm my results:
parent.html
1 2 3 4 5 | function foobar(value){ alert(value instanceof Array); alert(value instanceof child_window.Array); } var child_window = window.open('child.html'); |
child.html
1 | window.opener.foobar(new Array(1,2,3)); |
The first alert is false, while the second one is true.
In Javascript, all objects are “owned” at the root level by the window. Since the window is different for child windows, it makes sense that instanceof would break.
For most small applications, this doesn’t matter. But for Webmail, it does. I have a couple ideas for a good workaround, but nothing set in stone yet.