Julian Jelfs’ Blog

LESS (or SASS) can be MORE

Posted in Uncategorized by julianjelfs on April 27, 2013

When converting a conventional CSS file to SASS the other day it occurred to me that it could actually encourage less efficient CSS by creating the illusion of reuse. This seems specifically to be true when using mixins. Suppose I have several different kinds of icon and they just differ by background image, then I would naturally consider using a mixin to accomplish that like this:

@mixin icon($img) {
    background-image: url("#{$img}");
    background-repeat:no-repeat;
    background-position:center center;
    height:20px;
}

.error-icon
{
    @include icon("/images/error.png");
}

.save-icon
{
    @include icon("/images/save.png");
}

This gives me the illusion that I have reused that section of CSS. But really when you look at the output CSS you can see that the content of the mixin is duplicated:

.error-icon
{
    background-image: url("/images/error.png");
    background-repeat:no-repeat;
    background-position:center center;
    height:20px;
}

.save-icon
{
    background-image: url("/images/save.png");
    background-repeat:no-repeat;
    background-position:center center;
    height:20px;
}

In fact it is more efficient to create a separate CSS class for the common attributes and one for the icon specific background image like this:

.icon 
{
    background-repeat:no-repeat;
    background-position:center center;
    height:20px;
}

.error-icon
{
    background-image: url("/images/error.png");
}

.save-icon
{
    background-image: url("/images/save.png");
}

The moral of the story is not to forget that the important thing is is what actually gets generated, not just how cool your pre-processed file looks.

Advertisements
Tagged with: , ,

Dynamic validation with FluentValidation and MVC 4

Posted in MVC, Uncategorized by julianjelfs on March 7, 2013

FluentValidation is a very nice way to perform custom validations in .Net and integrating it into the built in validation system used in MVC 4 is relatively straightforward. But it is not immediately clear how you go about performing dynamic validation on a MVC model based on the state of that model. If you are implementing a workflow, for example, this is something that you may well want to do. For example, let’s say that you have the following model:

   1: public class Customer

   2: {

   3:     public int Id {get;set;}

   4:     public string Name {get;set;}

   5:     public string Email {get;set;}

   6:     public string Status {get;set;

   7: }

Suppose that you would like the Name to be mandatory if the Status property is set to “New”, but if the Status property is set to “Existing” you would like the Name and the Email to be mandatory. The standard integration of FluentValidation with MVC 4 allows you to correlate a controller action’s input parameter with a validator, by decorating the model type with a Validator attribute. It will then call the Validate method on that validator at the right point by plugging in to the MVC model validation infrastructure. So far this will only allow you to run the same validation regardless of context. The validation can be further customised by adding a CustomizeValidator attribute to the model parameter on your controller action.

The CustomizeValidator attribute allows you to override the properties to validate, the rule sets to validate and an interceptor to call before and after MVC validation takes place. To take advantage of model state to apply specific validation we first need to capture our different scenarios as rule sets in the validator as follows:

   1: public class CustomerValidator : AbstractValidator

   2: {

   3:     public CustomerValidator()

   4:     {

   5:             RuleSet("New", () => {

   6:             RuleFor(c => c.Name).NotEmpty();

   7:         });

   8:

   9:         RuleSet("Existing", () => {

  10:             RuleFor(c => c.Name).NotEmpty();

  11:             RuleFor(c => c.Email).NotEmpty();

  12:         });

  13:     }

  14: }

then attribute the model class with this validator:

   1: [Validator(typeof(CustomerValidator))]

   2: public class Customer ....

Create a validation interceptor to specify the correct selector on the ValidationContext based on the model state like this:

   1: public class CustomerValidatorInterceptor : IValidatorInterceptor

   2: {

   3:     public ValidationContext BeforeMvcValidation(ControllerContext controllerContext,

   4:                 ValidationContext validationContext)

   5:     {

   6:         if (validationContext.InstanceToValidate is Customer)

   7:         {

   8:             var customer = (Customer) validationContext.InstanceToValidate;

   9:             return new ValidationContext(customer, validationContext.PropertyChain,

  10:                 new RulesetValidatorSelector(customer.Status));

  11:         }

  12:         return validationContext;

  13:     }

  14:

  15:     public ValidationResult AfterMvcValidation(ControllerContext controllerContext,

  16:                 ValidationContext validationContext,

  17:                 ValidationResult result)

  18:     {

  19:         return result;

  20:     }

  21: }

  22:

and finally add this interceptor to your controller action via the CustomizeValidation attribute like this:

   1: public ViewResult UpdateCustomer(

   2:     [CustomizeValidator(Interceptor = typeof(CustomerValidatorInterceptor))]Customer model)

   3: {

   4:     ...

   5: }

And now we will execute the correct RuleSet according to the state of the Customer object and it will all integrate with the MVC validation infrastructure nicely.

Galloway marathon calculator app

Posted in Uncategorized by julianjelfs on February 6, 2013

…and as a follow up to my last post, I also wanted an easy way to calculate what my overall time over 50 miles might be which is a slightly annoying calculation when you’re running for 4 minutes at speed x then walking for 45 seconds at speed y and you have z checkpoints and you spend a certain amount of time in those checkpoints. So I also wrote a calculator to capture all of those variables to help me fine tune my strategy. 

Image

Source is also available on GitHub.

Of course in the end my strategy was just to keep going and try not to be sick, but it was nice to have the app anyway.

Android Lap Timer app

Posted in Uncategorized by julianjelfs on February 6, 2013

When I was training for my first ultra-marathon, I used the Galloway run-walk marathon training method, where you run for a bit and then walk for a bit (read about it here). I had been using 5 minutes running and then 1 minute walking and then later I moved to 4 minutes running and 45 seconds walking. 

I had programmed an advanced workout into my Garmin 405 to beep at me and help me maintain this cycle. On my 25+ mile training runs I realised that the Garmin (which I hate for many other reasons also) was not going to last the course before the battery died. I didn’t want to be clock watching while running this thing so I decided to create a (very) simple Android app. I just enter the run time in seconds and the walk time in seconds and hit start and it beeps and vibrates at the end of each cycle. 

Image

On many occasions when the Garmin was having one of its hissy fits this simple Android app came to the rescue and it performed beautifully on the day of the race too. 

For the 0.000001% of the population that run for more than 6 hours, use a run-walk approach to  training, are on the exact version of Android that I am and know how to build it – you can find the source on my GitHub!

Tagged with: ,

Who’d have thought it

Posted in Uncategorized by julianjelfs on July 16, 2010

Flock is actually pretty cool

Cross-domain automatic iframe resizing

Posted in Uncategorized by julianjelfs on December 3, 2009

As we all know there are security restrictions when script from domain A tries manipulate content from domain B. This causes a lot of inconvenience. One example is automatic iframe resizing. It sounds simple on the face of it. When your iframe content loads you just need to tell the parent window what the content size is and then it can resize the iframe for you. The problem is that if the iframe content does not come from the same domain as the main page, you cannot do this. At least you cannot do this in the way you expect to.

This is a fairly well documented problem and the most common solution is to use the url fragment identifier hack. Basically this hack exploits the fact that any window or frame can set the location of any other window or frame (although perhaps counter intuitively it cannot read the location of a window from a different domain).

This trick can be used to accomplish cross-domain iframe resizing. Having googled this subject I found a good post on how to do this here. While the code in that post works well, I think it is quite verbose and in the end I reduced it to the following:

For each frame on the page, set the hash fragment of the frame’s src attribute to be the frame’s id:

<iframe id="myFrame"
    scrolling="no"
    frameborder="0"
    width="100%"
    src="whatever.aspx?name=val#myFrame">
</iframe>

In the main page add the following script to execute when the page starts up (I’m using jQuery here but you don’t have to):

window.setInterval(function(){
    var hash = window.location.hash.replace("#","");
    if(hash.length == 0)
        return;

    var pair = hash.split("=");
    $("#"+pair[0]).animate({height:pair[1]});
    window.location.hash = "";
}, 100);
and in each content page being loaded add the follow script to execute when the page starts up:
window.setInterval(function(){
    if(top == self)
        return;

    var bh = $("body").height();
    var wh = $(window).height();

    if  (Math.abs(bh - wh) > 10){
        var hash = self.location.hash.replace("#","");
        if(hash.length == 0)
            return;
        top.location.hash = hash + "=" + (bh + 10);
    }
}, 100);

What’s happening? Each content window is running a loop which detects if its window is either too big or too small and if it is, it writes a name value pair containing the id of the frame and the required height e.g. frameId=500 to the hash fragment of the main window’s url. It gets the frameId from its own hash fragment. This is allowed because we are simply writing to the hash, not trying to read. It will not cause a reload because we are only updating the hash fragment.

Meanwhile the main page is running a loop to monitor its own hash fragment looking for modifications made by the frames. When it finds a name value pair in its hash fragment it simply finds the corresponding frame and sets its height (animation an optional extra).

Obviously you can set the interval on the loops to whatever is appropriate.

ClientScriptManager.GetWebResourceUrl type parameter

Posted in Uncategorized by julianjelfs on November 22, 2009

So this method returns a URL reference to a resource embedded in an assembly. No problem with that – useful. The thing that annoys me about this is the first parameter. It is a parameter of type “Type” and according to the documentation describes the type of the resource. This is obviously nonsense. If I am embedding a javascript file in an assembly what type is that? typeof(javascript file) ? In the remarks section on the documentation we get a bit more information:

“You specify the type based on the object that will be accessing the resource”

Which seems again to be meaningless. What does this mean for a script file? It turns out that the only thing you have to make sure of really is that the type you specify belongs to the same assembly that the resource is embedded in otherwise it will not work. This is the one important point that the documentation does not clearly tell you.

Command-Q without all the other crap

Posted in Uncategorized by julianjelfs on September 18, 2009

Background – I have an iMac, I’ve had it for about a year. Love the shiny hardware, hate the software. The beautiful thing is that all the evangelising in the world cannot make me wrong about this – I HATE MY MAC.

So I reduced the size of my OS X partition to the minimum and installed Windows  7 on it and the relief is enormous.

The one thing I missed was the Command-Q shortcut to close the active window (yes honestly this is the only thing I missed). In windows the shortcut is an irritatingly wrist twisting Alt-F4.

Then I found autohotkey which is a very nice open source tool for scripting hotkeys (and it seems a lot more besides).

All I have to do is drop a script like this:

#q::Send !{F4}

into my start up folder and I have all of the benefits of Mac OS with none of the tedious smug cruft. 

Another reason why the ScriptManager sucks …

Posted in Uncategorized by julianjelfs on August 1, 2009

There is a property on the ScriptManager called LoadScriptsBeforeUI. I have seen this little known property touted as a way to accomplish deferred script loading using the ScriptManager. However, it is not. To make sure that the UI is not blocked by your scripts you can use the defer attribute on the script tag. This is a good idea because  it means that the visible UI appears quicker which improves perceived performance. Setting aside the plainly ridiculous fact that this setting applies to the script manager as a whole rather than to individual script references – setting LoadScriptsBeforeUI to false does not add the defer attribute to the scripts, it simply moves them after any UI mark-up. This is good but it is not equivalent to the defer attribute which will also allow scripts to be downloaded in parallel (while maintaining execution order) whereas just moving them will not. So there must be some way to add the defer attribute to a script source using the ScriptManager mustn’t there? Nope. Perhaps because the defer attribute is perceived to be an IE only hack, but it is actually part of the html 4 spec though mysteriously not implemented by the other main browsers, which makes a change. So annoying. 

jquery hotkeys follow up

Posted in Uncategorized by julianjelfs on July 11, 2009

And I’m pleased to say there is a patched version of the excellent hotkeys plugin now available here. That’s what I call service.