Category Archives: Utilities

vLookup type rollup for SharePoint

02.03.2011 Updated the code for the file “vLookupForSharePoint.js” to v1.7.0

  • Add an “orderBy” option to sort the returned items by a FieldInternalName – See parameter descriptions below.
  • The dependencies upon interaction.js and stringBuffer.js has been eliminated.

10.06.2010 Updated the code for the file “vLookupForSharePoint.js” to fix some bugs.
This update includes:

  • Support for multiple webparts in one page
  • Bugfix: get listName in EditForm mode
  • Added option “DispFormRelURL” under “inQueryString” to provide current items relative DispForm URL
  • Handling multichoice values by replacing “;#” with “<br />”
  • Fixed bug with “newItemLink” if “linkBack” is not true
  • Added id tag for the “newItemLinkContainer” – to make hiding it possible.
  • Fixed bug when item has no “children” (newItemLink and inQueryString)
  • Fixed bug when matching on a calculated column

06.05.2010 Updated the code for the file “vLookupForSharePoint.js”.

This update includes:

  • Some small bugfixes
  • Added support for getting items connected by a multiLookup
  • Added createNewItem option by setting the parameter “newItemLink:true”
  • Added inQueryString option to include values from DispForm when creating new items using the “createNewItem” option
  • Added option to display vLookup connected items in EditForm
  • Localized for Norwegian, Swedish and English

01.04.2010 Small update to the file “vLookupForSharePoint.js”. I have modified the argument “hoverToView” to have separate settings for DispForm and for ListView. You must change the argument “hoverToView” to “hoverToViewDispForm” and “hoverToViewListView” in your calculated columns.


I have long thought of making a generic solution for pulling information from another list, kind of like you would do in Excel with the function vLookup. Here is my attempt to create just this. I’m fairly confident this solution will fill an empty space in many SharePointers hearts…

This solution features

  • Easy, generic interface to pull information from any list in current site or cross site
  • Concatenation of values from multiple items
  • Sum, average or count values from multiple items
  • Link back to filtered view of all matched items in “sum”, “avg” or “count” -mode, or to individual items in “concat” -mode
  • Direct link to documents
  • “Reverse lookup” on lookup columns – the “mother” item now has link back to the “children”.
  • And more…

The way this solution works is by using a calculated column to build a string with all the parameters like this:

This code matches the ID of the current item against a lookup column (the “child-list” has a lookup column named “ParentBug” targeting the “Mother-list” – what field the lookup is connected to is irrelevant as it is the ID we are looking for). This approach is a bit different than it will be for other columns as the ID is not accessible to a normal calculated column.

="listName:vLookupBugTrackerTasks|find:ID|findInCol:ParentBug|action:concat|linkBack:true|viewFields:Title#Title;TaskDescription#Task description;Deadline#Deadline"

This example matches the text in the “Title” column in one list against the “Title” column in another list.

="listName:vLookupBugTrackerTasks|find:"&Title&"|findInCol:Title|action:concat|linkBack:true|viewFields:Title#Title"

These are the available arguments:

  • listName: Name or GUID of the target list.
  • listBaseUrl: The base URL of the site the target list is located in. Defaults to current site is the argument is omitted.
  • find: The string to search for in the column specified as “findInCol” below. To use the current items ID (in case of a lookup connection), specify like this: “find:ID”.
  • findInCol: The FieldInternalName of the column to query against.
  • viewFields: “Array” of the fields of which to return a value for. Format: FieldInternalName1#DisplayName1. Separate multiple fields with semicolon.
  • action: “sum”, “avg”, “count” or “concat”.
  • sumOrAvgPrefix: A prefix in “sum” or “avg” -mode, like “$” for dollar.
  • sumOrAvgPostfix: As above, but postfix.
  • linkBack: true=Link back to item(s), false=no linkback. Default value: false
  • linkBackView: If in “sum”, “avg” or “count” -mode, set the target view name for the filtered result on “linkBack”. Defaults to “AllItems.aspx” if omitted.
  • hoverToViewListView: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in list view. Default value: false
  • hoverToViewDispForm: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in DispForm. Default value: false
  • hoverToViewEditForm: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in DispForm. Default value: false
  • newItemLink: (In “concat” -mode) true=Displays a “Create new item” link. Default value: false
  • inQueryString: (In “concat” -mode) semicolon separated array of FieldInternalNames to include the value from in the queryString that is passed to the NewForm. This only applies if the above parameter is set to true. Default value: “”. You need another script in the target list to pull the parameters from the query string and write them to a field in NewForm
  • orderBy: New! A FieldInternalName to sort the returned items by. Set the parameter “orderBy” in the calculated column like this: orderBy:Title. To have the result ordered descending, append a hash behind the FieldInternalName like this: orderBy:Title#

These are the base arguments that are required:
‘listName’,’find’,’findInCol’,’action’,’viewFields’

Note: If your formula errors out, it most likely has to do with the string being to long. To overcome this problem, just concatenate the string like this:
…first part of the string her”&”and the rest here…


Example images:

List view with tasks pulled from tasklist
IMG

Hover over each item for “link back menu”. Click on a “link back” will take you to the item
IMG

hoverToViewListView:true – before hover:
IMG

hoverToViewListView:true – after hover:
IMG

“sum”, “avg” or “count” looks like this:
IMG

A click on a “link back” on items in “sum”,”avg” or “count” -mode will take you to a filtered list of all matched items.
IMG
The target list view is set in the parameter “linkBackView”.

DispForm with “newItemLink:true”:
IMG

The same item in EditForm:
IMG

When setting the parameter inQueryString like this “inQueryString:Title;ID”, the value from these fields are included in the querystring of the URL (click to enlarge the image):
IMG
You need another script in the target list to pull the parameters from the query string and write them to a field in NewForm. Look here for an example.

When the code is added to the listView and to DispForm/EditForm, you create a new “enhanced lookup column” by creating a new field of type “Calculated (calculation based on other columns)” with a FieldInternalName starting with “vLookup” (you can rename the column afterwards, it’s only the FieldInternalName that is important). All fields with a FieldInternalName starting with this text will be included. No need to specify the columns to include! (this is not true for EditForm though, see separate instructions). Note: the ID column must be in the view (but can be hidden in the script).

Here is the code

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”).

The jQuery-library is referred from Google, but if you prefer a local copy, it is found here. The pictures and the sourcecode refers to jquery-1.5.1.min. If you download another version, be sure to update the script reference in the sourcecode.

The sourcecode for the file “vLookupForSharePoint.js” is found below.

Read here how to add a CEWP to the DispForm or EditForm.

Add this code in a CEWP below the list form in DispForm:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
  init_vLookupForSharePointDispForm();
</script>

Add this code in a CEWP below the list form in EditForm:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
  // This is an array of objects. Add more fields by adding a new object to the array
  // The "insertHere" value can be "top", "bottom" or a FieldInternalName to append the returned data to
  init_vLookupForSharePointEditForm([{'FieldInternalName':'vLookupTasks','FieldDisplayName':'Tasks','insertHere':'BugDescription'}]);
</script>

The reason the EditForm code is different is that the calculated column is not available unless we query for it using a CAML query. The “insertHere” parameter is used to place the “new field”.

Add this code in a CEWP below the list view:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
// The argument "true" sets the ID column to hidden
  init_vLookupForSharePointListView(true);
</script>

The code for the file “vLookupForSharePoint.js”:
download code

Upload the file to the scriptlibrary as described above.

If you find any bugs, please let me know!

Regards
Alexander

Add character or word count to SharePoint multi line plain text field and restrict input length

13.03.2011 Updated the code to handle pasting into the field by adding “blur” eventhandler. Referred jQuery from Google.


14.03.2010 Updated to count down from limit to 0 and color code the counter. Also merged the “Count characters” and the “Count words” functions to one. See new code and explanation below.

I got this request from Larry:

new request for you. Character/word counter for multiple line field to display below the field. Not general for all multiple lines, but setup in a way that can set fieldinternalnames in am arr. also can we add a character limit, so user can not enterany more text.

I have several character counters. cant get it on the form. I am also looking into adding it on the create field page. calculated fields can only accept about 1000 characters. would like a way to display the count on that page.

I cannot help with the “create new column page”, as it is a server side file, shared between all site collections running on this server.


IMG

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

Parameters explained:

  • FieldInternalName: FieldInternalName of the multi line plain text field.
  • countWords: true to count words, false to count characters.
  • limit: 0 for no limit and count up, a value bigger then 0 to set a limit and to count down.
  • colorCodeCounter: true to add orange/red coding when limit is approaching.
  • counterPrefix: The text to show before the counter.

Read here how to add a CEWP to the NewForm or EditForm and how to find the FieldInternalName of your columns.

Ask if anything is unclear
Alexander

Ratings for SharePoint lists

03.03.2010 Updated code for the file “RatingForSharePoint.js” due to a bug occurring when the ID column was hidden, but not placed far right in the view.

I got this request after enabling “rating” of the blog comments:

…How can we implement the thumbs up or down functionality you have on your site to a sharepoint list?

Tony


I have made a solution that uses a separate list to hold all the ratings. There will be written one line in this list for each rating of an item (list item or document).

This solution allows for one rating per item, per user, per session (browser session – new window = new session). There are an option to restrict or allow multiple ratings per user in different sessions.

The rating of the items are available in a list view (plain type, no boxed style), and in grouped plain list views. It is also available in DispForm.

ListView:
IMG

DispForm:
IMG

DispForm if already rated:
IMG

To enable rating of items, you add a calculated column to your list with this code:
[javascript]
=""
[/javascript]
Yes, only “equals” and two double quotes. You then assures that this new calculated column and the ID column is visible in the list view (there is an option in the script to hide the ID column).

Then you create a custom list for the ratings, with the name: RatingForSharePoint, and add these fields:

  • Plus The type of information in this column is: Number
  • Minus The type of information in this column is: Number
  • ListUrl The type of information in this column is: Single line of text
  • ItemID The type of information in this column is: Single line of text
  • ListGuid The type of information in this column is: Single line of text
  • ListName The type of information in this column is: Single line of text

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.

The file “sessvars.js” is found here.

The sourcecode for the file “RatingForSharePoint.js” is found below.

Add a CEWP below the listView 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/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Javascript/RatingForSharePoint.js"></script>
<script type="text/javascript">
ratingForSharePoint(‘Rating’,true,true);
</script>
[/javascript]
Parameters explained:

  • FieldInternalName: FieldInternalName of the calculated column created above.
  • hideIdCol: true to hide the ID column, false to let it be visible.
  • rateOnlyOnce: true to allow only one rating per user, false to allow multiple ratings (in different sessions)

Add a CEWP below your DispForm, 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/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Javascript/RatingForSharePoint.js"></script>
<script type="text/javascript">
// You must edit this GUID to match THIS list’s GUID – this is NOT the GUID of the "RatingForSharePoint"
thisListsGuid = ‘{77C35652-1D4D-4B09-B58C-D941068D251E}’;
ratingForSharePointDispForm(‘Rating’,true);
</script>
[/javascript]
Parameters explained:

  • thisListsGuid: This list’s GUID – this is NOT the GUID of the “RatingForSharePoint”
  • FieldInternalName: FieldInternalName of the calculated column created above
  • rateOnlyOnce: true to allow only one rating per user, false to allow multiple ratings (in different sessions)

Read here how to add a CEWP to the NewForm, DispForm or EditForm, how to find the list Guid of your list, and how to find the FieldInternalName of your columns.

The sourcecode for the file “RatingForSharePoint.js” looks like this:
[javascript]
/* Rating for SharePoint lists
* ———————————————
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.1
* LastMod: 03.03.2010
* ———————————————
* Must include reference to:
* jQuery – http://jquery.com
* interaction.js – http://spjslib.codeplex.com
* stringBuffer.js – http://spjslib.codeplex.com
* sessvars.js – http://www.thomasfrank.se
* RatingForSharePoint.js – This file
* ———————————————
*/

// If anonymous the SharePoint variable "_spUserId" does not exist
if(typeof(_spUserId)==’undefined’){
_spUserId = ”;
}
/************************************************************
*********************** ListView Code ***********************
************************************************************/
function ratingForSharePoint(FieldInternalName,hideIdCol,rateOnlyOnce){
if(typeof(ctx)==’object’){
var thisListsGuid=ctx.listName;
}
if(typeof(currentRatingObj)==’undefined’){
currentRatingObj = getRating();
}
if(typeof(FieldInternalName)!=’undefined’){
intName = FieldInternalName;
hideId = hideIdCol;
rateOnce = rateOnlyOnce;
// Fiend index of "Rating" column
$(".ms-viewheadertr th").each(function(){
if($(this).find(‘table:first’).attr(‘name’)==intName){
colIndex = $(this).attr(‘cellIndex’);
displayName = $(this).find(‘table:first’).attr(‘displayname’);
// Remove filtering possibility
$(this).removeClass(‘ms-vh2’).addClass(‘ms-vh2-nograd’).html(displayName);
}
});
// Find index of ID column
$(".ms-viewheadertr th").each(function(){
if($(this).find(‘table:first’).attr(‘name’)==’ID’){
IdColIndex = $(this).attr(‘cellIndex’);
// Hide ID column
if(hideId){
$(this).remove();
}
}
});
if(typeof(colIndex)==’undefined’ || typeof(IdColIndex)==’undefined’){
alert("Both the column with FieldInternalName ""+FieldInternalName+"" and the ID-column must be in the view.");
return false;
}
}

$("table.ms-listviewtable tbody:not([id^=’aggr’]) >tr[beenthere!=1]:has(td.ms-vb2)").each(function(){
$(this).attr(‘beenthere’,1);
var itemAlreadyRate = false;
var thisTd = $(this).find("td[cellIndex=" + colIndex + "]");
var thisIdColumn = $(this).find("td[cellIndex=" + IdColIndex + "]");
var thisId = thisIdColumn.text()
if(hideId){
thisIdColumn.remove();
}
var rPos = 0;
var rNeg = 0;
if(currentRatingObj[thisId]!=undefined){
// Previously rated by current user
if(rateOnce && currentRatingObj[thisId][‘ratedByMe’]==true){
itemAlreadyRate = true;
}
rPos = currentRatingObj[thisId][‘Plus’];
rNeg = currentRatingObj[thisId][‘Minus’];
}
// Rated in this session
if(sessvars[thisListsGuid+thisId]==1 && currentRatingObj!=false){
itemAlreadyRate = true;
}

var str = "<div style=’color:gray’>";
str += "<span><img ";
if(!itemAlreadyRate){
str += "onclick=’javascript:rateMe("up","+thisId+")’ title=’Rate Up’ ";
str += "style=’vertical-align:middle;cursor:pointer’ ";
}else{
str += "title=’You have already rated this item "+currentRatingObj[thisId][‘ratedByMeVal’]+"’ ";
str += "style=’vertical-align:middle;cursor:no-drop’ ";
}
str += "src=’/_layouts/images/arrupi.gif’></span>";
str += "<span style=’font-weight:bold;’ id=’rateUp_"+thisId+"’>"+rPos+"</span>";
str += "<span><img ";
if(!itemAlreadyRate){
str += "onclick=’javascript:rateMe("down","+thisId+")’ title=’Rate Down’ ";
str += "style=’vertical-align:middle;cursor:pointer’ ";
}else{
str += "title=’You have already rated this item "+currentRatingObj[thisId][‘ratedByMeVal’]+"’ ";
str += "style=’vertical-align:middle;cursor:no-drop’ ";
}
str += "src=’/_layouts/images/arrdowni.gif’></span>";
str += "<span style=’font-weight:bold;’ id=’rateDown_"+thisId+"’>"+rNeg+"</span>";
str += "</div>";
// Write HTML
thisTd.html(str);
});
}

function getRating(){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + ‘/_vti_bin/’;
var query = "<Where><Eq><FieldRef Name=’ListGuid’ /><Value Type=’Text’>"+ctx.listName+"</Value></Eq></Where>";
var rating = queryItems(‘RatingForSharePoint’,query,[‘Plus’,’Minus’,’ItemID’,’Author’]);
if(rating.count==-1){
alert("An error occured in the query:n"+query);
}else if(rating.count>0){
ratingObj = {};
$.each(rating.items,function(i,item){
var authorIdRaw = item[‘Author’];
var authorId = authorIdRaw.substring(0,authorIdRaw.indexOf(‘;#’));
var plusVal = item[‘Plus’];
var minusVal = item[‘Minus’];
if(plusVal==null)plusVal=0;
if(minusVal==null)minusVal=0;
if(ratingObj[item[‘ItemID’]]==undefined){
ratingObj[item[‘ItemID’]]={‘Plus’:parseInt(plusVal),’Minus’:parseInt(minusVal)};
}else{
ratingObj[item[‘ItemID’]][‘Plus’]+=parseInt(plusVal);
ratingObj[item[‘ItemID’]][‘Minus’]+=parseInt(minusVal);
}
// Rated by current user
if(_spUserId==authorId){
ratingObj[item[‘ItemID’]][‘ratedByMe’]=true;
if(item[‘Plus’]>0){
ratingObj[item[‘ItemID’]][‘ratedByMeVal’]="+1";
}else{
ratingObj[item[‘ItemID’]][‘ratedByMeVal’]="-1";
}
}
});
return ratingObj;
}else{
return false;
}
}

/************************************************************
*********************** DispForm Code ***********************
************************************************************/
function ratingForSharePointDispForm(FieldInternalName,rateOnlyOnce){
var queryStr = getQueryParameters();
if(typeof(fields)==’undefined’)fields = init_fields();
var itemAlreadyRate = false;
var thisId = queryStr.ID;
var currentRatingObj = getRatingDispForm(thisId);
if(currentRatingObj[thisId]==undefined){
rPos = 0;
rNeg = 0;
}else{
// Previously rated by current user
if(rateOnlyOnce && currentRatingObj[thisId][‘ratedByMe’]==true){
itemAlreadyRate = true;
}
rPos = currentRatingObj[thisId][‘Plus’];
rNeg = currentRatingObj[thisId][‘Minus’];
}
// Rated in this session
if(sessvars[thisListsGuid+thisId]==1 && currentRatingObj!=false){
itemAlreadyRate = true;
}
var thisTd = $(fields[FieldInternalName]).find(‘.ms-formbody’);
var str = "<div style=’color:gray’>";
str += "<img ";
if(!itemAlreadyRate){
str += "onclick=’javascript:rateMe("up","+thisId+")’ title=’Rate Up’ ";
str += "style=’vertical-align:middle;cursor:pointer’ ";
}else{
str += "title=’You have already rated this item "+currentRatingObj[thisId][‘ratedByMeVal’]+"’ ";
str += "style=’vertical-align:middle;cursor:no-drop’ ";
}
str += "src=’/_layouts/images/arrupi.gif’>";
str += "<span style=’font-weight:bold;’ id=’rateUp_"+thisId+"’>"+rPos+"</span>";
str += "<img ";
if(!itemAlreadyRate){
str += "onclick=’javascript:rateMe("down","+thisId+")’ title=’Rate Down’ ";
str += "style=’vertical-align:middle;cursor:pointer’ ";
}else{
str += "title=’You have already rated this item "+currentRatingObj[thisId][‘ratedByMeVal’]+"’ ";
str += "style=’vertical-align:middle;cursor:no-drop’ ";
}
str += "src=’/_layouts/images/arrdowni.gif’>";
str += "<span style=’font-weight:bold;’ id=’rateDown_"+thisId+"’>"+rNeg+"</span>";
str += "</div>";
// Write HTML
thisTd.html(str);
}

function getRatingDispForm(itemID){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + ‘/_vti_bin/’;
var query = "<Where><And><Eq><FieldRef Name=’ListGuid’ /><Value Type=’Text’>"+thisListsGuid+"</Value></Eq>"+
"<Eq><FieldRef Name=’ItemID’ /><Value Type=’Text’>"+itemID+"</Value></Eq></And></Where>";
var rating = queryItems(‘RatingForSharePoint’,query,[‘Plus’,’Minus’,’ItemID’,’Author’]);
if(rating.count==-1){
alert("An error occured in the query:n"+query);
}else if(rating.count>0){
ratingObj = {};
$.each(rating.items,function(i,item){
var authorIdRaw = item[‘Author’];
var authorId = authorIdRaw.substring(0,authorIdRaw.indexOf(‘;#’));
var plusVal = item[‘Plus’];
var minusVal = item[‘Minus’];
if(plusVal==null)plusVal=0;
if(minusVal==null)minusVal=0;
if(ratingObj[item[‘ItemID’]]==undefined){
ratingObj[item[‘ItemID’]]={‘Plus’:parseInt(plusVal),’Minus’:parseInt(minusVal)};
}else{
ratingObj[item[‘ItemID’]][‘Plus’]+=parseInt(plusVal);
ratingObj[item[‘ItemID’]][‘Minus’]+=parseInt(minusVal);
}
// Rated by current user
if(_spUserId==authorId){
ratingObj[item[‘ItemID’]][‘ratedByMe’]=true;
if(item[‘Plus’]>0){
ratingObj[item[‘ItemID’]][‘ratedByMeVal’]="+1";
}else{
ratingObj[item[‘ItemID’]][‘ratedByMeVal’]="-1";
}
}
});
return ratingObj;
}else{
return false;
}
}

/************************************************************
*********************** Shared Code ***********************
************************************************************/
function rateMe(upORdown,id){
if(typeof(ctx)==’object’){
var listGuid=ctx.listName;
var listTitle = $.trim($("td.ms-pagetitle").text());
}else{
var listGuid=thisListsGuid;
var listTitle = $.trim($("td.ms-pagetitle a").text());
}
// Only rate item if not already rated in this session
if(sessvars[listGuid+id]==undefined){
plus=”;
minus=”;
if(upORdown==’up’){
sessvars[listGuid+id]=1;
currVal = parseInt($("#rateUp_"+id).text());
$("#rateUp_"+id).text(currVal+1)
.prev().css({‘background-color’:’#C5E3BF’})
.parent().find(‘img’).attr({‘onclick’:”,’title’:’Rated +1′});
// Prepare for writing rating
plus=1;
}else{
sessvars[listGuid+id]=1;
currVal = parseInt($("#rateDown_"+id).text());
$("#rateDown_"+id).text(currVal+1)
//.parent().css({‘background-color’:’#FFE4E1′})
.prev().css({‘background-color’:’#FFE4E1′})
.parent().find(‘img’).attr({‘onclick’:”,’title’:’Rated -1′});
// Prepare for writing rating
minus=1;
}

// Get url
var urlDir = location.pathname;

// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + ‘/_vti_bin/’;
// Add item
var res = addItem(‘RatingForSharePoint’,
{‘Title’:"Rating for: " + listTitle,
‘Plus’:plus,
‘Minus’:minus,
‘ListUrl’:urlDir,
‘ListGuid’:listGuid,
‘ListName’:listTitle,
‘ItemID’:id});
}
}

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

// Function to separate each url search string parameters
function getQueryParameters(){
qObj = {};
var urlSearch = window.location.search;
if(urlSearch.length>0){
var qpart = urlSearch.substring(1).split(‘&’);
$.each(qpart,function(i,item){
var splitAgain = item.split(‘=’);
qObj[splitAgain[0]] = splitAgain[1];
});
}
return qObj;
}

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 as “RatingForSharePoint.js”, mind the file extension, and upload to the scriptlibrary as shown above.

Ask is something is unclear, and please report any bugs.

Regards
Alexander

Hit counter for SharePoint

28.05.2011 I have redone this solution to use a star-rating in stead of the simple “like” button. You find the new version here


01.11.2010 Redone the scripts and added support for rating individual items in a list – for example in “Dispform” in a blog:
IMG

The solution counts “Hits” and “Likes”.


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/Blog/Scripts” (a sub site named “test” with a sub site named “English” with a subsite named “Blog” and a document library named “Scripts”).

When you refer the scripts in the CEWP, ensure that you point to the correct location of your scripts.

The jQuery-library is found here. The CEWP code refers to jquery-1.4.2.min. If you download another version, be sure to update the script reference in the CEWP.

The sessvars.js is created by Thomas Frank and can be found here

The sourcecode for the file “HitCounterForSharePoint.js” is found here

Create a list with the name “HitCounter”, and add these fields:

  • URL: Multiline plain text
  • User: Person or Group
  • ReferringURL: Multiline plain text
  • Like: Single line of text

You have to give all users write access to the list “HitCounter”.

Add a CEWP where you want this counter to appear, and add this code:
[javascript]
<script type="text/javascript" src="/test/English/Blog/Scripts/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/test/English/Blog/Scripts/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Blog/Scripts/HitCounterForSharePoint.js"></script>
<script type="text/javascript">
hitCounter(true,true);
</script>
[/javascript]

Parameters:

  • oncePerSession: True to allow one “hit-count” per unique item per browser session.
  • isDispForm: If true, includes the ID of the item to allow individual counting of each item in a list.

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:
[javascript]
<script type="text/javascript" src="/test/English/EMSKJS/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="/test/English/EMSKJS/sessvars.js"></script>
<script type="text/javascript" src="/test/English/EMSKJS/OneClickEditCEWP.js"></script>
<script type="text/javascript">
var EditText = ‘Edit rich text|Edit code’; // The text of the edit link
var EditTextMouseOver = ‘Click to edit’; // Mouseover on edit-link
</script>
[/javascript]

This is the code for the file “OneClickEditCEWP.js”:
[javascript]
/* 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:
<script type="text/javascript" src="../EMSKJS/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="../EMSKJS/sessvars.js"></script>
<script type="text/javascript" src="../EMSKJS/OneClickEditCEWP.js"></script>
<script type="text/javascript">
var EditText = ‘Edit rich text|Edit code’; // The text of the edit link
var EditTextMouseOver = ‘Click to edit’; // Mouseover on edit-link
</script>
* ——————————————————–
* To exclude a webpart, add an empty DIV with class "customSkipThisCEWP" to the webpart body
* <div class="customSkipThisCEWP"></div>
* ——————————————————–
*/

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

SharePoint list’s or document library’s: Primary key in selected field

05.01.2010 Small update to hide the “OK-button” if the “keyIsNotUniqueCount” is greater than 0.
25.11.2009 Small update to the script for placing the image correctly when used with the headings script.

In this article I will give you a solution for adding “primary key support” to a list or a document library with JavaScript.

This will work with fields of type “Single line of text”, “Multiple lines of text (Plain text)” and “Number”. Note that if you activate this feature for a field of type “Number”, it strips off all other than numbers 0-9. No spaces, commas or periods are allowed. This is done to avoid conflicts based on different formats used in different language settings.

You can enable this feature for more than one field in a list or document library.

Note: This does only work in NewForm and EditForm, not if edited in DataSheet.

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

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

The last file in this screen-shot is the Right click and select Save picture as. Right click on the image and select “Save picture as”.

Add a CEWP below your list-form in NewForm and EditForm.
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/PrimaryKey.js"></script>
<script type="text/javascript">
// Enables "Primary key" on the "Title-field"
ensurePrimaryKey(‘Title’,”,’/test/English/Javascript/PrimaryKey.gif’,”);
</script>
[/javascript]

Your “Title-field” will look like this:
IMG

The check is attached to the “blur” event, and triggers when you removes focus on the field. If you try to add a “non-unique-value” to that field, you end up with this warning, and cannot save the list item:
IMG

If used with a field of type “Number”, the code strips away spaces, commas and periods as described above.

Parameters explained:

  • FieldInternalName: FieldInternalName of the field to add this feature to
  • PrimaryKeyViolationWarning: [optional] The text shown under the field if the key is not unique.
  • keyImageSrc: [optional] Image source for the “key.image” added before the field label. If not supplied it default’s to “/_layouts/images/prf16.gif”.
  • PrimaryKeyHoverImageText: [optional] Description text if hovered over the “key-image”.

Sourcecode for the file “PrimaryKey.js”:
[javascript]
/* Primary key for lists or Document libraries
* ———————————————
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.1
* LastMod: 05.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 NewForm orEditForm 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/PrimaryKey.js"></script>
<script type="text/javascript">
// Enables primary key for the "Title-field"
ensurePrimaryKey(‘Title’,’This field’s value has to be unique for this list.’,’/test/English/Javascript/PrimaryKey.gif’,’Primary key is enabled for this field’);
</script>
*/

if(typeof(fields)==’undefined’)fields = init_fields();
function ensurePrimaryKey(FieldInternalName,PrimaryKeyViolationWarning,keyImageSrc,PrimaryKeyHoverImageText){
if(fields[FieldInternalName]!=undefined){
listDisplayName = $("h2.ms-pagetitle a").text();
keyIsNotUniqueCount = 0;
// If PrimaryKeyViolationWarning is not defined, default to this text
if(PrimaryKeyViolationWarning==undefined || PrimaryKeyViolationWarning==”){
var PrimaryKeyViolationWarning = "This field’s value has to be unique for this list.";
}
// If PrimaryKeyHoverImageText is not defined, default to this text
if(PrimaryKeyHoverImageText==undefined || PrimaryKeyHoverImageText==”){
var PrimaryKeyHoverImageText = "Primary key is enabled for this field";
}
if(keyImageSrc==undefined || keyImageSrc==”){
keyImageSrc = "/_layouts/images/prf16.gif";
}
// If number – trim off all spaces, commas and periods
if($(fields[FieldInternalName]).html().match(‘SPFieldNumber’)!=null){
$(fields[FieldInternalName]).find(‘:input’).keyup(function(e){
var currVal = $(this).val();
$(this).val(currVal.replace(/[^0-9]/g,”));
});
}

// Determine where to put the image – if used with the Heading-script
if($(fields[FieldInternalName]).find("h3:has(‘div’)").length>0){
var insertImageHere = ‘h3 div’;
}else{
var insertImageHere = ‘h3’;
}

// Add blur function
$(fields[FieldInternalName]).find(‘:input’).blur(function(){
// Check if input value is unique in this list
checkPrimaryKey(FieldInternalName,$(this),PrimaryKeyViolationWarning);
})
// Add key image before label
.parents(‘tr:first’).find(insertImageHere)
.prepend("<img title=’" + PrimaryKeyHoverImageText + "’ src=’" + keyImageSrc + "’>");
}
}

function checkPrimaryKey(FIName,keyField,warningText){
wsBaseUrl = L_Menu_BaseUrl + ‘/_vti_bin/’;
var ItemId = getIdFromFormAction(); // Returns 0 if NewForm
var keyFieldVal = keyField.val().replace(/&/g,’&amp;’);

if(ItemId==0){ // NewForm
var query = "<Where><Eq><FieldRef Name=’" + FIName + "’/><Value Type=’Text’>" + keyFieldVal + "</Value></Eq></Where>";
}else{ // EditForm – skip current ID
var query = "<Where><And><Eq><FieldRef Name=’" + FIName + "’/><Value Type=’Text’>" + keyFieldVal + "</Value></Eq>" +
"<Neq><FieldRef Name=’ID’/><Value Type=’Counter’>" + ItemId + "</Value></Neq></And></Where>";
}
var res = queryItems(listDisplayName,query,[‘ID’]);
if(res.count==-1){
alert("An error occured in the query:n" + query);
}else if(res.count>0){
keyIsNotUniqueCount = keyIsNotUniqueCount + 1;
keyField.parents(‘td:first’).find(".customPrimaryKeyAlert").remove();
keyField.parents(‘td:first’).append("<div class=’customPrimaryKeyAlert’ style=’color:red’>" + warningText + "</div>");
}else{
keyField.parents(‘td:first’).find(".customPrimaryKeyAlert").remove();
if(keyIsNotUniqueCount>0){
keyIsNotUniqueCount = keyIsNotUniqueCount – 1;
}
}
// Hide button
if(keyIsNotUniqueCount>0){
$("input[id$=’SaveItem’]").hide();
}else{
$("input[id$=’SaveItem’]").show();
}
}

// This function gets the list item ID from the form’s action-attribute
function getIdFromFormAction(){
var action = $("#aspnetForm").attr(‘action’);
var IdCheck = action.substring(action.indexOf(‘?’)).indexOf(‘ID=’);
if(IdCheck==1){
var end = action.indexOf(‘&’);
if(action.indexOf(‘&’)<0){
id = action.substring(action.indexOf(‘ID=’)+3);
}else{
id = action.substring(action.indexOf(‘ID=’)+3,end);
}
}else{
id = 0; // Called from NewForm returns 0
}
return id;
}

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 as “PrimaryKey.js” and upload to the “script-library” as shown above.

This is not a “guaranteed” primary key, as it does not work in datasheet-editing, and I’m sure someone finds a way to trick it. I’m nevertheless confident that someone can make use of this code.

Let me know if something is unclear.

Regards
Alexander

Add HTML mouseover tooltip

28.12.2009: Updated the code in line 38 and 41 and added “stop(true,true)” to prevent animation from looping when mouse is rapidly hovered in and out.


In a previous post i described how to add a custom tool-tip on mouse-over a SharePoint field. This was using the “title-property” of a DOM element and therefore limited to plain text only.

Here is a method for adding HTML tool-tip

It uses a standard “Custom list” as a repository for the mouse-over tool-tip’s. This list can be used for multiple lists.

The tool-tip can look like this (but is unlimited as it uses HTML):
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

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.

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

Create the repository like this:
IMG

IMG

IMG

Add a CEWP below your NewForm and EditForm list-form (and DispForm if you like) like this:
IMG

With 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/HTML_style_ToolTip.js"></script>
<script type="text/javascript">
toolTip(‘MyTestList’,’MouseOverTooltipResources’);
</script>
[/javascript]

Sourcecode for the file “HTML_style_ToolTip.js”:
[javascript]
/* HTML style ToolTip
* ———————————————
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.1
* LastMod: 28.12.2009
* ———————————————
* Include reference to:
* jquery // jquery.com
* interaction.js // http://spjslib.codeplex.com/
* stringBuffer.js // http://spjslib.codeplex.com/
* ———————————————
* Call from a CEWP below the list form in NewForm, DispForm or EditForm like this:
* toolTip(ListnameOrToken,ResourcesListName)
*
* Parameters:
* ListnameOrToken = Identifier for the list – to distinguish between lists with similar FieldInternalName
* ResourcesListName = ListName or Guid of the tool-tip repository
*/

fields = init_fields();

function toolTip(ListnameOrToken,ResourcesListName){
tooltip = init_tooltip(ListnameOrToken,ResourcesListName);
$.each(tooltip,function(idx,item){
var split = item.split(‘|’);
var fieldName = split[0];
var displayText = split[1];
var toolTip = split[2];
if(fields[fieldName]!=undefined){
$(fields[fieldName]).find(‘td.ms-formbody’).prepend("<div class=’customMouseOverTooltip’ style=’float:right;cursor:hand’>&nbsp;" +
displayText + "&nbsp;<div style=’padding:3px;display:none;’>" + toolTip + "</div></div>");
}
});

$(".customMouseOverTooltip").hover(function(){
$(this).find(‘div:first’).css({‘position’:’absolute’,’background-color’:’f8f8ff’,’border’:’1px silver solid’}).stop(true,true).fadeIn(350)
},
function(){
$(this).find(‘div:first’).stop(true,true).fadeOut(150);
});
}

function init_tooltip(ConsumerListName,ProviderListName){
wsBaseUrl = L_Menu_BaseUrl + ‘/_vti_bin/’;
var query = "<Where><Eq><FieldRef Name=’Identifier’ /><Value Type=’Text’>" + ConsumerListName + "</Value></Eq></Where>";
var res = queryItems(ProviderListName,query,[‘Title’,’DisplayText’,’ToolTip’]);

tooltip = [];
if(res.count==-1){
alert("An error occured in the query:n" + query + "nnContact an administrator");
}else if(res.count>0){
$.each(res.items,function(idx,item){
if(item[‘ToolTip’]!=null){
var title = item[‘Title’];
var val = item[‘ToolTip’];
var DisplayText = item[‘DisplayText’];
tooltip.push(title + "|" + DisplayText + "|" + val);
}
});
}
return tooltip;
}

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 as “HTML_style_ToolTip.js” and upload to your scriptlibrary as shown above.

Enjoy!

Regards
Alexander