A dotless mixin for specifying both low-DPI and high-DPI backgrounds

Introduction
Almost all web applications use images as part of their presentation, often for logos and icons (and occasionally for layout graphics). To cater for smartphone displays (most of which are considered high-DPI), you often need to add @media declarations to switch out your images to high-DPI versions.

Normal and high-DPI images at 200% zoom

Normal and high-DPI images at 200% zoom

If you also want to support users that have changed their desktop browser’s zoom level, one of the best approaches is to use background-size. In combination with Modernizr, you might present a low-DPI version to any browser that doesn’t support background-size, and then present a high-DPI version to any browser that does.

Depending on your circumstances, it may be better to use a CSS fallback instead. Values after a slash in a background declaration are treated as the size, and you can rely on a rule being ignored in browsers that don’t support it. For example:

.logo {
	background: url(logo@1x.png) no-repeat 50% 50%;
	background: url(logo@2x.png) no-repeat 50% 50% / 128px 128px;
}

dotless mixin
If you’re using dotless, you can create a reusable helper to do the above more easily. For example, you might create a mixin called .background():

.background(@pathPrefix, @pathSuffix, @position, @size) {
	background: ~"url(@{pathPrefix}@1x@{pathSuffix})" @position;
	background: ~"url(@{pathPrefix}@2x@{pathSuffix})" @position ~"/" @size;
}

You would then convert the above .logo class to simply:

.logo {
	.background("logo", ".png", no-repeat 50% 50%, 128px 128px);
}

This can make it a lot easier to use high-DPI images, without removing support for older browsers, and without needing to use Modernizr or @media declarations.

Notes
The slash needs to be escaped in dotless, otherwise it is interpreted as a division operation. LESS (the original parser, not the .NET port) aims to fix this with a new strict math feature. In addition, in order for the slash syntax to work in a background declaration, you must include a position value. For example, the following rule is invalid:

.logo {
	background: url(logo@2x.png) no-repeat / 128px 128px;
	// invalid rule, requires a position value before the slash
}

Strongly-typed alternative to ViewBag in MVC/Razor views

Introduction
MVC and Razor provide several mechanisms to pass data between controllers, views, and layouts. In a typical web application, ViewBag/ViewData is used by the controller to store non-static information that a view needs to render itself, and Model is designed to handle form data, or data that will be posted back from the client.

Being a dynamic object, you often have to cast ViewBag properties to the expected type. Furthermore, you lose most of the design-time tools support (such as refactoring, intellisense, and error-checking).

For those who prefer working with strongly-typed objects, Arraybracket.TypedViews is a NuGet package that adds a strongly-typed ViewModel property to your views. Similar to the Model property, you specify the type of ViewModel using an @model declaration, and you specify its value as a parameter to the controller’s View() method.

Example
Let’s say you have a contact us page, and you want the user to be able to select the department to contact from a drop down list. Typically, you’d have a Department property in your Model type, and you’d pass in the options to display using the ViewBag. Because you can’t use extension methods with dynamic parameters, you’d have to cast the options to the expected type. For example:

@model ContactUsModel

@using (Html.BeginForm()) {
    <label>Department:</label>
    @Html.DropDownListFor(m => m.Department, (SelectList)ViewBag.DepartmentOptions);
}

With typed views, you specify the ViewModel type in the @model declaration, and you can use the type-safe ViewModel property instead. For example:

@model ContactUsViewModel, ContactUsModel

@using (Html.BeginForm()) {
    <label>Department:</label>
    @Html.DropDownListFor(m => m.Department, ViewModel.DepartmentOptions)
}

More information
Because this change has to modify web.config, it affects the entire web application. This means it’s best suited to new applications, as you can write them to work with typed views from the ground up. With the appropriate configuration, it could also be applied to a new subsection of a site (e.g. a specific MVC area or controller).

The readme provides some more information on how to set up your controllers and layouts to work with typed views, and there’s a sample web project that demonstrates all the concepts.

Arraybracket.TypedViews is licensed under the MIT license. The source code is available on GitHub.

Sorting a ScriptBundle based on /// <reference /> tags

Introduction
If you’re using ASP.NET Optimization to combine and minify your JavaScript or TypeScript files, you’ll notice that the bundling framework will put certain known scripts first (e.g. jQuery) and then sort the remaining ones alphabetically. However, if some scripts have dependencies on other scripts, you’re often forced to specify an explicit order and turn off the sorting.

Both Visual Studio’s JavaScript edtior and the TypeScript compiler use /// <reference /> tags to specify dependencies between files. I’ve just published a NuGet package, Arraybracket.Bundling, which includes functionality to order the scripts based on those /// <reference /> tags.

Usage
Using the package manager console:

Install-Package Arraybracket.Bundling

Then, if you’re using /// <reference /> tags for JavaScript intellisense or for TypeScript dependencies, then just change your ScriptBundle to use ScriptDependencyOrderer.

Example
For example, let’s say your app.ts file references helpers.ts, which in turn uses jQuery. The required order would be:

  • scripts/libs/jquery-1.9.1.js
  • scripts/helpers.ts
  • scripts/app.ts

In scripts/app.ts:

/// <reference path="helpers.ts" />
/// <reference path="modernizr/modernizr.d.ts" />
if (!Modernizr.vwunit)
	onLoadOrResize(() => console && console.log("perform some fallback layout resizing"));

In scripts/helpers.ts:

/// <reference path="libs/jquery.d.ts" />
function onLoadOrResize(handler) {
	$(handler);
	$(window).on("resize", handler);
}

In Global.asax.cs or BundleConfig.cs:

var scriptBundle = new ScriptBundle("~/scripts/combined");
scriptBundle.Include("~/scripts/libs/*.js").Include("~/scripts/*.ts");
scriptBundle.Transforms.Add(new JsTransformer()); // if you're using Bundle Transformer
scriptBundle.Orderer = new ScriptDependencyOrderer();
BundleTable.Bundles.Add(scriptBundle);

If you run your website in debug mode, you’ll see the scripts included in the expected order. If you go into web.config and turn off debug mode, you’ll see the combined file still has the correct order.

Name Matching and Exclusions
You’ll also notice that the example above showed helpers.ts referencing a file called jquery.d.ts, whereas the bundle included a file called jquery-1.9.1.js. The ScriptDependencyOrderer applies some naming conventions to make sure things like JavaScript intellisense files and TypeScript declaration files (whose filenames won’t exactly match bundled scripts) are detected correctly.

The example also references Modernizr as a dependency, but no Modernizr script is included in the bundle. Normally this would show an error indicating that name matching could not match a /// tag to a bundled script. However, Modernizr needs to be included in the <head> tag and can’t be part of the bundle, so ScriptDependencyOrderer knows to exclude it.

You can read more about Name Matching and Exclusions in the README on GitHub or by looking through the unit tests.

License and Source
Arraybracket.Bundling is licensed under the MIT license. The source code is available on GitHub.

Loading images with jQuery Deferreds

Introduction
jQuery 1.5 introduced a new deferred callback system that makes working with asynchronous tasks, such as $.ajax a lot tidier.

While the most common use for deferreds are with jQuery’s built-in ajax functions, creating your own custom deferred objects makes asynchronously loading resources a lot easier.

Creating a deferred for image loading
We’ll create a function called $.image(src) to let us asynchronously load an image, and then have behavior for when it is done (or fails). We could call it like so:

var imageUrl = "..."; // specify an image url
$.image(imageUrl).done(function (image) {
    $(image).hide().appendTo("#Filmstrip").fadeIn();
});

We can then define the $.image(src) function like so:

$.image = function (src) {
    return $.Deferred(function (task) {
        var image = new Image();
        image.onload = function () { task.resolve(image); }
        image.onerror = function () { task.reject(); }
        image.src = src;
    }).promise();
};

The result is an object that we can hook events on to, such as .done(func), .fail(func), .pipe(func). We can also combine it using $.when(...), like so:

$.when($.image(image1Url), $.image(image2Url), $.image(image3Url))
    .done(function(image1, image2, image3) {
        // process images
    });

This will load all three images in parallel and then run the event once all three have finished. These sorts of techniques could tidy up your gallery or slideshow code, or assist loading assets for an HTML game. A similar behavior can also be applied for Audio objects.

Improving Firefox HTML5 Canvas performance

Configuration
The default Firefox configuration may not be the most optimal for performance. I’ve found when developing my HTML5 game that you can get an increase from about 10fps to about 80fps by changing some settings in about:config.

The following settings are examples:

  • gfx.direct2d.force-enabled
  • layers.acceleration.force-enabled
  • layers.prefer-d3d9
  • layers.prefer-opengl

Date Navigation: calculating key relative dates

Introduction
I’ve added a library to NuGet called Arraybracket.DateNavigation. It provides a number of useful extension methods for working with dates that you would usually have to write as you need them.

DateNavigation provides extension methods to easily calculate key relative dates, such as navigating to the following week day, traversing to the following Tuesday, and calculating the end of the month.

Previous(), Following(), PreviousWeekDay(), and FollowingWeekDay()
date.Previous(DayOfWeek day, bool allowCurrent = false) – Calculates the most recent occurrence of the specified day of the week. For example, the previous Tuesday from Wednesday 20th is Tuesday 19th, and the prior Friday from Wednesday 20th is Friday 15th.

date.Following(DayOfWeek day, bool allowCurrent = false) – Traverses to the upcoming occurrence of a particular, specified day of the week. For example, the following Wednesday from Tuesday 19th is Wednesday 20th, and the next Saturday from Sunday 17th is Saturday 23rd.

date.PreviousWeekDay(bool allowCurrent = false) – Works out the most recent occurrence of a weekday. For example, the previous week day from Tuesday 19th is Monday 18th, and the prior weekday from Monday 18th is Friday 15th.

date.FollowingWeekDay(bool allowCurrent = false) – Navigates to the upcoming occurrence of a week day. For example, the following week day from Tuesday 19th is Wednesday 20th, and the next weekday from Friday 22nd is Monday 25th.

You can use the optional parameter, allowCurrent to include the current day in the date traversal. For example, the previous Thursday from Thursday 21st is normally Thursday 14th, but with allowCurrent it would be Thursday 21st. Note that the returned dates will retain the input date’s time components. If you wish to remove the time compoment, use date.Date.

StartOfMonth(), and EndOfMonth()
date.StartOfMonth() – Returns the start of the month, i.e. the first millisecond on the first day for the month specified in date. For example, the beginning of the month for “2011 May 20th” is “2011 May 1st”. This method can be useful when performing reports or date range filters.

date.EndOfMonth() – Calculates the end of the month, i.e. the last millisecond on the last day for the month specified in date. For example, for “2011 May 20th” the month end is “2011 May 31st 23:59:59.999″. The full time component is included so that you can filter against a date/time value, but you can use date.Date to suppress the time component if necessary.

IsWeekDay()
date.IsWeekDay() – Simply checks if the date is a week day, i.e. from Monday to Friday inclusive.

License and Source
Arraybracket.DateNavigation is released under the MIT License. You can download the binaries and source code directly as well.

Sync Visual Studio and Resharper settings with Live Mesh

Live Mesh settings sync

Live Mesh settings sync

Introduction
If you have Windows Live Mesh, you’ll know you can synchronize your Internet Explorer and Microsoft Office settings with your other computers. To my knowledge, there is presently no way to extend this list to cover other applications.

A lot of desktop programs store their configuration in the registry, which makes it difficult to set them up to sync their settings to the cloud and between computers. However, Visual Studio and Resharper simply use configuration files, which of course Live Mesh is good at handling.

Depending on which versions you use, your Visual Studio settings are stored at some variation of the path C:\Users\USERNAME\Documents\Visual Studio 2010\Settings and your Resharper settings are stored in C:\Users\USERNAME\AppData\Roaming\JetBrains\ReSharper\v5.1\vs10.0 or something similar.

If you simply go into Live Mesh now and synchronize these folders, you will run into some issues. For one, if you are syncing with another computer, they are likely to already have files in these folders, or you may have different versions of Resharper installed. Secondly, you will end up with a folder in Live Mesh called vs10.0, which isn’t too pleasant.

Setting up the Mesh folder
Instead, on your main computer (whose settings you presumably want to keep), create a folder called Resharper Settings and move the contents of that vs10.0 folder into it (as shown in step 1). Once you’ve done this, you need to synchronize the folder to Live Mesh (step 2), and then desynchronize it (step 3) by choosing Select devices and unselecting this computer (it will still be available in Skydrive).

Syncing to the Mesh folder
Now, on your main computer as well as your other computers, you need to delete the contents of the vs10.0 folder (step 4), go in to Live Mesh and choose Sync this folder next to Resharper Settings (step 5). Select the now-empty vs10.0 folder, and your configuration files will be synced into it.

Conclusion
Repeat this process for the Visual Studio settings, and your settings will be synchronized between your computers and backed up. This is the cleanest way to synchronize your Visual Studio and Resharper settings, and isn’t at all fiddly once it’s set up. You can even use Previous versions in one of those folders if your settings become corrupted or replaced, and then the reverted version will synchronize back out.

Follow

Get every new post delivered to your Inbox.