Thursday 9 January 2014

Hiding the Sharepoint 2010 ribbon from users without losing the scrollbar or title bar area when using a list webpart

There are many blog posts suggesting techniques to hide the Sharepoint ribbon using security trimmed controls in the Sharepoint masterpage, however I have found that none of them properly address the issue of how Sharepoint processes user clicks with the ribbon: namely that the titlebar area will disappear if the ribbon has been hidden with CSS!

In my site I use this area to display location specific information taken from a BCS connection, and provide location specific buttons and actions (all using sharepoint delegate controls), so there was no way I could lose this section of the page. I have therefore had to work out how to stop this from happening.


In order to solve this we must first implement the standard method of hiding the ribbon with CSS, and use a security trimmed control in order to decide which users get to access the ribbon and which do not. This has been gone over in detail elsewhere so I will only briefly recap this now.
First, edit the masterpage and set a style element in the "s4-ribbonrow" div to hide it:
<div class="s4-pr s4-ribbonrowhidetitle" id="s4-ribbonrow" style="display: none;"%>
<%--added display:none to hide Ribbon--%>
Next, add a security trimmed control to make the ribbon visible for administrators (in my case this is users with delete permission, hence I have used the "DeleteListItems" PermissionsString:
<%-- Show the ribbon to power users -->
<sharepoint:spsecuritytrimmedcontrol id="RIBBONHIDE_SPSecurityTrimmedControl3" permissionsstring="DeleteListItems" runat="server">
    <script type="text/javascript">
        document.getElementById("s4-ribbonrow").style.display = "block";
    </script>
</sharepoint:spsecuritytrimmedcontrol>

Installing this masterpage and applying it to your site will hide the ribbon from users without delete permission. Hooray!


HOWEVER...
When implementing this techniques you will find a major flaw: if a list webpart is on the page then when a user who has not got the ribbon clicks on the list webpart in a section that would normally cause the ribbon to show, the user will lose the title area at the top of the page. This includes the logo, the breadcrumb trail, and the social icons. After investigation I determined that this is caused by the Ribbon javascript replacing the title area element with the ribbon, and since you have hidden it, this mean that the whole title area is removed. I've followed this through the whole code and it seems to be related to the custom javascript scrolling function that Sharepoint 2010 uses.


The fix

In order to get around this, we have to make changes to a couple of other areas.

First, we must update the following javascript fuction "OnRibbonMinimizedChanged" that is found in the standard Sharepoint INIT.JS javascript file in the 14 hive. DO NOT edit the file directly! It can be simply overriden by including another javascript file later on in the masterpage (see below). To override this function, first create a file called "HideRibbon.js" with the following in it:
var g_spribbon = new Object();
g_spribbon.isMinimized = true;
g_spribbon.isInited = false;
g_spribbon.minimizedHeight = "44px";
g_spribbon.maximizedHeight = "135px";
function OnRibbonMinimizedChanged(ribbonMinimized) {
    ULSxSy: ;
    var ribbonElement = GetCachedElement("s4-ribbonrow");
    var titleElement = GetCachedElement("s4-titlerow");
    if (ribbonElement) {
        ribbonElement.className = ribbonElement.className.replace("s4-ribbonrowhidetitle", "");
        if (titleElement) {
            titleElement.className = titleElement.className.replace("s4-titlerowhidetitle", "");
            if (ribbonMinimized) {
                titleElement.style.display = "block";
            }
            else {
                //titleElement.style.display = "none"; // MODIFICATION -  Commented out - do not hide this element, or it will hide the whole title area when it thinks a ribbon is required
            }
        }
    }
    var wasInited = g_spribbon.isInited;
    g_spribbon.isInited = true;
    var lastState = g_spribbon.isMinimized;
    g_spribbon.isMinimized = ribbonMinimized;
    if (lastState != ribbonMinimized || !wasInited)
        FixRibbonAndWorkspaceDimensions();
}
Upload this file to your site somewhere (in this example I will use the "Shared Documents" list), and add the following to your masterpage in order to including it:
<asp:scriptmanager enablepagemethods="false" enablepartialrendering="true" enablescriptglobalization="false" enablescriptlocalization="true" id="ScriptManager" runat="server">
    <scripts>
        <asp:scriptreference path="<% $SPUrl:~sitecollection/Shared%20Documents/HideRibbon.js%>" runat="server"></asp:scriptreference> 
    </scripts> 
  </asp:scriptmanager>
Put this section after the body element, directly after the form element. I.e. after the following two lines of the masterpage:
<body scroll="no" onload="if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();" class="v4master">
  <form id="Form1" runat="server" onsubmit="if (typeof(_spFormOnSubmitWrapper) != 'undefined') {return _spFormOnSubmitWrapper();} else {return true;}">

Now change this line in you masterpage:
<div class="s4-pr s4-notdlg s4-titlerowhidetitle " id="s4-titlerow">

Change it to this to remove the class that tells the javascript that this is the bit to hide:
 <div class="s4-pr s4-notdlg " id="s4-titlerow">
<%-- Changed class to remove to s4-titlerowhidetitle so ribbon does not fire up over top of this --%>

Now you should find that the title bar remains active even when the ribbon is active (thus losing some screen real estate), but that restricted users with no ribbon do not lose their title area when they perform an action that would normally have opened the ribbon :)
Best of luck and happy coding!