Return of syntax highlighting and code completion for KnockoutJS in VS2010 (when using Razor)

OK, admittedly, this is a workaround for an issue where the syntax of jQuery Templates (used by KnockoutJS) doesn’t lend itself to the most pleasant editing experience in Visual Studio, but eh.

This was inspired after talking with Ryan a bit and seeing a recent post on his new web site. Here’s what I came up with.

Following a similar pattern to the BeginForm Helper, I created a “Template” helper. It’s simple to use as the code below demonstrates (the example is taken from the KnockoutJS web site).

<div data-bind='template: "personTemplate"'> </div>

@using (Html.Template("personTemplate"))
{ <text>    
    ${ name } is ${ age } years old
    <button data-bind='click: makeOlder'>Make older</button>
</text> }
     
<script type='text/javascript'>
    var viewModel = {
        name: ko.observable('Bert'),
        age: ko.observable(78),
        makeOlder: function () {
            this.age(this.age() + 1);
        }
    };
    ko.applyBindings(viewModel);
</script>

Sometimes, the Razor compiler/engine is confused by the template syntax however, so to work around that, you’ll need to add the <text>…</text> block to prevent the template syntax from being parsed as Razor syntax. The example above shouldn’t require it. The one that causes problems I’ve found mostly right now is the conditional {{ if }} block which apparently looks like Razor/C# code, and fails. The <text> tag syntax isn’t tragic. The most annoying part is that it highlights as bright yellow.

The Template Helper emits the start and end <script> tags appropriately. There’s an optional second parameter that allows the developer to override the default of the type being text/html.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace TestMVC.Web
{
    public static class MvcExtensions
    {
        /// <summary>
        /// Automatically generates a script block, useful for non-typical script
        /// tags that have HTML content inside (like those in jquery templates for example)
        /// Always use this within using statement as Dispose must be called to properly close
        /// the script tag.
        /// </summary>
        /// <param name="helper">Html Helper object</param>
        /// <param name="id">The ID for the generated script tag.</param>
        /// <returns>TemplateBlock object which must be disposed to properly emit
        /// the necessary script tags.</returns>
        public static TemplateBlock Template(this HtmlHelper helper, string id)
        {
            return Template(helper, id, "");
        }

        /// <summary>
        /// Automatically generates a script block, useful for non-typical script
        /// tags that have HTML content inside (like those in jquery templates for example)
        /// Always use this within using statement as Dispose must be called to properly close
        /// the script tag.
        /// </summary>
        /// <param name="helper">Html Helper object</param>
        /// <param name="id">The ID for the generated script tag.</param>
        /// <param name="type">Defaults to text/html, but may be overriden by setting
        /// this parameter.</param>
        /// <returns>TemplateBlock object which must be disposed to properly emit
        /// the necessary script tags.</returns>
        public static TemplateBlock Template(this HtmlHelper helper, string id, string type)
        {
            return new TemplateBlock(helper.ViewContext, id, type);
        }
    
    }

    public class TemplateBlock : IDisposable
    {
        private bool _disposed = false;
        public ViewContext ViewContext { get; private set; }
        
        public TemplateBlock(ViewContext context, string id, string type)
        {
            this.ViewContext = context;
            type = string.IsNullOrWhiteSpace(type) ? "text/html" : type;
            context.Writer.Write("<script type='{0}' id='{1}'>\n", type, id);
        }

        private void Disposing(bool disposing)
        {
            if (!_disposed)
            {
                _disposed = true;
                ViewContext.Writer.Write("</script>\n");
            }
        }
        public void Dispose()
        {
            this.Disposing(true);            
        }
    }

}

Enjoy.

Microsoft: Make the “Metro/Zune” look a standard. Publish it. Push it. Now.

Apple makes user experience inroads every day on Windows when a developer follows Apple’s Human Interface Guidelines for design for a Windows Application.

This post was inspired when imageI installed Miro this morning on my desktop PC. (Don’t get me started that it opts-in a bunch of changes and a toolbar for the browser. Convince me that I want to to do it because it’s the “right” thing – let me opt-in!)

In Miro’s words, it’s an “amazing open-source, non-profit video player.” (See previous annoyance about toolbars and other default-opt-in things the installer attempts).

In any case, it installed. The installer UI had a few cross platform oddities, including not being sized correctly, and worse, showing up too high on one of my monitors.

Here’s the default look:

SNAGHTML1c0109

Hey! It’s iTunes! Great. (iTunes, below as a reference).

image

On the left side (in both applications), is located a Source List (see “Source Lists” in the Apple Human Interface Guidelines). They flipped the play bar to the bottom and tweaked the general look and feel of the buttons, but it’s basically the same UI.

At first, you might think that there’s only so many ways to present that type of UI. I give you the Zune Player (4.7).

SNAGHTML204865

It’s so different I won’t even start listing the differences. I thought about other applications that I have on my Windows PC that follow this style. Admittedly, it’s not very many right now. MetroTwit generally follows the Metro style.

SNAGHTML250657

Windows Live Mail (somewhat) (along with the other Windows Live applications):

SNAGHTML2d268de

Actually, there’s not a formal guide for this style. The closet you might come today is the Windows Phone 7 UI Design and Interaction Guide. That’s a poor substitute though.

There is of course, the Windows User Experience Interaction Guidelines. Oh wow. It’s amazing the amount of bad examples that are sourced from earlier versions of Windows. There are so many (too many). Furthermore, it’s not free from errors itself:

image

image

Microsoft doesn’t bother following it, so it’s not too surprising that many Windows applications do not.

From the Guidelines:

image

From Word 2010:

image

My point isn’t to blast this document. What’s missing from the document is how to build an application that is smooth and modern. It’s an 882 page document currently, that helps you build a nice Windows 95 application. What? Seriously. If you look through the document, it’s really about fixing the problems of Windows 95 through Windows Vista. It doesn’t innovate anything new. It’s about putting up better error messages, being more consistent, etc. All of these things are great. But, can we move beyond that? Can we build something slick and modern that is more than just gas glass?

That’s why I’m pushing for anything more modern now. If the Zune/Metro isn’t it, then create something new for us to follow.

Applications for developers/designers that are released like WebMatrix are a sign that there’s an opportunity to think beyond just glass and better wording. In WebMatrix, I noticed that they’ve done away with standard Modal dialogs. They’re modal – but they float with the main application window (even when they’re showing), much like if they were a web page. Slick. The application is clean and modern. I like it.

SNAGHTML2c968bf

Why can’t we have more of this:

image

instead of this:

SNAGHTML2cbdb11

So, this was just a rant really. But, an important one. Will Windows 8 finally solve this and introduce a awesome and modern User Experience, one that is easily replicated by developers, without the use of dozens of third party components and questionable code from the Internet, and …. Please Microsoft. Do it. Do it for all of us. I don’t care if it’s the Metro/Zune theme or something else. You can do better than Apple.

It’s time for you to innovate again. You’ve got some super app creation platforms (like Silverlight and WPF) and you’ve got awesome development tools (Visual Studio and .NET 4), and you’ve got a lot of great developers ready to rock and roll. Help us build UX that are killer awesome. Build the components – ship them in V1. Do it!

(Oh, and by the way, could you please create a 10 hour battery life Windows 8 tablet? Pretty please?! I’ll buy one!)

Home Desk setup

image

I recently added a 30 inch Dell LCD display to my setup at home. I’d had a 24 inch for 5 years, and had the itch for more pixels!

So, I’ve now got 7,710,720 pixels available!

I couldn’t stand back far enough due to where my desk sits in my den to capture my desk and monitors adequately.

Derserializing ASP.NET MVC JSON formatted Date strings

Have you called an Ajax based action in MVC, only to find that the Date format is being serialized into something that isn’t entirely useful on the client?

{“result”:[{“Author”:”Aaron”,”SentAt”:”\/Date(1296824894700)\/”,”Text”:”Blah Blah”,”Id”:1}],”runAt”:”\/Date(1297031297600)\/”}

You’ll see that the Date is:

\/Date(1296824894700)\/

Alas, that’s not very friendly. For a quick translation, I added the following to jQuery’s dataFilter property so that the date would be formatted in a more human readable format. The dataFilter function is used to sanitize a response from a web server.  Here’s what I added:

$(function () {
    $.ajaxSettings.dataFilter = function (data, type) {
        if (type === 'json') {
            // convert things that look like Dates into a UTC Date string
            // and completely replace them. 
            data = data.replace(/(.*?")(\\\/Date\([0-9\-]+\)\\\/)(")/g,
                function (fullMatch, $1, $2, $3) {
                    try {
                        return $1 + new Date(parseInt($2.substr(7))).toUTCString() + $3;
                    }
                    catch (e) {}
                    // something miserable happened, just return the original string            
                    return $1 + $2 + $3;
                });
        }
        return data;
    };
});

The trick for converting the /\Date(#)\/ syntax easily was from StackOverflow. It even handles time zone info.

I added a regular expression to look for the various elements that represent a Date in Microsoft JSON serialization format. The resulting date is reformatted to a human readable string. There are 3 capturing groups that I’ve named $1, $2, and $3 which need to be preserved otherwise the JSON string is mangled beyond recognition. Those are returned concatenated to preserve the original formatting of the string.

The resulting date is translated to something like:

Fri, 4 Feb 2011 13:08:14 UTC

Of course, you could do whatever formatting you’d like.

 

Bonus

And, as a bonus, you did notice that if you’re using IE9, that the developer tools now have a network trace? Cool. (I’ll still use fiddler for many things, but this will be very handy on machines that don’t have fiddler installed).

SNAGHTML51b4c85a

jQuery 1.5, jquery.validate and Ajax/getJSON

Apparently, the new version of jQuery conflicts with the version of the jquery.validate plugin that is included with Microsoft’s MVC 3 template. After a frustrating hour of debugging and using Fiddler (as I didn’t realize the problem was related to a plugin I wasn’t actively using on the web page), I stumbled into the answer/workaround on github here.

The specific issue that I encountered was what I thought was a simple use of the ajax method of jQuery:

$.ajax({
    url: _fullRoute + "/Fetch",
    data: { since: this._lastRefresh },
    type: "get",            
    dataType: "json"
}).success(function (data) { alert("success"); }).
        error(function (e) { alert("error: " + e.toString()); }).
        complete(function () { alert("complete"); });
}

I’d tried lots of things, experimented with what seemed like countless JsonResult options (along with Json function call changes), and nothing worked. The JavaScript error callback function would always be called. The error: parseerror. Arrgh.

return Json(new { result = “why me!?” }, "application/json", JsonRequestBehavior.AllowGet);

Thankfully, a user on github, jfirebaugh, took the time to resolve the issue and produced a patch (change here).

You can look at the details on github.

After applying the patch, and using the Microsoft Ajax Minifier, I noticed that the file was about 4K smaller than the one that is included with the MVC 3 template. Smile

image