Posted on:
Categories: CodePlex;SharePoint;Office 365
Description:

​In one of my previous blog posts, I posted a solution on how to integrate tabs (or more precisely, tabbed web parts) into publishing pages in on-premise SharePoint installations.  However, since my CodePlex solution relied on deploying a farm-scoped WSP, it could not be used in SharePoint Online/Office 365.

Instead of creating a deployable package for SharePoint Online, I took a simpler approach: I posted a standalone publishing page layout which could be manually uploaded to the Site Collections Master Page Gallery, and that's it.

You can download the page layout directly from CodePlex here: https://sharepointtabs.codeplex.com/releases/view/117882

Or simply copy and paste the source code below (and modify to suit your needs!). 

<%@ Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,
Microsoft.SharePoint.Publishing,Version=15.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" 
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" 
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" 
Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls" 
Assembly="Microsoft.Office.Server, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="OSRVUPWC" Namespace="Microsoft.Office.Server.WebControls" 
Assembly="Microsoft.Office.Server.UserProfiles, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" 
Assembly="Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="SEARCHWC" Namespace="Microsoft.Office.Server.Search.WebControls" 
Assembly="Microsoft.Office.Server.Search, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" 
Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<asp:Content ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
 <SharePoint:FieldValue id="PageTitle" FieldName="Title" runat="server" />
</asp:Content>

<asp:Content ContentPlaceholderID="PlaceHolderPageTitleInTitleArea" runat="server">
 <SharePoint:FieldValue FieldName="Title" runat="server"/>
</asp:Content>

<asp:Content ContentPlaceHolderId="PlaceHolderPageImage" runat="server" />

<asp:Content ContentPlaceHolderId="PlaceHolderTitleBreadcrumb" runat="server" />

<asp:Content ContentPlaceHolderId="PlaceHolderBodyAreaClass" runat="server" />

<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    
    <PublishingWebControls:EditModePanel runat="server" id="editmodestyles">
  <SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/edit-mode-21.css %>"
   After="<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/page-layouts-21.css %>" runat="server"/>
 </PublishingWebControls:EditModePanel>
    
 <!-------------------------- DEPLOYMENT INSTRUCTIONS ---------------------------------->
 
 <!--  Requirements: SharePoint 2013 (Online or On-Premise)
      Publishing enabled (requires "E" subscription online, or requires Enterprise on-premise)
       -> enable site collection feature: SharePoint Server Publishing Infrastructure
       -> enable site feature: SharePoint Server Publishing
    Instructions: Simply manually upload this file into the Master Page Gallery 
      (site settings -> master pages and page layouts)
       -> ensure content type is set to "Page Layout"
       -> give it a title of your choice (you will need this later)
       -> under Associated Content Type, select "publishing content types", and "page" 
         (unless you have a custom publishing page content type you'd like to utilize)
       -> save the file
       -> make sure to check this file in, and publish/approve it if neccessary
      Now create or navigate to an existing publishing page, and edit the page
       -> click the "page" ribbon tab, then click the "page layout" ribbon button
       -> in the page layout dropdown, find this page layout 
         (it will be under the title you chose in the previous step), and click it
      Any webparts within the tabbed webpart zone will be displayed as tabs once you save the page!
 -->
 <!-------------------------------------------------------------------------------------->
 
    <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.0.min.js" 
  type="text/javascript"></script>
    <script src="//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.3/jquery-ui.min.js" 
  type="text/javascript"></script>
    <SharePoint:CssRegistration Name="//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.3/themes/redmond/jquery-ui.css" 
  After="Themable/corev15.css" runat="server" />

    <SharePoint:ScriptBlock runat="server">
        //for reference, http://kyleschaeffer.com/sharepoint/wp-tabify/
        //              http://jqueryui.com/tabs/

        (function (jQuery) {
            jQuery.fn.wpTabify = function () {
                
                // if we're not in edit mode
                if (jQuery('.ms-WPAddButton').size() == 0) {
        
                    // for each 
                    this.each(function (i) {
        
                        // create variables needed for assembling tabs within this web part zone
                        var idName = jQuery(this).attr('id');
                        var tabList = jQuery('<ul class="wpt-ui-tabs-nav"/>');
                        var panels = jQuery('<div class="wpt-ui-tabs-wrapper"/>');
        
                        // for each web part in the web part zone, assemble the tab headers
      // and tab content in the format JQuery UI tabs() method expects.
                        jQuery(this).find('div.ms-webpartzone-cell > div:first-child').each(function (j) {
                            jQuery(tabList).append('<li><a href="#ui-tab-panel' + 
        idName + i + j + '"><span>' + 
        jQuery(this).find('h2.ms-webpart-titleText').text() + 
        '</span></a></li>');
                            var thisPanel = jQuery('<div id="ui-tab-panel' + 
        idName + i + j + '" class="wpt-ui-tabs-panel"/>');
                            var panelContents = jQuery(this).detach();
                            jQuery(thisPanel).append(jQuery(panelContents).find('.ms-wpContentDivSpace'));
                            jQuery(panels).append(thisPanel);
                        });
        
                        // if we created any tabs, then push the new tabs structure back into the DOM, 
      // then call the jquery ui method .tabs()
                        if (jQuery(tabList).find('li').size() > 0) {
                            jQuery(this).prepend(panels);
                            jQuery(this).prepend(tabList);
                            jQuery(this).tabs();
                        }
        
                        // remove original webpart zone now that we've tabified
      //  what we wanted out of it
                        jQuery(this).find('div.ms-webpart-zone').remove();
                    });
                }
            };
        })(jQuery);

        function TabifyFnWrapper() {
            // tabify the appropriate web part zone for this page layout
            jQuery('#TabbedWebPartZoneWrapper').wpTabify();
        
            //regardless of the tabify result, display the web part zone
            jQuery('#TabbedWebPartZoneWrapper').css('display', 'inline-block');
        }
        
        // add to sharepoint javascript function queue to be called after page load
        _spBodyOnLoadFunctionNames.push('TabifyFnWrapper');

    </SharePoint:ScriptBlock>
</asp:Content>

<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <PublishingWebControls:EditModePanel runat="server" CssClass="edit-mode-panel title-edit">
  <SharePoint:TextField runat="server" FieldName="Title"/>
 </PublishingWebControls:EditModePanel>
    
    <div id="TabbedWebPartZoneWrapper" style="display:none;">
        <!-- note, the wrapper around the tabbed web part zone is initally hidden so 
            users don't see the shifting around while the tabs are being assembled -->
        <WebPartPages:WebPartZone runat="server" 
   Title="Tabbed Web Part Zone" ID="TabbedWebPartZone"  />
    </div>

    <div id="PublishingContentZoneWrapper">
        <!-- you can still have 1 or more publishing content zones on the page -->
        <PublishingWebControls:RichHtmlField FieldName="PublishingPageContent" 
   HasInitialFocus="True" runat="server"/>
    </div>

    <div id="NonTabbedWebPartZoneWrapper">
        <!-- you can still have normal non-tabbed web part zones also on the page -->
        <WebPartPages:WebPartZone runat="server" 
   Title="Non Tabbed Web Part Zone" ID="NonTabbedWebPartZone" />
    </div>
    
</asp:Content>