Category Archives: Requests

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
[javascript]
<link type="text/css" href="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Javascript/WebpartTabs.js"></script>
<script type="text/javascript">
// In a webpart-page: Specify whether to hide the title – it must be present initially to use as "tab title"
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 "tabs-collection"
initBuildTabs(‘one’);
</script>
[/javascript]

If you want another instance in the same page, modify the code like this (this webpart must be placed after the “primary” CEWP):
[javascript]
<script type="text/javascript">
// In a webpart-page: Specify whether to hide the title – it must be present initially to use as "tab title"
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 "tabs-collection"
initBuildTabs(‘two’);
</script>
[/javascript]

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:
[javascript]
/* 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("<div id=’skipThisCEWP’></div><div style=’padding:5px;width:100%’ id=’MyTabs_" + uniqueID + "’><ul></ul></div>");
var myDiv = $("#MyTabs_"+uniqueID);
// Code inactive in "edit page mode"
if($(".ms-WPAddButton").length==0){
var tabID = 0;
// Loop trough all webparts on the page
$(".ms-bodyareaframe td[id^=’MSOZoneCell_WebPartWPQ’]").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(".ms-WPHeader").hide();
}
// Build the tabs
myDiv.find(‘ul’).append("<li><a href=’#tabContent-" + uniqueID + tabID + "’ onclick=’preserveTab(" + tabID + ","" + uniqueID + "")’>" + tabTitle + "</a></li>");
var wrappedDiv = $("<div id=’tabContent-" + uniqueID + tabID+"’></div>");
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>1){
thisWP.parents(‘tr:first’).remove();
}else{
thisWP.parents(‘table:first’).remove();
}
}
}
});
// Make tabs
myDiv.tabs();
// Fix CSS
$(".ui-tabs-panel").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("<div style=’height:75px;background-color:#FFCC11;text-align:center;font-size:16px;padding-top:30px’>This is the Tabs CEWP</div>");
}
}

function includeThisWP(obj,tID){
// Is it skipped or hidden?
if(obj.find("#skipThisCEWP").length>0 || obj.find(‘table:first’).css(‘display’)==’none’){
return false;
}
if(arrOfTabHeadings[tID]!=undefined && arrOfTabHeadings[tID]!=”){
wpT = arrOfTabHeadings[tID];
}else{
wpT = getWPTitle(obj);
}
// Is it excluded
if($.inArray(wpT,arrOfTitlesToExclude)>-1){
return false;
}else if(arrOfTitlesToInclude==” || $.inArray(wpT,arrOfTitlesToInclude)>-1){
return wpT;
}else{
return false;
}
}

function getWPTitle(obj){
// Lists and librarys
if(obj.html().match(/ctx.ListTitle = "(.+)"/)!=null){
var tRaw = obj.html().match(/ctx.ListTitle = "(.+)"/)[1];
return unescape(tRaw.replace(/\u/g,’%u’))
}
// Other webparts
if(obj.find(".ms-WPHeader h3").length>0){
return obj.find(".ms-WPHeader h3").text();
}else{
return "<span title=’Webpart title must be visible under "Chrome Type" in webpart settings.’ style=’color:red’>No title</span>";
}
}

// Used to preserve the current tab when page loads (column filtering etc.)
function preserveTab(tabID,parentID){
sessvars[parentID]=tabID;
}
[/javascript]
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

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

Show current row wrapped in a floating table when hovered

This one is an attempt to answer Charlie’s request:

Hi Alexander:
On several of my lists, I struggle with the width of the page and too many fields. I use some simple javascript to wrap the column headers but I still need to prevent users from having to scroll side to side…

IMG

This script adds a mouse over preview of the current row in a floating DIV. It is related to the script Preview metadata in list view on mouseover, but is simpler as it does only wrap up the content of the current row.

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 add this code:
[javascript]
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/mouseOverWrapRowTableStyle.js"></script>
<script type="text/javascript">
// Initiate mouse over when hovered for 1000 milliseconds
initShowRowAsTable(1000);
</script>
[/javascript]

This is the sourcecode for the file “mouseOverWrapRowTableStyle.js”:
[javascript]
function initShowRowAsTable(delay){
if(typeof(delay)==’number’){
hoverDelay = delay;
}
if(typeof(hoverDelay)==’undefined’){
hoverDelay = 500;
}
// Add a "description" in the list view toolbar
if($("#hoverDelayInfo").length==0){
var str = "Hover over a row for " + hoverDelay/1000 + " second to view content "table-style"";
$("td.ms-toolbar[width=’99%’]").append("<div id=’hoverDelayInfo’ class=’ms-listheaderlabel’ style=’text-align:center;margin-top:-15px’>" + str + "</div>");
}

// Build object of all headings
if(typeof(objTH)==’undefined’){
objTH = {};
$(".ms-viewheadertr th").each(function(){
var colIndex = $(this).attr(‘cellIndex’);
if($(this).text()!=” ){
objTH[colIndex] = $(this).text();
}
});
}

$("table.ms-listviewtable tbody:not([id^=’aggr’]) tr:has(td.ms-vb2)[beenthere!=’1′]").each(function(){
$(this).attr(‘beenthere’,’1′);
// Add hover function
$(this).hover(function(e){
// Add highlighting of "hovered" row
$(this).addClass("ms-dialogHoverRow");
var row = $(this);
// If hovered more than "hoverDelay" – show contents
setTimeout(function(){
if(row.hasClass(‘ms-dialogHoverRow’)){
$("#customHoverDiv").remove();
pX = e.pageX + 10;
pY = e.pageY + 15;
showRowAsTable(row);
}
},hoverDelay);
},function(){
// Remove highlighting of "hovered" row
$(this).removeClass("ms-dialogHoverRow");
// Remove floating div
$("#customHoverDiv").remove();
});
});
}

function showRowAsTable(obj){
// Create new hidden DIV
var newDiv = $("<div style=’display:none’></div>").attr(‘id’,’customHoverDiv’).html(obj.html()).appendTo(".ms-bodyareaframe");
str = ”;

// Extract the contents of the row and build a new table
newDiv.find(‘>td’).each(function(idx){
if(objTH[idx]!=undefined){
if($(this).attr(‘class’)==’ms-vb-title’){
var value = $(this).text();
}else{
var value = $(this).html();
}
str += "<tr><td class=’ms-formlabel’ valign=’top’>" + objTH[idx] + ":</td><td class=’ms-formbody’> " + value + "&nbsp;</td></tr>";
}
});

// Replace the DIV-content with the newly buildt table
newDiv.html("<table cellpadding=’0′ cellspacing=’0′ class=’ms-formtable’>" + str + "</table>");
var contentWidth = ‘400’;
var contentHeight = $("#customHoverDiv").height();
var winHeight = $(window).height();
var winWidth = $(window).width();
var winScroll = $(window).scrollTop();
// Calculate the best position for the popup Y-axis
if((winHeight – pY) < contentHeight){
if((pY – winScroll) < contentHeight){
pY = winScroll + 10
}else{
pY = (pY – contentHeight) – 30
}
}
// Calculate the best position for the popup X-axis
if((winWidth – pX) < contentWidth){
pX = (pX – contentWidth) – 30;
}
// Show popup
newDiv.css({‘position’:’absolute’,
‘left’:pX,
‘top’:pY,
‘background-color’:’f8f8ff’,
‘border’:’2px silver ridge’,
‘padding’:3})
.show().mouseenter(function(){
$(this).hide();
});
}

// 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);
initShowRowAsTable();
}
[/javascript]
Save this as a file – name it “mouseOverWrapRowTableStyle.js”, and upload it to your script library as shown above.

Ask if something is unclear.

Alexander

Accordion in SharePoint form

12.03.2011: I have posted a new release, you find it here.


In this example i will show how to use the jQuery UI widget “Accordion” in a SharePoint form.

NewForm:
IMG
On form validation (refresh) it selects the first section containing empty fields:
IMG
DispForm with attachment:
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 (select the widgets and effects you want – the file is dynamically built according to your selection).

Add a CEWP below your NewForm, DispForm and EditForm.

Add this code:
[javascript]
<DIV id="accordion" style="font-size:14px">
<H3><A href="#accordion-0">Section 1</A></H3>
<div><table width="100%" id="accTable-0"></table>&nbsp;</div>
<H3><A href="#accordion-1">Section 2</A></H3>
<div><table width="100%" id="accTable-1"></table>&nbsp;</div>
<H3><A href="#accordion-2">Section 3</A></H3>
<div><table width="100%" id="accTable-2"></table>&nbsp;</div>
<H3><A href="#accordion-3">Attachments</A></H3>
<div><table width="100%" id="accTable-3"></table>&nbsp;</div>
</DIV>

<link type="text/css" href="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript">

// Array of all fields – format: accID|FieldInternalName
// Note that accID is zero-indexed
arrOfFields = [‘0|Title’,’0|SectionOneText’,’0|Section1Choice’,
‘1|Responsible’,’1|Section2Text’,
‘2|Section3Multiline’,’2|Section3Choice’];

// Initiate all the fields
fields = init_fields();

// Add the "accordion" to the formtable
$("#accordion").insertAfter(‘.ms-formtable’).accordion({autoHeight: false,animated: false});
// Loop trough all fields and move them to the right accordion section
fValAccID = ”;
$.each(arrOfFields,function(idx,item){
var split = item.split(‘|’);
var accID = split[0];
var fieldName = split[1];
if(fields[fieldName]!=undefined){
currField = $(fields[fieldName]);
currField.appendTo(‘#accTable-‘+accID);

// Formvalidation – find the first tab with empty required fields
if(fValAccID == ” && currField.find(‘.ms-formbody span.ms-formvalidation’).length>0){
fValAccID = accID;
}
}
});

// Move the Attachment’s to the last section
$("#idAttachmentsRow").appendTo(‘#accTable-3’);

// Are there any required fields not filled? – select the section containing the first field
if(fValAccID !=”){
// Show the right section
setTimeout(function(){$(‘#accordion’).accordion(‘activate’,parseInt(fValAccID));},10);
}

// Fix IE8 issue with content not showing (because it is in a table within the DIV) + remove the default padding
$(".ui-accordion-content").css({‘zoom’:1,’padding’:’0px’});

// function – to make "object" of all tr’s in the form
function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf(‘FieldInternalName="’)<0) return;
var start = $(this).html().indexOf(‘FieldInternalName="’)+19;
var stopp = $(this).html().indexOf(‘FieldType="’)-7;
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}
</script>
[/javascript]

The only parameters you need to edit in the script is the array of FieldInternalNames. The format of the variable “arrOfFields” is accID|FieldInternalName.

In the html above the script, adapt the number’s of sections – and the section’s display name. The accID corresponds with the index of the table to insert the content in (zero-indexed).

All fields must be added to a section – if not it looks ugly….

Note: As for the “Tabs in SharePoint form”, by now i have tested and found that columns of type “Multiple lines of text (Rich text or Enhanced rich text) do not work. What happens is that the section shows some of the fields hidden parts.

I have not done any testing on how to prevent this issue, so feel free to notify me if you find a workaround.

Note: The animation is disabled because of a “flicker problem” in IE8 due to the page being rendered in “Quirks Mode”.

Regards
Alexander

Tabs in SharePoint form

18.01.2011 I have posted a new solution compatible with both SP2007 and SP2010 and fixes the problems with rich text fields and “single lookup with more than 20 items under Internet Explorer – problem”. You find it her


23.01.2010 Updated the code to fix two issues regarding date and time columns. I added a <style> tag to set the font size of “.ms-dtinput” and “.ms-dttimeinput” to 0.7em.

I also added a custom handler to select the right tab on “empty field validation” on a date and time field. These are validated without page reload, and therefore did not work in the previous version.

Thank you all for the feedback and the testing.

15.12.2009 Update to support form validation. On submit – if there are required fields not filled – the tab containing the first required field is selected.


I got this request:

We have a custom list with a lot of fields. I need to divide it into sections and then easily show/hide those sections. I am going to try dividing the form into div tags and then use jQuery to display the sections in either Tabs or an accordion…

And made this demo based on the jQuery UI Widget “Tabs”.

NewForm:
IMG
DispForm:
IMG
DispForm with attachment:
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 (i have plucked only the necessary files – “UI Core” and “Tabs”).

Add a CEWP below your NewForm, DispForm and EditForm.

Add this code:
[javascript]
<!– Date field text size –>
<style type="text/css">
.ms-dtinput,.ms-dttimeinput{
font-size:0.7em;
}
</style>
<DIV id="tabs">
<UL style="font-size:12px">
<LI><A href="#tabs-1">Tab 1</A></LI>
<LI><A href="#tabs-2">Tab 2</A></LI>
<LI><A href="#tabs-3">Tab 3</A></LI>
<LI><A href="#tabs-4">Attachments</A></LI>
</UL>

<div><table cellpadding="0" cellspacing="0" id="tabs-1"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-2"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-3"></table></div>
<div><table cellpadding="0" cellspacing="0" id="tabs-4"></table></div>
</DIV>

<link type="text/css" href="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript">
// Array of all fields – format: tabID|FieldInternalName
arrTab = [‘1|Title’,’1|Tab1Text’,’1|Tab1Choice’,
‘2|Responsible’,’2|Tab2Text’,’2|Tab2Choice’,’2|Date’,
‘3|Tab3Text’,’3|Tab3Choice’,’3|Tab3MultilinePlain’];

// Initiate all the fields
fields = init_fields();

// Add the "tabs" to the formtable
$("#tabs").insertAfter(‘.ms-formtable’).tabs();
// Loop trough all fields and move them to the right tab
$.each(arrTab,function(idx,item){
var split = item.split(‘|’);
var tabID = split[0];
var fieldName = split[1];
if(fields[fieldName]!=undefined){
currField = $(fields[fieldName]);
currField.appendTo(‘#tabs-‘+tabID);
}
});

// Are there any required fields not filled? – select the tab containing the first field
selectTabOnFormValidation(false);
function selectTabOnFormValidation(preSave){
var formvalidationTab = ”;
// Formvalidation – find the first tab with empty required fields
$.each(arrTab,function(idx,item){
var split = item.split(‘|’);
var tabID = split[0];
var fieldName = split[1];
currField = $(fields[fieldName]);
// Handles DateTimeField (empty field validation is performed without page reload)
if(currField.find("SPAN[ID*=’_DateTimeField_’]").length>0){
if(currField.find(‘input:first’).val()==” && preSave){
formvalidationTab = tabID;
}
}
if(formvalidationTab == ” && currField.find(‘.ms-formbody span.ms-formvalidation’).length>0){
formvalidationTab = tabID;
}
});
// Select the first tab containing an empty required field
if(formvalidationTab!=”){
$(‘#tabs’).tabs(‘select’, formvalidationTab);
}
}

// Move the Attachment’s to the last tab
$("#idAttachmentsRow").appendTo(‘#tabs-4’).find(‘.ms-formlabel’).attr(‘width’,’165px’);

// function – to make "object" of all tr’s in the form
function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf(‘FieldInternalName="’)<0) return;
var start = $(this).html().indexOf(‘FieldInternalName="’)+19;
var stopp = $(this).html().indexOf(‘FieldType="’)-7;
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}

// Catch "empty field validation" on date and time columns
function PreSaveAction(){
selectTabOnFormValidation(true);
return true;
}
</script>
[/javascript]

The only parameters you need to edit in the script is the array of FieldInternalNames. The format of the variable “arrTab” is tabID|FieldInternalName.

In the html above the script, adapt the number’s of tabs – and the tab’s display name. The tabID corresponds with the number in the id attribute of the table to insert the tab content in.

All fields must be added to a tab – if not it looks ugly….

Note: By now i have tested and found that columns of type “Multiple lines of text (Rich text or Enhanced rich text) do not work. What happens is that the tabs script shows some of the fields hidden parts.

I have not done any testing on how to prevent this issue, so feel free to notify me if you find a workaround.

Regards
Alexander

Edit date, single line text, number or boolean columns directly in list view

31.03.2010 updated the code and reworked the article:

This solution enables you to edit a column of type “Date and Time (Date Only)”, “Single line of text”, “Number”, “Currency”, “Yes/No” and “single choice people picker” directly in a list view.

I’m planning on updating with support for columns columns later on.

Double click on a “TD” to edit – this action is per “TD”.
IMG

In this picture all “TD’s” are double clicked on.
IMG

The people picker is created with the jQuery UI widget “Autocomplete”.
IMG

When saved OK – a picture is appended to indicate “Save OK”.
IMG

A different picture is appended on save error.
IMG

This can be used in lists and document library’s, but requires that a the ID column is in the view (it can be hidden in the script by setting the argument “hideIdColumn” to true).

I have added support for “date”, “single line text”, “number”, “currency”, “boolean” and “single choice people picker” columns. I will update this article with support for choice columns later on.

All these columns – for filtering purposes – supply their FieldInternalName in the list header. This way i do not have to specify the column index where it is found – it dynamically adapts to changing column order.

This solution can be used with plain list view’s and 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

In addition to the above scripts, i have the jQuery UI 1.8 in a separate folder. See the CEWP code and point the links to your jQuery UI location.

The jQuery UI-library is found here. The pictures and the sourcecode refers to jquery-ui-1.8. The autocomplete widget is not found in previous releases.

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.4.min. The autocomplete widget is not supported in previous releases.

The scripts “interaction.js” and “stringBuffer.js” is created by Erucy and published on CodePlex.

Read here how to find the list Guid of your list, and how to find the FieldInternalName of your columns.

I have made one modification in the file “jquery-ui-1.8.custom.css” to correct the datepicker positioning of the date and year dropdowns. The style “.ui-datepicker select.ui-datepicker-year { width: 49%;}” is modified like this: “.ui-datepicker select.ui-datepicker-year { width: auto;}”. This might not affect your setup, and is merely a detail.

The sourcecode for “EditInListView.js” is provided below.

Add a CEWP below the list view webpart, and add this code:
[javascript]
<style type="text/css">
.ui-menu .ui-menu-item {
font-size:xx-small;
}
</style>
<link type="text/css" href="/test/English/jQueryUI18/smoothness/jquery-ui-1.8.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.min.js"></script>
<script type="text/javascript" src="/test/English/jQueryUI18/jquery-ui-1.8.custom.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/EditInListView.js"></script>
<script type="text/javascript">
// Set variables
hoverImgSrc = ‘/_layouts/images/DOWNARRW.GIF’;
hoverImgMouseOver = ‘Double click to edit’;
successImgSrc = ‘/_layouts/images/ServiceInstalled.gif’;
failureImgSrc = ‘/_layouts/images/ServiceNotInstalled.gif’;
dateFormat = ‘m/d/yy’; // alternative d.m.yy
decimalSeparator = ‘.’; // The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
boolYesNoText = ‘Yes|No’; // The display text in list view for a Yes/No-field
userListGuid = ‘570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF’;
userListBaseUrl = ”
arrToEdit = [‘MyDateField’,’SingleLine’,’Number’,’YesNo’,’MyPeoplePicker’];

// Call function
initCustomEditFunction(true);
</script>
[/javascript]

Edit the array “arrToEdit” to hold your FieldInternalNames, the “userListGuid” to hold your list guid, and other parameters if necessary.

Parameter’s explained:

  • hoverImgSrc: The source of the image indicating editable field
  • hoverImgMouseOver: The mouse over on the “hoverImgSrc-image”
  • successImgSrc: The source of the image displayed when saving the new value succeeds
  • failureImgSrc: The source of the image displayed when saving the new value fails
  • dateFormat: ‘m/d/yy’ – alternative ‘d.m.yy’
  • decimalSeparator: The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
  • boolYesNoText: The display text in list view for a Yes/No-field – format: Yes|No
  • userListGuid: The list guid for the userlist, used for the people picker
  • userListBaseUrl: Base URL for the list “People and Groups”. If in a managed path, reflect this path, else set to “” (blank string)
  • arrToEdit: Array of FieldInternalNames to address

The sourcecode for the file “EditInListView.js” looks like this:
[javascript]
/* Edit date, single line text, number, currency, boolean or single choice people picker directly in list view
* ———————————————
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.1
* LastMod: 31.03.2010
* ———————————————
* Must include reference to:
* jquery-1.4 – http://jquery.com
* jquery-ui-1.8 – http://jqueryui.com/
* interaction.js – http://spjslib.codeplex.com
* stringBuffer.js – http://spjslib.codeplex.com
* ———————————————
*
* Call from CEWP BELOW the list view like this:
<style type="text/css">
.ui-menu .ui-menu-item {
font-size:xx-small;
}
</style>
<link type="text/css" href="/test/English/jQueryUI18/smoothness/jquery-ui-1.8.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.min.js"></script>
<script type="text/javascript" src="/test/English/jQueryUI18/jquery-ui-1.8.custom.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/EditInListView.js"></script>
<script type="text/javascript">
// Set variables
hoverImgSrc = ‘/_layouts/images/DOWNARRW.GIF’;
hoverImgMouseOver = ‘Double click to edit’;
successImgSrc = ‘/_layouts/images/ServiceInstalled.gif’;
failureImgSrc = ‘/_layouts/images/ServiceNotInstalled.gif’;
dateFormat = ‘m/d/yy’; // alternative d.m.yy
decimalSeparator = ‘.’; // The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
boolYesNoText = ‘Yes|No’; // The display text in list view for a Yes/No-field
userListGuid = ‘570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF’;
userListBaseUrl = ”
arrToEdit = [‘MyDateField’,’SingleLine’,’Number’,’YesNo’,’MyPeoplePicker’];

// Call function
initCustomEditFunction(true);
</script>
*/

function initCustomEditFunction(hideIdColumn){
if(typeof(hideIdColumn)!=’undefined’){
hideId = hideIdColumn;
$(".ms-viewheadertr th").each(function(){
if($(this).find(‘table:first’).attr(‘name’)==’ID’){
IDcolIndex = $(this).attr(‘cellIndex’);
// Hide ID column
if(hideId){
$(this).addClass(‘dummyHideClass’);
}
}
});
}

if(typeof(IDcolIndex)==’undefined’){
alert("The ID column must be in the view.nYou may hide it in the script call by setting the argument "hideIdColumn" to true.");
}

if(typeof(arrTH)==’undefined’){
arrTH = [];
$(".ms-viewheadertr th").each(function(){
var colIndex = $(this).attr(‘cellIndex’);
var table = $(this).find(‘table’);
if(table.attr(‘name’)!=undefined){
var fldIntName = table.attr(‘name’);
var fldType = table.attr(‘fieldtype’);
if($.inArray(fldIntName,arrToEdit)>-1){
arrTH.push({‘colIndex’:colIndex,’fldType’:fldType,’fldIntName’:fldIntName});
}
}
});
}

addCustomEditFunction(arrTH);
// Hide ID column if specified
if(hideId){
$(".dummyHideClass").hide();
}
}

function addCustomEditFunction(arrToInclude){
$("table.ms-listviewtable tbody").each(function(){
if($(this).attr(‘id’).match(‘aggr’)==null){
$(this).find("tr:has(td.ms-vb2)[beenthere!=’1′]").each(function(){
$(this).attr(‘beenthere’,’1′);
var itemID = $(this).find(">td[cellIndex=" + IDcolIndex + "]").text();
// Hide ID column
if(hideId){
$(this).find("td[cellIndex="+IDcolIndex+"]").addClass(‘dummyHideClass’);
}
var pTR = $(this);
$.each(arrToInclude,function(idx,obj){
var col = obj[‘colIndex’];
var type = obj[‘fldType’];
var intName = obj[‘fldIntName’];
var TD = pTR.find(">td[cellIndex=" + col + "]");
var currVal = TD.text();
// Add onclick and append image
TD.dblclick(function(){editCurrentLine(type,itemID,intName)})
.attr({‘id’:’customEdit_’+intName+"_"+itemID,’fieldType’:type})
.css({‘cursor’:’pointer’});
if(type==’Number’ || type==’Currency’){
TD.find(‘div’).append("&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’>");
}else if(type==’User’){
if(TD.find(‘tr’).length>0){
TD.find(‘tr:first’).append("<td>&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’></td>");
}else{
TD.append("<div style=’padding-left:12px’>&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’></div>");
}
}else{
TD.append("&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’>");
}
});
});
}else if($(this).attr(‘id’).match(‘aggr’)!=null && $(this).attr(‘beenthere’)!=’1′ && hideId){
$(this).attr(‘beenthere’,’1′);
$(this).find("td[cellIndex="+IDcolIndex+"]").addClass(‘dummyHideClass’);
}
});
}

function editCurrentLine(type,id,intName){
var currField = $("#customEdit_" + intName+"_"+id);
var currVal = currField.text();
// Remove &nbsp;
currVal = $.trim(currVal.replace(/xA0/g,”));
if(type==’DateTime’){
if(currVal.indexOf(‘ ‘)>-1){
currVal = currVal.substring(0,currVal.indexOf(‘ ‘)); // Strip off any "time-value"
}
if($("#customEditInput_"+intName+"_"+id).length==0){
currField.css({‘width’:currField.width()}).html("<div>&nbsp;<a title=’Cancel’ href=’javascript:’ onclick=’javascript:cancelCustomSaveLine(""+intName+"",""+id+"",""+currVal+"")’>cancel</a>&nbsp;|&nbsp;" +
"<a title=’Clear’ href=’javascript:’ onclick=’javascript:customSaveLine(""+intName+"",""+id+"",""+currVal+""," + true + ")’>clear</a><br>" +
"<input class=’ms-input’ id=’customEditInput_"+intName+"_"+id+"’ style=’width:1px;height:1px;border:0px’ value=’" + currVal + "’ /></div>");
// Datepicker
$("#customEditInput_" + intName+"_"+id).datepicker({
dateFormat: dateFormat,
changeMonth: true,
changeYear: true,
showButtonPanel: true,
onSelect: function(dateText, inst){
customSaveLine(intName,id,currVal);
}
}).datepicker(‘show’);
}
}else if(type==’Text’ || type==’Number’ || type==’Currency’){
if($("#customEditInput_"+intName+"_"+id).length==0){
currField.css({‘width’:currField.width()}).html("<div>&nbsp;<a title=’Save’ href=’javascript:’ onclick=’javascript:customSaveLine(""+intName+"",""+id+"",""+currVal+"")’>save</a>&nbsp;|&nbsp;" +
"<a title=’Cancel’ href=’javascript:’ onclick=’javascript:cancelCustomSaveLine(""+intName+"",""+id+"",""+currVal+"")’>cancel</a><br>" +
"<input class=’ms-input’ id=’customEditInput_"+intName+"_"+id+"’ style=’width:99%’ value=’" + currVal + "’ /></div>");
// Focus on the input
setTimeout(function(){currField.find(‘input’).focus();},250);
// Add keyup/down function
currField.find(‘input’).keyup(function(e){
// If number – restrict input to numbers only – may need a little more tweaking
if(type==’Number’ || type==’Currency’){
var reg = new RegExp("[^0-9|\" + decimalSeparator + "]",’g’);
var thisVal = $(this).val().replace(reg,”);
$(this).val(thisVal);
}
}).keydown(function(e){
// Enter = save
if(e.keyCode==13){
customSaveLine(intName,id,currVal)
}
}).keyup();
}
}else if(type==’Boolean’){
if($("#customEditInput_"+intName+"_"+id).length==0){
if(currVal==” || currVal.toLowerCase().indexOf(‘n’)>-1){ // ‘n’ is found in ‘No’ and in Norwegian ‘Nei’
chk=”;
}else{
chk=’checked’;
}
currField.css({‘width’:currField.width()}).html("<div>&nbsp;<a title=’Cancel’ href=’javascript:’ onclick=’javascript:cancelCustomSaveLine(""+intName+"",""+id+"",""+currVal+"")’>cancel</a><br>" +
"<input type=’checkbox’ id=’customEditInput_"+intName+"_"+id+"’ " + chk + "/></div>");
$("#customEditInput_"+intName+"_"+id).click(function(){
customSaveLine(intName,id,currVal)
}).focus();
}
}else if(type==’User’){
if($("#customEditInput_"+intName+"_"+id).length==0){
currField.css({‘width’:currField.width()}).html("<div>&nbsp;<a title=’Cancel’ href=’javascript:’ onclick=’javascript:cancelCustomSaveLine(""+intName+"",""+id+"",""+currVal+"")’>cancel</a>&nbsp;|&nbsp;" +
"<a title=’Clear’ href=’javascript:’ onclick=’javascript:customSaveLine(""+intName+"",""+id+"",""+currVal+""," + true + ")’>clear</a><br>" +
"<input title=’Type into the textfield to get a list of users’ class=’ms-input’ id=’customEditInput_"+intName+"_"+id+"’ style=’width:99%’ value=’" + currVal + "’ /></div>");
// Autocomplete
if(typeof(allUsers)==’undefined’){
allUsers = getUsers();
}
currField.find(‘input’).autocomplete({
source: allUsers,
select: function(event, ui){
$(this).attr(‘hiddenVal’,ui.item.userID);
customSaveLine(intName,id,currVal);
return false;
}
});
// Focus on the input
setTimeout(function(){currField.find(‘input’).focus();},250);
}
}
}

function getUsers(){
var query = "<Where><And><IsNotNull><FieldRef Name=’EMail’ /></IsNotNull>" +
"<Eq><FieldRef Name=’ContentType’ /><Value Type=’Text’>Person</Value></Eq></And></Where>" +
"<OrderBy><FieldRef Name=’Title’ Ascending=’TRUE’/></OrderBy>";
wsBaseUrl = userListBaseUrl + ‘/_vti_bin/’;
var res = queryItems(userListGuid,query,[‘ID’,’Title’,’Name’,’EMail’,’ContentType’]);
var ret = [];
$.each(res.items,function(idx,item){
ret.push({label:item[‘Title’]+"<br>"+item[‘EMail’]+"<br>"+item[‘Name’],value:item[‘Title’],userID:item[‘ID’]});
});
return ret;
}

function cancelCustomSaveLine(intName,id,currVal){
var pTD = $("#customEdit_"+intName+"_"+id);
var type = pTD.attr(‘fieldType’);
if(type==’Number’ || type==’Currency’){
pTD.html("<div align=’right’>" + currVal + "&nbsp;<img style=’vertical-align:middle’ src=’" + hoverImgSrc + "’></div>");
}else if(type==’User’){
pTD.html("<div style=’padding-left:12px’>" + currVal + "&nbsp;<img style=’vertical-align:middle’ src=’" + hoverImgSrc + "’></div>");
}else{
pTD.html(currVal + "&nbsp;<img style=’vertical-align:middle’ src=’" + hoverImgSrc + "’>");
}
}

function customSaveLine(intName,id,currVal,clear){
wsBaseUrl = ctx.HttpRoot + ‘/_vti_bin/’;
listGuid = ctx.listName;

if(clear==undefined)clear=false;
var pTD = $("#customEdit_"+intName+"_"+id);
var type = pTD.attr(‘fieldType’);
var inpField = pTD.find(‘input’);
// Determine type and get value
if(type==’Boolean’){
var bSplit = boolYesNoText.split(‘|’);
var newVal = inpField.attr(‘checked’);
if(newVal){
newVal=’1′;
newValText=bSplit[0];
}else{
newVal=’0′;
newValText=bSplit[1];
}
}else{
var newVal = $.trim(inpField.val());
}
// Check if value has changed
if(newVal!=currVal || clear){
var data = {};
if(type==’DateTime’){
if(clear){
data[intName] = ”;
newVal = ”;
}else{
var isoDate = parseISO8601Date(newVal);
data[intName] = isoDate;
}
}else if(type==’User’){
if(clear){
data[intName] = "";
newVal = ”;
}else{
data[intName] = inpField.attr(‘hiddenVal’);
}
}else{
data[intName] = newVal;
}
// Write back data
var res = updateItem(listGuid,id,data);
// Success or failure
if(res.success){ // Save success
if(type==’Number’){
pTD.html("<div align=’right’>" + newVal + "&nbsp;<img style=’vertical-align:middle’ title=’Saved’ src=’" + successImgSrc + "’ width=’14’ height=’14’ border=’0′></div>");
}else if(type==’Boolean’){
pTD.html(newValText + "&nbsp;<img style=’vertical-align:middle’ title=’Saved’ src=’" + successImgSrc + "’ width=’14’ height=’14’ border=’0′>");
}else if(type==’User’){
pTD.html("<div style=’padding-left:12px’>" + newVal + "&nbsp;<img style=’vertical-align:middle’ title=’Saved’ src=’" + successImgSrc + "’ width=’14’ height=’14’ border=’0′></div>");
}else{
pTD.html(newVal + "&nbsp;<img style=’vertical-align:middle’ title=’Saved’ src=’" + successImgSrc + "’ width=’14’ height=’14’ border=’0′>");
}
}else{ // Failed to save
if(type==’Number’){
pTD.html("<div align=’right’>" + currVal + "&nbsp;<img style=’vertical-align:middle’ style=’vertical-align:middle’ title=’" + res.errorText + "’ src=’" + failureImgSrc + "’ width=’14’ height=’14’ border=’0′></div>");
}else if(type==’User’){
pTD.html("<div style=’padding-left:12px’>" + currVal + "&nbsp;<img style=’vertical-align:middle’ title=’" + res.errorText + "’ src=’" + failureImgSrc + "’ width=’14’ height=’14’ border=’0′></div>");
}else{
pTD.html(currVal + "&nbsp;<img style=’vertical-align:middle’ title=’" + res.errorText + "’ src=’" + failureImgSrc + "’ width=’14’ height=’14’ border=’0′>");
}
}
}else{ // If value is not changed, restore currVal
if(type==’Number’){
pTD.html("<div align=’right’>" + newVal + "&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’></div>");
}else if(type==’User’){
pTD.html("<div style=’padding-left:12px’>" + newVal + "&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’></div>");
}else{
pTD.html(newVal + "&nbsp;<img style=’vertical-align:middle’ title=’" + hoverImgMouseOver + "’ src=’" + hoverImgSrc + "’>");
}
}
}

function parseISO8601Date(str){
if(str!=”){
var strSplit = str.split(dateFormat.charAt(1));
switch(dateFormat){
case ‘m/d/yy’:
return strSplit[2] + "-" + strSplit[0] + "-" + strSplit[1] + "T12:00:00Z"; // set’s clock to 12:00 PM
break;
case ‘d.m.yy’:
return strSplit[0] + "-" + strSplit[2] + "-" + strSplit[1] + "T12:00:00Z"; // set’s clock to 12:00 PM
break;
}
}else{
return ”;
}
}

// 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);
initCustomEditFunction();
}

// Size of datepicker
$("body").css({‘font-size’:’55%’});
[/javascript]

Save this code as “EditInListView.js”, and upload to your scriptlibrary as shown above.

Note: Due to the number of DOM-modifications there might be a performance issue (prolonged load time of the page) when used.

To minimize the issue you can try:

  • Limit the number of columns this feature is applied to
  • Limit the item count in each page
  • Group your items and set “By default, show groupings: Collapsed”

Test it in your environment to find what settings suites you.

Ask if something is unclear.

Regards
Alexander

Link to fill user login name in people picker

By request from Charlie:

Hi:
Similar to the “Date Picker Clicker”, do you know if I could click a link and the users login name would fill a People Picker (person or group)?… on a newform or editform?

Charlie Epes

Here is a solution for inserting current user’s login name in a people picker by clicking on a link above the field.

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 “AccessUserProfileInWSS.js” is found here. Read the article as you have to set your “user list GUID” in the script.

The code for the file “SetPeoplePicker.js” is found below.

Add a CEWP below – it is essential that it is placed below – your list-form as described here, and add this code:
[javascript]
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/AccessUserProfileInWSS.js"></script>
<script type="text/javascript" src="/test/English/Javascript/SetPeoplePicker.js"></script>
<script type="text/javascript">
// Array of fields to add this function to
var arrOfFields = [‘MyPeoplePicker’,’AnotherPeoplePicker’];
initSetPeoplePicker(arrOfFields);
</script>
[/javascript]

The code for the file “SetPeoplePicker.js” looks like this:
[javascript]
/* Set people picker to current user login by click on a link above the field
* ———————————————
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.0
* LastMod: 04.12.2009
* ———————————————
* Include reference to jquery – http://jquery.com
* interaction.js – http://spjslib.codeplex.com/
* stringBuffer.js – http://spjslib.codeplex.com/
* AccessUserProfileInWSS.js – https://spjsblog.com/2009/09/20/accessing-user-profile-information-in-wss-3-0-with-javascript/
* ———————————————
* Call from a CEWP below the list form in NewForm or EditForm like this:
<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/AccessUserProfileInWSS.js"></script>
<script type="text/javascript" src="/test/English/Javascript/SetPeoplePicker.js"></script>
<script type="text/javascript">
// Array of fields to add this function to
var arrOfFields = [‘MyPeoplePicker’,’AnotherPeoplePicker’];
initSetPeoplePicker(arrOfFields);
</script>
*/

// Build the user information object
var ui = getUserInfo();

function initSetPeoplePicker(arr){
if(typeof(fields)==’undefined’)fields = init_fields();
$.each(arr,function(idx,item){
// Check if FieldInternalName is correct
if(fields[item]==undefined)return;
// Add clickable link over field – ui.Title=DisplayName of current user
$(fields[item]).find(‘.ms-formbody’).prepend("<div><a title="Set field’s value to " + ui.Title + "" href="javascript:setPeoplePicker(‘" + item + "’)">[" + ui.Title + "]</a></div>");
});
}

function setPeoplePicker(FieldInternalName){
var field = $(fields[FieldInternalName])
if(field.find(‘.ms-inputuserfield:visible’).length>0){
// IE
field.find(‘.ms-inputuserfield’).html(ui.Name);
field.find(‘img:first’).click();
}else{
// FF
field.find("textarea:first").val(ui.Name);
}
}

function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf(‘FieldInternalName="’)<0) return;
var start = $(this).html().indexOf(‘FieldInternalName="’)+19;
var stopp = $(this).html().indexOf(‘FieldType="’)-7;
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}
[/javascript]
Save this code as “SetPeoplePicker.js”, and upload to the script library as shown above.

Ask if something is unclear.

Regards
Alexander

Set datefield to first day of month, today’s date or last day of month

Change log
April 9, 2014
Updated the code example to fix some quotes that was formatted wrong due to migrating from my old server a long time ago. I also updated the function init_fields in the example.

I got this request from Charlie:

Hi Alexander:
Is it possible to add a clickable “button” or icon next to a date picker that would insert “Today’s Date” into the field box?

Yes it is. Here’s a solution for setting either “first day of month”, “today” or “last day of month” by clicking on a link above the date picker, or by pressing “F”, “T” or “L” in the date picker field itself.

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 code for the file “DateFieldValueOnClick.js” is found below.

Add a CEWP belowit is essential that it is placed below – your list-form as briefly described here, and add this code:

<script type="text/javascript" src="/Javascript/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/Javascript/DateFieldValueOnClick.js"></script>
<script type="text/javascript">
	// Array of fields to add this function to
	var arrOfFields = ['MyDateColumn1','MyDateColumn2'];
	setDateFieldValue(arrOfFields);
</script>

The variable “arrOfFields” is an array of the FieldInternalNames of all the date picker-fields you want to add this feature to.

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

/* Set datepicker value to "first day of month", "today" or "last day if month"
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 09.04.2014 
*/

function setDateFieldValue(arrOfFieldInternalNames){
if(typeof fields === 'undefined')fields = init_fields_v2();
// Get today's date
var today = new Date();
var m = today.getMonth()+1;
var d = today.getDate();
var y = today.getFullYear();
// Find last day in month
var lastDayRaw = new Date(y,m,0);
var dLast = lastDayRaw.getDate();

// Format your date
var T = m + "/" + d + "/" + y; // Today
var F = m + "/" + 1 + "/" + y; // First day in month
var L = m + "/" + dLast + "/" + y; // Last day in month
var fieldMouseoverTitle = "Press \"F\" for " + F + ", \"T\" for " + T + ", \"L\" for " + L;
$.each(arrOfFields,function(idx,item){
if(fields[item]==undefined)return;
$(fields[item]).find('input').attr('title',fieldMouseoverTitle).keyup(function(e){
if(e.keyCode==70){
setDate(item,F);
}
if(e.keyCode==84){
setDate(item,T);
}
if(e.keyCode==76){
setDate(item,L);
}
}).parents('td.ms-formbody:first').prepend("<div><span title='Set field value to \"" + F + "\"' style='cursor:pointer;' onclick=setDate(\"" + item + "\",\"" + F +"\")>First</span> | <span title='Set field value to \"" + T + "\"' style='cursor:pointer;' onclick=setDate(\"" + item + "\",\"" + T + "\")>Today</span> | <span title='Set field value to \"" + L + "\"' style='cursor:pointer;' onclick='setDate(\"" + item + "\",\"" + L +"\")'>Last</span></div>");
});
}

function setDate(fieldName,date){
	$(fields[fieldName]).find('input').val(date);
}

function init_fields_v2(){
	var res = {};
	$("td.ms-formbody").each(function(){
	var myMatch = $(this).html().match(/FieldName="(.+)"\s+FieldInternalName="(.+)"\s+FieldType="(.+)"\s+/);	
		if(myMatch!=null){
			// Display name
			var disp = myMatch[1];
			// FieldInternalName
			var fin = myMatch[2];
			// FieldType
			var type = myMatch[3];
			if(type=='SPFieldNote'){
				if($(this).find('script').length>0){
					type=type+"_HTML";
				}else if($(this).find("div[id$='TextField_inplacerte']").length>0){
					type=type+"_EHTML";
				}				
			}
			if(type==="SPFieldLookup"){
				if($(this).find("input").length>0){
					type=type+"_Input";
				}
			}
			// HTML Calc
			if(type==='SPFieldCalculated' && $(this).text().match(/(<([^>]+)>)/ig)!==null){
				$(this).html($(this).text());
			}		
			// Build object
			res[fin] = this.parentNode;
			$(res[fin]).attr('FieldDispName',disp);
			$(res[fin]).attr('FieldType',type);
		}		
	});
	return res;
}

Save this code as “DateFieldValueOnClick.js”, and upload to the script library as shown above.

Ask if something is unclear.

Regards
Alexander