Option to Show the SharePoint 2010 ribbon when hidden by default

At work we’ve been working on a new intranet project with SharePoint 2010 being our platform of choice. This site is mainly a view only type of site but we also wanted users to have the ability to create alerts and other similar activities. One of the requirements of this project was to remove the ribbon on every page. This brought complications for SP 2010 because so much is done in the ribbon. We decided to hide the ribbon by default and show a caret (or chevron) at the upper right of the screen to allow the ribbon to be shown and hidden by all users.

There are many solutions I’ve seen on the interwebs around hiding the ribbon for some and not hiding it for others so they were a good starting point for us but I couldn’t find anyone talking about having the ribbon being optional for everyone. This brought a few challenges such as keeping the ribbon shown on postbacks and displaying the ribbon when clicking on a list webpart.

The first challenge was easy to accomplish. Using a cookie to set whether the user currently has the ribbon open or closed allows the ribbon to “remember” that setting as a user is browsing and editing items in SP.

 var val = 'False';
 try { val = GetCookie('ShowHideRibbon'); } catch (err) { }
 var showRibbon = document.getElementById('ShowRibbon');
 var hideRibbon = document.getElementById('HideRibbon');
 var ribbon = document.getElementById('s4-ribbonrow');

 if (val == 'True') {
  ribbon.style.display = 'block'; ;
  if (showRibbon != null)
   showRibbon.style.display = 'none';
  if (hideRibbon != null)
   hideRibbon.style.display = 'block';
 }
 else {
  if (hideRibbon != null)
   hideRibbon.style.display = 'none';
  if (showRibbon != null)
   showRibbon.style.display = 'block';
 }

The second issue was more difficult and wasn’t initially obvious. The issue was that in SP 2010, when you click on a list view webpart it automatically activates the ribbon. This is great when using the checkboxes to select items or documents. Normal behavior is when the ribbon is activated it will hide the site level breadcrumbs / title bar and the top navigation to use that space for the ribbon itself. But with the ribbon being hidden, this causes the whole top part of the page to disappear including our caret to reopen the ribbon.

This resulted in a very bad user experience. I spent a lot of time debugging JavaScript trying to find the right SP JS function to “override” in order to tap into this action and unhide the ribbon first before the ribbon is activated. I got no where asking the google and ended up searching all of the SharePoint JS debug files and finally finding the function OnRibbonMinimizedChanged in init.js.

 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";
    }
   }
  }
...

I overrode the function with my own where I unhide the ribbon and then called the original function in init.js.

 function SetupEventHandler_HideShowRibbon() {
  if (original_functionEvent == null) {
   original_functionEvent = OnRibbonMinimizedChanged;
  }
  OnRibbonMinimizedChanged = OnRibbonMinimizedChanged_Delegate;
 }

 function OnRibbonMinimizedChanged_Delegate(ribbonMinimized) {
  if (IsRibbonHidden_HideShowRibbon() &&
   false == ribbonMinimized) {
   showRibbon__HideShowRibbon();
  }
  original_functionEvent(ribbonMinimized);
 }

I put all of my JS code into a user control which I added to my masterpage inside a SP delegate control. This allows me to use features to swap this code out with something different. For instance you could have a user control which can hide the ribbon by default and only show the caret / chevron when a user has certain permissions.

<%@ Control Language="C#"    compilationMode="Always" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="uc" TagName="ShowHideRibbonCore" src="~/_controltemplates/Custom/ShowHideRibbon.ascx" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<!-- Show / Hide Ribbon -->
<Sharepoint:SPSecurityTrimmedControl ID="SecurityTrimHideShowRibbonCurrentItem" runat="server" PermissionsString="AddAndCustomizePages" PermissionContext="CurrentItem">
    <uc:ShowHideRibbonCore ID="HideShowRibbonCoreCurrentItem" runat="server"/>
</Sharepoint:SPSecurityTrimmedControl>
<Sharepoint:SPSecurityTrimmedControl ID="SecurityTrimHideShowRibbonCurrentWeb" runat="server" PermissionsString="AddAndCustomizePages" PermissionContext="CurrentSite">
    <uc:ShowHideRibbonCore ID="HideShowRibbonCoreCurrentSite" runat="server"/>
</Sharepoint:SPSecurityTrimmedControl>

 

The code that we ended up doing is below. We hide the ribbon using CSS in the user control and then output the javascript.

<%@ Control Language="C#"    compilationMode="Always" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="uc" TagName="ShowHideRibbon" src="~/_controltemplates/Custom/ShowHideRibbon.ascx" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<!-- Hide Ribbon -->
<style type="text/css">
#s4-ribbonrow
{
    display:none;
}
</style>
<uc:ShowHideRibbonCore ID="HideShowRibbon" runat="server"/>

And here is my full code that I put in the user control ShowHideRibbon.ascx

<%@ Control Language="C#"    compilationMode="Always" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<!-- Show / Hide Ribbon Core -->
<script type="text/javascript">
    if (testForRibbon_HideShowRibbon == null) {
        var original_functionEvent = null;

        var testForRibbon_HideShowRibbon = function () {

            if (IsRibbonHidden_HideShowRibbon()) {
                ExecuteOrDelayUntilScriptLoaded(SetupEventHandler_HideShowRibbon, "init.js");

                var val = 'False';
                try { val = GetCookie('ShowHideRibbon'); } catch (err) { }
                var showRibbon = document.getElementById('ShowRibbon');
                var hideRibbon = document.getElementById('HideRibbon');
                var ribbon = document.getElementById('s4-ribbonrow');

                if (val == 'True' ||
                   (IsRibbonHidden_HideShowRibbon() &&
                    IsTitleRowHidden_HideShowRibbon())) {
                    ribbon.style.display = 'block';
                    if (showRibbon != null)
                        showRibbon.style.display = 'none';
                    if (hideRibbon != null)
                        hideRibbon.style.display = 'block';
                }
                else {
                    if (hideRibbon != null)
                        hideRibbon.style.display = 'none';
                    if (showRibbon != null)
                        showRibbon.style.display = 'block';
                }
            }
        }

        function IsRibbonHidden_HideShowRibbon() {
            return IsElementHidden_HideShowRibbon('s4-ribbonrow');
        }

        function IsTitleRowHidden_HideShowRibbon() {
            return IsElementHidden_HideShowRibbon('s4-titlerow');
        }

        function IsElementHidden_HideShowRibbon(elementId) {
            var computedStyle = function (el, style) {
                var cs;
                if (typeof el.currentStyle != 'undefined') {
                    cs = el.currentStyle;
                } else {
                    cs = document.defaultView.getComputedStyle(el, null);
                }
                return cs[style];
            }
            var element = document.getElementById(elementId);
            if (element != null &&
				computedStyle(element, 'display') == 'none') {
                return true;
            }
            return false;
        }

        function SetupEventHandler_HideShowRibbon() {
            if (original_functionEvent == null) {
                original_functionEvent = OnRibbonMinimizedChanged;
            }
            OnRibbonMinimizedChanged = OnRibbonMinimizedChanged_Delegate;
        }

        function OnRibbonMinimizedChanged_Delegate(ribbonMinimized) {
            if (IsRibbonHidden_HideShowRibbon() &&
				false == ribbonMinimized) {
                showRibbon__HideShowRibbon();
            }
            original_functionEvent(ribbonMinimized);
        }

        function makeDoubleDelegate_HideShowRibbon(function1, function2) {
            return function () {
                if (function1)
                    function1();
                if (function2)
                    function2();
            }
        }

        function getDocHeight_HideShowRibbon() {
            var D = document;
            return Math.max(
            Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
            Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
            Math.max(D.body.clientHeight, D.documentElement.clientHeight)
        );
        }

        function showRibbon__HideShowRibbon() {
            var newHeight = getDocHeight_HideShowRibbon();
            var ribbon = document.getElementById('s4-ribbonrow');
            ribbon.style.display = 'block';
            try {
                SetCookie('ShowHideRibbon', 'True', '/');
            } catch (err) { };
            document.getElementById('ShowRibbon').style.display = 'none';
            document.getElementById('HideRibbon').style.display = 'block';

            newHeight = newHeight - ribbon.offsetHeight;
            var ver = navigator.appVersion;
            if (ver.indexOf("MSIE") != -1) {
                newHeight = newHeight - 4;
            }
            document.getElementById('s4-workspace').style.height = newHeight + 'px';
        }

        function hideRibbon__HideShowRibbon() {
            document.getElementById('s4-ribbonrow').style.display = 'none';
            try {
                SetCookie('ShowHideRibbon', 'False', '/');
            } catch (err) { };
            document.getElementById('HideRibbon').style.display = 'none';
            document.getElementById('ShowRibbon').style.display = 'block';
            var newHeight = getDocHeight_HideShowRibbon();
            var ver = navigator.appVersion;
            if (ver.indexOf("MSIE") != -1) {
                newHeight = newHeight - 4;
            }
            document.getElementById('s4-workspace').style.height = newHeight + 'px';
        }

        window.onload = makeDoubleDelegate_HideShowRibbon(window.onload, testForRibbon_HideShowRibbon);

        document.write('<a id="ShowRibbon" href="#" onclick="showRibbon__HideShowRibbon(); return false;"><img src="/_layouts/images/downarrow.png" title="Show Ribbon" border="0"/></a>');
        document.write('<a id="HideRibbon" href="#" onclick="hideRibbon__HideShowRibbon(); return false;"><img src="/_layouts/images/uparrow.png" title="Hide Ribbon" border="0"/></a>');
    }
</script>
<style type="text/css">
#ShowRibbon
{
	position:fixed;
	top:0;
	right:15px;
	display: none;
	z-index: 100;
}

#HideRibbon
{
	position:fixed;
	top:45px;
	right:15px;
	display: none;
	z-index:100;
}
</style>

Update 4-6-2012

I realized there are instances when visiting a page (like dispform.aspx) where the ribbon is supposed to be open by default but instead showed the same bad behavior from above. I’ve updated my code above to now check if s4-titlerow is hidden in addtion to the s4-ribbonrow. If so, I unhide the ribbon. But I do not cookie this change. The only time this app “remembers” your setting is if you actually click the up or down arrow at the top right.