Serializing Objects in Javascript

It's worth noting that this post is rather old at this point. I don't use the function listed in this post anymore and haven't for a rather long time. If you are using it and it's working for you, great! But as Ron in the comments sections points out, there are a few issues with regards to strings and special characters. I recommend following the link he posts if your needs merit a very robust version of JSON serialization. I'm leaving this post up though, as I think it's helpful for folks who want to understand the general concept of recursion and serialization.

Recently, in a personal project I'm working on, I came across a need to be able to represent any Javascript object as a string. This isn't a problem since just about every object in Javascript can be represented with JSON (Javascript Object Notation). Every modern browser can parse JSON for you easily enough through eval(..), and Gecko-based browsers even have the ability to reverse the process ("uneval" if you will) and give you back a string representation of an object through a call to .toSource().

If you need this ability in any other browser though, you're gonna have to write it yourself. I needed this ability, so I wrote it (and posted it here for your enjoyment!)

Continue reading Serializing Objects in Javascript

.split(..) broken in IE

I discovered last weekend, something about IE which I had previously never known (probably because I use Firefox/Firebug to write and test most of my Javascript). It turns out that the implementation of .split(..) is broken in IE (for more complex cases). If you stick with the simpler cases when using this function, then you probably won't have ever noticed this. For example, the following works just fine:

var s = 'This-is-a-hyphen-delimited-string';
var split = s.split('-')// returns  ['This', 'is', 'a', 'hyphen', 'delimited', 'string']

The above code will work in just about every browser under the sun, including IE, but of course, it's the simplest case scenario for the .split(..) function. Many programmers will probably be aware that you're not limited to passing in a string; you can also pass in a regular expression, which IE (mostly) supports, but this is where things can start to fall apart on you (in IE anyway).

Read on to learn more.

Continue reading .split(..) broken in IE

Mouseenter and mouseleave events for Firefox (and other non-IE browsers)

Generally I favor Firefox and other W3C browsers over IE, and I think most people know that about me. Still, I like to think that I'm a fair person, and that means giving credit where credit is due. And sometimes, IE deserves credit where other browsers fall short.

Such is the case with two non-standard (but rather convenient) events that IE exposes: mouseenter and mouseleave.

The mouseenter and mouseleave events are similar to the more familiar mouseover/mouseout events, but with one important difference:

The mouseenter and mouseleave events don't bubble.

Now you might think then, that duplicating this effect is just a matter of stopping event propagation in non-IE browsers, but it's actually more complicated than that.

Read on to learn more.

Continue reading Mouseenter and mouseleave events for Firefox (and other non-IE browsers)

Emulating CSS word-wrap for Mozilla/Firefox

Be sure to check out the follow-up to this post: Word-wrap for Mozilla (take 2). It features a much simplified way of accomplishing the same thing, based on the comments from RichB.

IE has one nice CSS feature that a lot of other browsers lack, which is the ability to use CSS to wrap long words. It's easy to use. Something like this will do the trick:


.wrapme
{
   word-wrap: break-word;
}

Firefox lacks this feature, but it does offer some snazzy features of its own. One in particular is XBL.

In this blog entry, I'm going to demonstrate how to use Mozilla Bindings to (sort of) emulate CSS word-wrap. Since the ability to wrap a long series of unbroken characters is part of the CSS3 specification, I do expect to see this in future versions of Firefox. Until then, this is the best I've got.

An outside-the-box solution

For a long time, I didn't think there was really anything you could do about Firefox's lack of support for word-wrap. I figured the best you could do was set your containing element to hide overflowing data (which might be okay, but most likely not).

Just recently though, a co-worker of mine found a web page that explained how you could insert an invisible unicode character (​) at various points in a string to solve the Firefox word-wrap problem. Since Firefox views this unicode symbol as a valid character upon which to "break" a string (if necessary) it servers as a convenient to way get Firefox to wrap long strings of characters (the symbol remains completely invisible to the end user).

My co-worker first showed me a function he wrote which took a string parameter, inserted this unicode symbol every 5 characters, and then returned the modified string.

This is a good first start, but I wanted something more. I wanted a solution that didn't require me to execute a Javascript function, and I wanted a solution that could handle HTML intersperced throughout the string.

It turns out, that creating a solution that doesn't require executing a Javascript function isn't the hard part at all! In Firefox, this can be accomplished quite easily with XBL.

How does one utilize XBL? Glad you asked!

From the Mozilla Developer page:

Extensible Binding Language is a XML-based markup language to implement reusable components (bindings) that can be bound to elements in other documents. The element with a binding specified, called the bound element, acquires the new behavior specified by the binding. Bindings can be bound to elements using Cascading Style Sheets (CSS) or DOM. One element can be be bound to several bindings at once.

Setting up the binding is pretty easy, so let's tackle that part first:

.wordwrap
{
   -moz-binding: url('./wordwrap.xml#wordwrap');
}

With the CSS in place, "binding" to the DOM element is trivial: simply set the element's class property to "wordwrap".

<p id = "myParagraph" class = "wordwrap">
   SomeParagraphWithAVeryLongStringOfUnbrokenTextThatWillEventuallyWrap.
</p>

With the CSS and HTML taken care of, all that's left to do is write the XBL file. An XBL file is really nothing more than an XML with a specific structure so that Mozilla knows how to process it as a binding. In fact, if you prefer, you can name the file with an .xml extension (like I did), instead of an .xbl extension.

At its most basic, an XBL file takes the following form:

<?xml version = "1.0"?>

<bindings xmlns = "http://www.mozilla.org/xbl" xmlns:html = "http://www.w3.org/1999/xhtml">

<binding id = "wordwrap" applyauthorstyles = "false">

   <implementation>
      <constructor>
         //
            /* ECMAScript code here */
         //
      </constructor>
   </implementation>

</binding>

</bindings>

The binding id attribute:

The root element of the file is <bindings>. Within the root element, you'll have one or more <binding> elements, each with its own unique id. Since an XBL file can have more than one binding definition, the id instructs the browser as to which binding we're interested in. Remember, back when we specified the url for the -moz-binding property, we specified the binding id by appending to it, a "#" symbol followed by the binding id (in this case "wordwrap"). So the full url ended up being: "./wordwrap.xml#wordwrap".

The applyauthorstyles attribute:

The "applyauthorstyles" attribute determines whether or not to allow styles from the document on the bound element (other than the -moz-binding). The default value is false, but you're free to change this if you want (or need) to.

The <implementation> and <constructor>

Every binding has an <implementation> element and, within it, a <constructor> element. This is where most of your ECMAScript code will go (in our case, this is where all of the ECMAScript code will go).

With a very basic explanation of an XBL file's structure out of the way, we can now go ahead and write the implementation of our binding.

It's important to note that all of the ECMAScript you write needs to go inside a CDATA block (this an XML file after all). Other than that though, you don't have too many restrictions. In fact, one nice thing about writing a binding, is that you have a great deal of flexibility. Pretty much all of the ECMAScript you're used to writing is going to work inside the XBL file. And to sweeten the deal even more, you've got some nice extras that aren't available in your normal, day-to-day ECMAScript (we'll look at one of them shortly).

Referencing the bound element:

Perhaps the most important thing you need to know (before you can do anything productive in your binding) is how access the bound element. In other words, how do you access the element to which the class (in our case "wordwrap") was applied? Fortunately, it turns out to be brain-dead easy. You simply using the this keyword; that's it!

Once you have a reference to the bound element, you can do most (if not all) of the things you'd normally do with a DOM element. You could, for instance, wire up logic such that a particular function execute whenever the bound element is moused over, as in:

var elem = this;
elem.addEventListener('mouseover', function(e)
{
   alert('The text of this element will eventually be wrapped!');
}, false);

If you put the preceding code inside the <constructor> element of the binding definition, then any time a user moused over the <p> (#myParagraph), he would see an alert saying "The text of this element will eventually be wrapped!"

Making the text wrap:

At this point, it should be fairly clear what the plan of action is:

  1. Access the bound element's text.
  2. Insert the special unicode symbol between the characters of the string.
  3. Update the bound element's text with the newly modified text.

From the instructions above, I've made it sounds pretty simple. Unfortunately, it's a bit more complicated than I let on. I (conveniently) failed to mention that if the bound element's text contains HTML, we need to take extra care not to insert the special unicode symbol into any of the HTML tags (or else we'll end up disrupting the author's markup).

Actually, the final solution I came up with doesn't take care not to insert the special unicode symbol into HTML tags. Instead, I willingly make a mess out of the markup and then write a bit of logic to clean it up later on, but I'll explain all of that as we get further into the binding's ECMAScript code.

The word wrap code

The code to make this happen isn't long, so rather than try to explain it up front, I'll first show the full code, and then provide an explanation afterwards:


<?xml version = "1.0"?>

<bindings xmlns = "http://www.mozilla.org/xbl" xmlns:html = "http://www.w3.org/1999/xhtml">

<binding id = "wordwrap" applyauthorstyles = "false">

   <implementation>
      <constructor>
         //

         var elem = this;           // maintain a reference to the bound element

         elem.addEventListener('overflow',
         function()
         {
            // matches any "mangled" HTML tag
            var exp = /<&#8203;\/*[&#8203;_\s="'\w]+>/g;

            var txt = elem.innerHTML;     // the bound element's innerHTML
            var chars = txt.split('');
            var newTxt = chars.join('&#8203;');
            newTxt = newTxt.replace(exp, reconstructTag);
            elem.innerHTML = newTxt;
         },false);

         function reconstructTag(_tag)
         {
            return _tag.replace(/&#8203;/g, '');
         }

         //
      </constructor>
   </implementation>

</binding>

</bindings>

Explanation:

The first thing we do is stuff the bound element (this) in a variable, elem. This is of course, totally optional, but it helps me (my brain is small and remembering what this represents eludes me quickly and frequently).

Next, we add an event listener to the bound element that "listens" for the 'overflow' event (whenever text overflows its containing element). You're probably aware the in typical Javascript, there is no such 'overflow' event. This, along with its counterpart, 'underflow' are just two the many "extras" that you get when writing Javascript in XBL.

The remainder of the code will all take place within the context of the anonymous function that executes on 'overflow'.

Next, we create a regular expression that matches any "mangled" HTML tag (more on this in a bit).

The next three steps are all quite straight-forward. We store the bound element's innerHTML in a variable called, txt. We then call .split('') on that text and store it in the variable, chars. Passing an empty string into the .split(..) function will yield an array of characters representing the string that was split. In other words, each character in the string is now an element in the array chars. Finally, we put all of those characters back together by calling chars.join('&#8203'); and stuffing the result in newTxt. This inserts that special unicode symbol between each character in the array as it joins them back together.

The tricky part:

If you were paying attention, then at this point, you'd realize that any HTML that existed inside of the bound element, just got totally mangled with that last .join(..). statement. Think about it: if the bound element's innerHTML were something like this:

This <span>is a</span> paragraph.

Then after executing the .join(..) statement, the variable, newTxt would now be equal to:

&amp;#8203;T&amp;#8203;h&amp;#8203;i&amp;#8203;s&amp;#8203; &amp;#8203;<&amp;#8203;s&amp;#8203;p&amp;#8203;a&amp;#8203;n&amp;#8203;>&amp;#8203;i&amp;#8203;s&amp;#8203; &amp;#8203;a&amp;#8203;<&amp;#8203;/&amp;#8203;s&amp;#8203;p&amp;#8203;a&amp;#8203;n&amp;#8203;>&amp;#8203; &amp;#8203;p&amp;#8203;a&amp;#8203;r&amp;#8203;a&amp;#8203;g&amp;#8203;r&amp;#8203;a&amp;#8203;p&amp;#8203;h&amp;#8203;.&amp;#8203;

Besides perhaps giving you a head-ache, the above HTML snippet should make you realize that the insertion of that special unicode symbol between every character in the string has a really detrimental effect on the <span> tag.

The solution:

The follow-up to this post explains a much easier method that doesn't involve mangling the HTML. It is highly recommended that you check out that approach as well.

It turns out, that "unmangling" the HTML tags isn't too too hard (just takes some fancy regular expression work). The regular expression, exp will match any HTML tag that has had the special unicode symbol inserted into it. We can utilize this regular expression to match all occurrences of "mangled" HTML tags and (with some help from the .replace(..) function) replace them with "unmangled" versions of the tag.

In order to do this though, we need to make of use a callback function when we invoke the .replace(..) function. When you pass a function reference as the second parameter into a .replace(..) call (as in: myString.replace(regex, myFn)) Javascript will automatically pass the matched string into the callback function for you!

This is an extremely powerful concept. We can now take all "mangled" HTML tag matches and send them through the reconstructTag(..) function. The reconstructTag(..) function simply returns a copy of the string sent into it, but with all occurrences of that special unicode symbol stripped out (thus returning our "mangled" HTML tags to proper form).

With all of these concepts working together, we end up with a string that looks perfectly unaltered to the end user, but which wraps nicely when it would otherwise overflow its container.

See for yourself on my demo page: Word Wrap Binding Demo.

And, to see a slightly more complex example, take a look at my implementation of an ellipsis for Mozilla using XBL: Mozilla Ellipsis.

Final thoughts:

Mozilla Bindings offer tremendous power to the developer. You can do virtually anything with them; the sky is the limit really. In this blog post, we just looked at one example: how to make long, unbroken strings wrap when they would otherwise overflow their container. But we also saw how you can take this further (see the ellipsis demo link above).

Important Warning / Disclaimer!

It should be noted that I have absolutely no idea what kind of effect inserting the special unicode symbol (needed to make this technique work) might have on accessibility. It's an important question. Is that character going to be read aloud by screen readers (what in the world would it say)? Will search engines see it and have no idea what your text represents, thereby hurting your search engine ranking? My fear is that the effect of inserting this character into your string might not be good. But of course, without any real testing, I can't say for sure.

My recommendation would be to use this concept with caution and only when absolutely necessary. A little common sense will go along way towards ensuring you're not bloating your page will a lot of "fancy-just-for-the-heck-of-it" code.

So there ya go! Word wrap in Mozilla. Happy Binding!

Wrapping DOM elements for easier cross-browser Javascript

One thing that has always bugged me a little about the cross-browser Javascript functions I write, is that they usually take as their first argument, the DOM element upon which the function is going to act. For example:

addEvent(myElem, evtName, myFn, false);

Here, we're forced to pass the DOM element into the function as the first argument. This works just fine, but it's a little cumbersome and doesn't read nearly as nicely as the standardized .addEventListener(..) or even the proprietary .attachEvent(..).

myElem.addEventListener(evtName, myFn, false);

Notice how in the second case, we're not passing the DOM element into the function. Rather, the function is a public member of the DOM element that we can invoke, and in my opinion, this feels a lot more natural than the first scenario.

As it turns out, mimicking this style of programming in a cross-browser fashion isn't all that hard.

Continue reading Wrapping DOM elements for easier cross-browser Javascript

Retrieving Elements by Class Name

Everyone is already familiar with document.getElementById(..). Sometimes though, you don't want to (or can't) retrieve an element by its id. What would be nice was if there was some way to "query" for all elements of a certain CSS class name and then return them all in an array. Well there is no such function, but there's not reason we can't write one!

Read on to learn more.

Continue reading Retrieving Elements by Class Name

Fixing IE's .attachEvent(..) failures

Welcome to another addition of Beating IE into submission!

It's a well know fact that IE's proprietary .attachEvent(..) function fails with regards to a number of W3C recommendations:

  1. Fails to honor the 'this' keyword when wiring up events to DOM objects.
  2. Fails to enforce just one function wired to a given event for a given object.
  3. Fails to name events appropriately, that is: without prefixing event names with the word 'on'.
  4. Fails to accept a 3rd parameter, useCapture, which would allow for event capture instead of event bubbling.

In this blog entry, I'm going to look at how to solve the first 3 of these issues (the 4th is more complicated is beyond the scope of this entry).

Before continuing, you may want to review one of my previous entries: The .call(..) and the .apply(..) functions. Understanding these functions will be helpful in understading the techniques we're going to use to fix IE's .attachEvent(..) failures.

Read on to learn more.

Continue reading Fixing IE's .attachEvent(..) failures

Converting to Pixels with javascript

A few entries back, I wrote about CSS Computed Style. In that blog entry, I discussed a cross-browser javascript function to retrieve the computed style of a DOM element on the page.

If you need a quick refresher… javascript doesn't allow you to access arbitrary style properties of a DOM element via .style unless you've previously set that property using javascript OR if you've defined the style using an inline style attribute of the DOM element.

This is where CSS Computed Style can really come in handy. By retrieving an element's computed style, you can retrieve style properties just as they were when you defined them in your CSS file (regardless of whether or not you've ever set them in javascript).

But there's a gotcha (isn't there always). If you remember, IE doesn't really support computed style. Instead, IE offers .currentStyle which, while similar, is most definitely NOT the same thing.

Perhaps the most inconvenient shortcoming of .currentStyle is the fact that it fails to normalize all units to pixels, as the W3C recommends.

In this blog entry, I'm going to explain how to write a function that will convert these non-pixel values to pixels for you.

Read on to learn more.

Continue reading Converting to Pixels with javascript