Using Google Chrome Frame with Sitecore CMS

Chrome Frame allows old none HTML5 browsers to still use your HTML5 site.
October 21 2011

Basics

Chrome Frame from Google is a plugin for IE that contains a mini version of the Chrome browser, allowing users of older IE browsers to see new HTML5/CSS sites in all their glory.  With Chrome Frames enabled for your site, IE users will be prompted to install Chrome Frames.  They can by default choose to not install Chrome Frames and continue viewing the site using the Trident rendering engine in IE.  Using Chrome Frames will not only improve the look of your site in IE, it will probably also improve it's performance.

The quickest and easiest way to get Chrome Frames working with your site is to include the correct meta tag in your header

<meta http-equiv="X-UA-Compatible" content="chrome=1" />

will turn on Chrome Frames for all versions of IE.  To enable for specific versions, change the chrome value to IE8 which will do all IE versions up to and including 8 or IE7 which will do all IE versions up to and including 7 etc.

You can then use either Javascript or server-side User-Agent sniffing.  To use server-side, look for the string 'chromeframe’ in the user-agent header and then include the meta element above in the header.

The details of a basic implementation can be found at the project home

 

Providing a friendly page consistent with site design

The basic implementation is all well and good but you’ll probably want to present a user friendly page to IE users explaining that your site requires a HTML5 compliant browser, and how to install Chrome Frame. In my case, the site I’m working on required that users that can’t support HTML5 be not allowed to use the site at all.  This makes overall site development much easier, as I don’t have to code for HTML5 as well as older HTML4 that lacks the semantic mark-up in HTML5 as well as the CSS3 goodness we’ve all come love, rounded borders and shadows.

First step is to create the HTML page for the warning page (/browser-warning in my case).  I took a copy of my site’s default Browser layout and modified HTML5 elements to use HTML4 elements, basically I replaced section, header, footer, and nav with div’s.

I also included an IE stylesheet that included the styles for my divs that replaced the HTML5 elements.

Next, because the Chrome Frame will only appear if the browser is IE , I restricted inclusion of the styles and javascript to only IE.

<!--[if IE]>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js"></script>    
<style>        
    .chromeFrameInstallDefaultStyle { 
        position:relative;                        
        left: 0;
        top: 0;
        margin: 20px 0 0 0;   
        height: 730px;    
    }
</style>
<script type="text/javascript">
    $(document).ready(function() {            
        CFInstall.check({ 
            mode: "inline", 
            node: "gcfprompt",
            destination: "/"
        });    
                    
        $("iframe").removeAttr("frameborder");                 
        $("iframe").attr("frameBorder", 0);            
        $("iframe").attr("scrolling","no");            
    });
</script>   
<![endif]—>

I then configure the options for the Chrome Installer.

mode: "inline", 
node: "gcfprompt",
destination: "/"

I want it to display inline, in the div with id “gfcprompt”.  When the installation is complete I want the user to be directed back to the home page.  I’ve also included some code to remove the frame borders from the Chrome Frame installation iframe.

My html body looks like the following

<body>
<div class="container_24">
    <div id="heading">   
        <div class="grid_6">
            <a href="/"><img src="/images/logo.png" /></a>
        </div>            
        <div class="clear"></div>
    </div>
    <sc:placeholder ID="headerPlaceHolder" runat="server" key="header"></sc:placeholder>                                        
    <form method="post" runat="server" id="mainform">                
        <div id="body" class="grid_24">                                                                         
            <div class="nav"><sc:xslfile ID="Xslfile1" runat="server" renderingid="{EF44E8F3-FD7D-4F9C-B6B1-DA24353C74EA}" path="/xsl/Breadcrumb.xslt"></sc:xslfile></div>
            <sc:placeholder ID="bodyPlaceHolder" runat="server" key="body" />                
            <!--[if IE]>
            <div id="gcfprompt"></div>
            <![endif]-->                
        </div>            
    </form>
    <div id="footer" class="clearfix">            
        <sc:Sublayout ID="Sublayout2" runat="server" path="/layouts/footer details.ascx" />            
    </div>
</div>
</body>

You can see I’m providing the ability for site authors to modify the friendly message that gets displayed.

 

Capturing all requests from an IE browser

Now the tricky part.  I need to capture all requests from IE browsers.  Sitecore CMS uses Devices to simulate different browsers, so one option is to create a new device for IE and assign that device to my warning page.  The problem is I need to detect no matter what page, so it doesn’t quite fit.

What I need to do is use a HttpModule to intercept the request, inspect the User-Agent header or Browser and redirect to my warning page.  In Sitecore this is done by hooking into the appropriate pipeline.  In my case, I need to hook into the httpRequestBegin pipeline.

public class ChromeFrameProcessor : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        var warningItemPath = Settings.GetSetting("IEWarningUrl", "/sitecore/content/home/browser warning");

        // Need to allow access to /sitecore/ via IE.      
        if (Context.Database == null)
            return;
        if (Context.Database.Name != "web")
            return;

        // We want to stop browsers that are non-HTML5 compliant and redirect to the IEWarning page.                                 
        if (args.Context.Request.Browser.Browser == "IE")
        {
            var warningItem = GetItemFromItemPath(warningItemPath);
            var warningItemUrl = LinkManager.GetItemUrl(warningItem);
            if (warningItemUrl != args.Context.Request.Url.AbsoluteUri)
                WebUtil.Redirect(warningItemUrl);
        }
    }

    public static Item GetItemFromItemPath(string itemPath)
    {
        Item temp = null;
        using (new Sitecore.SecurityModel.SecurityDisabler()) {
            temp = Context.Database.GetItem(itemPath);
        }

        return temp;
    }

    public static Item GetItemFromUrl2(string url)
    {
        string referring_item_path = null;

        if (Uri.IsWellFormedUriString(url, UriKind.Relative))
            url = Sitecore.Web.WebUtil.GetFullUrl(url);
        if (Uri.IsWellFormedUriString(url, UriKind.Absolute)) {
            var uri = new Uri(url);
            if (uri.AbsolutePath.StartsWith("/sitecore/"))
                referring_item_path = uri.AbsolutePath;
            else
                referring_item_path = Sitecore.Context.Site.StartPath + uri.AbsolutePath;
        }
        referring_item_path = Regex.Replace(referring_item_path, @"(?:\.aspx|\.ashx)", "/");
        Item retVal = null;
        using (new Sitecore.SecurityModel.SecurityDisabler()) {
            retVal = Sitecore.Context.Database.GetItem(referring_item_path);
        }

        return retVal;            
    }
}

The first step is to get the item to redirect to if IE is used.  This is kept as a setting in the web.config file. Next up we need to inspect the request to determine if we need to show the warning page.

 if (args.Context.Request.Browser.Browser == "IE")

We only need to check for IE here.  If Chrome Frame is installed, the user-agent and browser will be Apple / Webkit and not IE / MSIE.  Once we know we need to do a redirect we can retrieve the CMS item for the warning page and extract it’s Url, using LinkManager. Then it’s just a matter of redirecting to that URL.

if (warningItemUrl != args.Context.Request.Url.AbsoluteUri)
    WebUtil.Redirect(warningItemUrl);

If we don't put the check for Url in here we'll get an infinite loop as the redirect causes another browser check.

Post a comment

comments powered by Disqus