<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Belfry Images &#187; Tutorials</title>
	<atom:link href="http://blog.belfryimages.com.au/category/tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.belfryimages.com.au</link>
	<description>Ben Scott's personal blog</description>
	<lastBuildDate>Fri, 20 Aug 2010 22:31:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Mercurial: Undoing an uncommitted merge</title>
		<link>http://blog.belfryimages.com.au/2010/07/12/mercurial-undoing-an-uncommitted-merge/</link>
		<comments>http://blog.belfryimages.com.au/2010/07/12/mercurial-undoing-an-uncommitted-merge/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 04:10:56 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=314</guid>
		<description><![CDATA[I&#8217;ve moved from Subversion to Mercurial at work to get past some merge problems SVN was giving me. After a few teething problems everything is working out fantastic. I&#8217;m also mainly using the command line rather than a GUI front end which is surprisingly efficient. I just did a merge to a stable branch then [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve moved from Subversion to Mercurial at work to get past some merge problems SVN was giving me. After a few teething problems everything is working out fantastic. I&#8217;m also mainly using the command line rather than a GUI front end which is surprisingly efficient.</p>
<p>I just did a merge to a stable branch then realised I had forgotten a change that really should be done on the branch I was merging from (just a version number update). Unfortunately you can&#8217;t seem to merge revisions over the top of an existing uncommitted merge so I needed to roll back the merge and start again. In Subversion I would just revert the changes, but Mercurial is a bit smarter about its merges.</p>
<p>To see the parents of the working copy, run <code>hg parents</code>. After doing the merge there should be two parents. There are two steps in rolling back the merge. Note the period (<code>.</code>) at the end of both of these commands:</p>
<pre class="brush: plain">
hg revert --all -r .
hg update -C -r .
</pre>
<p>Calling <code>hg parents</code> should now just show the original parent.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2010/07/12/mercurial-undoing-an-uncommitted-merge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Accessing anonymous object properties using reflection</title>
		<link>http://blog.belfryimages.com.au/2010/04/19/accessing-anonymous-object-properties-using-reflection/</link>
		<comments>http://blog.belfryimages.com.au/2010/04/19/accessing-anonymous-object-properties-using-reflection/#comments</comments>
		<pubDate>Sun, 18 Apr 2010 22:38:50 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=304</guid>
		<description><![CDATA[Anonymous objects are a way to create strongly typed objects without having to declare a class or struct in C# 3.5 and above. Declaring an anonymous object is easy: var breakfast = new { Cereal = "High fibre", Coffee = "Latte", Bacon = "Crispy" }; In the scope of the object&#8217;s declaration, accessing the properties [...]]]></description>
			<content:encoded><![CDATA[<p>Anonymous objects are a way to create strongly typed objects without having to declare a class or struct in C# 3.5 and above. Declaring an anonymous object is easy:</p>
<pre class="brush:c#">
var breakfast = new
{
    Cereal = "High fibre",
    Coffee = "Latte",
    Bacon = "Crispy"
};
</pre>
<p>In the scope of the object&#8217;s declaration, accessing the properties of <code>breakfast</code> is as simple as <code>breakfast.Cereal</code>. However accessing the properties outside of that scope is not as simple. Say we have an object <code>ben</code> with a method <code>Eat(object meal)</code>. Within <code>ben.Eat()</code> we can&#8217;t do something directly with <code>meal.Coffee</code> because <code>Coffee</code> isn&#8217;t known in <code>ben.Eat()</code>&#8216;s scope.</p>
<p>Getting a property value using reflection is pretty basic but takes a couple of steps. There are much more advanced uses of reflection that allow access to hidden properties, fields and methods, but picking public properties is probably the easiest case. The following method returns the value of a public property of an object. This could be used on an anonymous object, or on any other class of object.</p>
<pre class="brush:c#">
using System.Reflection;
...
object GetPropertyValue(object o, string propertyName)
{
    var prop = o.GetType().GetProperty(propertyName);
    if (prop == null) return null;
    return prop.GetValue(o, null);
}
...
var cereal = GetPropertyValue(breakfast, "Cereal");
Assert.That(cereal, Is.EqualTo("High fibre"));
</pre>
<p><code>prop</code> is a PropertyInfo object that lets the value of a property be retrieved via reflection. The same method can be used to get a dictionary of [property name, value] from an anonymous object:</p>
<p><code>prop</code> is a PropertyInfo object that lets the value of a property be retrieved via reflection. The same method can be used to get a dictionary of [property name, value] from an anonymous object:</p>
<pre class="brush:c#">
IDictionary&lt;string, object&gt; ObjectToDictionary(object o)
{
    var dict = o.GetType().GetProperties().ToDictionary(
        prop => prop.Name, prop => prop.GetValue(o, null)
            );
    return dict;
}
</pre>
<p>This sets up a dictionary where the key is the name of the property, and the value is (ahem) the value of the property:</p>
<pre class="brush:c#">
var breakfastDictionary = ObjectToDictionary(breakfast);
Assert.That(breakfastDictionary.Count, Is.EqualTo(3));
Assert.That(breakfastDictionary["Coffee"], Is.EqualTo("Latte"));
</pre>
<p>Using anonymous objects and reflection is a bit slower to execute than using strongly-typed objects, but once the methods are in place to access the properties, the savings in developer time can be great. Leaving more time for breakfast. Speaking of which, I&#8217;m late for work.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2010/04/19/accessing-anonymous-object-properties-using-reflection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Extension Methods in C#</title>
		<link>http://blog.belfryimages.com.au/2010/03/20/extension-methods-in-c/</link>
		<comments>http://blog.belfryimages.com.au/2010/03/20/extension-methods-in-c/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 03:22:43 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=299</guid>
		<description><![CDATA[This is pretty basic and has been around for a while but I always forget about it until it&#8217;s too late. From C# 3.0 onwards we&#8217;ve been able to declare methods that extend a class. There&#8217;s no magic, the method doesn&#8217;t actually get added to the class and can&#8217;t access the internals of the class, [...]]]></description>
			<content:encoded><![CDATA[<p>This is pretty basic and has been around for a while but I always forget about it until it&#8217;s too late. From C# 3.0 onwards we&#8217;ve been able to declare methods that extend a class. There&#8217;s no magic, the method doesn&#8217;t actually get added to the class and can&#8217;t access the internals of the class, it&#8217;s just a shorthand way of making a static call.</p>
<p>The extension method is declared in a static class:
<pre class="brush:c#">
public static class PimpMyStringExtension
{
    public static string Pimp(this string s)
    {
        return s + " is pimped out";
    }
}
</pre>
<p>Adding the <code>this</code> keyword to <code>Pimp</code>&#8216;s <code>string s</code> argument is what indicates that <code>Pimp</code> is an extension method to the <code>string</code> class. The <code>Pimp</code> method can now be called against any string:</p>
<pre class="brush:c#">
Assert.That("test".Pimp(), Is.EqualTo("test is pimped out"));
</pre>
<p>As long as the <code>PimpMyStringExtension</code> is accessible to the consuming code, the <code>String</code> gets the <code>Pimp()</code> method added. <code>"test".Pimp()</code> actually just calls the static method under the covers, which is actually still an option:</p>
<pre class="brush:c#">
Assert.That(PimpMyStringExtension.Pimp("test"), Is.EqualTo("test is pimped out"));
</pre>
<p>Extra arguments can be added to the extension method as well:</p>
<pre class="brush:c#">
 public static string Pimp(this string s, int i)
{
    return s + " has been pimped with " + i;
}
...
Assert.That("test".Pimp(7), Is.EqualTo("test has been pimped with 7"));
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2010/03/20/extension-methods-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Jeditable for inline editing</title>
		<link>http://blog.belfryimages.com.au/2010/02/04/using-jeditable-for-inline-editing/</link>
		<comments>http://blog.belfryimages.com.au/2010/02/04/using-jeditable-for-inline-editing/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 15:02:43 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Web design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=255</guid>
		<description><![CDATA[Using the Jeditable plugin for jQuery enables inline editing of a block of text. This makes it easy to take a static view and simply drop in editability. Say we start with the following HTML: &#60;label&#62;Name:&#60;/label&#62; &#60;span class=&#34;employeeName&#34;&#62;Ben Scott&#60;/span&#62;&#60;br/&#62; &#60;label&#62;Rating:&#60;/label&#62; &#60;span class=&#34;employeeRating&#34;&#62;Highly awesome&#60;/span&#62; We want to be able to edit the employeeName and employeeRating spans. [...]]]></description>
			<content:encoded><![CDATA[<p>Using the <a href="http://www.appelsiini.net/projects/jeditable">Jeditable</a> plugin for <a href="http://jquery.com/">jQuery</a> enables inline editing of a block of text. This makes it easy to take a static view and simply drop in editability. Say we start with the following HTML:</p>
<pre class="brush: html">
&lt;label&gt;Name:&lt;/label&gt; &lt;span class=&quot;employeeName&quot;&gt;Ben Scott&lt;/span&gt;&lt;br/&gt;
&lt;label&gt;Rating:&lt;/label&gt; &lt;span class=&quot;employeeRating&quot;&gt;Highly awesome&lt;/span&gt;
</pre>
<p>We want to be able to edit the <code>employeeName</code> and <code>employeeRating</code> spans. We need two actions (asssuming an MVC framework) to update the name and rating. The URLs might be something like <code>/employee/set_name/{id}</code> and <code>/employee/set_rating/{id}</code>. Each action should accept HTTP POST, take the new value in <code>$_REQUEST['new_value']</code> or similar, and return a HTTP status of 200 on success and 500 on failure, with the error message in the response. For example, using Slab (my PHP5 MVC framework, in development) the <code>set_name</code> action might be like this:</p>
<pre class="brush: php">
class EmployeeController extends AppController {
	function set_name($id) {
		$this-&gt;Employee-&gt;save(array(
			'id' =&gt; $id',
			'name' =&gt; $this-&gt;data['new_value']);
		));
		return $this-&gt;ajaxSuccess($this-&gt;data['new_value']);
	}
}
</pre>
<p>Slab catches uncaught exceptions and returns an AJAX failure with the exception message as the body of the response.</p>
<p>To hook up the fields to the actions, modify the HTML to include the URLs to the actions. While this means the markup has behavioural elements and isn&#8217;t purely presentational (and has a non-standard attribute), it makes the script a bit simpler and easy to move into a static .js file, and is a quick way to get a page working.</p>
<pre class="brush: html">
&lt;label&gt;Name:&lt;/label&gt; &lt;span class=&quot;employeeName&quot; editUrl=&quot;/employee/set_name/7&quot;&gt;Ben Scott&lt;/span&gt;&lt;br/&gt;
&lt;label&gt;Rating:&lt;/label&gt; &lt;span class=&quot;employeeRating&quot; editUrl=&quot;/employee/set_rating/7&quot;&gt;Highly awesome&lt;/span&gt;
</pre>
<p>Now for the script itself:</p>
<pre class="brush: javascript">
$(function(){
	$('.employeeName, .employeeRating').editable(
		function(value, settings) {
			return $.ajax({
				url: $(this).attr('editUrl'),
				data: { 'new_value': value },
				async: false,
				type: 'post'
			}).responseText;
		}, {
			indicator: 'Saving...',
			tooltip: 'Click to edit',
			onblur: 'submit'
		}
	);
});
</pre>
<p>The first argument is a function that returns the new value of the field. This is important when doing things like replacing line breaks with <code>&lt;br/&gt;</code> which we&#8217;re not worrying about, but it also gives us the ability to write our own AJAX code. By default Jeditable makes assumptions about how the update is done. The <code>async</code> option in the call to <code>$.ajax()</code> blocks until the call returns, and lets the function return the response of the AJAX call. The second argument are options to set some text to show while calling the update function, the tooltip to display when hovering over the span, and to submit changes on blurring the input which makes it seem a bit more usable when there are multiple fields.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2010/02/04/using-jeditable-for-inline-editing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Injecting Rhino Mocks with Ninject</title>
		<link>http://blog.belfryimages.com.au/2010/01/20/injecting-rhino-mocks-with-ninject/</link>
		<comments>http://blog.belfryimages.com.au/2010/01/20/injecting-rhino-mocks-with-ninject/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 13:36:15 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=243</guid>
		<description><![CDATA[So today I hit a hat trick. I needed to test a class that had an injected dependency, and needed some functionality that I didn&#8217;t want to add to a fake and would rather isolate to the test. I needed to use a mocking framework. This is my first time using mocks (and only my [...]]]></description>
			<content:encoded><![CDATA[<p>So today I hit a <a href="http://en.wikipedia.org/wiki/Hat-trick">hat trick</a>. I needed to test a class that had an injected dependency, and needed some functionality that I didn&#8217;t want to add to a fake and would rather isolate to the test. I needed to use a mocking framework. This is my first time using mocks (and only my second week of dependency injection) so this may not use best practices, but this _is_ a blog after all.</p>
<p>I&#8217;m using <a href="http://github.com/enkari/ninject">Ninject 2</a> for dependency injection, <a href="http://www.nunit.org/index.php">NUnit 2.5.3</a> for unit testing, and <a href="http://www.ayende.com/projects/rhino-mocks.aspx">Rhino Mocks 3.6</a> for mocking. NUnit has a mocking framework built in but it doesn&#8217;t use strong typing, which I think was causing problems with Ninject.</p>
<p>What I&#8217;m really showing here is an example of how to inject a dynamically declared mock instead of a concrete fake. The fact that it is in the context of a test is actually irrelevant, but using mocks and fakes are obviously important in testing to reduce the complexity of the test.</p>
<p>Initially I&#8217;m using the default <code>ConcreteFoo</code> implementation of <code>IFoo</code> in the test. This test fails as intended:</p>
<pre class="brush: c#">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Ninject;
using NUnit.Framework;
using Rhino.Mocks;

namespace Trifecta
{
    public interface IFoo
    {
        string Name { get; }
    }
    public class ConcreteFoo : IFoo
    {
        public string Name { get { return &quot;You don't want to see me&quot;; } }
    }

    public class FooConsumer
    {
        [Inject] public IFoo Foo { get; set; }

        public FooConsumer() {}
    }

    [TestFixture]
    public class FooConsumerTestFixture
    {
        IKernel Kernel { get; set; }

        [SetUp]
        public void SetUp()
        {
            // This is the standard setup that will need to be overridden in the
            // test.
            Kernel = new StandardKernel();
            Kernel.Bind&lt;IFoo&gt;().To&lt;ConcreteFoo&gt;();
        }

        [Test]
        public void FooConsumerGetsTheFoo()
        {
            // This test depends on a specific behaviour in IFoo, but ConcreteFoo
            // is going disappoint right now.
            var fooConsumer = Kernel.Get&lt;FooConsumer&gt;();

            Assert.That(fooConsumer.Foo.Name, Is.EqualTo(&quot;The foo for you&quot;));
        }
    }
}
</pre>
<p>Settting up and binding the mock is all done in the test method. The mock <code>IFoo</code> instance is created, and the functionality that the test requires is added. IFoo is then bound to a delegate which returns the mock instance. The binding has a condition that causes the mock binding to be used rather than the <code>ConcreteFoo</code> binding, this seems to be easier then setting up the kernel from scratch for the test (possibly I&#8217;m just missing how to rebind).</p>
<pre class="brush: c#">
[Test]
public void FooConsumerGetsTheFoo()
{
		// Create a mock implementation of IFoo that has the behaviour the test requires
		var mocks = new MockRepository();
		var mockFoo = mocks.StrictMock&lt;IFoo&gt;();
		Expect.Call(mockFoo.Name).Return(&quot;The foo for you&quot;);
		mocks.ReplayAll();

		// Bind the mock when injecting IFoo into FooConsumer. This overrides the binding
		// created in SetUp()
		Kernel.Bind&lt;IFoo&gt;().ToMethod(context =&gt; mockFoo).WhenInjectedInto&lt;FooConsumer&gt;();

		// fooConsumer's Foo should now be the mock IFoo created above
		var fooConsumer = Kernel.Get&lt;FooConsumer&gt;();

		Assert.That(fooConsumer.Foo.Name, Is.EqualTo(&quot;The foo for you&quot;));
}
</pre>
<p>The test should now pass.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2010/01/20/injecting-rhino-mocks-with-ninject/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Form validation with jQuery</title>
		<link>http://blog.belfryimages.com.au/2009/12/09/form-validation-with-jquery/</link>
		<comments>http://blog.belfryimages.com.au/2009/12/09/form-validation-with-jquery/#comments</comments>
		<pubDate>Wed, 09 Dec 2009 09:40:50 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[Web design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=204</guid>
		<description><![CDATA[Every time I&#8217;ve implemented client-side form validation I&#8217;ve started from scratch and done it a little differently. Usually it devolves into a messy set of if statements and duplicated code. Here&#8217;s my latest method, which separates the validation rules from the processing. It uses jQuery because if you&#8217;re not using a Javascript library you should [...]]]></description>
			<content:encoded><![CDATA[<p>Every time I&#8217;ve implemented client-side form validation I&#8217;ve started from scratch and done it a little differently. Usually it devolves into a messy set of <code>if</code> statements and duplicated code. Here&#8217;s my latest method, which separates the validation rules from the processing. It uses <a href="http://jquery.com">jQuery</a> because if you&#8217;re not using a Javascript library <a href="http://www.codinghorror.com/blog/archives/001275.html">you should be</a>. This will only handle relatively simple validation cases.</p>
<p>So start with a form:</p>
<pre class="brush: html">
	&lt;form id="mailingListSubscription" action="subscribe.php"&gt;
		Name: &lt;input type="text" name="name" id="name" /&gt;&lt;br /&gt;
		Email: &lt;input type="text" name="email" id="email" /&gt;&lt;br /&gt;
		Phone: &lt;input type="text" name="phone" id="phone" /&gt;&lt;br /&gt;
		&lt;button type="submit"&gt;Subscribe&lt;/button&gt;
	&lt;/form&gt;
</pre>
<p>All fields are required, and I&#8217;m going to use some magical regex (found on the interthingy somewhere) to validate the email address. This script sets up the rules:</p>
<pre class="brush: javascript">
	var rules = [
		{ id: 'name', test: function(val) { return val != ''; }, msg: 'Please enter your name' },
		{ id: 'email', test: function(val) { return val.search(/^[^@]+@[^@]+.[a-z]{2,}$/i) != -1; }, msg: 'Please enter a valid email address' },
		{ id: 'phone', test: function(val) { return val != ''; }, msg: 'Please enter your phone number' }
	];
</pre>
<p>Each rule has the id of the form element being tested, a message that gets displayed on failing the rule, and a function that validates the value of the form element. I also could add multiple rules for the one input.</p>
<p>This script sets up the <code>submit</code> handler for the form, which does the validation using the array of rules set up above:</p>
<pre class="brush: javascript">
	$(function(){
		$('form#mailingListSubscription').submit(function(){
			for (var i = 0; i &lt; rules.length; i ++) {
				var rule = rules[i];
				var target = $('#'+rule.id);
				if (!rule.test(target.val())) {
					alert(rule.msg);
					target.focus();
					return false;
				}
			}
			return true;
		});
	});
</pre>
<p>On a test failing, the rule&#8217;s <code>msg</code> value is shown and the target of the test gets focus. This could be changed to something more user friendly like showing the message next to the target field.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2009/12/09/form-validation-with-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deleting items in a table with AJAX via JQuery</title>
		<link>http://blog.belfryimages.com.au/2009/11/29/deleting-items-in-a-table-with-ajax-via-jquery/</link>
		<comments>http://blog.belfryimages.com.au/2009/11/29/deleting-items-in-a-table-with-ajax-via-jquery/#comments</comments>
		<pubDate>Sun, 29 Nov 2009 05:04:42 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[HTML/XHTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web design]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=197</guid>
		<description><![CDATA[This is a very straight-forward tutorial on implementing a jQuery-driven &#8216;delete via AJAX&#8217; feature. Say we have a plain HTML table containing a list of items and a &#8216;Remove&#8217; link. I&#8217;m not going to describe the back-end, but I&#8217;m assuming something groovy like CakePHP or ASP.NET MVC. I&#8217;ve also assumed that the delete request always [...]]]></description>
			<content:encoded><![CDATA[<p>This is a very straight-forward tutorial on implementing a jQuery-driven &#8216;delete via AJAX&#8217; feature. Say we have a plain HTML table containing a list of items and a &#8216;Remove&#8217; link. I&#8217;m not going to describe the back-end, but I&#8217;m assuming something groovy like <a href="http://cakephp.org/">CakePHP</a> or <a href="http://www.asp.net/mvc/">ASP.NET MVC</a>. I&#8217;ve also assumed that the delete request always succeeds and never returns an error, which may not be the case. The script itself is a more than required but is my preferred method as I can extend the elements in the UI fairly easily.</p>
<pre class="brush: html">
	&lt;table&gt;
		&lt;tr&gt;&lt;td&gt;Chickpeas&lt;/td&gt;      &lt;td&gt;&lt;a href="/items/delete/1" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
		&lt;tr&gt;&lt;td&gt;Garlic&lt;/td&gt;         &lt;td&gt;&lt;a href="/items/delete/2" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
		&lt;tr&gt;&lt;td&gt;Olive oil&lt;/td&gt;      &lt;td&gt;&lt;a href="/items/delete/3" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
		&lt;tr&gt;&lt;td&gt;Tahini&lt;/td&gt;         &lt;td&gt;&lt;a href="/items/delete/4" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
		&lt;tr&gt;&lt;td&gt;Cumin&lt;/td&gt;          &lt;td&gt;&lt;a href="/items/delete/5" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
		&lt;tr&gt;&lt;td&gt;Lemon juice&lt;/td&gt;    &lt;td&gt;&lt;a href="/items/delete/6" class="delete"&gt;Delete&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
	&lt;/table&gt;
</pre>
<p>The delete hrefs (<code>/items/delete/XX</code>) link to an action or page that deletes the specified item and returns a HTTP status of 200 (OK). If the action just redirected to the current page then this table should work as it stands, which is probably a good way to check that everthing works as expected without involving AJAX features. If you just want to set up the client side without implementing any server-side code, create the following in delete_test.php and use it for the delete links:</p>
<pre class="brush: php">
&lt;?php header('HTTP/1.1 200 OK'); ?&gt;
</pre>
<p>Make sure that jQuery 1.3+ has been included in the page and add the following:</p>
<pre class="brush: javascript">
&lt;script type="text/javascript"&gt;
$(function(){
	var ui = {
		init: function(){
			$('a.delete').live('click', ui.delete_click);
		},

		delete_click: function(){
			link = this;
			$.get(link.href, function(data, status) {
				$(link).parents('tr').remove();
			});
			return false;
		}
	};

	ui.init();
});
&lt;/script&gt;
</pre>
<p>Very basic stuff but it works. It could be jazzed up by fading out the items first or updating a status label. If there is a significant delay between calling the delete action and getting a response the user may not think anything has happened, so perhaps the delete link should change or be disabled.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2009/11/29/deleting-items-in-a-table-with-ajax-via-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Subversion on a USB stick</title>
		<link>http://blog.belfryimages.com.au/2009/09/27/subversion-on-a-usb-stick/</link>
		<comments>http://blog.belfryimages.com.au/2009/09/27/subversion-on-a-usb-stick/#comments</comments>
		<pubDate>Sun, 27 Sep 2009 08:07:10 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Version Control]]></category>

		<guid isPermaLink="false">http://blog.belfryimages.com.au/?p=154</guid>
		<description><![CDATA[I use Subversion for version control at work, so I wanted to use it for a couple of websites and projects that I play with at home. I&#8217;ve been thinking about buying a cheap server or NAS that I could set up but couldn&#8217;t justify the cost and electricity just for want of version control. [...]]]></description>
			<content:encoded><![CDATA[<p>I use <a href="http://subversion.tigris.org/">Subversion</a> for version control at work, so I wanted to use it for a couple of websites and projects that I play with at home. I&#8217;ve been thinking about buying a cheap server or NAS that I could set up but couldn&#8217;t justify the cost and electricity just for want of version control.</p>
<p>As it happens, my Subversion client of choice <a href="http://tortoisesvn.tigris.org/">TortoiseSVN</a> can create and access local Subversion repositories. Probably all SVN clients can do this, and this is just a feature of the system, but when I&#8217;m used to seeing the version control purely as a client/server configuration this was a bit of a surprise. TortoiseSVN integrates nicely with Windows Explorer which makes it extremely easy to work with. If I had to load a seperate SVN client just to commit changes I would most likely put it off and/or forget about it. TortoiseSVN makes working with Subversion so easy that it is the main reason I keep giving up on Linux for my development machines.</p>
<p>One of the attractions of version control is that the project is portable &#8211; I can check out (make a local copy of) a website on my home PC, make changes, commit the changes to the server, then update the site on my laptop, without having to worry about copying files (and having different versions of files in the one place). That requires the Subversion server to be accessible on both machines, and if I don&#8217;t happen to have internet access for any reason that may not be possible.</p>
<p>Setting up a repository on a USB stick gives me most of the benefits of the typical client/server setup. The biggest downside is a lack of backups, which is something that needs to be maintained on a server anyway, and should be worked around by making backups of the repositories on the USB stick. In any case even if the repository fails I still should have multiple working copies on various machines. Not ideal but at least the files won&#8217;t be lost.</p>
<p>So how to do this? First install TortoiseSVN. I&#8217;m going to assume familiarity with SVN, and with TortoiseSVN in particular.</p>
<p>On the USB stick, make a folder to store the repositories. I called my folder <code>svnrepos</code>. Inside that folder, make another folder for the first repository. This is the name of the repository so call it something sexy, like <code>bentest</code>. Right click the folder, go to TortoiseSVN, and Create repository here. Wheels will turn, and a message should appear saying the repository was created.</p>
<p>Now go to your development folder, or wherever you want to check out a working copy of the project. Right-click the development folder (eg <code>C:\Development\www</code>) and select SVN Checkout.</p>
<p>The URL of repository is the path to the local repository that you created, as a file URL. Mine is <code>file:///E:/svnrepos/bentest</code> (note there are <strong>three</strong> slashes after the file: part). The checkout directory is where the working copy will be created. It should be automatically filled in when editing the repository URL, but can be changed. Mine is <code>C:\Development\www\bentest</code>. Click OK and you should have revision 0 of the repository ready to create trunk, branch and tag folders and add content.</p>
<p>Version control. Distributed backups of your precious work. No reliance on internet access and access to private Subversion server. Beautiful.</p>
<p>I haven&#8217;t experimented with this so far but I suspect there may be issues if the USB drive comes up on another driver letter. The repository url will probably need to be changed in the working copy. That should be possible via the Relocate command in TortoiseSVN&#8217;s context menu.</p>
<p><em>UPDATE: Relocate is indeed the command to use. TortoiseSVN throws up a warning about corrupting your working copy, but as long as the path entered is the <strong>new path to the same place in the repository</strong> (eg from <code>file:///<strong>H</strong>:/svnrepos/bentest/trunk</code> to <code>file:///<strong>F</strong>:/svnrepos/bentest/trunk</code>) this is the best/only method.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2009/09/27/subversion-on-a-usb-stick/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Editing past log comments in Subversion</title>
		<link>http://blog.belfryimages.com.au/2008/03/18/editing-past-log-comments-in-subversion/</link>
		<comments>http://blog.belfryimages.com.au/2008/03/18/editing-past-log-comments-in-subversion/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 04:20:55 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://belfryimages.com.au/2008/03/18/editing-past-log-comments-in-subversion/</guid>
		<description><![CDATA[Subversion is my source version control software of choice, but it&#8217;s not immediately obvious how to edit the log comment of a past commit (such as after adding a particularly scathing remark that may not be a wise career move). A caveat is that you need to have administrator access to the Subversion repository. In [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://subversion.tigris.org/">Subversion</a> is my source version control software of choice, but it&#8217;s not immediately obvious how to <a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-repository-hooks.html">edit the log comment of a past commit</a> (such as after adding a particularly scathing remark that may not be a wise career move). A caveat is that you need to have administrator access to the Subversion repository.</p>
<p>In the repository directory (wherever you created the repository) is a <code>hooks</code> folder (on my system this is <code>H:\IT\svnrepos\pas\hooks</code>). This folder contains scripts that are called by Subversion when various events occur (hooks). The files that are created in a repository&#8217;s hooks folder by default are templates of hooks designed for Linux etc. On a Windows server they need to be created as batch files (*.bat) to be executed.</p>
<p>What you need to do is create a hook that will run prior to changing a revision property (such as a log comment) and let Subversion know that changing the comment is permitted. By default changing the log comment is disabled (obviously, or you wouldn&#8217;t be reading this). Make a new file in the hooks folder called <code>pre-revprop-change.bat</code> and write the following into it:</p>
<pre class="brush:text">
if &quot;%4&quot; == &quot;svn:log&quot; exit 0

echo Property '%4' cannot be changed &gt;&amp;2
exit 1
</pre>
<p><P>The <code>%4</code> argument contains which operation is being performed. If the operation is <code>svn:log</code> we indicate success, which is a return code of 0. Otherwise it prints an error and exits with a non-zero, which indicates an error (and that the operation shouldn&#8217;t be allowed). Once that is saved, you should be able to use your to Subversion client to <a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-showlog.html#tsvn-dug-showlog-4">edit the comment</a>. Be careful with what you do, as revision properties aren&#8217;t versioned, and you won&#8217;t be able to undo your changes. You should also probably rename <code>pre-revprop-change.bat</code> to <code>pre-revprop-change.bat.bak</code> once finished.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2008/03/18/editing-past-log-comments-in-subversion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Displaying Contacts in Microsoft Outlook Address Book</title>
		<link>http://blog.belfryimages.com.au/2007/12/04/displaying-contacts-in-microsoft-outlook-address-book/</link>
		<comments>http://blog.belfryimages.com.au/2007/12/04/displaying-contacts-in-microsoft-outlook-address-book/#comments</comments>
		<pubDate>Mon, 03 Dec 2007 23:46:34 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[OS]]></category>
		<category><![CDATA[Tech Support]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://belfryimages.com.au/2007/12/04/displaying-contacts-in-microsoft-outlook-address-book/</guid>
		<description><![CDATA[If you can&#8217;t get your contact list coming up in Outlook, here&#8217;s a how-to that works well. Two things to look out for are Outlook not closing properly (it may run as a notification button, open Task Manager and kill the Outlook process off just to make sure) which seems to stop the fix from [...]]]></description>
			<content:encoded><![CDATA[<p>If you can&#8217;t get your contact list coming up in Outlook, <a href="http://www.computing.net/howto/simple/addressbook/">here&#8217;s a how-to that works well</a>. Two things to look out for are Outlook not closing properly (it may run as a notification button, open Task Manager and kill the Outlook process off just to make sure) which seems to stop the fix from working, and the fact that right-clicking on the Outlook icon to get to mail settings doesn&#8217;t work if the Outlook icon is a shortcut (ie 99% of the time). To get into mail settings, open Control Panel then Mail once Outlook is shut down.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.belfryimages.com.au/2007/12/04/displaying-contacts-in-microsoft-outlook-address-book/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
