Sunday, July 12, 2009

Best practices?: Modifying HTMLCollections in IE

I just ran into a very weird IE quirk, and I'm wondering what the best practice would be regarding it. (I've only tested in IE7; it might show up in other versions.)

Before I had IE installed, I had to modify a form and then find my elements in it to modify them again, and the elements' names were the most convenient way to accomplish the second part. So of course I went for the form.elements collection, and this works fine in Firefox. But not only is this property actually the form itself in IE, the developers apparently didn't read this part of the spec:
http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-1019015399
Note: Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed.
To demonstrate what this means, I threw together a small test page (post continues below):
<html>
<head>
<title>IE DOM modifications</title>
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
<script type="text/javascript">
window.onload = function(){
var form = document.forms.namedItem('test');
var input = document.createElement('input');
input.name = 'foo';
input.type = 'hidden';
input.value = 'bar';
form.appendChild(input);
console.log(form.childNodes[0]);
// form[input.name] = input;
console.log(form['foo']);
console.log(form.elements.namedItem('foo'));
};
</script>
</head>
<body>
<form name="test">

</form>
</body>
</html>

If form[input.name] = input; (a very ugly hack) is commented, the first call to console.log works but the other two don't. Otherwise, the first two work but the last still doesn't.

So here's my question: Is this the best way to workaround this quirk? The idea of form elements being direct properties of the form isn't in the standard, and the standard namedItem function remains broken. I managed to still use namedItem by default, but I really don't like the hack at all.

Here's how I retrieved my element:form.elements.namedItem(name) || form[name]

Friday, June 5, 2009

Pandora stopped working, Firefox's fault?

Pandora suddenly stopped in the middle of a song today. I was afraid it wouldn't ever work again, which would seem to herald the old problems returning and a new laptop purchase. I refreshed the window, same problem. Then I closed Firefox (had to end it in System Monitor) and Pandora was revived. Yay!

Saturday, May 30, 2009

My Ubuntu Adventure

A long time ago, I encountered the open-source movement as a hobbyist programmer (which I still am, unfortunately) and wanted to try Linux out. I found the Debian site, but the instructions were way over my head so I didn't dare touch it. I'm not sure whether I had my laptop at that time, but I was at least expecting to buy one. Some time later, I met a guy named Nathan and we became fast friends. While he had never used Linux, he knew of Ubuntu and suggested that I request a CD. I did, and what a learning experience it's been!

I was completely ignorant of partitions, and I think I resized the one on which Windows XP Professional was pre-installed. Hey, where'd my data go? Over the next year, I had loads of newbie problems and started experiencing really weird bugs:

  • Certain keys would stop working for no apparent reason;[1]

  • Firefox started giving JavaScript errors about ordinary whitespace;[2]

  • Flash would crash Firefox;[3]

  • sound of different types progressively failed until I had almost none left;[4]

  • I tried to fix Apache by reinstalling and apt-get choked - hard;[5]

  • programs compiled from the same source by gcc became inconsistent;[6]

  • diffs contained corrupted data.[7]

So now, even though I was fighting to keep coding, I had run into crippling problems with JavaScript, PHP, and C. Even fixing really basic bugs in GNOME which didn't require testing, I was encumbered by diff's corruption. So now I was reduced to typing (also encumbered) and playing games until I could reinstall.

After I finally got my /home directory backed up correctly, I used fdisk to repartition because I had been warned of the Live CD's "idiosyncrasies" (although I did have to tweak from the CD because of cylinder boundaries). I installed Jaunty and put the data back where it belonged. That messed GNOME up and broke the sudo command[8], both presumably because the data was generated on Intrepid. So for a while I only ran on the Live CD, which uses RAM as hard drive space; that got old really fast, although Google's storage came in handy.

I tried to install Jaunty on another partition, but the Live CD's second option installed it on a very small one that I had intended for something else. I only found out when the JRE required more space than I had. I had to repartition because the second installation made new sections that I didn't want. After figuring out how to work around memory conversion bugs in the Live CD's partition editor, I finally got a clean install.

I installed Jaunty again to get a programming partition, and again on the partition I intend for Windows so I can debug my /home data. All three use the same /home partition so I can easily transfer data. My backup has a profile folder named "chris" as does my main install, so I had to extract without ruining the clean profile. I managed that by renaming the real one "_chris" and copying the extracted data to the temporary installation's profile. The user ids were (I guess) the same for both users, so ownership was automatically transferred.

The other time that I extracted my data, I only ran into problems after restarting. This time, I tried running Pandora, to lighten up my debugging tedium, and it froze Firefox like the bad old days. So now I know two things about the remaining bugs:

  1. They reside in my profile;

  2. they are not all triggered at startup.

This post is intended for two purposes. I would really like to get some help in the comments, as the gurus on Ubuntu Forums seem tired of my queries. I also hope to help the poor Googler who finds my experience all too familiar, and maybe even get whatever bug(s) are behind it fixed.


  1. http://ubuntuforums.org/showthread.php?t=1012239

  2. http://forums.mozillazine.org/viewtopic.php?f=25&t=940905

  3. I didn't make a thread for this case, although this one is related; the above case was later and (I think) cross-browser.

  4. No thread for this one either, but this is related.

  5. http://ubuntuforums.org/showthread.php?t=1038787

  6. http://cboard.cprogramming.com/c-programming/114634-exiting-gtkplus-allowing-cli-continue.html

  7. http://ubuntuforums.org/showthread.php?t=1126698

Saturday, July 19, 2008

Is JavaScript a type of Java?

Nope, JavaScript and Java are completely different languages. Java is a language officially developed by the Java Community Process, but in practice Sun Microsystems is its author and maintainer (because their version is nearly universal). Java is a completely system-independent ('portable') language with syntax similar to C++, implemented for the main operating systems (Windows, GNU/Linux, Mac, Unix) and maybe some others. It's a multipurpose language like C++ but of a slightly higher level (generally less efficient but safer and easier to understand).

A language originally named Mocha was invented by Netscape for Netscape Navigator; they renamed it to LiveScript until buying (from whom I don't know exactly, but mainly Sun) the right to re-rename it JavaScript. This was during the "browser wars" between Netscape and Microsoft, I think in the mid-90s. Determined to compete, Microsoft made a work-alike language named JScript for Internet Explorer. The European Computer Manufacturers Association later standardized the language, officially named ECMAScript to appease both Netscape and Microsoft. Microsoft ultimately won the browser wars and Netscape's source code, named Mozilla, was released as an open-source project. The current Mozilla Foundation carried it from there and derived its entire set of programs from it, the most notable being Firefox. (ActionScript is Adobe's ECMAScript implementation for Flash.)

ECMAScript is normally known as JavaScript, except where clarity (or politics) is needed, but Microsoft generally uses JScript. Curiously, Opera Software and Apple Computer seem to get away with calling it JavaScript for their browsers Opera and Safari.

Sunday, December 9, 2007

JavaScript Closures

Closures are a fairly advanced JavaScript feature which I have only seen discussed in special articles rather than tutorials. (Before anyone asks, I don't know how they got that name.) While I wish someone would write a tutorial that would introduce beginners to the concept, I don't have the time and might not have the expertise, so this is going to follow that trend.


First, let's have a definition. A closure is the scope of an outer function made accessible to all inner functions. When I look at code which uses closures, it seems like common sense that outer variables would be available from inner functions, but, at the same time, I wouldn't expect the effect sometimes. The effect can manifest similarly to the private declaration of properties in PHP or Java, or the static declaration of PHP as used at the first of a PHP function. Like both of these, a closure allows variables to be accessible only from within a certain context, across repeated calls to a certain set of functions.


JavaScript With(out) Closures
If JavaScript is written strictly without using closures, it can get pretty cluttered. Let's say I want to return Function B from Function A, then call Function B to manipulate variables initialized in Function A. (What a mouthful.)
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                window.varA = 'a variable';
                    function funcB(){
                    alert(varA);
                }
                return funcB;
            }
            window.onload = function (){
                var funcB = funcA();
                alert(varA + '... Uh-oh...');
                    funcB();
            }
        </script>
    </head>
</html>
(The mention of window is unnecessary, but I want to make it obvious that varA is global.) This works, but, as the call to alert in window.onload shows, it also exposes your variables to overwriting (and hacking, but a hacker can always overwrite your functions anyway). This is a more private way to do it (still without closures):
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                var result = {
                    varA: 'a variable';
                funcB: function (){
                    alert(this.varA);
                }
                return result;
            }
            window.onload = function (){
                var objA = funcA();
//                alert(varA + '... Uh-oh...');
                objA.funcB();
            }
        </script>
    </head>
</html>
But that's not exactly what we wanted. Because I was restricting myself from using closures, I had to use some other mechanism to do the same thing. I used a custom object, whose member 'funcB' is the focal point of the script. Here's a script that accomplishes the same thing as the previous two, but privately and without the object:
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                var varA = 'a variable';
                function funcB(){
                    alert(varA);
                }
                return funcB;
            }
            window.onload = function (){
                var funcB = funcA();
//                alert(varA + '... Uh-oh...');
                funcB();
            }
        </script>
    </head>
</html>
Uncommenting the call to alert in window.onload causes an error, because varA is only defined within funcA's scope (= funcB's closure). Closures allow you to set up code boundaries at your convenience.


Final Notes
Pay attention if you declare several inner functions in one outer, particularly in a loop; the closure is a variable scope (as it exists when the inner function in question is executed) rather than a permanent snapshot of that scope from when the function was declared, and so there is one per call to the outer function, not one per inner function per call to the outer function. So this doesn't work as it would if closures were snapshots specific to inner functions:
function loopyLooper(){
    var demos = [];
    for(var i0 = 0; i0 < 10; i0++){
        demos[i0] = function(){
            alert(i0);
        };
    }
    return demos;
}
var demos = loopyLooper();
for(var demo in demos){
    demo();
}
Here's a correct solution to accomplish this in similar steps (but without using the closure):
function looper(){
    var demos = [];
    for(var i0 = 0; i0 < 10; i0++){
        demos[i0] = {
            func: function(){
                alert(this.num);
            },
            num: i0
        };
    }
    return demos;
};
var demos = looper();
for(var demo in demos){
    demo.func();
}

Here's a loop-less function that expects a snapshot instead of the actual scope:
function loopyLoopless(){
    var i = 0;
    function result(){
        alert(i);//should alert 0
    }
    i = 1;
    return result;
}



//user code

loopyLoopless()();//alerts 1 - The JavaScript interpreter must be broken!
And here's a correct version that preserves the user's control over when and in what context the resulting function is executed (while still using a closure):
function loopless(callback){
    var i = 0;
    callback(function(){
            alert(i);//should alert 0
        });
    i = 1;
}
//user code
loopless(function(result){
        result();//alerts 0
    });

As usual, discussion is invited.

Friday, December 7, 2007

JavaScript Format

I'm pretty picky about my code, so I want to detail my pet peeves and preferences. I'll assume that everyone knows what objects, arrays, strings, regular expressions (or "regexes"), numbers, functions, classes, methods, procedures, and properties are.


Operators
I put spaces on each side of my operators (=, +, -, *, /, %, ?, :, &&, ||, ==, !=, ===, !==, <, <=, >, >=, ^, ~, &, |, <<, >>, >>>), except for commas, colons used for assignment/labeling, exclamation points, and increment/decrement signs (++ and --). Commas and assignment/label colons get no spaces before and one space after.


Most JavaScript strings are enclosed in single quotes. This makes it easier to write HTML attributes and user-friendly quotes from JavaScript, and causes problems only if apostrophes get involved (in which case double quotes may be used). Alternatively, either type of quote may be escaped with a single backslash, and this is valid for both types within both types ("so \'this\' is valid").


Each line which would end with a semicolon in most languages will in my JavaScript. This way, code is more likely to be compatible in future versions of JavaScript, readability is enhanced (I believe), and some rare ambiguous situations are clarified for the browser. (I can't think of any of those ambiguous situations offhand, so you'll have to take my word for it and keep your eyes open.)


Curly brackets are always reason to break the line if there's anything in them; round brackets, square brackets, and ternary operators are only when their contents get too long for the screen. All such containers increase the indentation of any contained lines by one.


Iterators
Most people use alphabetical iterator identifiers (i, j, k, etc.) in their for loops. However, I got very frustrated and embarrassed (in my high school Computer Science class) by a simple bug - a spelling error - and now use numeric identifiers (i0, i1, i2, etc.) to make the difference between my first (i or i0) and second (j or i1) visually obvious. I also have a higher range of identifiers that don't cause confusion available; whereas someone else's 19th iterator might be called "zi," mine would simply be "i18."


When needed, my program-initialization procedure will be directly assigned to window.onload:
<html>
   <head>
      <title>Titled Document</title>
      <script type="text/javascript">
         function main(){
            //
         }
      </script>
   </head>
   <body onload="main();">
      
   </body>
</html>



Here's a demonstration of everything mentioned above:
var one = 1;
var two = one * 2;
var three = two + one;
var yup = true;
if(!yup || (three <= two)){
   alert('This can't be happening!');
}
for(var i0 = 0; i0 < 10; i0++){
   //
}
var object = {
   numbers: [ //This array really isn't long enough to break, but
      one,    //I want to show what I mean.
      two,    //(This applies to argument lists, too.)
      three
   ],
   do: function(){
      alert(function dummy(){
            //This is just a dummy.
         });//The round brackets don't break, but the curly ones do.
   }
}
var something = yup ? object : null;
switch(something){
   case object:
      //
      break;
   case null:
      //
      break;
   default:
      //
}
window.onload = function(){
   //Do something.
};

JavaScript Glossary

This post is currently under construction; please post any comments below.


Argument - An independent variable declared in a function's header and defined by the function's caller. An argument (or "arg") is only visible within the declared function's scope. If an argument uses the same identifier as another variable in a scope which contains the function, the argument hides the other variable.
function getArgument(arg){
alert('Your argument is ' + arg + '.');
}
getArgument('weak');// alerts "Your argument is weak."



Boolean - The binary (either true or false) datum type named after George Boole. Boolean values are immutable.


Class - A contrived notion in JavaScript which is nonetheless frequently used for transitioning class-based programmers into the prototype-based language. Classes are simulated in JavaScript via prototypes of constructors.


Constructor - A function called with new. By convention, constructor names should always be in UpperCamelCase. In the body of a constructor, the pseudo-variable this refers to each individual instance of that constructor that will ever exist.
function Foo(){
alert(this.constructor.name);
}
var foo = new Foo();//alerts "Foo"
Foo();//alerts "undefined" because this.constructor (i.e. window.constructor) doesn't exist in this case



Clone - An object which inherits every current property of its constructor's prototype.


Datum Type - One of at least 5 types of values: boolean; function; number; object; and string. The type of the literal undefined value is "undefined" but I don't consider that a real type. A value's type is returned by typeof value. See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:typeof_Operator and http://en.wikipedia.org/wiki/Data_type.


Event - An object which represents a change in the browser's state; is passed as an argument to any event-handler as called by the browser.


Event-handler - A function called by the browser when a specific type of event occurs. Event-handlers can also be explicitly called by a script, but this is very uncommon.
window.onload = function (){
alert('Do something useful!');
};



Function - The datum type which represents sets of instructions to be executed by the browser at the prompting of either scripting or, in the case of event-handlers, the browser itself. Being objects, JavaScript functions are first-class. Functions are mutable.


Global - Owned by window. Global variables are accessible from every scope.


Local - Declared independently and therefore owned by no particular object.


Method - A function which happens to be the property of an object. Methods, like all other properties, should always have lowerCamelCase names (again, by widely accepted convention). In a method, this refers to the object in whose context the method was called.


Number - The signed, floating-point, numeric datum type. Numbers may be specified as either decimal, hexadecimal, or octal values. Numbers are immutable.


Object - The catch-all datum type. If a value is defined but doesn't fit in the boolean, function, number, or string groups (the members of which also being objects), then it's called an object. Object values are mutable.


Procedure - A method of no particular object (or of window). A function which is called as a property of no particular object is a local procedure; a function explicitly assigned to a property of window is a global procedure. Like methods', procedures' names should be in lowerCamelCase.


Prototype - An object whose properties are inherited by one or more clones. At its core, JavaScript is prototype-based.


String - The datum type of character sequences. Any length of non-newline characters delimited by two single- or double-quotes ( ' or " ) is a string. If a newline is interposed between the quotes, an "Unterminated string constant" error is issued. String values are immutable.