MonthSeptember 2013

Manually setting the navigator.geolocation

Firefox is probably my most favorite browser. Mostly because of all the great extensions.
Every web developer should know Firebug. It really makes my life so much easier. I use it a lot for:

  • Examining and manipulating dom elements
  • Run JavaScript
  • Inspect ajax calls (request and response)
  • Resource manager (see what’s being loaded, cached, etc)

But this post is not about Firebug.
Another great extension is Geolocator.
This tool allows you to change your geolocation. Let me first explain what the geolocation is.
The geolocation is your current position provided by your browser.
It can be requested via JavaScript. This is one of the new features described in the HTML5 standard.

navigator.geolocation

The geolocation object has three methods:

  • getCurrentPosition
  • watchPosition
  • clearWatch

getCurrentPosition gives you the current position, this method accepts two arguments, the first argument is the method called when the position is successfully retrieved. The second argument is the method called when the position could not be retrieved. This could also be because the user has denied location sharing.


function onSuccess(position)
{
    var lat = position.coords.latitude;
    var long = position.coords.longitude;
}

function onError()
{
    // handle failed retrieving of location.
}

navigator.geolocation.getCurrentPosition(onSuccess, onError);

The watchPosition method also returns the current position, but continues to return updated positions.
The clearWatch method stops the watchPosition method.

Not all browsers support html5, so not all browsers support geolocation. You first need to check if geolocation is available.


if (navigator.geolocation) {
    // do location based stuff here
}

I was working on a location based application and wanted to test the applications with different positions, and that’s when I came across the Geolocator extension.
I created several locations and when I reloaded the page, Firefox showed a dropdownlist with my locations so I could easily switch my position.

Locations can be added by going to the Add-ons menu and select the Geolocator options. Search for your location, leave the search screen (tweak settings a bit if you’d like) and click the save button.

Mobile devices, detection and views in .Net MVC

Mobile is hot, and will probably only get hotter. Sites need to be viewable on any kind of devices, so mobile detection is a hot issue.

Headers

But how do we detect mobile devices?

Every http request send to a page or website contains headers. These headers give us information about the sender. A nice tool to intercept a request and check the headers is fiddler. I have been using this tool for some years now, and I gained a lot of knowledge about requests and responses.


GET http://vicreative.nl/ HTTP/1.1
Host: vicreative.nl
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4

This is an example of a request to my website. This request is sent by Chrome.

The header we are looking for is the User-Agent. This header gives us information about the indentity of the browser who send the request. In above example, you can see that the request is send with a Chrome browser. This header will also tell us when the request is send by a mobile browser. I used a mobile device emulator to fake a mobile request:

GET http://www.vicreative.nl/ HTTP/1.1
User-Agent: Opera/9.80 (Android 2.3.7; Linux; Opera Mobi/46154) Presto/2.11.355 Version/12.10
Host: www.vicreative.nl
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, multipart/mixed, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Device-Stock-UA: Opera Mobile Emulator (no stock UA available)

Another header to keep in mind is the following:


X-Requested-With: XMLHttpRequest

This header information tells us that this is an ajax request. This is also used to determine the IsAjaxRequest property in a MVC controller.

So many devices

Now that we know that every device and browser sends its own User-agent header, you will probably think that it’s impossible to know all devices and browsers and operation systems. Well, you’re right.

I think that’s why the mobile device detection of Microsoft does not work so great. They just can’t update it enough to make it work for all devices.

So do not use HttpCapabilitiesBase.IsMobileDevice. It will only work if you override it and set the correct value.

There is a NuGet package which contains many devices and is updated regularly: 51 degrees.mobi

It also comes with a config, which allows you to set actions for mobile devices, like redirects.

Setting Mobile context

Whether a browser is mobile, can be manually overridden:

HttpContext.SetOverriddenBrowser(this.Request.Browser.IsMobileDevice
                                        ? BrowserOverride.Mobile
                                        : BrowserOverride.Desktop);

The 51 degrees framework will automatically do that, so you don’t really have to do this, but it can come in handy when you want to force it for some reason.

The Browser object has a lot more useful properties for determining which view to display, for instance the property Platform.

Creating Display Modes

As described above, the Browser object has a lot of information about the requested device.
At application start, we can create specific display modes for device types. For instance for Andriod devices:

DisplayModes.Modes.Insert(0, new DefaultDisplayMode("android")
{
    ContextCondition = Context => Context.Request.Browser.Platform == "Android"
});

Keep it clean and create a (static) class in the App_start folder called DisplayModes which contains a method RegisterDisplayModes which registers all display Modes:

public class DisplayModes
{
    public static void RegisterDisplayModes(DisplayModeProvider displayModeProvider)
    {
        displayModeProvider.Modes.Insert(0, new DefaultDisplayMode("android")
        {
            ContextCondition = Context => Context.Request.Browser.Platform == "Android"
        });
        .....
    }
}

Now call this method from the App_Start in the Global.asax file:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    DisplayModes.RegisterDisplayModes(DisplayModeProvider.Instance);
    .....
}

Now that we have registered a display mode for android, we can create android specific views.

Know that the first matching DisplayMode will be used. So the order of registration is very important! The mobile display mode is already registered.

Mobile views

Let’s make some mobile views now.

Creating views for devices is really simple, just add the name of the view before the extension of the file and the ViewEngine will automatically pick up the view for the correct device.

mobile-views

This example has a default Index view (index.cshtml) a mobile view for all mobile devices (Index.mobile.cshtml) and a android specific view (Index.android.cshtml).

This works for all views, including layouts, partial views, shared views, strongly typed views etc.

Because we registered the android DisplayMode at position 0 (first), all android devices will be provided with this view.  When the device is not an android device, but is a mobile device, the mobile view will be presented. For all other devices, the normal index view will be displayed.

Testing

It’s kinda difficult to test this from your developer laptop/pc, but there are many tools who simulate mobile devices. I like the mobile emulator from Opera. It has a lot of presets for mobile devices.

But there are many other emulators, even microsoft has its own.

Caching issues MVC 4

Now that you have created and published your mobile friendly application, you deploy it to your server and quickly check it on your mobile to see if it really works. And it works! Hooray!

Soon people start complaining about seeing strange views. It looks like a mixture of mobile and default views.

This is because of a bug in MVC4. The MVC team has released a patch for it, available here on NuGet.

Sitecore Multisite – Generating out of context links

Linking to items in other sites gives a lot of problems and strange urls.
Sitecore creates links by using the context of the current site.
There is an easy solution for creating out of context links, just switch the context!

First we need to find the site context of the item. The Sitecore.Configuration.Factory gives us access to all available sites.

var sites = Sitecore.Configuration.Factory.GetSiteInfoList();

Now we need to find the corresponding site.

SiteContext siteContext  = null;
foreach (var site in sites)
{
    var fullPath = string.Concat(site.RootPath + site.StartItem);
    if (item.Paths.FullPath.StartsWith(fullPath))
    {
        siteContext = new SiteContext(site);
        break;
    }
}

Now that we’ve got the site context, we can generate the correct url.

var urlOptions = LinkManager.GetDefaultUrlOptions();
urlOptions.Site = siteContext;
var url = LinkManager.GetItemUrl(item, urlOptions);

Automatic Bundling and Minification in .Net

One of the cool new features of .Net 4.5 is the bundling and minification feature. This can save so many requests to your server and saves you many kbs without creating a debug hell. The amount of data is getting more and more important, because of the mobile devices. People pay lots of money on data bundles for their mobile device, we better not waste it. It also decreases loading time!! Reasons enough to start using bundling and minification!

First thing you need to do is download and install the Microsoft ASP.NET Web  Optimization Framework nuget package.

The bundles are registered at application startup. This event is handled in the Application_Start method in the Global.asax. I always try to keep my Global.asax as clean as possible and split all registrations to seperate files in the App_Start folder. So I created a static BundleConfig class in the App_Start folder. This class contains one method, Register with the current Bundles as argument.

BundleConfig.RegisterBundles(BundleTable.Bundles);

BundleConfig

The BundleConfig class registers all JavaScript and Stylesheet bundles, Both Bundles can be added to the same BundleCollection, but both bundles have their own classes. JavaScript bundles are created by using the ScriptBundle class and Stylesheet Bundles are created by using the StyleBundle class.

bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));

This creates a JavaScript bundle named “~/bundles/jquery”  and includes one file, “~/Scripts/jquery-{version}.js”.  {version} is automatically resolved to the version of the jquery file in the scripts folder.

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

This creates a Stylesheet bundle names “~/content/css”” and contains one file “~/Content/site.css”. Adding more files is easy, just add more files to the include and separate them by a comma.

Adding bundles to a view

The only thing left to do, is adding the bundles to a view.

MVC (Razor)

@Scripts.Render("~/bundles/jquery")

WebForms

<%: Scripts.Render("~/bundles/jquery") %>

The above code renders the JavaScript bundle.

MVC (Razor)

@Styles.Render("~/Content/css")

WebForms

<%: Styles.Render("~/Content/css") %>

The above code renders the Stylesheet bundle.

All the requests to the bundles have a querystring parameter (v=CkVTG71m7lHB5jSCpyOSxbeCVJLIPag7u7NL4ykFenk1). This is to make sure that no old versions of this file are cached and retrieved.

Config files

Bundles can also be configured in config files. This allows you to make changes to your bundle without having to rebuild the project. It also allows frontend developers to easily include, remove or change files in a bundle without having to use visual studio.

An example of a bundle.config file

<?xml version="1.0" encoding="utf-8" ?>
<bundles version="1.0">
  <styleBundle path="~/Content/css">
    <include path="~/Content/Site.css" />
  </styleBundle>
</bundles>

Debugging

One of the biggest problems of minified files is debugging. It’s almost impossible to debug those files.

That’s when the best feature of this minification framework comes in place. When compilation is set to debug (in web.config), the files will not be minified, which makes it a lot easier to debug.

<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>

Creating custom bundle transforms

Custom transforms can be created by implementing the IBundleTransform interface.,

using System.Web.Optimization;

public class MyByndleTransform : IBundleTransform
{
   public void Process(BundleContext context, BundleResponse response)
   {
       // Process bundle tranform here
   }
}

The custom transform can now be added to the transform of a bundle

var myBundle = new Bundle("~/My/Files/To/Include");
lessBundle.Transforms.Add(new MyBundleTransform());

This bundle can now be added to the bundles collection in the BundleConfig file.

Why creating custom bundle transforms? Just think of less or coffeescript, or whatever bundle you want.

Simple CKEditor MVC EditorTemplate

I like using wysiwyg editors in my projects. It gives the user a lot of freedom in creating content.

There are a lot of wysiwyg editors, like TinyMCE, CKEditor, etc. I prefer CKEditor (formerly known as FCKEditor), because it is flexible, extendible, has a lot of plugins and creates clean (and customizable) html.

Most of my projects are MVC projects and I created a simple solution for using the CKEditor for content properties of my model.

First I mark the Properties in my model as html Properties by using the UIHint attribute.

public class Page
{
    public string Title { get; set; }

    public string SubTitle { get; set; }

    [UIHint("html")]
    public string Content { get; set; }
}

The UIHint attribute is part of the System.ComponentModel.DataAnotations namespace and can be combined with any other (MVC) attribute.

Now we need to create a view for this model:

@model MvcApplication1.Models.Page

<h2>Create new Page</h2>

<div>
    @Html.EditorForModel()
</div>

This will render an input for every property in the model. In this case, three inputs of type texy are rendered, because the type of the three properties in the Page model are strings and the application does not know how to handle the “html” value in the UIHint attribute of the Content Property.

By calling Html.EditorForModel all properties in the provided model are rendered. The attributes influence the rendering of the properties. The UIHint attribute lets you change which template is used for rendering this property. MVC searches for templates in the EditorTemplates folder. It searches in the controller folder for an EditorTemplates folder. When this folder is not found, it searches in the Shared folder for an EditorTemplates folder. When no folder is found, it will use the default template for the type of this property. When an EditorTempaltes folder is found, it will look for an html.csharp file. This is because of the value in the UIHint attribute. I want to use the html editor for every controller, so I place the html.csharp file in the Shared/EditorTemplates folder. It is also possible to override any default template, so you can make your own template for strings by creating a string.cshtml file and place it in the EditorTemplates.

When calling Html.DisplayForModel (or Html.DisplayFor), it searches in the DisplayTemplates folder. This has the same fallback scenario as described above for EditorTemplates.

My html.csharp file contains the following code:


@model String

@Html.TextArea("", Model, new { @class = "htmleditor" })

<script type="text/javascript">
    $(document).ready(function () {
        var id = "@ViewData.TemplateInfo.HtmlFieldPrefix";
        var instance = CKEDITOR.instances[id];
        if (instance) {
            delete CKEDITOR.instances[id];
        }
        $("#" + id).ckeditor();
    });
</script>

This creates a new instance of the CKEditor and deletes the old instance if exists.

Sitecore’s sublayout datasource, brilliant! Or maybe not?

One of the strengths of Sitecore is the DMS (Digital Marketing System). DMS collects user information and allows you to personalize the website based on the user’s profile.

One of the possible personalizations is changing the content of a sublayout by changing its datasource.

This sounds great, but sitecore made one big design flaw!

The items in the datasource are not stored by ID, but by the selected items path! This means that changing one of the item names in the tree of the selected item (or the selected item name itself) will break the datasource. Moving the item will also break the datasoure. Beware of that!!!

Sitecore announced to fix this in a future version.

I’m also not very happy about the way you have to retrieve the datasource item:

Item item;
string datasource = ((Sitecore.Web.UI.WebControls.Sublayout)this.Parent).DataSource;
if (!string.IsNullOrEmpty(datasource) {
    item = Sitecore.Context.Database.SelectSingleItem(datasource);
}