Archives for category: Tutorials

For anybody who doesn’t know, working at Umbraco HQ, every Fridays is Freedom Fridays, in which the whole team take a break from their usual projects, and spend the day doing some personal development.

Having spent a fair bit of time playing around with Knockout.js recently (If you haven’t done already I urge you to checkout the Introduction to Knockout JS talk I gave at the Umbraco UK Festival back in November), I thought I’d have a go at writing my own plugin for it.

With that in mind, I introduce to you, Knockout Hotkeys.

Knockout Hotkeys is a custom binding plugin for Knockout that allows you to define global hotkeys for elements in your design, allowing you to effectively develop keyboard driven interfaces.

You can define a hotkey by using one of three binding attributes

  •     hotkeydown
  •     hotkeyup
  •     hotkeypress

The actual syntax is then as follows (NB: Modifier keys should be defined in alphabetical order, ie alt+ctrl+shift):

<input type="text" data-bind="hotkeydown: { shift1 : doSomething }" />

If you would prefer your key combinations to be a little more readable, you can also define them in the following format:

<input type="text" data-bind="hotkeydown: { 'shift+1' : doSomething }" />

You can also register multiple hotkey combos within a single binding statement as follows:

<input type="text" data-bind="hotkeydown: [{ 'shift+1' : doSomething }, { 'shift+2' : doSomethingElse }]" />

In addition to the key combination option, you can also provide an if statement which must be met to allow the hotkey to trigger:

<input type="text" data-bind="hotkeydown: { 'shift+1' : doSomething, if: currentItem() == $data }" />

Lastley, you can also use a more verbose syntax to allow the creating of dynamic key combinations:

<input type="text" data-bind="hotkeydown: { key: 'shift+' + $data.substr(0,1).toLowerCase(),  do: doSomething }" />

If you’d like to give Knockout Hotkeys ago, you can grab it now over on bitbucket.

All in all, it’s been a lot of fun creating this plugin. The more I explore Knockout, the more I love it. From the beautiful syntax, to the amazing documentation. I wish more libraries could be like this.

A little while ago I blogged about how I automate my package creation in Umbraco v4 using some custom MSBuild tasks I wrote. Since then, I’ve been lucky enough to join the Umbraco HQ and get some early exposure to Umbraco v5 (aka Jupiter). One of the changes in v5 is around how packages work, moving away from the proprietary package manifests used in v4, in favour of the standard NuSpec manifests used in NuGet packages. This means Umbraco packages are now just plain old NuGet packages.

With this change, I thought I’d have a go at updating my build scripts so that I can continue to automate the package creation process. After a quick search, I couldn’t find any specific MSBuild tasks for NuGet package creation, so I went and wrote some =)

So here is the updated process.

Prerequisites

As I’m using MSBuild, you’ll obviously need to have the .NET framework installed. In addition, you’ll need to download the NuGet.exe command line executable from Codeplex, and my custom MSBuild.NuGet.Tasks dll and targets file.

Project Structure

Now this is completely up to you, but for this example and for my own projects, this is the project structure I use.

  • Lib - Referenced 3rd party libraries
  • Src - Source code for your application
    • MyProject - Project folder
      • MyProject.proj - Project file
  • Tools - Build tools
    • MSBuildNuGetTasks - The NuGet MSBuild tasks
    • NuGet - The NuGet command line executable
  • MyProject.sln – The project solution file
  • Package.build.cmd - The command file for triggering the package build process
  • Package.build.xml - The package MSBuild script
  • Package.nuspec - The package manifest file

Package.nuspec

This is the manifest file for your package. The manifest is responsible for holding all the metadata about your package such as name, version and description aswell as listing the package files and, in the future, your package dependencies.

If you actually looked at the package manifest files in v4, then these will actually look pretty similar. The namespaces might have changed a little, but the function is exactly the same.

What follows is a demo manifest file.

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>MyPackage</id>
    <version>0.0.0</version>
    <title>My Package</title>
    <authors>Matt Brailsford</authors>
    <owners>Matt Brailsford</owners>
    <projectUrl>http://blog.mattbrailsford.com</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>My Package Description</description>
    <summary>My Package Summary</summary>
    <language />
  </metadata>
  <files />
</package>

Package.build.xml

This is the build script for the package, and is responsible for orchestrating the build process. This hasn’t actually changed that much from my original build script, with the only real difference being a different packaging task (the ManifestUpdate task has also been updated, but the signature is pretty much the same as before). The options on the pack task exactly match those of the pack command of the NuGet command line tool.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Package">

  <!--
  	****************************************
  	* IMPORTS
	****************************************
  -->
  <PropertyGroup>
  	<MSBuildNuGetTasksPath>$(MSBuildProjectDirectory)\Tools\MSBuildNuGetTasks</MSBuildNuGetTasksPath>
  </PropertyGroup>

  <Import Project="$(MSBuildNuGetTasksPath)\MSBuild.NuGet.Tasks.Targets" />

  <!--
  	****************************************
  	* PROPERTIES
	****************************************
  -->
  <PropertyGroup>
	<PackageVersion>1.0</PackageVersion>
  </PropertyGroup>

  <PropertyGroup>
	<RootDir>$(MSBuildProjectDirectory)</RootDir>
	<BuildDir>$(RootDir)\Build</BuildDir>
	<PackageDir>$(RootDir)\Package</PackageDir>
	<ProjectDir>$(RootDir)\Src\Namespace.MyProject</ProjectDir>
  </PropertyGroup>

  <!--
  	****************************************
  	* TARGETS
	****************************************
  -->

  <!-- CLEAN -->
  <Target Name="Clean">
	<RemoveDir Directories="$(BuildDir)" Condition="Exists('$(BuildDir)')" />
  	<RemoveDir Directories="$(PackageDir)" Condition="Exists('$(PackageDir)')" />
	<MakeDir Directories="$(BuildDir)" />
  	<MakeDir Directories="$(PackageDir)" />
  </Target>

  <!-- COMPILE -->
  <Target Name="Compile" DependsOnTargets="Clean">
	<MSBuild Projects="$(ProjectDir)\Namespace.MyProject.csproj" />
  </Target>

  <!-- PREPAIRE FILES -->
  <Target Name="PrepairFiles" DependsOnTargets="Compile">
    <ItemGroup>
      <BinFiles Include="$(ProjectDir)\Bin\Namespace.MyProject.dll" />
      <ViewFiles Include="$(ProjectDir)\Views\*.cshtml" />
      <PackageFile Include="$(RootDir)\Package.nuspec" />
    </ItemGroup>
	<Copy SourceFiles="@(BinFiles)" DestinationFolder="$(BuildDir)\lib" />
	<Copy SourceFiles="@(ViewFiles)" DestinationFolder="$(BuildDir)\content\views" />
	<Copy SourceFiles="@(PackageFile)" DestinationFolder="$(BuildDir)" />
  </Target>

  <!-- MANIFEST -->
  <Target Name="Manifest" DependsOnTargets="PrepairFiles">
	<ItemGroup>
      <ManifestFiles Include="$(BuildDir)\**\*" Exclude="$(BuildDir)\Package.nuspec" />
    </ItemGroup>
	<ManifestUpdate
		ManifestFile="$(BuildDir)\Package.nuspec"
		WorkingDirectory="$(BuildDir)"
		Version="$(PackageVersion)"
	    Files="@(ManifestFiles)" />
  </Target>

  <!-- PACKAGE -->
  <Target Name="Package" DependsOnTargets="Manifest">
	<Pack NuGetExePath="$(RootDir)\Tools\NuGet\NuGet.exe"
		ManifestFile="$(BuildDir)\Package.nuspec"
		BasePath="$(BuildDir)"
		OutputDirectory="$(PackageDir)"
		Verbose="true" />
  </Target>

</Project>

Package.build.cmd

This is a simple command script and is responsible for triggering the build process. Again, this hasn’t changed greatly from before, with the only change being and update to the msbuild executable used.

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild.exe Package.build.xml

Conclusion

All in all, there haven’t been any huge changes to the script from before, with the majority of the changes being hidden away in the MSBuild tasks. Hopefully this will make it easier for people who used my script before to make the leap into v5. As an added bonus, since Umbraco packages in v5 are just plain old NuGet packages, these MSBuild tasks can actually be used for creating any other kind of NuGet packages aswell.

Happy packaging =)

For a long time, whenever I’ve been developing a site, I would always set it up in IIS with a custom host header and modify my windows hosts file to wire it all up. I know a lot of developers don’t go to this extent, instead plumping to only run it via Visual Studio and Cassini. I’ve never been a fan of this way of working, mainly because I like to have access to my sites at all times, without having to launch Visual Studio (especially if I’m developing an Umbraco site, and all I need to do is update some CSS or something which I can do easily and quickly via the UI). The downside to setting sites up in IIS though, is that it does add extra steps to the beginning of a project, which can get tedious.

After reading a blog post by Aaron Powell, it got me thinking though. Why not use IIS Express to dynamically serve a directory as and when I need it? So with that, I knocked together a simple .vbs script you can drop in your “Send To” context menu folder (C:\Users\[YOUR_USERNAME]\AppData\Roaming\Microsoft\Windows\SendTo\), which will launch an IIS Express instance with it’s path attribute set to the “Sent” folders path, and it’s port attribute set to a random number between 1024 and 9999. The script will also then launch the generated URL in your default web browser. When you want to shutdown the web server, you can stop it using the IIS Express System Tray context menu.

If you’d like to try this yourself, just drop the following into a .vbs file and save it to your “Send To” folder.

' Init randomization
Randomize

' Set random port number
Dim port
port = Int(Rnd() * 8974) + 1025

' Launch IIS Express / Browser
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run """%programfiles%\iis express\iisexpress"" /path:""" & WScript.Arguments.Item(0) & """ /port:" & CStr(port) & " /systray:true", 0, False
WshShell.Run "http://localhost:" & CStr(port), 9, False
Set WshShell = Nothing

UPDATE – March 15, 2011 12:25

As highlighted by Lee Kelleher in the comments, if you are using a 64bit OS, then please make sure to change %programfiles% to %programfiles(x86)%

Follow

Get every new post delivered to your Inbox.