All posts in Javascript

jQuery Collapsable Quick Launch – Plugin Update & Cookie States & 2013 Compatibility

Overview

Christmas is nearly with us and it has been a long while since my last post.  To try and give some people a little Christmas cheer I am releasing part one of my new set of jQuery plugins for many of my Quick Tips that I have posted.  Today’s update is to the ability for a user to hide / show the Quick Launch menu.   Although the previous version worked well, there were a number of requests for new functionality which I have integrated into my new version.  The new version also makes configuration MUCH easier and friendlier for non-techy types.

New Features:

  • Plug-in Architecture based on jQuery Boilerplate
  • Ability to set default state of the Quick launch (HideOnDefault)
  • Quick launch state is now saved across page views using Cookies.  This can be turned off.
  • Re-written code.
  • Fully configurable for various scenarios (Have tested on OOTB & Custom Masterpages)
  • 2013 Compatible.  I can confirm the plug-in works on the OOTB Seattle.master with no code changes (only plug-in configuration).

How to use:

The quick launch plug-in can be used and applied as follows:

$('#s4-leftpanel').quicklaunchHide()

Options:

The following default options are available:

// collapsed state image
collapseImage: '/_layouts/images/mewa_leftPage.gif',

// expanded state image
expandImage: '/_layouts/images/mewa_rightPage.gif',

// location for the button to be prepended to
prependLocation: '.s4-tn',

// The Main 'content' div that the main body content is within
mainDiv: '.s4-ca',			                

// The Margin that the mainDiv will have once hidden.
leftMargin: 0,	

// Do you want to hide the quicklaunch as a default.  (Overwritten when cookies are enabled)
hideOnDefault: false,   

// Allow Cookies to be set
allowCookie: false,

// Name of the Cookie
cookieName: 'quicklaunchStatus',

No CSS is required for the plugin and the main plugin selector should be the side navigation div that you are hiding.  So in the case of SharePoint 2010 this will be “#s4-leftpanel”

Full Usage (2010 / 2013)

2010 Full Usage (OOTB Masterpage)

	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
	<script type="text/javascript" src="jquery.LISP.Quicklaunch.js"></script>
    <script type="text/javascript">
	    $(document).ready(function() {
	        $('#s4-leftpanel').quicklaunchHide({
	            collapseImage: '/_layouts/images/mewa_leftPage.gif',
	            expandImage: '/_layouts/images/mewa_rightPage.gif',
	            prependLocation: '.s4-tn',
	            mainDiv: '.s4-ca',			                
	            leftMargin: 0,	
	            hideOnDefault: false,   
	            allowCookie: false,
	            cookieName: 'quicklaunchStatus'	        
            });
	    });
    </script>

2013 Full Usage (OOTB Masterpage)

	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
	<script type="text/javascript" src="jquery.LISP.Quicklaunch.js"></script>
    <script type="text/javascript">
	    $(document).ready(function() {
	        $('#sideNavBox').quicklaunchHide({
	            collapseImage: '/_layouts/images/mewa_leftPage.gif',
	            expandImage: '/_layouts/images/mewa_rightPage.gif',
	            prependLocation: '.s4-titlerow',
	            mainDiv: '#contentBox',			                
	            leftMargin: 20,	
	            hideOnDefault: false,   
	            allowCookie: false,
	            cookieName: 'quicklaunchStatus2013'	        
            });
	    });
    </script>

Hope you enjoy this plug in and as always if you have any issues please let me know.

 Download

Developer Version : jQuery.LISP.quicklaunch.js

MinifiedVersion : jQuery.LISP.quicklaunch.min.js

Quick Tip – jQuery Collapsable Quicklaunch for SharePoint 2010

accordion_hide

 

 

Another day, another jQuery Quick Tip.  Today we have a piece of jQuery that will enable an end user to hide the Quicklaunch from view and free up some additional space if you have a lower resolution.  As with my other Quick Tips the following code uses the OOTB v4.master so may not work if you have customised your design. (Changes to selectors should be all that would be required to get it working with your own design)

	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

	<script type="text/javascript">
	jQuery(function($) {
        var CookieName = "QuickLaunchHidden";
	    var MainArea = $('.s4-ca');
	    var MainAreaLeftMargin = $(MainArea).css('margin-left');
	    var NoLeftMargin = "0px";
	    var LeftArea = $('#s4-leftpanel');
	    var Collapse = "/_layouts/images/mewa_leftPage.gif";
	    var Expand = "/_layouts/images/mewa_rightPage.gif";

	    $(MainArea).prepend('<a class=\'min\' style=\'float:left; position:absolute; top:0px; left:0px;\' title=\'Hide \\ Show Quick Launch\'><img src=\''+ Collapse +'\'/></a>');

	    $('.min').click(function(){
			//Toggle the Left Panel to hide it
			$(LeftArea).toggle();
			$(LeftArea).is(":visible") ? MainArea.css('margin-left',MainAreaLeftMargin ) :  MainArea.css('margin-left',NoLeftMargin);
			var img = $(this).children();
			$(LeftArea).is(":visible") ? img.attr('src',Collapse) : img.attr('src',Expand );
		});
	});
	</script>

The script above is not much more complicated than previous ones but as always i will go through it piece by piece so you are clear as to what is going on.  The first line is getting a hosted version of the jQuery library, obviously if you have this locally then it may be worth updating this reference appropriately.

	    var MainArea = $('.s4-ca');
	    var MainAreaLeftMargin = $(MainArea).css('margin-left');
	    var NoLeftMargin = "0px";
            var LeftArea = $('#s4-leftpanel');
	    var Collapse = "/_layouts/images/mewa_leftPage.gif";
	    var Expand = "/_layouts/images/mewa_rightPage.gif";

The first six lines of code are to setup some variables that will be used during the rest of the script.  We first get a reference to the main Right hand content div which in the case of the OOTB masterpage is the s4-ca classed div.  Next we save the size of the left margin of this div so that it can be used later.  We then set the LeftArea div for the item which will be hidden and also define the size of the left margin when collapsed which is what line three is for.  Finally we have two variables that define the expand and collapsed images.

	    $(MainArea).prepend('<a class=\'min\' style=\'float:left; position:absolute; top:0px; left:0px;\' title=\'Hide \\ Show Quick Launch\'><img src=\'' + Collapse + '\'/></a>');

The next line is quite a long one but its nothing complicated.  What we are doing is to the Defined MainArea we are adding our image with a hyperlink on it which is positioned at the top of the parent container.

	    $('.min').click(function(){
			//Toggle the Left Panel to hide it
			$(LeftArea).toggle();
			$(LeftArea).is(":visible") ? MainArea.css('margin-left',MainAreaLeftMargin ) :  MainArea.css('margin-left',NoLeftMargin);
			var img = $(this).children();
			$(LeftArea).is(":visible") ? img.attr('src',Collapse) : img.attr('src',Expand );
		});

This final piece of code is the core of the script and contains the click event handler for our dynamically added code shown above.  We first define the click handler, then we toggle the configured LeftArea so that it is hidden.  Now if we stopped there we would have hidden the quicklaunch but the page would not expand to provide any more room.  To fix this we then need to adjust the MainArea left-margin.  Line four first checks if the left section is visible, and then if it is we set the MainArea margin-left to the configured NoLeftMargin otherwise we “reset” to the left-margin that was set on load.  The final two lines updates the image to show the collapse or expand image depending on the status of the LeftArea.

That’s all there is to it.  I hope like previous snippets that this will be useful for someone and if you have any recommendations or suggestions of new functionality that you would like to see then please let me know.  As always your positive comments are always welcomed and keep me working on new content for you.

 

iGoogle UI for SharePoint – Part Five : SharePoint 2010 Integration

part5

Series Content

  1.     Part One – Overview, Concept,  HTML Structure & jQuery Basics
  2.     Part Two – Dragging, Dropping,  Sorting and Collapsing
  3.     Part Three – Saving WebPart states using Cookies
  4.     Part Four – Control Adaptersc
  5.     Part Five – SharePoint 2010 Integration – Current Article
  6.     Part Six – Bringing it all together
  7.     Bonus – Saving WebPart States using the Client Object Model

Overview

In Part Five, we will take the previous posts and show you how to get it into SharePoint 2010.  I’ll show how to create the Visual Studio Project, and then deploy the assets into SharePoint to create a working example.

Visual Studio Project & Assets

For this post will be using Visual Studio 2010 as our development platform.  As part of my default development build i like to have the following VS plug-ins installed.

For this post, we will be using Visual Studio 2010 as our development platform.  As part of my default development build, I like to have the following VS plug-ins installed:

SPI’s & Features

Our project will contain the following SPI’s (SharePoint Item) to deploy the required assets.

  •  Module – This will deploy an iGoogle.aspx page with the configured WebPart Zones, and some dummy content editor webparts (CEWP) to show a working example.
  • Mapped Folder – A Mapped folder to the /_layouts directory will be used to deploy the css, images, and javascript files required and created from the first three parts of this series.
  • Control Adapter – Although technically not an SPI, the control adapter code from the previous post will also be created.

The Project will contain only a single feature which will deploy all the assets required for the iGoogle interface.  This will be a SITE scoped feature with an event receiver to manage the addition of values to the compact.browser file.

Visual Studio

The first step for this and pretty much every other SharePoint Project is to fire up Visual Studio 2010 and create a new SharePoint 2010 Project. Call the project LifeInSharePoint.iGoogle. On the next screen we would also like to create this as a FARM solution.  Sandbox solutions will not work as control adapters cannot be deployed using a Sandbox Solution.

Now that we have a project created, we first need to create some folders to contain our SPI’s.  I like to organise my folders in a manner that I feel makes it easier to understand, so I will first create a Common folder which will contain a sub folder called ControlAdaptersNOTE: I do not have spaces in my folder names as visual studio will replace them with “_” in namespaces.  I will now create another top level folder called Root and within this I will create another folder called Content.  These two folders will contain the module that will deploy the iGoogle.aspx page and place WebParts onto the page.  To ensure that we can access the images, js and css from anywhere, we will place them in the /_layouts folder.  To deploy these to the Layouts folder from Visual Studio is very simple.  Firstly you will need to right click on the project in Visual Studio > Add > SharePoint “Layouts” Mapped Folder.

This will create you a project named sub folder which we can use to place our css etc.  Once this has been done your folder structure should look like this.

Now that I have the basic folder structure, I will now create a new a new class file for my ControlAdapter called WebPartRenderControlAdapter.cs. For the info on how to create and what goes into this class file, please see the previous post where I go into a lot more detail. iGoogle UI for SharePoint 2010 – Part Four: Control Adapters.

The next step is to add the CSS, JS, and Image that we created in the first three parts of this blog series.  (These will be available at the end of this post) in the supplied zip file.

Adding Content & Pages

Next, we need to create the root content module.  This module contains two items.  The first is the Elements.xml file which will contain the XML required to deploy our page, and the second item is the default.aspx page which we will provision.  This default.aspx page contains the HTML snippets from the first couple of posts in this series as well as the references to our javascript and css which we are storing above in the /_layouts folder.  Below is a snippet from within the default.aspx page.

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
	<table cellspacing="0" border="0" width="100%">
	  <tr class="s4-die">
	   <td class="ms-pagebreadcrumb">
		  <asp:SiteMapPath SiteMapProvider="SPContentMapProvider" id="ContentMap" SkipLinkText="" NodeStyle-CssClass="ms-sitemapdirectional" runat="server"/>
	   </td>
	  </tr>
	  <tr>
	   <td class="ms-webpartpagedescription"><SharePoint:ProjectProperty Property="Description" runat="server"/></td>
	  </tr>
	  <tr>
		<td>
		 <table width="100%" cellpadding="0" cellspacing="0" style="padding: 5px 10px 10px 10px;">
		  <tr>
		   <td valign="top">
               <div class='column' id='leftCol'>
			        <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="Left" Title="iGoogle Left" />
			   </div>
                <div class='column' id='middleCol'>
			        <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="Center" Title="iGoogle Center" />
			    </div>
                <div class='column' id='rightCol'>
			        <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="Right" Title="iGoogle Right" />
			    </div>
		   </td>
		  </tr>
          <tr>
            <td colspan="7">
	            <div id='toolbox-wrapper'>

		            <div id='toolbox-controls'>
			            <div class='badge'></div>		
			            <p class="slide"><a href="#" class="btn-slide">Toolbox</a></p>	
			            <p class="reset"><a href="#" class="btn-reset">Reset Widgets</a></p>	
		            </div>
		            <div class='column' id='toolbox'>

		            </div>	
		            <div style='clear:both;'></div>				
	            </div>	            
            </td>
          </tr>
		 </table>
		</td>
	  </tr>
	</table>

    <link rel="stylesheet" type="text/css" media="all" href="/_layouts/LifeInSharePoint.iGoogle/css/style.css" />
	<!-- Load the jQuery Libraries -->
	<script src="/_layouts/LifeInSharePoint.iGoogle/js/jquery-1.6.2.min.js" type="text/javascript"></script>
	<script src="/_layouts/LifeInSharePoint.iGoogle/js/jquery-ui-1.8.16.custom.min.js" type="text/javascript"></script>			
	<script type="text/javascript" src="/_layouts/LifeInSharePoint.iGoogle/js/iColorPicker.js"></script>		
	<script type="text/javascript" src="/_layouts/LifeInSharePoint.iGoogle/js/jquery.cookie.js"></script>	
	<script type="text/javascript" src="/_layouts/LifeInSharePoint.iGoogle/js/jquery.corner.js"></script>		
	<!-- script file to add your own JavaScript -->
	<script type="text/javascript" src="/_layouts/LifeInSharePoint.iGoogle/js/script.js"></script>	
</asp:Content>

As you can see I have made some small changes by placing our three columns within a table to keep things nice and neat.  The script references have also been updated to point to our deployed assets.  The elements.xml file is very simple. It takes the default.aspx page and deploys it to the root of the current site creating an iGoogle.aspx page at that location.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Root" Url="" Path="">
    <!-- iGoogle PAGE -->
      <File Name="iGoogle.aspx" Url="Root.Content.Pages/default.aspx" NavBarHome="True">
      <Property Name="Title" Value="SharePoint iGoogle Interface" />
      <Property Name="ContentType" Value="Document" />

      </File>
</Module>
</Elements>

As you can see there is not a lot to it. We are setting the name of the deployed file to iGoogle.aspx and the Url in this case is the relative url within the project, NOT the location it will appear on the site, a common mistake I have made many times.  If you wanted to place the page in another location you can modify URL and Path attributes in the <module> tag to point to another location.  Since we want to place the page on the root, these are left blank.

Adding WebParts

The final addition to this elements.xml file is to add some default WebParts on to the page.  For this demo we are going to use some Content Editor WebParts which will have some dummy Lorem Ipsum text within.  (You can replace the xml with some other WebParts if you like, as long as you know the XML)  The XML element you need to add WebParts on to the page is the <AllUsersWebPart> Node.  This node has attributes which we use to define the order on the page, as well as the WebPart Zone the WebPart is to appear in.  The Snippet below shows a single item.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Root" Url="" Path="">
    <!-- iGoogle PAGE -->
      <File Name="iGoogle.aspx" Url="Root.Content.Pages/default.aspx" NavBarHome="True">
      <Property Name="Title" Value="SharePoint iGoogle Interface" />
      <Property Name="ContentType" Value="Document" />
        <AllUsersWebPart WebPartOrder="1" WebPartZoneID="Left">
          <![CDATA[
          <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2"
          xmlns:cewp="http://schemas.microsoft.com/WebPart/v2/ContentEditor">
          <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
          <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName>
          <Title>Left Content Editor</Title>
          <FrameType>None</FrameType>
          <cewp:Content>
              Duis sit amet turpis risus. Proin turpis orci, tristique porttitor venenatis eget, lacinia vitae dolor. Maecenas ultrices elementum est, ut dictum velit interdum vel. Maecenas vel urna eu quam rutrum aliquam eget quis dui. Nunc fermentum neque quis dolor facilisis hendrerit. Curabitur semper fermentum tortor, ut consequat turpis facilisis vel. Aliquam erat volutpat. Nam viverra molestie ipsum, vel tempus magna suscipit id.        
          </cewp:Content>
          </WebPart>
        ]]>
        </AllUsersWebPart>
      </File>
</Module>
</Elements>

You can also see from the code above that we are surrounding the WebPart XML with a <![CDATA[]]> tag which means that the text within will be ignored by the XML Parser.

Creating the Feature

Now that we have nearly all the pieces of the puzzle, the next step is to create a feature in our solution which will deploy the items to SharePoint.  You should notice in your project there is a Web scoped default feature called Feature1.  We need to rename our feature to something more meaningful, so in the Solution Explorer right click and rename the feature.  My preference for naming Features is as follows:

SCOPE.ProjectName.FeatureName

The reason for this is that there is no quick and easy way to know the scope of a feature from glancing at the solution explorer as all icons are the same.  Therefore in our solution the feature will be:

SITE.LifeInSharePoint.iGoogle.Assets

The next step is to double click on this feature and it should open the feature management screen on the left side of the window. Within this window you are able to change the Display Title and Description as well as manage the items in the feature.  We will call our feature LifeInSharePoint.iGoogle, the description can be what ever you please and the Scope should be set to SITE.  Finally add the Root.Content.Pages SPI into the feature and we are nearly complete.

Writing the Feature Receiver

For those who remember the last post, the control adapter requires an entry into the compact.browser file.  This entry registers our control adapter for use and it would be very useful if this was added automatically as part of our deployment.  To do this we will need to create a small feature receiver to do this for us.  To add a receiver, right click on the feature and click the Add Event Receiver link.

We are only going to manage the addition of the code to the compact.browser and not the retraction from the solution.  This can be added to your solution if you wish but to save time I will ignore it.

Our first step is to create two string constants which will contain the Control Adapter Type and the Assembly Name of the Solution.  The Assembly name will only contain the first part as the full assembly name will be retrieved later through reflection.

        private const string WEBPART_ADAPTER_CONTROL_TYPE = "System.Web.UI.WebControls.WebParts.WebPartZone";
        private const string WEBPART_ADAPTER_TYPE = "LifeInSharePoint.iGoogle.Common.ControlAdapters.WebPartRenderControlAdapter,";

The next step is to uncomment the FeatureActivated method and add the following code in.

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            // Load up the Compat.browser and add the the control adaptor
            // Get the site collection
            SPSite SiteCollection = (SPSite)properties.Feature.Parent;
            UpdateCompatBrowser(SiteCollection);
        }

This code simply gets the current Site Collection from the features property collection and then passes that SPSite object to the UpdateCompactBrowser method which is explained below in the code comments for each line.

        /// <summary>
        /// Add our control adaptor to the Compat.Browser file
        /// </summary>
        /// <param name="SiteCollection"></param>
        private void UpdateCompatBrowser(SPSite SiteCollection)
        {
            //Loop through each IISSetting in the current site collections Web App
            foreach (var IISSetting in SiteCollection.WebApplication.IisSettings)
            {
                //Create a path to the compact.browser
                String pathToCompatBrowser = IISSetting.Value.Path + @"\App_Browsers\compat.browser";

                //Load the Xml element
                XElement compatBrowser = XElement.Load(pathToCompatBrowser);

                //Select the correct element
                XElement existingElement = compatBrowser.XPathSelectElement(String.Format(
                                "./browser[@refID = \"default\"]/controlAdapters/adapter[@controlType=\"{0}\" and @adapterType=\"{1}\"]",
                                WEBPART_ADAPTER_CONTROL_TYPE,
                                WEBPART_ADAPTER_TYPE + Assembly.GetExecutingAssembly().FullName));

                //If it cannot find the element then it will add it
                if (existingElement == null)
                {
                    // Get the node for the default browser.
                    XElement controlAdapters = compatBrowser.XPathSelectElement("./browser[@refID = \"default\"]/controlAdapters");

                    // Create and add the markup
                    XElement newAdapter = new XElement("adapter");
                    newAdapter.SetAttributeValue("controlType", WEBPART_ADAPTER_CONTROL_TYPE);
                    newAdapter.SetAttributeValue("adapterType", WEBPART_ADAPTER_TYPE + Assembly.GetExecutingAssembly().FullName);

                    controlAdapters.Add(newAdapter);

                    // Overwrite the old version of compat.browser with the new version
                    compatBrowser.Save(pathToCompatBrowser);
                }
            }
        }

If we save all the items in the project, we are now ready to deploy our project to our site.  When the feature activates it will run the code above which will make the necessary changes to the compact.browser file and our solution should work as expected.

Deployment & Testing

To deploy the solution we need to build the solution by right clicking on the project and clicking Build. After the project has been built and no errors are found, we can then deploy by again right clicking on the project and clicking Deploy.  The default deployment configuration in Visual Studio will automatically activate the feature on the destination site. After deployment, navigate to the site and view the site collection features. We should see our feature deployed and activated.

If we now navigate to the root of the site collection and change the url to http://[SITE URL]/igoogle.aspx, then you should see our newly deployed interface with 5 different CEWP with some Lorem Ipsum text.

You should now be able to drag and drop these WebParts around the page, close, and change the colour. When you have finished and navigate away, refresh the page and the WebParts will remember their states.  If you edit the page you will see how the Control Adapter does not render in edit mode enabling you to add new WebParts.  You can see below that I have added a new Image WebPart to show how easy it is to create new “Widgets”.

NOTE:  It is important to understand that this interface is designed for “Rollup” style WebParts.  Due to how SharePoint 2010 and the Ribbon works with WebParts you may find some OOTB WebParts do not function fully. (Calendar WebPart, ListViewWebPart) The reason for some WebParts not working is that we are replacing the Chrome around the WebParts with our custom HTML (ControlAdapter). Many of the required ID’s etc are removed and therefore the Javascript that works with the Ribbon & Ajax fails.  I am working on this and will post an update when I find a solution.

Summary

In this post we have outlined how to get the iGoogle interface into a SharePoint environment.  Using a Visual Studio 2010 Project we have deployed css, images and javascript, created and deployed a Control Adapter, and added a page full of WebParts on to a site.  I hope this post gives you a stepping stone on how to implement something similar on your SharePoint Deployments.  Below I have uploaded a link to my Solution ZIP file that you can use and test on your environments.  I have not done lots of cross browser or different environment testing of the solution so should you find an issue let me know and I will try my best to find a solution.  In the next post I will show you how you can use the techniques shown in this series to come up with some innovative designs and implementations.

Download

LifeInSharePoint.iGoogle.zip

Quick Tip – jQuery click to expand / collapse Quicklaunch – UPDATED 20/06/2012

jquery_collapse_accordion

Hello everyone, following on from the previous Quick Tip I have yet another cool little snippet of jQuery code to enable a manually collapsable quicklaunch.  Many users who have downloaded my Metro UI masterpage commented if there was a way to have the hover quicklauch accordion replaced with a clickable version.  Well your requests have been answered and below is a snippet that will work on any v4.master page.  I have included some comments within the source code to help you out.

    <script type="text/javascript" src="http://ajax.Microsoft.com/ajax/jQuery/jquery-1.7.1.min.js"></script>    
    <script type="text/javascript">
    jQuery(function($) {
        //Hide all 
        $('.s4-ql li ul').hide();
        
        //Set the Images up
        var Collapse = "/_layouts/images/collapse.gif";
        var Expand = "/_layouts/images/expand.gif";        

        //Find each top level UI and add reletive buttons & children numbers
         $('.s4-ql ul li').find('ul').each(function(index) {
            var $this = $(this);            
            $this.parent().find('a:first .menu-item-text').parent().parent().parent().prepend(['<a class=\'min\' style=\'float:right; margin-left:5px;margin-top:6px;margin-right:5px;\'><img src=\'/_layouts/images/expand.gif\'/></a><span style=\'margin-top:5px;float:right;font-size:0.8em;\'>(', $this.children().length, ')</span>'].join(''));
        });
        
        //Setup Click Hanlder
        $('.min').click(function() {
            //Get Reference to img
            var img = $(this).children();
            //Traverse the DOM to find the child UL node
            var subList = $(this).siblings('ul');
            //Check the visibility of the item and set the image            
            var Visibility = subList.is(":visible")? img.attr('src',Expand) : img.attr('src',Collapse);;
            //Toggle the UL
            subList.slideToggle();
        
        });                
    });
    </script>

I hope that this code is what you were hoping for, and i will soon be updating the Metro Masterpage for Farm Solutions to include an option to choose your accordion type and a Metro UI version of the code.

As always comments / issues always welcome :)

UPDATE 20/06/2012.

Thanks to Anastacia for pointing out the issue with the script in Firefox.  I have updated the script to fix this issue by placing the anchor in a different location and updating the rest of the script. Please use the new script above which solves the issue.  Chris

 

EU Cookie Law & SharePoint – What’s affected?

cookies

What is the new EU Cookie Law?

The EU Cookie Law is intended to prevent information being stored on people’s computers, or to be used to recognise them through the device they are using, without their knowledge or agreement. The rules are not intended to restrict the use of particular technologies.  The deadline for compliance with the Cookie Law is the 26th May 2012. All websites in the UK must comply with the Information Commissioner’s Office guidance on the use of cookies, gain informed consent from your site visitors, or face up to a £500,000 fine.

What Kinds of Cookies are affected?

There are different types of cookies, and this new law applies to all of them:

Session cookies
These save information about your current viewing session – for example:

  • If you are logged in
  • If you have added items to the shopping basket

These are often less of a privacy concern as they only last for the duration of your browsing session and are generally required for the function of a website.

Persistent Cookies
A persistent cookie is stored on your device and generally remembers your preferences across one or many websites. Some examples are:

  • Whether you want to view comments in threaded or flat view
  • What font size you want to view the site in
  • What language you want to view the site in

First party cookies
First party cookies are set by the same domain that you are visiting – for example to authenticate you with that site.

Third party cookies
Third party cookies are set by websites other than the one you are visiting, and these tend to be in the ‘shady area’ when it comes to privacy. For example, when you visit a site it might store a cookie called ad.myadvertisingcompany.com. When you visit another site, it might store another cookie similar to this. Eventually the information is sent back to My Advertising Company to build up a profile of your web activity. (Note most browsers allow you to block 3rd party cookies)

What will happen if i do nothing?

The first thing to remember is that there are millions of websites on the internet, and many of them are personal blogs such as this one.  There are going to be millions of casual bloggers who have no idea what a cookie is, let alone how to comply with the new law.  Below is an extract from the ICO website explaining what they can do if they are not compliant.

Information notice: this requires organisations to provide the Information Commissioner with specific information within a certain time period.

Undertaking: this commits an organisation to a particular course of action in order to improve its compliance.

Enforcement notice: this compels an organisation to take the action specified in the notice to bring about compliance with the Regulations. For example, a notice may be served to compel an organisation to start gaining consent for cookies. Failure to comply with an enforcement notice can be a criminal offence.

Monetary penalty notice: a monetary penalty notice requires an organisation to pay a monetary penalty of an amount determined by the ICO, up to a maximum of £500,000. This power can be used in the most serious of cases and if specific criteria are met, for example, if any person has seriously contravened the Regulations and if the contravention was of a kind likely to cause substantial damage or substantial distress. In addition, the contravention must either have been deliberate or the person must have known or ought to have known that there was a risk that a contravention would occur and failed to take reasonable steps to prevent it.

How do i know what Cookies my site uses?

Many companies on the internet are providing services which are called Cookie Audits.  Having not paid for one of these, I can only assume they deliver on the price tag being asked for (some of them are £300+). Most will promise to analyse your website and inform you of all the cookies your site uses, comparing them with a reference database to provide you with a report.  If you have a very large site, with hundreds if not thousands of pages, then this may be money well spent.  On the other hand, if you have a smaller site then you can do some of the research very easily with a free Firefox extension called View Cookies.  After installing View Cookies, you will find a new Cookies-tab in the Page Info dialog box. You can open the Page Info dialog box by selecting Page Info in the Tools menu. You can also right-click on the webpage and select View Page Info from the drop down menu.

Using this extension should help the majority of users on the internet get a general view of the scale of the cookies.  This blog for example has three cookies for Google Analytics. As of the deadline, these cookies will require the user to “allow” these to be used and set.

IMPORTANT: The UK law does not allow you to retrospectively set cookies and then delete them if the user opts out.  You have to ensure that they are only set after user confirmation.

How does this affect my SharePoint Site?

It is important to know that technically, even Intranets are covered by this law.  The framework will insist that websites ask their users for permission before recording their activities online. The implication is that if you use cookies on your intranet, you may have to ask for your employee’s permission first.

I have done some initial research, and I will try my hardest to keep this updated on cookie usage information. SharePoint 2010 uses cookies to log session information, Web Analytics, and FBA Login information.  There is a cookie called “OfflineClientInstalled” which is set on the settings pages, which I can assume could be something to do with SharePoint Workspace Manager or possibly Office?  Others found on list view pages are “stsSyncAppName” and “stsSyncIconPath”, which I am still investigating.

If you find any commonly set cookies or have any information on the ones listed above, please leave a comment and we can try to build up a repository of cookies and their purpose.

How do I make my site EU Cookie Compliant?

One of the most common solutions for becoming compliant will be through the use of Javascript code. The code will create a cookie to store the users preference and then depending on their response, additional Javascript code would set or remove cookies.

There are many different solutions you can use to present the user with the information:

  1. Modal Dialogue
    Using a modal dialogue would be the most intrusive method to ask users for permission.  It is a simple enforced call to action which will outline the reasons for the cookies you would like to set.  The problems with this method is that it will prevent users from interacting with the website and could increase the bounce rate from your site.
  2. Status Bar
    Subtle status bars on the top or bottom of a website can be included to inform users about the cookie policy.  This would remain on all pages until they either accept or decline cookie usage.  While this is less intrusive than the previous solution, it could be so subtle that a user never opts into the usage agreement, and functionality may be reduced for the visitor.
  3. Warning Panel
    A warning panel is similar to the previous option however it has the advantage of informing the visitor to your site what setting the page is using.  Downsides however are that a user may not decide to opt in and a warning bar would obscure parts of the page.

Which option you decide to go with is up to you, as all options have pros and cons.  If you have any other suggestions for how you could accomplish the task, please feel free to share your ideas.

After some quick searching online, one of the better solutions I found was “Simple Cookie Prompt” (http://www.pandadoodle.com/cookies/)  This lightweight Javascript code places a subtle status bar message for users at the top of each page and then sets one of four options depending on answer.

There are 4 possible returned values:

  1. The user has actively opted out of all cookies on the site. Shows the red notification.
  2. The user has seen a warning about cookies, but neither accepted nor declined, this is classed as inferred acception. Shows the blue notification
  3. The user has accepted all cookies to the site. Shows the green notification.
  4. The user’s first visit to the site, no cookies accepted or declined. Shows the yellow notifcation

Using a small piece of JS code to wrap around your existing code is as simple as this:

if(cPrompt.checkCookie() == 1 || cPrompt.checkCookie() == 2){
    /**
       Cookie Storing Code Here
    **/
}

Summary

The EU Cookie Law itself is nothing new, however with the pending deadline, companies are becoming increasingly worried about their compliance.  I have noticed only a handful of UK taking steps to become compliant e.g. (http://www.bt.co.uk/) and I’m sure that in the coming months all the big players will be compliant.  If you have a simple website, then becoming compliant will be relatively straight forward, however if you are running a highly complex e-commerce site or one with detailed user customisation, then you will have a much tougher battle on your hands.  Please give me your feedback on your thoughts about this issue, and how you are going to make your SharePoint website / intranet EU Compliant.