Nerdworks logo "The nerd shall inherit the earth."

Nerdworks Blogorama

Nerdspeak

Debugging existing Windows Store apps
Technobabble
5/23/2013 12:59:02 PM  

Did you know that you can debug pretty much any installed store app on your machine?  Let’s say you want to know exactly why is it that the Windows Mail app acts funny sometimes.  Here’s what you’d do:

  1. Go to the modern desktop and type “Debuggable Package Manager” and launch it.

    clip_image001

    This opens up a powershell window.

  2. Run Get-AppxPackage to list the packages installed and use Where-Object to filter for what you’re looking for. Since were interested in the mail app we run this:

    Get-AppxPackage | Where-Object PackageFullName -like "*commu*"
  3. Note the value of the “PackageFullName” property and enable debugging by running this:

    Enable-AppxDebug microsoft.windowscommunicationsapps_17.0.1114.318_x64__8wekyb3d8bbwe
  4. Now launch the app.  Then launch Visual Studio, hit Ctrl+Alt+P and select the instance of WWAHost.exe which looks like the app you’re interested in.

    image

  5. Debug away!

    image

Link Comment
 
Screen scraping with your browser’s JavaScript console
Technobabble
5/5/2013 11:04:43 AM  

I needed to experiment a bit with language packs for IE 10 the other day and that involved downloading and installing all the available language packs. Unfortunately I couldn’t find a single convenient file for download that’d install everything. The language packs were available as separate downloads for each supported language. Like this:

image

This was a problem as I was in no mood to download each file individually and there were 100s of “download” buttons there. I figured I’d see if I can screen scrape the links from the DOM of this page and then write a little script to download all of them in one go. So I fired up an instance of IE and hit F12 to launch the developer tools and used the “Select element by click” button to quickly navigate to the markup associated with a “download” button.

select-element

As you can tell, all the download buttons are basically anchor tags and the href attribute points to the MSU file for that particular language. Also, you’ll note that each such anchor tag has a class called “download” applied on it. So I should be able to fetch all the links by simply iterating through all anchor tags which have the “download” class applied on them. I switched to the “Console” tab in the developer tools window and ran the following script:

document.querySelectorAll("a.download")

And sure enough this produced a list of all the anchor tags I was interested in. I needed the URL however and not the DOM elements themselves. So I ran this next:

Array.prototype.forEach.call(
    document.querySelectorAll("a.download"),
    function (a) {
        console.log(a.href);
    });

This produced a list of links such as this (snipped since there are quite a lot of them):

http://download.microsoft.com/download/D/9/A/.../IE10-Windows6.1-LanguagePack-x64-zh-tw.msu 
http://download.microsoft.com/download/D/9/A/.../IE10-Windows6.1-LanguagePack-x64-zu-za.msu 
http://download.microsoft.com/download/D/9/A/.../IE10-Windows6.1-LanguagePack-x86-af-za.msu 
http://download.microsoft.com/download/D/9/A/.../IE10-Windows6.1-LanguagePack-x86-am-et.msu

If you’re wondering why I had to iterate through each element in the list of nodes returned by querySelectorAll via Array.prototype.forEach.call then that’s because what querySelectorAll returns isn’t a JavaScript array object, i.e., it doesn’t inherit from Array.prototype. It is instead a NodeList object which looks a lot like an array! It has numeric properties starting from 0 to N-1 where N is the number of elements returned and it has a length property as well which is equal to N. It turns out that all the Array methods are perfectly capable of dealing with such “array like” objects just as well as genuine, certified JavaScript arrays. Here’s an example of what I am talking about:

var notArray = {
    0: "This ",
    1: "is ",
    2: "not ",
    3: "really ",
    4: "an ",
    5: "array.",
    length: 6
};

console.log(Array.prototype.reduce.call(
    notArray,
    function (previous, current) {
        return previous + current;
    },
    ""));

This snippet prints the following text to the console:

This is not really an array.

If you take another look at the list of URLs our script printed to the console, you’ll notice from the file names that this list includes both x86 files and x64 files. I wanted only x64 files. So, I next changed the script to this:

Array.prototype.forEach.call(
    document.querySelectorAll("a.download[href*=x64]"),
    function (a) {
        console.log(a.href);
    });

The selector syntax above looks for all anchor tags in the DOM which has a class called “download” applied where the href attribute’s value contains the string “x64”. I had first implemented this via another call to Array.prototype.filter before learning that CSS3 selector syntax already provides for it! Pretty nifty no? That’s pretty much it. I wanted to run a download script for fetching all the files so I slightly modified the script to produce wget calls like so:

Array.prototype.forEach.call(
    document.querySelectorAll("a.download[href*=x64]"),
    function (a) {
        console.log("wget " + a.href);
    });

And plonked the output into a batch file and ran it. Mission accomplished!

Now, it turned out that this particular page in question includes the jQuery library as well as can be seen when you pull up the files list from the “Script” tab in the developer console.

image

I could have done the same thing I did above using a slightly terser syntax using jQuery as well. Here’s how:

$("a.download[href*=x64]").each(function () {
    console.log("wget " + this.href);
});

Not having to resort to the Array.prototype weirdness does make the code a lot cleaner doesn’t it?

Link Comment
 
Building an Instagram clone – Part 2
Technobabble
4/19/2013 9:50:27 AM  

In part 1 we took a look at some of the UI layout implementation details of the InstaFuzz app.  You can get the source code for the app from here if you wish to run it locally.  In this installment we’ll take a look at some of the other bits such as how drag/drop, File API, Canvas and Web Workers are used.

Drag/Drop

One of the things that InstaFuzz supports is the ability to drag and drop image files directly on to the big blackish/blue box. Support for this is enabled by handling the “drop” event on the CANVAS element. When a file is dropped onto an HTML element the browser fires the “drop” event on that element and passes in a dataTransfer object which contains a files property that contains a reference to the list of files that were dropped. Here’s how this is handled in the app (“picture” is the ID of the CANVAS element on the page):

var pic = $("#picture");
pic.bind("drop", function (e) {
    suppressEvent(e);
    var files = e.originalEvent.dataTransfer.files;
    // more code here to open the file
});
pic.bind("dragover", suppressEvent).bind("dragenter", suppressEvent);
function suppressEvent(e) {
    e.stopPropagation();
    e.preventDefault();
}

The files property is a collection of File objects that can then subsequently be used with the File API to access the file contents (covered in the next section). We also handle the dragover and dragenter events and basically prevent those events from propagating to the browser thereby preventing the browser from handling the file drop. IE for instance might unload the current page and attempt to open the file directly otherwise.

File API

Once the file has been dropped, the app attempts to open the image and render it in the canvas. It does this by using the File API. The File API is a W3C specification that allows web apps to programmatically access files from the local file system in a secure fashion. In InstaFuzz we use the FileReader object to read the file contents as a data URL string like so using the readAsDataURL method:

var reader = new FileReader();
reader.onloadend = function (e2) {
    drawImageToCanvas(e2.target.result);
};
reader.readAsDataURL(files[0]);

Here, files is the collection of File objects retrieved from the function handling the “drop” event on the CANVAS element. Since we are interested only in a single file we simply pick the first file from the collection and ignore the rest if there are any. The actual file contents are loaded asynchronously and once the load completes, the onloadend event is fired where we get the file contents as a data URL which we then subsequently draw on to the canvas.

Rendering the filters

Now the core functionality here is of course the application of the filters. In order to be able to apply the filter to the image we need a way to access the individual pixels from the image. And before we can access the pixels we need to have actually rendered the image on to our canvas. So let’s first take a look at the code that renders the image that the user picked on to the canvas element.

Rendering images on to the canvas
The canvas element supports the rendering of Image objects via the drawImage method. To load up the image file in an Image instance, InstaFuzz uses the following utility routine:
App.Namespace.define("InstaFuzz.Utils", {
    loadImage: function (url, complete) {
        var img = new Image();
        img.src = url;
        img.onload = function () {
            complete(img);
        };
    }
});

This allows the app to load up image objects from a URL using code such as the following:

function drawImageToCanvas(url) {
    InstaFuzz.Utils.loadImage(url, function (img) {
        // save reference to source image
        sourceImage = img;

        mainRenderer.clearCanvas();
        mainRenderer.renderImage(img);

        // load image filter previews
        loadPreviews(img);
    });
}

Here, mainRenderer is an instance created from the FilterRenderer constructor function defined in filter-renderer.js. The app uses FilterRenderer objects to manage canvas elements – both in the preview pane as well as the main canvas element on the right. The renderImage method on the FilterRenderer has been defined like so:

FilterRenderer.prototype.renderImage = function (img) {
    var imageWidth = img.width;
    var imageHeight = img.height;
    var canvasWidth = this.size.width;
    var canvasHeight = this.size.height;
    var width, height;

    if ((imageWidth / imageHeight) >= (canvasWidth / canvasHeight)) {
        width = canvasWidth;
        height = (imageHeight * canvasWidth / imageWidth);
    } else {
        width = (imageWidth * canvasHeight / imageHeight);
        height = canvasHeight;
    }

    var x = (canvasWidth - width) / 2;
    var y = (canvasHeight - height) / 2;
    this.context.drawImage(img, x, y, width, height);
};

That might seem like a lot of code but all it does ultimately is to figure out the best way to render the image in the available screen area considering the aspect ratio of the image. The key piece of code that actually renders the image on the canvas occurs on the last line of the method. The context member refers to the 2D context acquired from the canvas object by calling its getContext method.

Fetching pixels from the canvas
Now that the image has been rendered we will need access to the individual pixels in order to apply all the different filters that are available. This is easily acquired by calling getImageData on the canvas’s context object. Here’s how InstaFuzz calls this from instafuzz.js.
var imageData = renderer.context.getImageData(
    0, 0,
    renderer.size.width,
    renderer.size.height);

The object returned by getImageData provides access to the individual pixels via its data property which in turn is an array like object that contains a collection of byte values where each value represents the color rendered for a single channel of a single pixel. Each pixel is represented using 4 bytes that specify values for the red, green, blue and alpha channels. It also has a length property that returns the length of the buffer. If you have a 2D co-ordinate you can easily transform that into an index into this array using code such as the following. The color intensity values of each channel ranges from 0 through 255. Here’s the utility function from filters.js that accepts as input an image data object along with 2D coordinates for the pixel the caller is interested in and returns an object containing the color values:

function getPixel(imageData, x, y) {
    var data = imageData.data, index = 0;

    // normalize x and y and compute index
    x = (x < 0) ? (imageData.width + x) : x;
    y = (y < 0) ? (imageData.height + y) : y;
    index = (x + y * imageData.width) * 4;

    return {
        r: data[index],
        g: data[index + 1],
        b: data[index + 2]
    };
}
Applying the filters
Now that we have access to the individual pixels, applying the filter is fairly straightforward. Here, for instance is the function that applies a weighted grayscale filter on the image. It simply picks intensities from the red, green and blue channels and sums them up after applying a multiplication factor on each channel and then assigns the result for all 3 channels.
// "Weighted Grayscale" filter
Filters.addFilter({
    name: "Weighted Grayscale",
    apply: function (imageData) {
        var w = imageData.width, h = imageData.height;
        var data = imageData.data;
        var index;
        for (var y = 0; y < h; ++y) {
            for (var x = 0; x < w; ++x) {
                index = (x + y * imageData.width) * 4;
                var luminance = parseInt((data[index + 0] * 0.3) +
                                         (data[index + 1] * 0.59) +
                                         (data[index + 2] * 0.11));
                	    data[index + 0] = data[index + 1] =
                    data[index + 2] = luminance;
            }

            Filters.notifyProgress(imageData, x, y, this);
        }

        Filters.notifyProgress(imageData, w, h, this);
    }
});

Once the filter has been applied we can have that reflected on the canvas by calling the putImageData method passing in the modified image data object. While the weighted grayscale filter is fairly simple most of the other filters use an image processing technique known as convolution. The code for all the filters is available in filters.js and the convolution filters were ported from the C code available here.

Web Workers

As you might imagine doing all this number crunching to apply the filters can potentially take a long time to complete. The motion blur filter for instance uses a 9x9 filter matrix for computing the new value for every single pixel and is in fact the most CPU intensive filter among them all. If we were to do all this computation on the UI thread of the browser then the app would essentially freeze every time a filter was being applied. To provide a responsive user experience the app delegates the core image processing tasks to a background script using the support for W3C Web Workers in modern browsers.

Web workers allow web applications to have scripts run in a background task that executes in parallel along with the UI thread. Communication between the worker and the UI thread is accomplished by passing messages using the postMessage API. On both ends (i.e. the UI thread and the worker) this manifests as an event notification that you can handle. You can only pass “data” between workers and the UI thread, i.e., you cannot pass anything that has to do with the user interface – you cannot for instance, pass DOM elements to the worker from the UI thread.

In InstaFuzz the worker is implemented in the file filter-worker.js. All it does in the worker is handle the onmessage event and apply a filter and then pass the results back via postMessage. As it turns out, even though we cannot pass DOM elements (which means we cannot just hand a CANVAS element to the worker to have the filter applied) we can in fact pass the image data object as returned by the getImageData method that we discussed earlier. Here’s the filter processing code from filter-worker.js:

importScripts("ns.js", "filters.js");

var tag = null;
onmessage = function (e) {
    var opt = e.data;
    var imageData = opt.imageData;
    var filter;
    
    tag = opt.tag;
    filter = InstaFuzz.Filters.getFilter(opt.filterKey);

    var start = Date.now();
    filter.apply(imageData);
    var end = Date.now();

    postMessage({
        type: "image",
        imageData: imageData,
        filterId: filter.id,
        tag: tag,
        timeTaken: end - start
    });
}

The first line pulls in some script files that the worker depends on by calling importScripts. This is similar to including a JavaScript file in a HTML document using the SCRIPT tag. Then we set up a handler for the onmessage event in response to which we simply apply the filter in question and pass the result back to the UI thread by calling postMessage. Simple enough!

The code that initializes the worker is in instafuzz.js and looks like this:

var worker = new Worker("js/filter-worker.js");

Not much is it? When a message is sent by the worker to the UI thread we handle it by specifying a handler for the onmessage event on the worker object. Here’s how this is done in InstaFuzz:

worker.onmessage = function (e) {
    var isPreview = e.data.tag;
    switch (e.data.type) {
        case "image":
            if (isPreview) {
                previewRenderers[e.data.filterId].
                    context.putImageData(
                        e.data.imageData, 0, 0);
            } else {
                mainRenderer.context.putImageData(
                    e.data.imageData, 0, 0);
            }

            break;
        // more code here
    }
};

The code should be fairly self-explanatory. It simply picks the image data object sent by the worker and applies it to the relevant canvas’s context object causing the modified image to be rendered on screen. Scheduling a filter for conversion with the worker is equally simple. Here’s the routine that performs this function in InstaFuzz:

function scheduleFilter(filterId,
                        renderer,
                        img, isPreview,
                        resetRender) {
    if (resetRender) {
        renderer.clearCanvas();
        renderer.renderImage(img);
    }

    var imageData = renderer.context.getImageData(
        0, 0,
        renderer.size.width,
        renderer.size.height);

    worker.postMessage({
        imageData: imageData,
        width: imageData.width,
        height: imageData.height,
        filterKey: filterId,
        tag: isPreview
    });
}

In conclusion

We saw that fairly intricate user experiences are possible today with HTML5 technologies such as Canvas, Drag/Drop, File API and Web Workers. Support for all of these technologies is quite good in pretty much all modern browsers. One thing that we did not address here is the question of making the app compatible with older browsers. That, truth be told, is a non-trivial but necessary task that I will hopefully be able to talk about in a future article.
Link Comment (2)
 
Building an Instagram clone – Part 1
Technobabble
4/17/2013 5:31:26 PM  

Introduction

When I started out on this app I was only really just interested in seeing if the web platform had really evolved to a point where an app like the hugely popular Instagram app could be built using just HTML, JavaScript and CSS. As it turns out we can in fact do exactly that. This article walks you through the technologies that make this possible and shows how it is entirely feasible today to build interoperable web applications that provide a great user experience no matter what brand of browser the user is running.

If you happen to be one of the two or so people who have not heard about Instagram then you might be pleased to hear that it is a hugely popular photo sharing and social networking service that allows you to take pictures, apply interesting digital filters on them and share them with the world to see. The service got so popular that it was acquired by Facebook for a bag full of cash and stock in April of 2012.

InstaFuzz is the name of the app I put together and while I don’t expect to be acquired by Facebook or anybody else for a billion green it does however make the case that an app such as this one can be built using only standards compliant web technologies such as Canvas, File API, Drag/Drop, Web Workers, ES5 and CSS3 and still manage to run well on modern browsers such as Internet Explorer 10, Google Chrome and Firefox.

About the app

If you’d like to take a look at the app, then here’s where it is hosted at:

http://blogorama.nerdworks.in/arbit/InstaFuzz/

You can download the source and run locally from here.  While this is a Visual Studio 2012 project there really isn’t any server code or anything like that.  You can use your favorite editor to look at the source and run it from the file system if you are so inclined.

As soon as you load it up, you’re presented with a screen that looks like this:

clip_image002

The idea is that you can load up a photograph into the app either by clicking on the big red “Add” button on the bottom left hand corner or drag and drop an image file into the blackish/blue area on the right. Once you do that you get something that looks like this:

clip_image003

You’ll note that a list of digital filters are listed on the left of the screen showing a preview of what the image would look like if you were to apply the said filter. Applying a filter is a simple matter of clicking on one of the filter previews on the left. Here’s what it looks like after applying the “Weighted Grayscale” filter followed by a “Motion Blur”. As you can tell filters are additive – as you keep clicking on filters, they are applied on top of what was applied earlier:

clip_image004

Let’s next take a look at how the UI layout has been put together.

UI Layout

The HTML markup is actually so little that I can actually reproduce the contents of the BODY tag in its entirety here (excluding the SCRIPT includes):

<header>
    <div id="title">InstaFuzz</div>
</header>
<section id="container">
    <canvas id="picture" width="650" height="565"></canvas>
    <div id="controls">
        <div id="filters-list"></div>
        <button id="loadImage">Add</button>
        <input type="file" id="fileUpload"
               style="display: none;"
               accept="image/gif, image/jpeg, image/png" />
    </div>
</section>

<!-- Handlebar template for a filter UI button -->
<script id="filter-template" type="text/x-handlebars-template">
    <div class="filter-container" data-filter-id="{{filterId}}">
        <div class="filter-name">{{filterName}}</div>
        <canvas class="filter-preview" width="128" height="128"></canvas>
    </div>
</script>

There’s nothing much going on here. Pretty much everything should be standard fare. I will however draw attention to the fact that I am using the Handlebars JavaScript templating system here for rendering the markup for the list of filters on the left of the screen. The template markup is declared in the HTML file (the SCRIPT tag in the snippet shown above) and then used from JavaScript. The template markup is then bound to a JavaScript object that supplies the values for handlebars expressions such as {{filterId}} and {{filterName}}. Here’s the relevant piece of JS from the app with a bit of DOM manipulation help from jQuery:

var templHtml = $("#filter-template").html(),
    template = Handlebars.compile(templHtml),
    filtersList = $("#filters-list");
var context = {
    filterName: filter.name,
    filterId: index
};

filtersList.append(template(context));

As you can tell from the HTML markup all the filter preview boxes feature a CANVAS tag as does the big box on the right where the final output is rendered. We’ll go into a bit more detail later on in the article as to how canvas technology is used to achieve these effects.

The app also uses CSS3 @font-face fonts to render the text in the header and the “Add” button. The fonts have been taken from the excellent Font Squirrel site and here’s what the declaration looks like:

@font-face {
    font-family: 'TizaRegular';
    src: url('fonts/tiza/tiza-webfont.eot');
    src: url('fonts/tiza/tiza-webfont.eot?#iefix')
           format('embedded-opentype'),
         url('fonts/tiza/tiza-webfont.woff') format('woff'),
         url('fonts/tiza/tiza-webfont.ttf') format('truetype'),
         url('fonts/tiza/tiza-webfont.svg#TizaRegular') format('svg');
    font-weight: normal;
    font-style: normal;
}

This directive causes the user agent to embed the font in the page and make it available under the name assigned to the font-family rule which in this case is “TizaRegular”. After this we can assign this font to any CSS font-family rule like how we normally do. In InstaFuzz I use the following rule to assign the font to the header element:

font-family: TizaRegular, Cambria, Cochin, Georgia, Times,
   "Times New Roman", serif;

You might also have noticed that there is a subtle shadow being dropped on the page by the container element.

clip_image001[4]

This is made possible using the CSS3 box-shadow rule and here’s how it’s used in InstaFuzz.

-moz-box-shadow: 1px 0px 4px #000000, -1px -1px 4px #000000;
-webkit-box-shadow: 1px 0px 4px #000000, -1px -1px 4px #000000;
box-shadow: 1px 0px 4px #000000, -1px -1px 4px #000000;

This causes the browser to render a shadow around the relevant element. Each comma separated section in the value specifies the following attributes of the shadow:

  1. Horizontal offset

  2. Vertical offset

  3. Spread distance – positive values have the effect of softening the shadow

  4. Shadow color

One can specify multiple shadow values separated by comma as in fact has been done above. Note that I’ve also specified the shadow using vendor prefix syntax for Firefox and Chrome/Safari using the moz and webkit prefixes. This causes the shadow to continue to work in versions of those browsers where support for this capability was provided using the vendor prefixed version of the rule. Note that the W3C version of the rule – box-shadow – is specified last. This is done deliberately to ensure that in case the browser supports both the forms then only the W3C behavior is actually applied to the page.

One often finds that web developers either fail to include vendor prefixed version of a given CSS3 rule for all the browsers that support that rule and/or fail to include the W3C version as well. Often developers just put the webkit version of the rule ignoring other browsers and the W3C standard version. This causes two problems – [1] poor user experience for users who are using non-webkit browsers and [2] it ends up resulting in webkit becoming a de-facto standard for the web. Ideally we want W3C to be driving the future of the web and not one specific browser implementation. So here are some things to remember when playing with experimental implementations of CSS features:

  1. Use vendor prefixed versions of CSS rules by all means but remember to specify the rule for all supported browsers and not just the one that you happen to be testing the page in (if you’re using Visual Studio to edit your CSS then you might be interested in the supremely excellent extension for Visual Studio called Web Essentials that makes the job of managing vendor prefixes about as simple as it can possibly get).

  2. Remember to specify the W3C version of the rule as well.

  3. Remember to order the occurrence of the rules so that the W3C version shows up last. This is to allow clients that support both the vendor prefixed version and the W3C version to use the W3C specified semantics for the rule.

That’s all for now.  In the next and final post in this series we’ll take a look at how the app supports drag/drop of files, the use of File API, how the filters themselves work and how we prevent the UI thread from freezing by delegating the core number crunching work to web workers.

Link Comment
 
Organizing your JavaScript with WinJS
Technobabble
6/9/2012 10:34:17 AM  

While the JavaScript framework for creating metro style apps is surprisingly flexible, in that it allows you to use pretty much any JavaScript framework that’s already out there, there is actually some really useful functionality available in the WinJS library that ships out of the box. And since the JavaScript projection for WinRT itself uses this library it might make sense to use this for our own code as well. In this post I cover some basic ways you can organize your JavaScript code using WinJS.

Namespaces

One common challenge that we tend to encounter with any JavaScript app (whether web or desktop), is the question of being disciplined about introducing symbols into the global namespace. The general guideline is to, well, not do it! Using WinJS it is possible to organize your own classes and functions into well-defined namespaces. Here’s an example:

(function () {
    'use strict';

    // export this "enum"
    var ShapeType = Object.freeze({
        None: 0,
        Line: 1,
        Ellipse: 2,
        Rectangle: 3,
        Arc: 4,
        Bezier: 5
    });

    WinJS.Namespace.define("Acme.Shapes", {
        ShapeType: ShapeType
    });

})();

What this does is to basically create only one new symbol in the global namespace called “Acme”. All the remaining objects are child properties of this root object – essentially acting like a namespace. The above given code snippet for instance will enable you to access the ShapeType enumeration from pretty much everywhere else like so:

var type = Acme.Shapes.ShapeType.Arc;

You can see how easy it is to extend this to define pretty much your entire project - grouping all your code under a single root namespace. We’ll see further examples of how namespaces can be used as we talk about other capabilities that WinJS brings to the table.

Classes

While JavaScript itself is a weakly typed language it is possible to pretend like it isn’t and create and use “classes”. With WinJS you define a class by calling WinJS.Class.define. This method accepts 3 parameters: a constructor function, a JavaScript object defining the instance members and another JavaScript object defining the static members. Here’s an example:

(function () {
    "use strict";

    // constructor function
    function initShape(type) {
        this.id = Acme.Shapes.Shape.newId(); // calling a static member
        if (type) {
            this.type = type;
        }
    }

    var instanceMembers = {
        id: null,
        type: Acme.Shapes.ShapeType.None,
        draw: function () {
            console.log("Shape.draw");
        }
    };

    var staticMembers = {
        // private member
        _counter: 0,
        newId: function () {
            return Acme.Shapes.Shape._counter++;
        }
    };

    var Shape = WinJS.Class.define(initShape, instanceMembers, staticMembers);

    // add to namespace
    WinJS.Namespace.define("Acme.Shapes", {
        Shape: Shape
    });
})();

Now you can create and use instances of Shape like so:

var s = new Acme.Shapes.Shape(); 
s.draw();

The first parameter to WinJS.Class.define is a constructor function. This gets invoked whenever a new instance is created and is the place where you write your object initialization code. The second parameter is an object that describes the runtime shape of the object, i.e. what instance members it will contain. The third parameter defines the set of static members that you can access directly from the class without creating an instance. In the snippet above you’ll note that we invoke the static method newId from Shape’s constructor.

Finally, you can have static and instance non-enumerable members by prefixing the name with an underscore character. This has the effect of the member not being available when you reflect on the object and try to access its members. In the example above the static member _counter is not intended to be accessed directly by client code. We express this by prefixing an underscore character and WinJS makes sure that it sets the enumerable property descriptor to false when it creates the property. When we call Object.keys for instance, on the Shape constructor, here’s what we get:

console.log(Object.keys(Acme.Shapes.Shape));
// prints "newId"

As you can see it does not indicate _counter as being a member of Shape. Having said that if you do go ahead and access _counter anyway, it’ll still work! If you want a member to be really inaccessible then you might want to use closures.

Inheriting from classes

You can inherit one class from another by calling WinJS.Class.derive. Here’s an example:

(function () {
    'use strict';

    // constructor function
    function initLine() {
        // call the base constructor
        Acme.Shapes.Shape.call(this, Acme.Shapes.ShapeType.Line);
    }

    var instanceMembers = {
        // overriding Shape.draw
        draw: function () {
            // call base
            Acme.Shapes.Shape.prototype.draw.call(this);
            console.log("Line.draw");
        }
    };

    // inherit from Shape
    var Line = WinJS.Class.derive(Acme.Shapes.Shape, initLine, instanceMembers);

    WinJS.Namespace.define("Acme.Shapes", {
        Line: Line
    });
})();

The first parameter is a reference to the base class, followed by the constructor function and the instance members. Just like class definition, you can also pass static members if need be as the fourth argument. Note that when you inherit from another class, you do not inherit the static members. In the example above you cannot call newId via Line. You’ll also note that we call base class methods via Function.call instead of directly invoking them, i.e. we do not, for instance, do the following from Line.draw.

Acme.Shapes.Shape.prototype.draw(); // DO NOT do this

This won’t work because in this case the “this” pointer inside Shape.draw will point to the Shape’s prototype and not to the Line instance on which Line.draw was called. We will therefore need to explicitly specify the context for the call via Function.call.

Mixing functionality in

Let’s say you find this awesome piece of code somewhere that you think would be a great fit for one of the classes you are defining and it’d simply be too much trouble to manually copy and paste all of that code into your class definition (besides being error prone and quite simply a bad idea). In this case you can choose to “mix-in” that functionality into your existing class by calling WinJS.Class.mix. Here’s an example:

// mix-in some functionality from somewhere; pretend
// that we got this by including a JS or something
var SuperDrawModule = {
    superDraw: function() {
        console.log("SuperDrawModule.superDraw");
    }
};

Line = WinJS.Class.mix(Line, SuperDrawModule);

Now the method superDraw becomes a part of Line which means I can do the following now:

var l = new Acme.Shapes.Line();
l.draw();

// call mixin method
l.superDraw();

Adding eventing capabilities

WinJS ships with a useful little mixin object that automatically adds the ability to call addEventListener, removeEventListener and dispatchEvent on your own objects. The mixin in question is WinJS.Utilities.eventMixin. Here’s how you can use it:

(function () {
    "use strict";

    // constructor function
    function initShape(type) {
        this.id = Acme.Shapes.Shape.newId(); // calling a static member
        if (type) {
            this.type = type;
        }
    }

    var instanceMembers = {
        id: null,
        type: Acme.Shapes.ShapeType.None,
        draw: function () {
            // fire event "draw" via "dispatchEvent"
            this.dispatchEvent("draw", { source: this });
            console.log("Shape.draw");
        }
    };

    var staticMembers = {
        // private member
        _counter: 0,
        newId: function () {
            return Acme.Shapes.Shape._counter++;
        }
    };

    var Shape = WinJS.Class.define(initShape, instanceMembers, staticMembers);

    // add eventing capability to Shape
    Shape = WinJS.Class.mix(Shape, WinJS.Utilities.eventMixin);

    // add to namespace
    WinJS.Namespace.define("Acme.Shapes", {
        Shape: Shape
    });
})();

Take note of the lines in bold. We add the event mixin to Shape like any other mixin and call eventMixin.dispatchEvent to actually fire the event. Client code that handles the event would look like any other event handling code that you might have written to handle DOM events.

var l = new Acme.Shapes.Line();
l.addEventListener("draw", function () {
    console.log("Line was drawn.");
});
l.draw();

Note that stuff that you add to a base class via a mixin does in fact get inherited in sub-classes. In the sample snippet above, though the event mixin was added to Shape I am able to call addEventListener on the sub-class Line.

Turning your events into properties

WinJS.Utilities.eventMixin allowed us to make our classes act like DOM objects in supporting the registering of event handlers and in dispatching events. We can take things to the next level and add properties to our classes and add an alternative mechanism for registering event handlers. Our Shape class for instance, supports the raising of the “draw” event. Wouldn’t it be nice if it supported a property called ondraw to which we can assign a callback function and have it invoked whenever the event is raised? Turns out that is exactly the sort of thing that WinJS.Utilities.createEventProperties enables. Here’s an example:

// add "onevent" properties for all events we support
var eventPropMixin = WinJS.Utilities.createEventProperties("initialized", "draw", "disposed");
Shape = WinJS.Class.mix(Shape, eventPropMixin);

WinJS.Utilities.createEventProperties basically creates a mixin object that contains properties which have the same name as the strings passed to it as parameters except for the prefixing of the word “on” to them. This function can accept a variable number of parameters – one for each event that your class supports. With this in place, now you can write code such as the following:

var l = new Acme.Shapes.Line();
l.ondraw = function () {
    console.log("Line was drawn.");
};
l.draw();

One benefit of using WinJS is that you automatically get intellisense support in VisualStudio for stuff you add to your classes using it. Here’s a screen shot:

p1

That’s pretty much all I wanted to talk about. With these few simple methods from WinJS it is quite possible to be fairly disciplined about your JavaScript code and believe me, JavaScript being JavaScript, you’re going to need all the help you can get! Winking smile I have created a small project with all of the code snippets given above here.

Link Comment (2)
 
blogorama home
about this blog
email the author
where on earth am i?
subscribe to mailing list
feeds Use these links for feed syndication
rss  |  atom
by category
technobabble (59)
philosophical crud (3)
irrelevant stuff (7)
archive
november, 2011 (2)
october, 2011 (1)
september, 2011 (7)
july, 2011 (3)
june, 2011 (2)
may, 2011 (3)
april, 2011 (1)
march, 2011 (1)
february, 2011 (1)
february, 2010 (1)
october, 2009 (1)
september, 2009 (1)
july, 2009 (5)
march, 2009 (2)
august, 2008 (2)
march, 2008 (1)
january, 2008 (1)
september, 2007 (2)
april, 2007 (1)
february, 2007 (2)
december, 2006 (1)
october, 2006 (1)
september, 2006 (4)
august, 2006 (3)
july, 2006 (4)
june, 2006 (3)
may, 2006 (6)
april, 2006 (2)
recent entries
Debugging existing...
Screen scraping wit...
Building an Instagr...
Building an Instagr...
Organizing your Jav...
290690 hits