Tuesday, 17 September 2013

Hiding links in Welcome Control in SharePoint 2013

Lately, I came across a requirement around hiding the "About Me" link in the welcome control dropdown. The simplest and quickest solution that seemed to me was to play some tricks using css.
Using firebug, I tried to analyse how OOB SharePoint Welcome Control menu renders. Below is the screenshot of how it works.


Now the game is simple. As you can see in the above screenshot, the menu is rendered as ul and li.
There are two dropdown items in the Welcome Menu - About Me link and the Sign Out link each as li tags inside the ul tag.


I did some manipulation with the css and boom the About Me link got hidden.


Now if you have a look at the welcome menu it has the About Me link hidden.  



This might not be the best solution to do it but very simple to do. Hope it helps !!!

Wednesday, 7 August 2013

Unexpected response from server. The status code of response is '0'. The status text of response is ''

Recently while working with ECMASCRIPT I came across an issue that stated "Unexpected response from server. The status code of response is '0'. The status text of response is ''. Now, I got this error in the error logger list which is a custom list that we created to log any exceptions that arise.
To my utter surprise, I was not able to reproduce the issue at my local environment as well as production site and no complaints of any broken functionality also came from the client. But randomly this error was getting logged in the logger list. This made me think as to what could be the cause of the issue. I tried various ways to reproduce this error and voila, I was able to get to this error when I navigated to some other page before the asynchronous call that my ecmascript code was making had completed. I tried this a couple of times and everytime I navigated to the other page before the call had completed, I got this error logged in the logger. This way I could understand as to why this happened.
After some more analysis, I found out that status code 0 comes when you make an ajax call and refresh the page or navigate to some different page without getting the ajax response. So for all my dear friends out there, if you ever come across this random weird error, then probably it is because your asynchronous call was cancelled before getting the response. Hope it gives some pointer.

Navigating to different URL from Desktop and Mobile View in SharePoint 2013

Recently, while incorporating device channels in SharePoint 2013 Online site, I came across a requirement where users were to be navigated to different pages for a particular menu item in the Top navigation. We were using Managed Metadata Navigation and the Top Navigation that was getting rendered was same for both desktop and mobile view. Since it was all dynamic so as per my understanding the option we had was to change this navigation at runtime on the fly. Out of various options that might be available for this, the simplest to me seemed to be dynamically change the URL using Jquery and CSS. I did some analysis as to how the navigation is getting rendered in the Mobile and what classes are getting attached and based on that came up with the following solution 




If you look at the above code snippet which I see for my mobile device channel, every menu item , irrespective of the first level of navigation or the second level of navigation, renders as an li tag with an anchor tag. The anchor tag is having class as level1 for First Level of navigation and level2 for Second Level of navigation. Now, we can play with level1 or level2 class based upon which level of navigation we want to change and hence achieve the desired functionality.

$(".level2:Contains('Menu Item Title')").each(function () {

                    var menuItem = $(this);
                    var parentItem = menuItem.closest("a");
                    parentItem.attr("href", "Desired Navigation Url");


});

Now, what the above code snippet does is that it checks for all the menu items where the title exists that I need to change and for that menu item, it changes the href attribute to the desired navigation url. This code snippet can be placed in the mobile master page for the device channel.

Please note that the above approach is a workaround only and not a perfect solution as there are some side effects of this approach. The above jquery will fire everytime the page loads as we have written it in the masterpage and on the fly it will change the navigation url if we are using the mobile master page. Also, since these classes are OOB so if in future Microsoft changes the class names then this will not work and we need to change it accordingly. However, we can try to explore more around SharePoint ASP menu and try to apply some custom class there and see how that works. Also, for readers who want to explore more options can try to play around with taxonomy using ecmascript and see what can be achieved using that. Above approach is a quick fix and used with caution.

Happy Reading :)




Mobile Panel in SharePoint 2013

In my previous post on Device Channel, I explained how to create a device channel to target different devices. In this blog post, I will explain about Mobile Panels and Device Channel Panels and why to use them. I am going to explain a scenario which me and my friend worked on in order to have an understanding on the exact need for these panels.
There are times when you want to target only specific content of a page based on devices. Most of the times you might have noticed that many websites have a whole bunch of features when you have a look at the site in the desktop mode and have filtered set of features when viewed on mobile.
When it comes to SharePoint 2013, then Microsoft has came up with the concept of Mobile Panel and Device Channel Panel to provide a similar feature. These help in targeting specific content of a page layout on mobile and desktop. Mobile Panel allows content authors to target specific content for different devices. For example, mostly you have observed a banner image coming as a feature area on the sites. Now, this looks nice on the desktop version, but on mobiles, this does not seem much relevant. So, the requirement is to show this banner only is the user is in desktop view and not when in mobile view. Device Channel Panel is also a snippet that we can add to master page or to a page layout to control what content is rendered for the channels that we create. So for the above scenario, we want to have a single page layout which should be intelligent enough to show content specific to each of these channels.

Now, the main thing here is to create a page layout which could be shared across all mobile devices as well as the desktop view. In order to do that we need to make it device enabled using Mobile Panel. The normal way of proceeding on this is to have a region where all the common webparts both for mobile and desktop should go and another region where desktop specific should go. But this is not as simple as it seemed. We started with adding device channel for desktop and added a webpart zone there so as to add our banner webpart there which was meant to be visible only in desktop version. Then outside that device channel, we added webpart zones that will hold all the webparts that were common for mobile and desktop version. But to our surprise, this did not work. This logically correct solution was not showing the behavior that we expected from it.
Then we thought of creating two device channels, one for mobile and the other for desktop each having webpart zones and then we added all the mobile specific webpart to the device channel meant for Mobile and all the desktop specific webparts to the Default Channel(which is used for Desktop view). But the results were surprising again. In the desktop view, everything seemed correct but as soon as we switched to mobile view, we observed that the banner webpart, which we had only added in the desktop view and not in the mobile view, was visible in the mobile as well. On editing the page, we saw that in mobile view, edit page is showing the webpart but in wrong zone.
After some analysis, we found that the issue is that when a webpart is added to a webpart zone in one mobile panel and if that webpart zone does not exist in the other mobile panel then that webpart will automatically move to the next available webpart zone. Therefore, when we added the banner webpart to a zone in the Desktop device channel and when the page is viewed in mobile view, then because the banner webpart zone did not exist in the mobile view, the banner webpart got added to one of the webpart zones of the mobile device channel. So, after some drilling, we came to a solution that since the availability of the webpart zones is causing an issue, what if we design the layout in a way that the desktop device channel will have webpart zones in the mobile panel and the mobile device channel will have Publishing HTML fields instead to add the webpart. Therefore, if there will be no webpart zone in the mobile view, then there will be no zone available for the banner webpart to get added to. We tried this approach and Voila it worked. Below is the code snippet for what we actually did.


Now in the above code if you see, we have added two MobilePanels, one for the desktop and other for the Mobile. Both the MobilePanels have an attribute named IncludedChannels, which tells the panel which channel to target. "DEFAULT" is used for desktop view and "MOBILE" in our case is used for targeting mobile devices.
The above solution has however the following limitations
  1. User has to manually add webparts to the mobile device panel. You can however overcome this limitation by automating adding of webparts to the RichHtmlField.
  2. Two copies of the same webpart will be there on the page for the common webparts. However, for example say we have written a webpart whose business logic is written in a separate js file then this does not mean that the js file will be loaded twice on the page one for the desktop and one for the mobile view. The js file will be loaded only once for each channel. So performance wise, it will not impact.
This is how you can target specific content of the page layout for different channels using MobilePanels.
Please note here that the MobilePanels are now deprecated and instead we should use DeviceChannelPanels. DeviceChannelPanels are used in the same way as we used the MobilePanels above and they offer the same functionality. 

Hope this helps somewhere. :)

Friday, 2 August 2013

Device Channel in SharePoint 2013


Amongst many new features introduced in SharePoint 2013, one of the key features is Device Channel. With the continuous growth in the mobility sector, mostly smartphones are being widely used to  surf net. As a result, it is very important to provide a user friendly experience to any user visiting your website on mobile.

Microsoft has come up with the concept of Device Channels in SharePoint 2013. For all those who have not heard about Device Channels, let me explain it briefly.

Device Channels allows you to target your SharePoint site (Device Channels are available only if publishing feature is activated.) on mobile devices. It helps you in setting different master pages and css for different devices like Tablet, Windows Phone, iPhone etc. As a result, you can have a user friendly experience for your website when viewed on mobile device.

The very first thing that needs to be done is to create Device Channel for your site. In order to do the same, you need to go to the Site Settings > Look and Feel section and click Device Channels link.
 
 
After clicking this link, you will be directed to the list that contains all the device channels. By default you will see one device channel created for you already. It is the default channel which will be visible when no other channels are active or when the device's user agent string does not match the device inclusion rules for any active channel.
 
 
 
 
When you try to create a new device channel for your devices, you need to specify a few important parameters i.e. Alias, Device Inclusion Rules and Active.
Alias is the unique ID that helps in determining the device channel in the code. This comes handy when working with Device Channel Panel (will come on this a little later).
Device Inclusion Rules contains the user agent substring such as Windows Phone OS. This substring will be matched against the browser's user agent string in the device and based on that master page will be applied.
Active checkbox enables the device channel if it is checked.
 
The next thing that is required to be done is to associate a master page to the newly created device channel. To do this, go back to the site settings Look and Feel section and click on Master Page link.
 
 
There you can configure a master page for your newly created Device Channel.
 
After setting the master page for your device, now if you view the site in the device, you will see the device channel applied. 
In case you directly want to test the changes, you can do it by appending the following to the url in the browser.
?DeviceChannel=Alias
eg http://somedomain.com?DeviceChannel=mobile
Hope it gives you a brief idea about what device channels are and how they can be configured. In my next post , I will explain about Device Channel Panels. Till then stay tuned. :)
Happy SharePointing :)
 
 

Monday, 22 July 2013

JQuery to identify "Potrait" or "Landscape" mode for device

Hello Kind Readers,

Recently while enabling Device Channel for SharePoint 2013, I came across a requirement to identify whether the device is in Potrait Mode or Landscape Mode. Based on the mode of the device, different behaviour should happen. There is a simply jQuery event that helps you capture this device transition from Potrait to Landscape or vice versa.

You need to make use of jquery mobile which has an event as orientationchange that gets triggered whenever we make the transition.

Below code snippet will explain more on this.

<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>

<script type="text/javascript">

$(window).on( "orientationchange", function(event ) {
  alert("This device is in " + event.orientation + " mode!" );
});

// You can also manually force this event to fire.
$(window).orientationchange();
</script>

In this way, using orientationchange event and fetching the value of event.orientation method, you can find the device mode.

Hope it Helps !

Wednesday, 3 July 2013

JSRequest to play with Query string

At times we are required to fetch some parameters from query string. There are various ways to play with it. Recently I came across a short and simple object to fetch parameters from query string.
JSRequest is a javascript object that lives on the SharePoint page through which you can easily find the query string parameter, filename and path name.

Usage

e.g. URL is /Pages/default.aspx?fName=Geetanjali&lName=Arora

JSRequest.EnsureSetup();            //mandatory
var fName = JSRequest.QueryString["fName"]; // returns Geetanjali
var lName = JSRequest.QueryString["lName"]; // returns Arora
var fileName = JSRequest.FileName;                // returns default.aspx
var pathName = JSRequest.PathName;             // returns /Pages/default.aspx


Quite simple as you can see from the above snippet. Hope it helps.

Sunday, 7 April 2013

A subsite cannot be created inside an app web

For all those who have started exploring SharePoint 2013 must be by now aware of the term App Web. Recently , I did a small POC to see how we can provision a subsite inside an app web. Now on first glance it seems to be a quite simple requirement as you are simply going to create a subsite. But this is not the case.
For App's things are a bit different. After some struggle to create a subsite inside an APP Web, I got an error message stating that "A subsite cannot be created inside an APP Web" .
For all those who wants to drill down further as to how this message came, please have a look at the below code snippet that gave the above result.



var hostweburl,appweburl;
jQuery(document).ready(function () {
    hostweburl = decodeURIComponent(
                getQueryStringParameter("SPHostUrl")
        );
    appweburl =
        decodeURIComponent(
            getQueryStringParameter("SPAppWebUrl")
    );

    
    jQuery("#btnSubmit").click(function () {
 
        createSite();
        
    });

});

function getQueryStringParameter(paramToRetrieve) {
    var params =
        document.URL.split("?")[1].split("&");
    var strParams = "";
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split("=");
        if (singleParam[0] == paramToRetrieve)
            return singleParam[1];
    }
}

function createSite() {

        context = new SP.ClientContext(appweburl);
        currentWeb = context.get_web();

        context.load(currentWeb);
                   context.executeQueryAsync(onCreationSuccess, OnFailure);
    }

    function onCreationSuccess() {

        var appInstanceID = currentWeb.get_appInstanceId();

        var webCreateInfo = new SP.WebCreationInformation();
        webCreateInfo.set_description("This site created from ECMA script");
        webCreateInfo.set_language(1033);
        webCreateInfo.set_title("Test");
        webCreateInfo.set_url("Test");
        webCreateInfo.set_useSamePermissionsAsParentSite(true);
        webCreateInfo.set_webTemplate("APP#0");

       web = currentWeb.get_webs().add(webCreateInfo,false,appInstanceID);

        context.load(web);
        context.executeQueryAsync(onSuccess, OnFailure);
        
    }

    function onSuccess() {
        alert("Web created");
    }

    function OnFailure(sender, args) {
        alert(args.get_message());
    }