How to add a floating menu to a page in SharePoint 2010

Problem:

My customer wanted to had a floating menu to the NewForm.aspx page for one of the lists. The floating menu will stay on the top left corner of the page as page scrolls.

Demo:

This was done on our internal website, but it works similar to this post http://css-tricks.com/examples/ScrollingSidebar/

Solution:

After a few searches online, I found it’s often done in HTML using CSS or JavaScript. See the References section for the list of articles I found relating to this feature.

The article worked really well for me is this one. The article talked about how to make the quick launch float, but I changed the div name and works for a  normal menu.

Here is how:

1. Go to the article page, download the stickyQL.js file.

2. Open the stickyQL.js file, change

var elem = "#s4-leftpanel";

to

var elem = "#YourFloatingDivID";

3. Save the file in the site collection’s style library. We’ll need to reference the file later.

4. Go to the site and open SharePoint Designer. From the left pane, select Master Pages.

5. Open the v4.master. Find </head>. Add the following lines before </head>

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="[servername]/Style Library/MyJS/stickyQL.js"></script>

6.Go to the NewForm.aspx page, edit the page and add a new content editor web part.

7. Add the following code to the CEWP’s HTML source.

<div id="sidebar" style="width: 15%; float: left; z-index: 1;">Some text on the floating menu.</div>

8. Click “Stop Editing” to exit editing.

References:

Floating menu in HTML using CSS or JavaScript

Floating sidebar in HTML using CSS and JavaScript

Sticky or Floating box in SharePoint 2013 site’s Sidebar

Unable to display this Web Part. SharePoint 2010 Data View Web Part issue.

Problem:

On our intranet, we have been constantly getting the following errors on pages that contains a Data View Web Part. Although I said constantly, it doesn’t mean that the error shows on a page all the time. It meant that a page sometimes works sometimes doesn’t. But if it doesn’t, it will show that error message. The inconsistant of the error makes it more difficult to debug and the log file wasn’t helpful either.

Data View Web Part Error

After searching online, a few people has had the same problem. Someone said it had something to do with a SharePoint Update and suggested to install a hotfix, but we didn’t have that update installed so we didn’t want to try the hotfix. Another post mentioned that adding the “AllowPersonalization” property to a web part zone should fix the problem. However, it didn’t say how to add this property.

Solution:

Open up the root site in SharePoint Designer. From the left Navigation pane, choose Page Layouts. I had a custom Page Layout used by those pages that displays the Data View Web Part, so I opened that page layout. Follow the prompt and check it out. Click the “Advanced Mode” button on the top ribbon. In your code, search for “WebPartPages:WebPartZone” and inside that tag, add AllowPersonalization=”true”.

For example:

<WebPartPages:WebPartZone id="g_9973D18452754B25AAF6B1DBDC75CF6A" runat="server" AllowPersonalization="true" title="Box 1"><ZoneTemplate></ZoneTemplate></WebPartPages:WebPartZone>

After editing the page layout, make sure to check in and publish it.

SharePoint 2010 Best Bets Configuration

Visit this page for setting up best bets in OOTB search:

http://www.techgrowingpains.com/2011/02/sharepoint-2010-search-best-bets-and-you/

The surfray site also provided an article about this: http://www.surfray.com/blog/2013/05/30/adding-best-bets-to-sharepoint-2010-search/

One thing either of the sites mentioned was to add a best bet web part to the result page to display the best bets.

Add a jQuery accordion with a SharePoint CQWP

Requirements:

  • Create a web part to display categories and procedures.
  • Group the procedures by category.
  • Can add, edit and delete categories and procedures.
  • Can view the full detail of a procedure

Final delivery:

result

Features:

  • No custom solution developed. Applied custom CSS and JavaScript to an OOTB content query web part.
  • Used jQuery accordion to toggle the categories and items belonging to the category.
  • Edit category and procedure in a modal dialog box.

Solution:

1. Create two lists, Category and Procedure

Category list columns:

Title: Single Line of Text

Description: Multiple Line of Text

                Procedure list columns:

Procedure Name: Single line of text

Category: Lookup (Lookup to Category list, tick the ID checkbox)

ProcID: Calculated (Formular: =TEXT(Created,”ddMMyyhhmmss”))

ProcLink: Calculate (Formular: =”/pages/DisplayFullProc.aspx?ProcID=”&ProcID)

 

2. Create DisplayFullProc.aspx page with a data view web part. The DVWP displays a single Procedure item. (This step is optional)

3. Go to a page and add a CQWP. Export it to your local desktop.

4. Open the exported .webpart file in a text editor.

5. Change the following code:

<property name="Title" type="string">Accordion</property>
<property name="ItemXslLink" type="string">/Style Library/XSL Style Sheets/AccordionStyle.xsl</property>
<property name="MainXslLink" type="string">/Style Library/XSL Style Sheets/AccordionCQWP.xsl</property>
<property name="Xsl" type="string">&lt;xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime" exclude-result-prefixes="xsl cmswrt x" &gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/Header.xsl" /&gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/AccordionStyle.xsl" /&gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/AccordionCQWP.xsl" /&gt; &lt;/xsl:stylesheet&gt;</property>
     <property name="UseCache" type="bool">False</property>

6. Upload the edited .webpart file to the Web Part Gallery in the root site.

7. Open your root site in SharePoint Designer. Navigate to All Files->Style Library->XSL Style Sheets. Create a new file and call it AccordionStyle.xsl.  This is the style file is for each procedure item in the list. Copy the following code to the document.

<xsl:stylesheet
  version="1.0"
  exclude-result-prefixes="x d xsl msxsl cmswrt"
  xmlns:x="http://www.w3.org/2001/XMLSchema"
  xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
  xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
  xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt">

<!-- Procedure Item Template -->
    <xsl:template name="Accordion" match="Row[@Style='Accordion']" mode="itemstyle">
       <!--Need to pass the category ID value to the group header, but the ID doesn't need to be displayed-->          
                   <div style="display:none">
                                <xsl:value-of select="@CategoryID" />
                   </div>
       <div>
                  <!--Edit Proc Button-->
                      <a href="#">
                                                <xsl:attribute name="onclick">
                                                                javascript:portal_openEditProModalDialog('<xsl:value-of select="@ProcID"/>')
                                                </xsl:attribute>
                                             <img src="/Style Library/Images/edit-icon-thumb.png" border="0"></img>
                                  </a>

                                  <!--Delete Proc Button-->
                                  <a href="#">
                                                <xsl:attribute name="onclick">
                                                                deleteProc('<xsl:value-of select="@ProcID"/>')
                                                </xsl:attribute>
                                                <img src="/Style Library/Images/delete-icon-thumb.png" border="0"></img>
                                  </a>

                      <xsl:text>                </xsl:text>

                                  <a href="{@ProcLink}" target="_blank">
                                <xsl:value-of select="@Title"/>
                      </a>
       </div>
    </xsl:template>
</xsl:stylesheet>

8. In the XSL Style Sheets folder, make a copy of the ContentQueryMain.xsl file and rename it to AccordionCQWP.xsl. Make the following modifications:

  • Replace dfwp-list with accordion (Line 32 and 83)
  • Replace dfwp-item with accordion-item (Line 34)
  • Replace Line 83 with the following code:

This code displays the Expand All, Collapse All, Add Category and Add Procedure links before the list. To make it easier to see, visit this site and this site for conversion.

<xsl:variable name="BeginColumn1" select="string('&lt;div class=&quot;expand-all&quot;&gt;Expand All&lt;/div&gt;&lt;div class=&quot;collapse-all&quot;&gt;Collapse All&lt;/div&gt;&lt;div class=&quot;add-cat&quot;&gt;&lt;a href=&quot;/ippreserver/Lists/Category/NewForm.aspx?IsDlg=0&quot;&gt;Add Category&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;add-proc&quot;&gt;&lt;a href=&quot;/ippreserver/Lists/Procedure/NewForm.aspx?IsDlg=0&quot;&gt;Add Procedure&lt;/a&gt;&lt;/div&gt;&lt;ul class=&quot;accordion&quot; style=&quot;width:')" />

9. In the XSL Style Sheets folder, back up the Header.xsl file by making a copy of the original file and rename it to Header_original.xsl. The Header.xsl is the style file for each category group the list.  Edit the Header.xsl file. Paste the following code before </xsl:stylesheet>

<xsl:template name="IPCat" match="*[@GroupStyle='IPCat']" mode="header">
    <div>
      <a href="#">
              <xsl:attribute name="onclick">
                      javascript:portal_openEditCatModalDialog('<xsl:value-of select="@CategoryID"/>')
              </xsl:attribute>
              <img src="/Style Library/Images/edit-icon-thumb.png" border="0"></img>
      </a>                  
      <a href="#" >
              <xsl:attribute name="onclick">
                       deleteCategory('<xsl:value-of select="@CategoryID"/>')
              </xsl:attribute>
              <img src="/Style Library/Images/delete-icon-thumb.png" border="0"></img>
      </a>

      <xsl:text>                </xsl:text>

      <xsl:call-template name="OuterTemplate.GetGroupName">
        <xsl:with-param name="GroupName" select="@*[name()=$Group]"/>
        <xsl:with-param name="GroupType" select="$GroupType"/>
      </xsl:call-template>
    </div>
  </xsl:template>

10. Go back to the SharePoint site. Open the site in SharePoint Designer. Navigate to Site Pages. Upload an empty .txt file. This file will be used to store JavaScript and CSS. A content editor web part will reference this file. It actually can be uploaded to any location.

11. Paste the following code to the .txt file:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
 
<script type="text/javascript">
/*--------------------------Expand All, Collapse All and Category Header Click--------------------------*/
function accordionLoad() {
 
    $(".accordion-header").removeClass("expanded");
    $(".accordion-content").hide();
 
    $(".accordion-header").bind("click", function(){
        $(this).toggleClass("expanded");
        $(this).siblings(".accordion").find(".accordion-content").slideToggle();
        $(this).siblings(".accordion").find(".accordion-content").css("border-bottom","1px solid #ccc");
    })
 
    $(".expand-all").bind("click",function(){
        $(this).siblings(".accordion").find(".accordion-content").slideDown();
        $(this).siblings(".accordion").find(".accordion-header").addClass("expanded");
    })
 
    $(".collapse-all").bind("click",function(){
        $(this).siblings(".accordion").find(".accordion-content").slideUp();
        $(this).siblings(".accordion").find(".accordion-header").removeClass("expanded");
    })
}
/*--------------------------End Expand All, Collapse All and Category Header Click--------------------------*/
 
/*--------------------------Pop up IPPreserver Category Edit Form--------------------------*/
function portal_openEditCatModalDialog(id){
    var options = {
        url:"/ippreserver/Lists/Category/EditForm.aspx?ID="+id+"&IsDlg=1",
        dialogReturnValueCallback: CatDialogCallback
        };
 
    SP.UI.ModalDialog.showModalDialog(options);
}
 
function CatDialogCallback(dialogResult, returnValue){
                if (dialogResult != 0)
                {
                                document.location.reload(true);
                }
}
/*--------------------------End Pop up IPPreserver Category Edit Form--------------------------*/
 
/*--------------------------Delete the selected category--------------------------*/
var oListItem;
var categoryName;
var clientContext;
function deleteListItem(id) {
 
    this.itemId = id;
                var siteUrl = '/ippreserver';
 
    clientContext = new SP.ClientContext(siteUrl);
    var oList = clientContext.get_web().get_lists().getByTitle('Category');
                oListItem = oList.getItemById(id);
    
    clientContext.load(oListItem, 'Title');
    clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
 
function onQuerySucceeded() {                 
                categoryName = this.oListItem.get_item('Title');
    oListItem.deleteObject();
    clientContext.executeQueryAsync(Function.createDelegate(this, this.onSecondQuerySucceeded), Function.createDelegate(this, this.onSecondQueryFailed));    
}
 
function onQueryFailed(sender, args) {
 
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
 
function onSecondQuerySucceeded() {                                  
    alert('Category deleted: ' + categoryName);
    location.reload();
}
 
function onSecondQueryFailed(sender, args) {
 
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
 
 
function deleteCategory(id)
{
                var x;
                var r=confirm("Are you sure you want to delete this category?");
                if (r==true)
                {
                                deleteListItem(id);                           
                }              
}
/*--------------------------End Delete the selected category--------------------------*/
 
/*--------------------------Pop up IPPreserver Procedure Edit Form--------------------------*/
function portal_openEditProModalDialog(id){
    var options = {
        url:"/ippreserver/Lists/Procedure/EditForm.aspx?ID="+id+"&IsDlg=1",
        dialogReturnValueCallback: ProDialogCallback
        };
 
    SP.UI.ModalDialog.showModalDialog(options);
}
 
function ProDialogCallback(dialogResult, returnValue){
                if (dialogResult != 0)
                {
                                document.location.reload(true);
                }
}
/*--------------------------End Pop up IPPreserver Category Edit Form--------------------------*/
 
/*--------------------------Delete the selected procedure--------------------------*/
var pListItem;
var procName;
var pContext;
function deleteProcItem(id) {
 
    this.itemId = id;
                var siteUrl = '/ippreserver';
 
    pContext = new SP.ClientContext(siteUrl);
    var oList = pContext.get_web().get_lists().getByTitle('Procedure');
                pListItem = oList.getItemById(id);
    
    pContext.load(pListItem, 'Title');
    pContext.executeQueryAsync(Function.createDelegate(this, this.onPQuerySucceeded), Function.createDelegate(this, this.onPQueryFailed));
}
 
function onPQuerySucceeded() {                              
                procName = this.pListItem.get_item('Title');
    pListItem.deleteObject();
    pContext.executeQueryAsync(Function.createDelegate(this, this.onSecondPQuerySucceeded), Function.createDelegate(this, this.onSecondPQueryFailed));    
}
 
function onPQueryFailed(sender, args) {
 
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
 
function onSecondPQuerySucceeded() {                                                
    alert('Procedure deleted: ' + procName);
    location.reload();
}
 
function onSecondPQueryFailed(sender, args) {
 
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
 
 
function deleteProc(id)
{
                var x;
                var r=confirm("Are you sure you want to delete this procedure?");
                if (r==true)
                {
                                deleteProcItem(id);                         
                }              
}
/*--------------------------End Delete the selected category--------------------------*/
 
$(document).ready(function(){
    accordionLoad();
       
});
 
</script>
 
/*--------------------------Style Sheet--------------------------*/
<style>
 
ul.accordion {
                list-style:none;
                margin:0px;
                padding:0px;
}
.accordion-item {
/*           border-top:1px solid #ccc;*/
}
.accordion-header {
                font-size:1.3em;
                cursor:pointer;
                padding:10px;
                border-bottom:1px solid #ccc;
}
.accordion-header:hover {
                background:#efefef;
}
.accordion-header.expanded {
                background:#dfdfdf;
}
.accordion-content {
                padding:5px 20px;
}
.expand-all,
.collapse-all {
                display:inline-block;
                cursor:pointer;
                padding:5px 10px;
zoom:1; *display: inline; _height: 30px;
 
}
.expand-all:hover,
.collapse-all:hover {
background:#efefef;
}
 
.add-cat,
.add-proc {
                display:inline-block;
                cursor:pointer;
                padding:5px 10px;
zoom:1; *display: inline; _height: 30px;
 
}
.add-cat:hover,
.add-proc:hover {
background:#efefef;
}
 
.editIcon
{
                vertical-align:middle
}
 
.deleteIcon
{
                vertical-align:middle;
                width:20px;
}
</style>
/*--------------------------End Style Sheet--------------------------*/

12. Upload the edit and delete icon to Style Library-> Images folder in SharePoint Designer

13. Go to the SharePoint page. Add a CEWP and enter the .txt file’s link to the Content Link field.

14. Add the uploaded CQWP from Step 6.

15. Edit the CQWP’s properties.

Browse to the Procedure list.

1

2

3

4

16. Overall structure:

  • Category and Procedure lists
  • OOTB CQWP, CEWP
  • AccordionStyle.xsl
  • AccordionCQWP.xsl
  • Header.xsl
  • text file to store CSS and JavaScript

References:

Demo: http://www.isb.bj.edu.cn/admissions/Pages/Frequently-Asked-Questions.aspx

Source file: https://bentedder.qx.ly/2yPB

Steps to create your own: http://www.bentedder.com/create-a-jquery-accordion-with-a-sharepoint-cqwp/

HTML Encoder/Decoder:

http://www.web2generators.com/html/entities

http://www.textfixer.com/html/html-character-encoding.php

 

Three Common Mistakes with SharePoint Governance

1. People don’t know why they should follow your governance policy

What often happens with SharePoint governance plans is that they’re produced (usually a lengthy document), uploaded to SharePoint along with an email to staff saying it’s there and they should refer to it for any SharePoint related guidance. This method of communication is what I call “toss it over the fence and hope that someone catches it”. Do this and it’s very unlikely that your SharePoint governance document is going to be read, let alone followed.

Fix it

Once your SharePoint governance policy is finished, make sure you communicate why you want people to follow this. Simply stating that people should follow it is not going to cut it. Telling people that they have to follow these policies just because is not going to be as effective as telling them if you tag your document it will make it easier to find later on. Or by following this policy you are helping us avoid legal issues.

Think about your own governance policies and what positive effects will flow from following them. Are there some time consuming tasks that can be sped up by following correct SharePoint governance policy? Will complying with these policies improve business productivity? Will it help staff build better working relationships with their colleagues? Most people have a commitment to making the business work as well as to their colleagues but only if they understand why they are doing it.

2. You make it hard for people to be compliant

Complying with a governance policy is important, especially when there are legal ramifications. For example, one of the bigger issues especially in the US is that if you have a governance policy and you’re not following it, you have created a big litigation risk. So one of the real reasons to focus on governance is to avoid the risk of not meeting legal requirements or having to spend a lot of money in the eDiscovery process when you get sued.

But perhaps people don’t know about this risk (see number one above) or the process for complying contains so many steps and is so time consuming that people are not going to bother with it.

Fix it

Automate as much as possible to take the hard work out of complying with your SharePoint governance policy. Use templates so that all sites start with good governance built right in. When possible, use a third-party tool to make it easier to ensure compliance.

3. Your SharePoint governance policy is a beast of a document

We’re really good at writing 100+ page governance documents. Even if you believe it’s a masterpiece and you can think of nothing better than pouring a good glass of red and settling in for the night to read it, I don’t know many people who would agree. It’s a shame because your governance plan actually contains valuable information that people need to know.

Fix it

No one reads long documents so don’t create a SharePoint governance plan as a long, boring document. Think about creating small bits of consumable information. Wiki pages and quick guides are a great way to easily great small, visually appealing consumable bits of governance guidance.

But if you really want to make it easy for people, deliver your governance content in the context of where people work. For the most part, people won’t pay much attention to governance (or training) until they need to know how to do something. Try to go for “just in time governance”: small chunks of SharePoint governance information delivered at the moment you need it.

For example, if I’m creating a document, I’m probably concentrating on writing the document, not thinking about what file naming convention I should use. I’m only worried about this when it comes to saving my document. So ideally you want your quick guide about file naming conventions to surface when I’m about to save it. Like magic!

A simple, “no code” way to do this is to use Content Editor Web Parts (CEWP) on document library pages. CEWPs allow you to surface information “in place” for this kind of thing.

describe the imageAlthough SharePoint governance plans can be seen as just a necessity, the information in your plan is extremely valuable and can help make life easier, not harder, for your users. Make sure you’re communicating the value to your users, making it easy through automation tools and providing “just in time” governance and training.

 

Reference: http://www.blog.shareconference.com/blog/bid/345767/Do-you-make-these-three-common-mistakes-with-SharePoint-governance?utm_campaign=other&utm_source=hs_email&utm_medium=email&utm_content=10757188&_hsenc=p2ANqtz-8uXvYG_3z20YPgozJHofhWA7LuRZVip_LFxjl1-xHKasnfxChkC47mZ6zAEbk29bjpv6dG5vNjtyV4nLfv9fWwzHAEtQ&_hsmi=Optional.of%2810757188%29

Using SPServices to provide data to autocomplete field on Nintex

Environment:

SharePoint Server 2010, Nintex Form 2010, SPServices 2013.01

Problem:

In one of our Nintex form, we need to allow people to search for items that are stored on another list and set the search result to be the input field’s value.

Narrative:

Initially, I found a method called $().SPServices.SPAutocomplete from the SPServices site . In their SP2007 demo site, it worked perfectly on a normal form. So I copied the code to my Nintex form and it threw a error saying “Column is not an input control or is not found on page”. I searched that error message and found this article which had the same error. After reading it, I realise that Nintex form might have changed the control id therefore, the script couldn’t find it. The code posted by hilary86 worked the trick.

Result:

This is the screenshot of my final result. When user start typing in the JournalTitle input field, items that contains the typed in words will show in the dropdown.

To delete

How to make it happen:

  1. The items showed in the autocomplete dropdown list are stored in another SharePoint list. So first of all, we need to create a SharePoint list and add a few items to the list. I called it “Journals”.
  2. Download the SPServices file from http://spservices.codeplex.com/, unzip it.
  3. Open the jquery.SPServices-VersionNumber.min.js  file and search for “(jQuery)”. It should be in the last line of the file. Replace it with “(NWF$)”. Save the file.
  4. Upload it to the site collection’s Style Library.
  5. Create another js file in the Style Library, my one called NF_AutoComplete.js
  6. Type the following code to the NF_AutoComplete.js
    NWF$(document).ready(function() {   
       //The source data for the autocomplete is the Journals list  
       //Store the journal titles in a array variable  
       var externalParties = [];     
       NWF$().SPServices({      
          operation: "GetListItems",      
          async: false,      
          listName: "Journals",      
          CAMLViewFields: "<ViewFields><FieldRef Name='Title' /></ViewFields>",   //the name needs to be changed accordingly   
          completefunc: function (xData, Status) {        
             NWF$(xData.responseXML).SPFilterNode("z:row").each(function() {          
                externalParties.push(NWF$(this).attr("ows_Title"));        
             });      
          }    
       });        
       //journalinput is added on the control in the NF  
       NWF$("#" + journalinput).autocomplete({      
          source: externalParties  
       });
    });
  7. Go to the Nintex Form. In the ribbon, navigate to the form’s Settings. Expand the Advanced section, add the URLs of the  jquery.SPServices-VersionNumber.min.js  and NF_AutoComplete.js to the Custom JavaScript Includes box. Save it.
  8. Click on the input box control which will display the autocomplete and click Control Settings from the ribbon.
  9. Expande the Advanced section, change the Store Client ID in JavaScript variable value to Yes. Enter the id used in the code in Step 6. So for me, it was journalinput. Save it.
  10. Make sure you publish the form.
  11. That’s it. There are some other options can be added to the autocomplete, change to suit your needs.

References:

A big thanks to Marc Anderson and the team who developed SPServices!!