16 Nov 2011, 07:07

event.layerX and event.layerY are broken and deprecated in WebKit.

If you’ve been testing any web development against Chrome developer builds, you’ve quite possibly seen this warning show up in your console:

event.layerX and event.layerY are broken and deprecated in WebKit.They will be removed from the engine in the near future.

I found a handy little Javascript that will alleviate this problem (though I can’t seem to find the source of it now; if you do, please let me know). It looks like this:

// Prevent "event.layerX and event.layerY are broken and deprecated in WebKit. They will be removed from the engine in the near future."
// in latest Chrome builds.
(function () {
    // remove layerX and layerY
    var all = $.event.props,
        len = all.length,
        res = [];
    while (len--) {
        var el = all[len];
        if (el != 'layerX' && el != 'layerY') res.push(el);
    }
    $.event.props = res;
} ());

This self executing function goes through jQuery’s $.event properties and removes the references to event.layerX and event.layerY so that jQuery won’t try to copy them to new objects in the future.

The root of the problem is that whenever jQuery binds events, it copies those properties. If you execute this function before you do any event binding with jQuery, those properties don’t exist to be copied. Bye bye warnings!

Updates:

This address the problem for jQuery >= 1.7: > jQuery Ticket #10531: Consider removing layerX and layerY from $.event.props

The source of the snippet appears to be http://jsperf.com/removing-event-props/2 via http://stackoverflow.com/questions/7825448/webkit-issues-with-event-layerx-and-event-layery.

03 Nov 2011, 14:40

Browser specific Javascript loading with jquery.loadScriptForBrowser.js

It’s not very often that I write Javascript that needs to be downloaded and run by only one browser, but when I have to, I want it to be easy. I don’t want to waste a bunch of time doing user agent parsing and checking, I want to just write what I need for that specific browser, and go on my way.

A quick look through the Googles didn’t really yield anything that I could use, so I threw together a jQuery plugin; jquery.loadScriptForBrowser.js. The browser detection functionality & logic is from the excellent jQuery Browser Plugin (which I’ve used many, many times before to allow me to target CSS to specific browsers without having to resort to difficult to read, maintain, and understand hacks). Just as the code from the jQuery Browser Plugin, this plugin is MIT licensed.

Sample usage for this plugin:

<script type="text/javascript" src="./js/jquery.loadScriptForBrowser.min.js"></script>
<script type="text/javascript">
    $.loadScriptForBrowser({
        'chrome': [
            './js/chrome.specific.js'
        ],
        'msie': [
            function(){console.log('Browser: MSIE')}
        ]
    });
</script>

Not much to it. You can check it out at http://git.sdb.cc/projects/jquery-loadscriptforbrowser-js, or just go ahead and clone the repository: git clone git://git.sdb.cc/jquery-loadscriptforbrowser-js.

25 Oct 2011, 14:54

Jasmine, Chrome, and Access-Control-Allow-Origin

I recently updated a project I’ve been working on from jQuery 1.4 to jQuery 1.6.4 and ran the suite of Javascript unit tests (written in Jasmine) associated with it. It took me quite a while and lots of digging and debugging before I even noticed that Chrome’s console had logged a few errors. One of which was:

Origin null is not allowed by Access-Control-Allow-Origin when trying to call loadFixtures();

Well of course this would be responsible for all of my jQuery selectors coming back empty for elements that I knew existed; Jasmine couldn’t load the fixture so there weren’t any elements to actually select.

As it turns out, this issue is isolated Chrome’s behavior and how it deals with accessing local files. You’ll see similar behavior when trying to fire off AJAX requests in some situations. You can work around this problem for local debugging by calling Chrome as chrome.exe --allow-file-access-from-files which will disable that access control. After launching Chrome with that parameter, running the test suite passed (as it should) and all was happy!

13 Apr 2011, 01:05

HTML5 websockets

AKA: The Death Of Polling

Imagine for a moment if you will, a scenario where you have a page on a website that you’d like to update on a regular basis with new content as it becomes available. How would you go about implementing that? Until just recently, you didn’t have a lot of options. You could spin up some Javascript that would do a little setTimeout() magic with some ajax voodoo to call a webservice to get some new data if it’s there. That’s pretty standard, and at least you’re not refreshing the entire page (think meta refresh), right? But, you’re making a lot of consistent, unnecessary calls that may or may not ultimately provide anything valuable. That’s a lot of extra server and network overhead for nothing.

There’s got to be a better way! Enter HTML5!

Part of the HTML5 spec has support for a new technology called websockets.  Just what are websockets?  A websocket is basically a TCP connection for the web, enabling the browser to hold open a connection to a server, and to send and receive messages through that pipe.  What does that mean for us though?

Instead of our setTimeout()/Ajax/webservice cycle, we can simply open a websocket, and wait for our data to show up for us.

Pretending that you’ve installed the Websockets prototype from Microsoft’s HTML5 Labs http://html5labs.interoperabilitybridges.com/prototypes/available-for-download/websockets/html5protos_Download, we can do something like this for a simple echo server:

namespace WebsocketSample {
    using System.ServiceModel;

    public class EchoSvc : WebSocketsService {
        public override void OnMessage(string message) {
            this.SendMessage(message);
        }
    }
}

Pretty trivial there.  Now, how can we use it?

Sprinkle a little markup about, like this:

<input id="input" type="text" /><input id="send" type="button" value="Send" />
<input id="output" type="text" />

And a little Javascript/jQuery action, like so:

var connection = new Websockets("ws://uri/to/EchoSvc");

connection.onopen = function () {
    $('#send').click(function() {
        connection.send($('#input').val());
    });
};

// Log messages from the server
connection.onmessage = function (e) {
    $('#output').val(e.data);
};

And now you have a persistent TCP connection directly from your browser to the server, skipping all of the overhead of the constant polling loop, and multiple server requests.  Muy bueno!

12 Apr 2011, 05:05

HTML5 data-* Attributes

The project that I’m currently working on had a requirement from the User Experience folks to have a button’s text change the first time it was clicked, and then on the second click, the intended action would be performed.  One of the UI design guys on my team suggested adding some new classes that would serve as markers for the text that would be needed.  Something like this:

<input class="switchTo-Buy_Now" type="button">

Technically, yes, that would work.  And then you could bind some jQuery to the click event, parse out the last bit of the class, do some voodoo, and make it go.  But, it’s ugly. 

There’s got to be a better way! Enter HTML 5!

The HTML 5 spec contains support for data-* attributes.  That is, any attribute on any element that starts with data-* is valid HTML 5 syntax, and is used to store data that doesn’t affect the layout, rendering, or function of the elements that it’s attached to.  Finally we can hold any arbitrary data on any element and still have valid syntax!

Further, there’s support for this in jQuery core (as well as vanilla Javascript, but who really cares about that anymore anyway?).

So, we used to have some markup similar to this (which didn’t validate):

<input type="button" class="switchTo-Buy_Now" text="Buy Now!" />

And some jQuery a little something like this:

$("[class$=Buy_Now]").bind('click', function() {
    var class = $(this).attr('class');
    var switchTextId = class.substr(class.lastIndexOf('-')+1, class.length - class.lastIndexOf('-'));
    var switchText = "";
    if (switchTextId == "Buy_Now") {
        switchText = "$4.99";
    }
    // Repeat that a lot.  Or pull it off of some other
    // non-standard attribute.
});

And NOW we have something like this (which is valid to boot!):

<input type="button" class="switchTo" data-switch-text="$4.99" text="Buy Now!" />

and a little jQuery action like this:

$('.buyTo')bind('click', function() {
    var switchText = $(this).data('switch-text');
});

Pretty boss.