All posts by Alexander Bautz

Add resize handle to multiline text field (plain text, rich text and enhanced rich text)

13.03.2011: Updated the code and made it easier to use by referring jQuery and jQueryUI from Google.


I got this request from Larry:

Maybe this time I can post something we can get to work. I have been trying to peice together several scripts, including yours to make the multiple line text fields expandable. I found a workiong script but it only worked on plain text. I am trying to modify it to work on rich text. When i add your script for fieldinternalname I can at least see the image under the rich text box, but it does not work. using the new script I can not get the plain text to work. this is the link to the jquery plugin for textarea resizer…

The plain text multi lines are no problem, but the rich text and enhanced rich text ones are a bit tricky. They are made up of <IFRAME>’s, and the input does not go in a <textarea> tag.

I have made this solution based on the jQuery UI “Interaction” Resizable.

Internet Explorer 8:
IMG
Firefox 3.5.7:
IMG

Add a CEWP below your NewForm and EditForm and add this code:
Get the code here

Ask if anything is unclear.

Regards
Alexander

Add a Success Ratio label to the first group header in a dual grouped list view

27.01.2012 Updated to support SharePoint 2010.


By request from Charlie Epes i have made a function for adding a “Success Ratio” to the ms-gb-row (first group in grouped list view):
IMG

This function takes two arguments:

  • leadText: The text added before the percentage value
  • txtToFind: The text to search for and to get the number of items from

The value is a product of the number of items in the group that matches the “txtToFind”, divided by the total number of items from the ms-gb-row (first group) times 100 to get the percentage.

Add a CEWP below the list view you want this to apply to, and add this code (Modify the text values in line 18 to match your values in the second group):

&lt;script type=&quot;text/javascript&quot; src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
/* Function for adding a &quot;Success Ratio&quot; to the ms-gb-row (first group in grouped list view).
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * LastMod: 27.01.2012
 * ---------------------------------------------
 This function takes two arguments:
   leadText - The text added before the percentage value
   txtToFind - The text to search for and to get the number of items from
 
  The value is a product of the number of items in the group that matches the &quot;txtToFind&quot; divided 
  by the total number of items from the ms-gb-row (first group) times 100 to get the percentage.
*/

successRatio('Success Ratio = ','Sold');

function successRatio(leadText,txtToFind){	
	$(&quot;.ms-gb&quot;).each(function(){
		var gbID, textRaw, gbText, gbVal, htmlRaw, part1, part2;
		gbID = $(this).parents('tbody:first')[0].id;
		textRaw = $(this).text();
		gbText = textRaw.substring(textRaw.indexOf(':')+2,textRaw.indexOf('(')-1);
		gbVal = textRaw.match(/d+/);
		getSubGroupes(leadText,gbVal,gbID,txtToFind,this);
		htmlRaw = $(this).html();
		part1 = htmlRaw.substring(0,htmlRaw.lastIndexOf('(')+1);
		part2 = htmlRaw.substring(htmlRaw.lastIndexOf('(')+1);
		$(this).html(part1 + &quot;total=&quot; + part2)	
	});
}

function getSubGroupes(lt,tot,gID,ttf,obj){
	$(&quot;tbody[id^='&quot;+gID+&quot;']:has('td.ms-gb2')&quot;).each(function(){
		var gb2ID, gb2TextRaw, gb2Text, gb2Val
		gb2ID = this.id;
		gb2TextRaw = $(this).text();
		gb2Text = gb2TextRaw.substring(gb2TextRaw.indexOf(':')+2,gb2TextRaw.indexOf('(')-2);
		gb2Val= gb2TextRaw.match(/d+/);
		if(gb2Text==ttf){
			val = Math.round((gb2Val/tot*100)*10)/10;
			$(obj).append(&quot;&lt;span style='padding-left:25px;color:red;font-weight:bold'&gt;&amp;nbsp;&quot; + lt + val + &quot;%&lt;/span&gt;&quot;);
		}
	});
}
&lt;/script&gt;

Ask if anything is unclear.

Regards
Alexander

Check workflow status and refresh page when status equals “Completed”

11.01.2010: Updated code due to a bug (line 36 is updated). Thanks to Scott Muldowney for spotting it.


The scenario:
You open a list item in EditForm, and the list item has a running (not yet completed) workflow. Nothing prevents you from editing the item, but when you try to save your edited item:

Save Conflict
Your changes conflict with those made concurrently by another user. If you want your changes to be applied, click Back in your Web browser, refresh the page, and resubmit your changes.

In this article i will provide a solution for:

  • Checking the workflow status, and if not finished, set a timer that checks the workflow every 5 seconds for a set period of time.
  • Refresh the page if the workflow finishes within the maximum wait time.

If status is “In progress”, the timer runs, and the status is checked every 5 seconds:
IMG
If timed out, you get this:
IMG

This article is a follow-up on Prevent editing of a list item if the workflow has failed. You have to read that article before continuing with this one.

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The scripts “interaction.js” and stringBuffer.js” is created by Erucy and published on codeplex – you find them here.

Add a CEWP below your EditForm, and add this code:

&lt;div id=&quot;customTimerMsg&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;customTimer&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;customTimerCheck&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/interaction.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/stringBuffer.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/RefreshWhenWorkflowCompletes.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
  // How long will the timer run before aborting
  maxWaitSec = 20; 
  // Change ListGuid and Workflow &quot;FieldInternalName&quot;
  listNameOrGuid = 'A3749468-0C23-493B-8854-06DF04200B43';
  workFlowInternalName = 'MyWF';
  administratorEmail = 'alexander.bautz@gmail.com';
&lt;/script&gt;

Parameters explained:

  • maxWaitSec: The max wait time in seconds
  • listNameOrGuid: Display name or Guid of current list
  • workFlowInternalName: The “FieldInternalName” of the workflow to check
  • administratorEmail: The administrator’s email – for when the workflow has failed

The code for the file “RefreshWhenWorkflowCompletes.js” is found here:

/* Refresh list item when workflow finishes
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.0
 * LastMod: 10.01.2010
 * ---------------------------------------------
 * Include reference to:
 *  jquery - http://jquery.com
 *  interaction.js - http://spjslib.codeplex.com/
 *  stringBuffer.js - http://spjslib.codeplex.com/
 * ---------------------------------------------
 * Call from a CEWP below the list form in EditForm
*/

$(document).ready(function(){
	checkStatusAndRefresh();
});

var SiteTitle = $.trim($(&quot;.ms-sitetitle a&quot;).text());
var ListName = $.trim($(&quot;.ms-pagetitle a&quot;).text()); 

function checkStatusAndRefresh(){
var wfStatus = getWorkflowStatus();
	if(wfStatus==3){ // 3 = &quot;Error Occured&quot;
		$(&quot;#part1&quot;).hide(); // Hide the list form
		$(&quot;#part1&quot;).before(&quot;&lt;div class='ms-sitetitle'&gt;A workflow has failed. You cannot edit this item until this issue is resolved.&lt;/div&gt;&quot; + 
			&quot;&lt;div style='padding-left:10px'&gt;&lt;a title='Click to send e-mail to an administrator' href='mailto:&quot; + administratorEmail + &quot;?subject=Failed workflow on site: &quot; + SiteTitle + 
			&quot;, list: &quot; + ListName + &quot;, itemId: &quot; + getID() + &quot;'&gt;Click to send e-mail to an administrator&lt;/a&gt;&lt;/div&gt;&quot;);
	}else if(wfStatus==2){
		$(&quot;#part1&quot;).hide(); // Hide the list form
		waitingForRefresh = true;				
		customTimer();
	}else{
		if(typeof(waitingForRefresh)!='undefined' &amp;&amp; waitingForRefresh){
			refreshPage();
		}
	}
}

function customTimer(s){ 
if(typeof(s)=='undefined')seconds = 0;
if(typeof(accumulated)=='undefined')accumulated = 0;
	if(accumulated&lt;maxWaitSec){
		if(seconds&lt;5){	
			seconds+=1
			$(&quot;#customTimerMsg&quot;).html(&quot;&lt;div class='ms-sitetitle'&gt;The workflow has not yet finished: Waiting for a maximun of &quot; + maxWaitSec + &quot; seconds,&lt;br&gt;checking the workflow every 5 seconds.&lt;/div&gt;&quot;);
			$(&quot;#customTimer&quot;).html(&quot;&lt;div style='padding-left:10px'&gt;Waiting: &quot; + (accumulated + seconds) + &quot;&lt;/div&gt;&quot;); 
			setTimeout(function(){
				customTimer(seconds);
			},1000);
		}else{
			accumulated = accumulated + seconds;
			$(&quot;#customTimerCheck&quot;).html(&quot;&lt;div style='padding:10px;color:red'&gt;Checking WF...&lt;/div&gt;&quot;).show().fadeOut(1750);
			checkStatusAndRefresh();
		}
	}else{
		$(&quot;#customTimerMsg&quot;).html(&quot;&lt;div class='ms-sitetitle'&gt;The workflow did not finish during the time specified.&lt;/div&gt;&quot; + 
		&quot;&lt;div style='padding:10px;font-size:12px'&gt;&lt;a href='&quot; + L_Menu_BaseUrl + &quot;'&gt;Return to site &quot;&quot; + SiteTitle + &quot;&quot;&lt;/a&gt;&amp;nbsp;|&amp;nbsp;&quot; + 
		&quot;&lt;a href='javascript:refreshPage();'&gt;Wait for &quot; + maxWaitSec + &quot; new seconds.&lt;/a&gt;&lt;/div&gt;&quot;);
		$(&quot;#customTimer&quot;).html(''); 
	}
}

function refreshPage(){
	window.location.reload();
}

function getWorkflowStatus(){
var thisID = getID();
	wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
    var item = getItemById(listNameOrGuid,thisID,[workFlowInternalName]); 
    if(item != null){
        return  item[workFlowInternalName];
    }
}

function getID() {
var ID = '';
var end = window.location.search.indexOf('&amp;');
	if(window.location.search.indexOf('&amp;')&lt;0){
		ID = window.location.search.substring(4);
	}else{
		ID = window.location.search.substring(4,end);
	}
	return ID;
}

Save as “RefreshWhenWorkflowCompletes.js”, and upload to your scriptlibrary as shown above.

Ask if anything is unclear.

Regards
Alexander

Arrange webparts in tabs in webpart page

04.07.2010 Updated the code for the file “WebpartTabs.js” to fix an issue with grouped webparts being expanded by default. Thanks to Bullvan for noticing.

02.02.2010 Update to add possibility to set the tab titles in an array. Useful when viewing multiple views of the same list in a list view.

12.01.2010: Updated the function “getWPTitle” in the code for the file “WebpartTabs.js”.

11.01.2010: Updated the code to allow multiple instances in one page. Please read trough the article as the approach has changed from the code posted two days ago.


In this article i will describe a method for adding webparts in a webpart page as tabs somewhere in the page.

Christophe at PathToSharePoint has already made a solution like this, but i got a request for a method a bit different than his solution:

tecrms Says:
I really like your Tabs in SharePoint form you posted. Is there any chance that you might create a tab container that places webparts on the page into it? For maximum user could they be selected by webpart ID and not by the zone. This way more than one tab container could be placed anywhere are the page.

Alexander Says:
Hi,
Take a look at “Easy Tabs” from Christophe at PathToSharepoint.

No need to invent it again if his solution does what you want…

If this is not what you need, let me know and i will look at it.

Alexander

tecrms Says:
Christophe’s Easy Tabs is an excellent webpart but it grabs everything within a webpart zone. What would be nice is to allow the selection of which webparts are to be placed in the tabs from the webpart zone. This will give one more ability to have more than one “Eays Tab” type webpart within a webpart zone.

I decided to make my own solution:

  • Multiple instances in one page.
  • Optional arrays to specify which webpart’s to include and which to exclude from being “tabbed”.
  • If there are no titles specified in the array’s, the code “consumes” all webparts rendered before the CEWP containing the script
  • Preserves selected tab on page load – for filtering columns etc.
  • Works in webpartpages and in list views
  • …requests anyone?

Images:
IMG

IMG

IMG


As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

A folder named “jQueryUI” containing the scripts and the “images”-folder for the selected theme:
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The jQuery UI-library is found here. Find the theme of your choice – mine is “smootness” – and download the files (the only necessary files are “UI Core” and “Tabs”).

The file “sessvars.js” is found here.

The code for the file “WebpartTabs.js” is provided below.

The way this script works is that you put a CEWP containing the code below the webparts you want to add to the tabs. If you want to add four webparts to the top of a webpart-page, you add the webparts from the top down, and places the CEWP with the script as webpart number five.

The code then (if the webparts has not been excluded) consumes all the webparts stacked above, and adds them as tabs in the order of appearance.

Add a CEWP below the webparts you want to “tab”, and insert this code

&lt;link type=&quot;text/css&quot; href=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/sessvars.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/WebpartTabs.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// In a webpart-page: Specify whether to hide the title - it must be present initially to use as &quot;tab title&quot;
hideWPHeader = true;
// Specify webparts to exclude
arrOfTitlesToExclude = ['Announcements'];
// Specify webparts to include - if empty it consumes all webparts rendered before this CEWP
arrOfTitlesToInclude = [];
// Specify tab title - useful in a view of a list where webpart titles cannot be used
arrOfTabHeadings = [];
// Call the script with an unique identifier of the &quot;tabs-collection&quot;
initBuildTabs('one');
&lt;/script&gt;

If you want another instance in the same page, modify the code like this (this webpart must be placed after the “primary” CEWP):

&lt;script type=&quot;text/javascript&quot;&gt;
// In a webpart-page: Specify whether to hide the title - it must be present initially to use as &quot;tab title&quot;
hideWPHeader = true;
// Specify webparts to exclude
arrOfTitlesToExclude = ['Announcements'];
// Specify webparts to include - if empty it consumes all webparts rendered before this CEWP
arrOfTitlesToInclude = [];
// Specify tab title - useful in a view of a list where webpart titles cannot be used
arrOfTabHeadings = [];
// Call the script with an unique identifier of the &quot;tabs-collection&quot;
initBuildTabs('two');
&lt;/script&gt;

Parameters explained:

  • hideWPHeader: If in a webpart-page – true – hides the webpart title
  • arrOfTitlesToExclude: Array of webpart-titles to exclude from tabs
  • arrOfTitlesToInclude: Array of webpart-titles to include in tabs. If left empty, it consumes all visible webparts rendered before this CEWP (that are not actively excluded)
  • arrOfTabHeadings: Array of webpart titles. If this array contains a value for the current tabID, it is used in stead of the default title pulled from the webpart. To specify the title for tabID 2 you must set the array like this: [”,”,’This is the new title’]. Note that tabID 0 and 1 is not altered as the value for those are empty strings.

The code for the file “WebpartTabs.js” looks like this:

/* Add webparts to tabs
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * Copyright (c) 2010 Alexander Bautz (Licensed under the MIT X11 License)
 * v1.4
 * LastMod: 04.07.2010
 * ---------------------------------------------
 * Include reference to:
 *  jQuery - http://jquery.com
 *  jQuery UI - http://jqueryui.com
 *  sessvars.js - http://www.thomasfrank.se/sessionvars.html
 * ---------------------------------------------
 * See this blog post for instructions:
   
Arrange webparts in tabs in webpart page
*/ function initBuildTabs(uniqueID){ if(typeof(arrOfTitlesToExclude)=='undefined')arrOfTitlesToExclude = []; if(typeof(arrOfTitlesToInclude)=='undefined')arrOfTitlesToInclude = []; if(typeof(arrOfTabHeadings)=='undefined')arrOfTabHeadings = []; // Insert the tabs placeholder document.write(&quot;&lt;div id='skipThisCEWP'&gt;&lt;/div&gt;&lt;div style='padding:5px;width:100%' id='MyTabs_&quot; + uniqueID + &quot;'&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/div&gt;&quot;); var myDiv = $(&quot;#MyTabs_&quot;+uniqueID); // Code inactive in &quot;edit page mode&quot; if($(&quot;.ms-WPAddButton&quot;).length==0){ var tabID = 0; // Loop trough all webparts on the page $(&quot;.ms-bodyareaframe td[id^='MSOZoneCell_WebPartWPQ']&quot;).each(function(){ var thisWP = $(this); if(!thisWP.data('done')){ thisWP.data('done',true) // Is it hidden or skipped? tabTitle = includeThisWP(thisWP,tabID); if(tabTitle!=false){ // Hide the webpart title? if(hideWPHeader){ thisWP.find(&quot;.ms-WPHeader&quot;).hide(); } // Build the tabs myDiv.find('ul').append(&quot;&lt;li&gt;&lt;a href='#tabContent-&quot; + uniqueID + tabID + &quot;' onclick='preserveTab(&quot; + tabID + &quot;,&quot;&quot; + uniqueID + &quot;&quot;)'&gt;&quot; + tabTitle + &quot;&lt;/a&gt;&lt;/li&gt;&quot;); var wrappedDiv = $(&quot;&lt;div id='tabContent-&quot; + uniqueID + tabID+&quot;'&gt;&lt;/div&gt;&quot;); wrappedDiv.append(thisWP.find('table:first')); myDiv.append(wrappedDiv); tabID+=1; // Remove the empty placeholders to prevent them from taking up space if(thisWP.parents('table:first').find('tr').length&gt;1){ thisWP.parents('tr:first').remove(); }else{ thisWP.parents('table:first').remove(); } } } }); // Make tabs myDiv.tabs(); // Fix CSS $(&quot;.ui-tabs-panel&quot;).css({'padding':'0px','text-align':'left','margin':'0 auto'}); // Select the active tab on page reload if(sessvars[uniqueID]!='undefined'){ myDiv.tabs('select', sessvars[uniqueID]); } }else{ document.write(&quot;&lt;div style='height:75px;background-color:#FFCC11;text-align:center;font-size:16px;padding-top:30px'&gt;This is the Tabs CEWP&lt;/div&gt;&quot;); } } function includeThisWP(obj,tID){ // Is it skipped or hidden? if(obj.find(&quot;#skipThisCEWP&quot;).length&gt;0 || obj.find('table:first').css('display')=='none'){ return false; } if(arrOfTabHeadings[tID]!=undefined &amp;&amp; arrOfTabHeadings[tID]!=''){ wpT = arrOfTabHeadings[tID]; }else{ wpT = getWPTitle(obj); } // Is it excluded if($.inArray(wpT,arrOfTitlesToExclude)&gt;-1){ return false; }else if(arrOfTitlesToInclude=='' || $.inArray(wpT,arrOfTitlesToInclude)&gt;-1){ return wpT; }else{ return false; } } function getWPTitle(obj){ // Lists and librarys if(obj.html().match(/ctx.ListTitle = &quot;(.+)&quot;/)!=null){ var tRaw = obj.html().match(/ctx.ListTitle = &quot;(.+)&quot;/)[1]; return unescape(tRaw.replace(/\u/g,'%u')) } // Other webparts if(obj.find(&quot;.ms-WPHeader h3&quot;).length&gt;0){ return obj.find(&quot;.ms-WPHeader h3&quot;).text(); }else{ return &quot;&lt;span title='Webpart title must be visible under &quot;Chrome Type&quot; in webpart settings.' style='color:red'&gt;No title&lt;/span&gt;&quot;; } } // Used to preserve the current tab when page loads (column filtering etc.) function preserveTab(tabID,parentID){ sessvars[parentID]=tabID; }

Save as “WebpartTabs.js” – mind the file extension, and upload to the scriptlibrary as shown above.

This script may need a bit more testing so please let me know if you have some comments or finds a bug.

Regards
Alexander

Limit number of allowed selections in Checkboxes choice

Change log
October 22, 2014
v1.1: Updated the code to support new versions of jQuery and added support for Surveys (tested in SP2010).

In this article will show you how to limit the number of allowed selections in a column of type “Choice: Checkboxes (allow multiple selections)”.

The reason for this is that a column of type “Choice: Radio Buttons”, cannot be “unselected” once it is selected.

The code gives you the ability to specify the number of options a user can select.

The script behaves differently for “single choice” and for “multi choice”.

Single: The selection “moves” when you select another option – only one “tick” is allowed
Multiple: A message appears beneath the checkboxes announcing the allowed number of selection. You cannot select another option until you have removed one of the previous selections.

IMG
The “errorText” will disappear after 4 seconds.

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

October 22, 2014: Please note that the updated code example requires jQuery verions above v1.6

Add a CEWP below your NewForm and EditForm with this code:

<script type="text/javascript" src="/Javascript/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="/Javascript/LimitSelectionsInCheckboxes.js"></script>
<script type="text/javascript">
initLimitSelections('YourFieldInternalName',2,'Only 2 selections allowed.');
</script>

Parameters explained:

FieldInternalName: FieldInternalName of your “Checkboxes-column”.
allowedSelections: Number of selections allowed.
errorText: The text shown below the checkboxes if the selections exceed the allowed number of selections. Not used if the parameter “allowedSelections” is 1.

The sourcecode for the file “LimitSelectionsInCheckboxes.js” looks like this

/* 
 * Limit allowed selections in Checkboxes-column
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 22.10.2014
*/

var multiChoiceFields = init_multiChoiceFields();

function initLimitSelections(FieldInternalName,allowedSelections,errorText){
	if(typeof errorText === "undefined" || errorText === ""){
		errorText = "You can only select " + allowedSelections + " options.";
	}
	$(multiChoiceFields[FieldInternalName]).find("input").click(function(){
		limitSelections($(this),FieldInternalName,allowedSelections,errorText);
	});
}

function limitSelections(currOpt,fin,n,errText){
	var f = $(multiChoiceFields[fin]), c, chk;
	$("#customMultiSelectValidation").remove();
	c = f.find("input:checked").length;
	// If allowedSelections = 1 move selection
	if(n === 1){
		chk = currOpt.prop("checked");
		f.find("input:checked").each(function(){
			$(this).prop("checked",false);
		});
		currOpt.prop("checked",chk);
	}else{
		// Uncheck current selection and give user a visual feedback on number of allowed selections
		if(c > n){
			currOpt.prop("checked",false);
			f.find("td[class^='ms-formbody']").append("<div id='customMultiSelectValidation' class='ms-formvalidation'>" + errText + "</div>");
			$("#customMultiSelectValidation").fadeOut(4000)
		}
	}
}

function init_multiChoiceFields(){
	var res = {}, myMatch, disp, fin, type;
	$("td[class^='ms-formbody']").each(function(){
	myMatch = $(this).html().match(/FieldName="(.+)"\s+FieldInternalName="(.+)"\s+FieldType="(.+)"\s+/);	
		if(myMatch!=null){
			// Display name
			disp = myMatch[1];
			// FieldInternalName
			fin = myMatch[2];
			// FieldType
			type = myMatch[3];
			if(type!=='SPFieldMultiChoice'){
				return;
			}		
			// Build object
			res[fin] = this.parentNode;
			$(res[fin]).attr('FieldDispName',disp);
			$(res[fin]).attr('FieldType',type);
		}		
	});
	return res;
}

Save this code as “LimitSelectionsInCheckboxes.js” – mind the file extension, and upload to the scriptlibrary as shown above.

Ask if something is unclear.

Regards
Alexander

Highlight row by value in Yes/No-column

08.10.2011 Updated with SharePoint 2010 code.


22.04.2010 Updated the code to support multiple views of the same list in the same page, as requested by Mich.

The file “HighlightRowByYesNoColumn.js” is updated.


In this post i will show you how to highlight a row in a list view based on the value in a column of type “Yes/No (check box)”. The code would work on other types of columns as well.

IMG
This is from a standard list view, it does also work in grouped view’s.

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

Add a CEWP below the list view and insert this code:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/HighlightRowByYesNoColumn.js"></script>
<script type="text/javascript">
highlightRowByYesNoField('Yes','YesNo','#FFD700','Highlighted rows awaiting action...');
</script>

Parameters explained:

  • valToTriggerHighlighting: The text you want to trigger the highlighting on – “Yes”
  • FieldInternalName: The FieldInternalName of the column to get the value from – must be in view
  • highlightColor: The background color of the highlighted row
  • mouseOverOnRow: The mouse over message when hovered over a highlighted row

The sourcecode for the file “HighlightRowByYesNoColumn.js” looks like this:

SharePoint 2007
/* Highlight row in list view based on value in a Yes/No-column
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 22.04.2010
 * ---------------------------------------------
 * Include reference to jquery - http://jquery.com
 * ---------------------------------------------
 * Call from a CEWP below the list view with this code:
	<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
	<script type="text/javascript" src="/test/English/Javascript/HighlightRowByYesNoColumn.js"></script>
	<script type="text/javascript">
		highlightRowByYesNoField('Yes','YesNo','#FFD700','Highlighted rows awaiting action...');
	</script>
*/

function highlightRowByYesNoField(valToTriggerHighlighting,FieldInternalName,highlightColor,mouseOverOnRow){
	if(typeof(valToTriggerHighlighting)!='undefined'){
		valToFind = valToTriggerHighlighting;
	}
	if(typeof(FieldInternalName)!='undefined'){
		fin = FieldInternalName;
	}
	if(typeof(highlightColor)!='undefined'){
		bgColor = highlightColor;
	}
	if(typeof(mouseOverOnRow)!='undefined'){
		mouseOver = mouseOverOnRow;
	}
	
	$("table.ms-listviewtable").each(function(){
		var thisListView = $(this);
		// Find colindex of YesNo-field
		thisListView.find(".ms-viewheadertr th").each(function(){
			if($(this).text()==fin){
				colIndex = $(this).attr('cellIndex');		
			}
		});
		
		// Loop trough all rows and highlight matched rows
		thisListView.find("tbody:not([id^='aggr']) tr:has(td.ms-vb2)[highlighted!='1']").each(function(){			
			var rowVal = $(this).find("td[cellIndex='"+colIndex+"']").text();
			if(rowVal==valToFind){
				$(this).attr({'highlighted':'1','title':mouseOver}).css({'background-color':bgColor});		
			}		
		});
	});
}

// Attaches a call to the function to the "expand grouped elements function" for it to function in grouped listview's
function ExpGroupRenderData(htmlToRender, groupName, isLoaded){
	var tbody=document.getElementById("tbod"+groupName+"_");
	var wrapDiv=document.createElement("DIV");
	wrapDiv.innerHTML="<TABLE><TBODY id="tbod"+groupName+"_" isLoaded=""+isLoaded+"">"+htmlToRender+"</TBODY></TABLE>";
	tbody.parentNode.replaceChild(wrapDiv.firstChild.firstChild,tbody);
highlightRowByYesNoField();
}
SharePoint 2010
/* Highlight row in list view based on value in a Yes/No-column
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1 for SharePoint 2010
 * LastMod: 08.10.2011
 * ---------------------------------------------
 * Include reference to jquery - http://jquery.com
 * ---------------------------------------------
 * Call from a CEWP below the list view with this code:
*/

function highlightRowByYesNoField(valToTriggerHighlighting,FieldInternalName,highlightColor,mouseOverOnRow){
	var fName;
	if(typeof(valToTriggerHighlighting)!='undefined'){
		valToFind = valToTriggerHighlighting;
	}
	if(typeof(FieldInternalName)!='undefined'){
		fin = FieldInternalName;
	}
	if(typeof(highlightColor)!='undefined'){
		bgColor = highlightColor;
	}
	if(typeof(mouseOverOnRow)!='undefined'){
		mouseOver = mouseOverOnRow;
	}
	$("table.ms-listviewtable").each(function(){
	
		var thisListView = $(this);
		// Find colindex of YesNo-field
		thisListView.find(".ms-viewheadertr th").each(function(){				
			fName = $(this).find('div:first').attr('name')
			if(fName==fin){
				colIndex = this.cellIndex;
			}
		});
		// Loop trough all rows and highlight matched rows
		thisListView.find("tbody:not([id^='aggr']) tr:has(td.ms-vb2)[highlighted!='1']").each(function(){
			var rowVal = $(this).find(">td:eq("+colIndex+")").text();
			if(rowVal==valToFind){
				$(this).attr({'highlighted':'1','title':mouseOver}).css({'background-color':bgColor});
			}
		});
	});
}

function customTimeoutLoop(id){
var obj = $("#"+id);
var isloaded = ($(obj).attr('isloaded')=='true')?true:false;
	if(!isloaded){
		$(obj).hide();
		setTimeout(function(){
			customTimeoutLoop(id);
		},10);
	}else{
		$(obj).show();
		highlightRowByYesNoField();		
	}
}

function ExpGroupRenderData(d, a, e) {
    ULSA13: {
    }
    var c = document.getElementById("tbod" + a + "_"), b = document.createElement("DIV"), f = a.split("-");
    b.innerHTML = "<TABLE><TBODY id="tbod" + a + "_" isLoaded="" + e + "">" + d + "</TBODY></TABLE>";
    c.parentNode.replaceChild(b.firstChild.firstChild, c); 
 customTimeoutLoop("tbod" + a + "_");   
}

Save the code as a file named “HighlightRowByYesNoColumn.js” – mind the file extension, and upload to the scriptlibrary as shown above.

Note when combining with other scripts that embeds the function “ExpGroupRenderData”: The function “ExpGroupRenderData” is not to be added twice. You must leave the one in the script called last, and include the function call to both/all custom function that is to be triggered by expanding grouped view’s – like in line 58 in the SP2007-code above.

Ask if something is unclear

Regards
Alexander

CEWP – one click edit: Rich text or Sourcecode

This script adds “one click edit of an CEWP”. It supports both “Rich text editor…” and “Source code editor…”.

NOTE: You must add the site to “Local Intranet” in IE, if not the one click edit might not work.

The function checks that the logged in user has “Edit Page rights” before adding these links. The check is simply done by checking if the “Edit Page” link is present in the page.

IMG

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The file “sessvars.js” is found here.

The code for the file “OneClickEditCEWP.js” is provided below.

Add a CEWP below the WebPart’s you want to add this feature to, and add this code to it:

&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/EMSKJS/jquery-1.3.1.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/EMSKJS/sessvars.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/EMSKJS/OneClickEditCEWP.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
   var EditText = 'Edit rich text|Edit code'; // The text of the edit link
   var EditTextMouseOver = 'Click to edit'; // Mouseover on edit-link
&lt;/script&gt;

This is the code for the file “OneClickEditCEWP.js”:

/* One click edit of CEWP - Rich text or code edit
 *  Author Alexander Bautz
 *  alexander.bautz@gmail.com
 *  https://spjsblog.com
 *  v1.0
 *  LastMod: 22.12.2009
 *
 * Requirements:
 * jQuery library http://jquery.com
 * sessvars.js from http://www.thomasfrank.se/sessionvars.html
 *
 * Define these variables in CEWP at the bottom of the page:
 * var EditText = 'Edit rich text|Edit code'; // The text of the edit link
 * var EditTextMouseOver = 'Click to edit'; // Mouseover on edit-link
 * 
 Example of CEWP in WebPartPage:
 	&lt;script type=&quot;text/javascript&quot; src=&quot;../EMSKJS/jquery-1.3.1.min.js&quot;&gt;&lt;/script&gt;
 	&lt;script type=&quot;text/javascript&quot; src=&quot;../EMSKJS/sessvars.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;../EMSKJS/OneClickEditCEWP.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;
		var EditText = 'Edit rich text|Edit code'; // The text of the edit link
		var EditTextMouseOver = 'Click to edit'; // Mouseover on edit-link
	&lt;/script&gt;
 * --------------------------------------------------------
 * To exclude a webpart, add an empty DIV with class &quot;customSkipThisCEWP&quot; to the webpart body
 * &lt;div class=&quot;customSkipThisCEWP&quot;&gt;&lt;/div&gt;
 * --------------------------------------------------------
 */ 

$(document).ready(function(){
var split = EditText.split('|');
var editRichText = split[0];
var editCode = split[1];
if($(&quot;*[id$='MenuItem_EditPage']&quot;).length&gt;0){
		$(&quot;td[id ^= 'MSOZoneCell_WebPartWPQ']&quot;).each(function(){
		if($(this).find(&quot;.customSkipThisCEWP&quot;).length==0){
			var uniqueID = $(this).find(&quot;.ms-WPBody&quot;).attr('webpartid');
			var wpIdRaw = $(this).attr('id');
			var wpId = wpIdRaw.substring(wpIdRaw.indexOf('_')+4);			
				if(uniqueID != undefined){			
					var editLink = &quot;&quot;;			
						editLink += &quot;&lt;a title='&quot; + EditTextMouseOver + &quot;' href='#' &quot;;
						editLink += &quot;onclick='javascript:sessvars.wpId=&quot;&quot; + wpId + &quot;&quot;;MSOTlPn_ShowToolPane2Wrapper(&quot;Edit&quot;,&quot;129&quot;,&quot;&quot; + uniqueID + &quot;&quot;);sessvars.EditCode=false'&gt;&quot;;
						editLink += editRichText + &quot;&lt;/a&gt;&amp;nbsp;|&amp;nbsp;&lt;a title='&quot; + EditTextMouseOver + &quot;' href='#' &quot;;
						editLink += &quot;onclick='javascript:sessvars.wpId=&quot;&quot; + wpId + &quot;&quot;;MSOTlPn_ShowToolPane2Wrapper(&quot;Edit&quot;,&quot;129&quot;,&quot;&quot; + uniqueID + &quot;&quot;);sessvars.EditCode=true'&gt;&quot;;
						editLink += editCode + &quot;&lt;/a&gt;&quot;;
						editLink = &quot;&lt;div style='display:none;font-size:xx-small;color:gray;' id='customEditLink_&quot; + wpId + &quot;'&gt;&quot; + editLink + &quot;&lt;/div&gt;&quot;;
					$(this).prepend(editLink);
					$(this).hover(function(){	
						var offset = $(this).offset();
						$(&quot;#customEditLink_&quot; + wpId).css({'position':'absolute','left':offset.left,'top':(offset.top-12)}).show().stop().fadeTo('fast',1);
					},function(){
						$(&quot;#customEditLink_&quot; + wpId).stop().fadeTo('slow',0);
					});
				}
			}
		});	
		// Open the editor only if it has been triggered by the custom link
		if($(&quot;#MsoContentToolpartBasicContentProperty&quot;).length&gt;0 &amp;&amp; sessvars.wpId!=undefined){
			if(sessvars.EditCode){
				$(&quot;#MsoContentToolpartBasicSourceViewLiteral&quot;).click();
			}else{
				$(&quot;#MsoContentToolpartBasicDesignViewLiteral&quot;).click();				
			}
			sessvars.$.clearMem();
			window.location.href(window.location.href);
		}			
	}
});

Save the file as “OneClickEditCEWP.js”, and upload to the scriptlibrary as shown above.

Note:

  • The reason for using the “sessvars.js”, it so prevent “hijacking” of the page if manually edited trough “Edit page-link”
  • If the page only refreshes without showing the “edit window”, you may have a pop up-blocker activated. Manually edit the page, and allow any pop up’s
  • To exclude a CEWP from being equipped with an “Edit-link”, add a “dummy” DIV-tag with class “customSkipThisCEWP” to the CEWP code.

Ask if something is unclear

Regards
Alexander