x First time here? Check out the FAQ
  • Avatar338posts468karma

    How to determine Mobile and Tablet and sending them to different alt templates. This is how to....

    Carlos started this topic March 7, 2011 @ 06:47

    We had been working on a project for a while weighing out options between mobile detection via Javascript, jQuery mobile, and 51degrees.mobi. 

    We went our own way. We found that 51degrees.mobi is a great platform BUT is limited by only sending the user to an alternate URL such as mobile.mysite.com or m.mysite.com or something like that.

    We have a HUGE site and did not want to create another URL but just added alternate templates to our URL.
    We also needed MULTIPLE alt templates such as:
    /tablet-home, /tablet-page, /tablet-listingpage, mobile-home, /mobile-page, /mobile-listingpage.
    These are all alternate templates that we created and added them to the doc type in order for the content author to choose the mobile or tablet template needed for the page.  This is easier on us since the structure of our site is not cohesive everywhere and some sections are audience specific so different templates are needed alternately from our general public audience.

    We ran into some issues with this. Mainly that Android devices all are determined (at the moment) as "mobile". No matter if is a tablet or not, all Android devices are mobile in the eyes of the User Agent detection.
    We wanted to do a few things Server Side and determining the Useragent is easy, it is the screen dimension that is not possible server side.  This is what we did.
    ALL of this is done in our Global/Master template.

    1. We used in template C# to determine the Useragent
    2. We used Javascript (client side) to determine the width of the screen being used by the Device, mainly for Android tablet devices.
    3. We created an UpdatePanel, put a hidden text field in our UpdatePanel and ran the text box at server. This will get populate the screen res value to our hidden text field and grab the text field value at the server and plug that in to make Android tablet work and swtich the Android tablets to our Tablet templates.

    I will try to explain a lot of this in comments below in our code. Again all of this is in our Global/Master TEMPLATE. Using C# in our template header as a <script runat=server>.  Thank you Umbraco for keeping this feature available in your templates.

    As follows:

    We put this C# in our Master template header:

    <script runat="server">
    /*
    We make our value that we get back from our hidden text box into an int and use that to just make it equal to our MaxScreenPadWidth.  This will get used below for our Android devices with res >= 1024.
    */
            private const int MaxScreenPadWidth = 1024;
            protected void Page_Load(object sender, EventArgs e)
            {
                int myResWidth = -1;
                if (!IsPostBack)
                {
                    if (Session["rWidth"] != null)
                    {
                        int intTry = -1;
                       
                        if(int.TryParse(Session["rWidth"].ToString(),out intTry))
                        {
                            myResWidth = intTry;
                        }
                    }
                }
                else
                {
                    int intTry = -1;

                    if (int.TryParse(resW.Value, out intTry))
                    {
                        myResWidth = intTry;
                    }
                   
                    Session["rWidth"] = myResWidth;
                }
               
    //We have to determine and initiate all of our possible devices via a Request.UserAgent.

                string strUserAgent = Request.UserAgent.ToLower();
                if (strUserAgent != null)
                {   
    /*
    We commented our the IsMobileDevices because it wrecked havoc with Android devices. Again, at the moment all Android devices are "mobile".
    We use a huge "OR" statement to target what we want. Mainly good new devices. The beauty about Android is it is all encompassing not just device specific like Apple products.
    */
               if (
                      //Request.Browser.IsMobileDevice == true ||
                        strUserAgent.Contains("iphone")
                       || strUserAgent.Contains("ipod")
                       || strUserAgent.Contains("android")
                      // || strUserAgent.Contains("mobile")
                       || strUserAgent.Contains("blackberry")
                       || strUserAgent.Contains("windows ce")
                       || strUserAgent.Contains("opera mini")
                       || strUserAgent.Contains("palm")
                      //|| strUserAgent.Contains("chrome")
                       || strUserAgent.Contains("ipad")
                        )
                    {
    /*
    If the user agent is iPad or an Android with res of 1024 or above we switch the user to the chosen property we stuck in our doc type.
    We use our const int from above and use that as our value below.
    Our properties we use for the alt templates are chosen by the Author and hey have to choose a Tablet and Mobile template.  We determine our URL and add the /tablet-templateName or /mobiletemplateName to the end of the URL
    */

       if (strUserAgent.Contains("ipad") || (strUserAgent.Contains("android") && myResWidth >= MaxScreenPadWidth))
                        {
                         
                      if (umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseTabletTemplate") != null)
                            {
                                Response.Redirect(HttpContext.Current.Request.Url.AbsoluteUri + "/" + umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseTabletTemplate").Value);
                            }
                        }
    /*
    Else if is not an iPad or or Android device with res of 1024 or above but IS still a mobile device go to our mobile alt template.  If it is a desktop browser it will completely ignore the Tablet and mobile if else stuff. Unless you determine it in the User agent string as you can see I did with Chrome.
    */
                        else
                        {
                      if (umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseMobileTemplate") != null)
                            {
                                Response.Redirect(HttpContext.Current.Request.Url.AbsoluteUri + "/" + umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseMobileTemplate").Value);
                            }
                        }
                    }
                } 
            }
             
        </script>

    We put this code (below) in our template. This is the hidden text field where our client side value is stored but invisible to the user. It MUST be in a form tag ran at server and it MUST have a Script Manager.

    <form id="mainForm" runat="server">
         <asp:ScriptManager ID="mSrptMngr" runat="server"></asp:ScriptManager>
                <div id="allContent">
                    <asp:ContentPlaceHolder ID="MainContentPlaceholder" runat="server">
                    </asp:ContentPlaceHolder>
                </div>
       <asp:UpdatePanel ID="myUpdatePanel" runat="server">
                   <ContentTemplate>
                      <input type=hidden name=resW id=resW runat=server />
                      <input type=hidden name=resH id=resH runat=server />     
                    </ContentTemplate>
        </asp:UpdatePanel>
    </form>

    We then put this code (below) just inside our closing </body> tag.

        <script type="text/javascript">
            document.getElementById('<%= resW.ClientID  %>').value = window.screen.width;
            document.getElementById('<%= resH.ClientID  %>').value = window.screen.height;
            __doPostBack('<%= myUpdatePanel.ClientID  %>', '');
        </script>

    This determines our screen size client side and sends our value to our hidden text box with then sends it to the server. We have the Javascript do a PostBack to post back our value. You need this because of the way ASP.net loads the page. I loads the serverside stuff first then client side stuff. So we had to have the client side JS post back our update panel to grab our value and send it to the server so we can grab it in our C# code.

    Again, we would have liked to use a more elegant solution such as 51degrees.mobi, but that was just TOO limited for our needs and the use of a Client side UserAgent request is great for us to target specific devices. The only drawback at the moment is keep up a list (if we choose to) of user agents, but we only plan on targeting a select few devices that have capabilities (Apple devices, Android phones, Android tablets, Blackberry, other devices that may catch up).  But for now this is works great for our site.

    Note: The template is still in our testing environment behind our Firewall.  The live version should be our in about a 2 weeks to 1 month Depending on my time table. I will post it when it is live but for now if you want to just check on our progress in 2 weeks or so our URL is http://www.dmns.org.

    Below is basically our template. I stripped out a bunch of stuff for ease of reading.

    <head id="head">
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script runat="server"> 
            private const int MaxScreenPadWidth = 1024;
       
            protected void Page_Load(object sender, EventArgs e)
            {
                int myResWidth = -1;
                if (!IsPostBack)
                {
                    if (Session["rWidth"] != null)
                    {
                        int intTry = -1;
                       
                        if(int.TryParse(Session["rWidth"].ToString(),out intTry))
                        {
                            myResWidth = intTry;
                        }
                    }
                }
                else
                {
                    int intTry = -1;

                    if (int.TryParse(resW.Value, out intTry))
                    {
                        myResWidth = intTry;
                    }
                   
                    Session["rWidth"] = myResWidth;
                }
               
                string strUserAgent = Request.UserAgent.ToLower();

                if (strUserAgent != null)
                {

                    if (
                      //Request.Browser.IsMobileDevice == true ||
                        strUserAgent.Contains("iphone")
                       || strUserAgent.Contains("ipod")
                       || strUserAgent.Contains("android")
                        // || strUserAgent.Contains("mobile")
                       || strUserAgent.Contains("blackberry")
                       || strUserAgent.Contains("windows ce")
                       || strUserAgent.Contains("opera mini")
                       || strUserAgent.Contains("palm")
                      //|| strUserAgent.Contains("chrome")
                       || strUserAgent.Contains("ipad")
                        )
                    {


       if (strUserAgent.Contains("ipad") || (strUserAgent.Contains("android") && myResWidth >= MaxScreenPadWidth))
                        {
                         
                      if (umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseTabletTemplate") != null)
                            {
                                Response.Redirect(HttpContext.Current.Request.Url.AbsoluteUri + "/" + umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseTabletTemplate").Value);
                            }
                        }
                        else
                        {
                      if (umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseMobileTemplate") != null)
                            {
                                Response.Redirect(HttpContext.Current.Request.Url.AbsoluteUri + "/" + umbraco.presentation.nodeFactory.Node.GetCurrent().GetProperty("chooseMobileTemplate").Value);
                            }
                        }
                    }
                }

            }
             
        </script>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>
            <asp:placeholder runat="server">
                    <umbraco:item field="browserTitle" useifempty="pageName" runat="server"></umbraco:item>
                    <umbraco:item field="siteName" inserttextbefore=" : " recursive="true" runat="server"></umbraco:item>
                </asp:placeholder>
        </title>
        <meta name='description' content='<umbraco:Item field="metaDescription" recursive="true" runat="server"></umbraco:Item>' />
        <meta name='keywords' content='<umbraco:Item field="metaKeywords" recursive="true" runat="server"></umbraco:Item>' />
        <meta name="robots" content="index,follow" />
        <link rel='index' title='Denver Museum of Nature & Science' href='http://www.dmns.org' />
        <link rel="stylesheet" type="text/css" href="/css/reset.css" />
        <asp:contentplaceholder id="HeaderPlaceholder" runat="server">
         </asp:contentplaceholder>
    </head>
    <body class="no-JS accessibility">
        <!--[if IE 6]>
          <div id="IE-BrowserWarning">
              <p><strong>PLEASE UPDATE YOUR BROWSER</strong><br />As part of our update process, the Denver Museum of Nature &amp; Science will no longer be supporting your browser, Internet Explorer 6. Please upgrade to a more modern and secure browser.</p>
              <a href="http://www.microsoft.com/upgrade/"><img src="/media/2253/IE8Logo.jpg" /></a>
              <a href="http://www.mozilla.com/en-US/firefox/personal.html" ><img src="/media/2251/FirefoxLogo.jpg" /></a>
              <a href="http://www.google.com/chrome"><img src="/media/2252/GoogleChromeLogo.jpg" /></a>
              <span id="CloseBtn">X</span>
          </div>
      <![endif]-->
        <div id="mainWrapper">
            <ul id="SkipToContainer">
                <li><a href="#allContent">Skip To Content</a></li>
                <li><a href="#mainNav">Skip To Navigation</a></li>
            </ul>
            <div id="Header">
                <h1 id="siteName">
                    <a href="/">
                        <umbraco:item runat="server" field="siteName" recursive="true" />
                    </a>
                </h1>
                <a href="/" title="Back to DMNS Homepage">
                <![if !IE 6]>
                    <img id="Logo" src="/imagesource" alt="Denver Museum of Nature &amp; Science" /></a>
                <![endif]>
                <!--[if IE 6]>
                <img id="Logo" src="/imagesource" alt="Denver Museum of Nature &amp; Science" /></a>
                <![endif]-->
                <div class="jq-checkpoints">
                    <a href="/ourlink" class="headerBuyTixBtn" title="Buy Tickets"></a>
                    <div class="jq-checkpointSubhead">
                        <p>
                            Buy Tickets to the Museum, Event and Memberships</p>
                    </div>
                </div>
                <!--jq-checkpoints-->
                <div id="addressHolderTop">
                    <h3>
                    Address &amp; Hours</h3>
                    2001 Colorado Blvd.<br />
                    Denver, CO 80205<br />
                    303.370.6000<br />
                    Museum open daily<br />
                    9 am - 5 pm
                </div>
                <umbraco:macro alias="MainDropMenu" runat="server"></umbraco:macro>
            </div>
            <form id="mainForm" runat="server">
            <asp:scriptmanager id="myScriptManager" runat="server"></asp:scriptmanager>
            <div id="allContent">
                <asp:contentplaceholder id="MainContentPlaceholder" runat="server">
                </asp:contentplaceholder>
            </div>
               <asp:updatepanel id="myUpdatePanel" runat="server">
                    <ContentTemplate>
                   <input type=hidden name=resW id=resW runat=server />    
                  </ContentTemplate>
                </asp:updatepanel>
            </form>
            <!--End All Content-->
            <div id="footer">
            </div>
        </div>
        <!--End Main Wrapper-->
        <script type="text/javascript">
            document.getElementById('<%= resW.ClientID  %>').value = window.screen.width;
            document.getElementById('<%= resH.ClientID  %>').value = window.screen.height;
            __doPostBack('<%= myUpdatePanel.ClientID  %>', '');
        </script>
    </body>
    </html>

     

    Any questions please let me know.

    If you have suggestions also please feel free to comment.

    Thanks.


  • Avatar338posts468karma
    Comment with ID: 68212
    Carlos posted this reply March 7, 2011 @ 07:20

    UMBRACO ADMINS:
    How come when I try to edit posts or my comments on these forums I get an XSLT error?


  • Avatar338posts468karma
    Comment with ID: 68927
    Carlos posted this reply March 11, 2011 @ 05:19

    If anyone knows how to do this a better way or how to do with similar solution where we can access the 51Degrees or WURFL stuff in the Umbraco Global template and the redirect to the template our Authors use would be very helpful.

    Thanks.


  • Avatar338posts468karma
    Comment with ID: 70197
    Carlos posted this reply March 21, 2011 @ 04:22

    BIG TIME EDIT.

    So I made my some edits to the code that differentiates between Android tablets and Android Mobile without any Javascript screen detection.

    Here you go, http://our.umbraco.org/forum/templating/templates-and-document-types/18616-Detecting-mobile-and-tablets


  • herman fraley posted this reply April 18, 2012 @ 01:04

    good blog really and good sharing

     software update


Please login or Sign up To post replies