Category Archives: Javascript

Redirect on NewForm and EditForm another method

This is another method for redirecting a user to a custom page on “OK” and another page on “Cancel”.

I have described two methods in this previous article. This method is a god replacement for the “simple redirect” described in the previous article.

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

Add a CEWP below your list-form in NewForm or EditForm, and add this code:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
fields = init_fields();
// Where to go when cancel is clicked
goToWhenCanceled = '/test/English/YouCanceled.aspx';

// Edit the redirect on the cancel-button's
$('.ms-ButtonHeightWidth[id$="GoBack"]').each(function(){
    $(this).click(function(){
			STSNavigate(goToWhenCanceled);
	  })
});

// Edit the form-action attribute to add the source=yourCustomRedirectPage
function setOnSubmitRedir(redirURL){
var action = $("#aspnetForm").attr('action');
var end = action.indexOf('&');
	if(action.indexOf('&')<0){
		newAction = action + "?Source=" + redirURL;
	}else{
		newAction = action.substring(0,end) + "&Source=" + redirURL;
	}
$("#aspnetForm").attr('action',newAction);
}

/*
// Use this for adding a "static" redirect when the user submits the form
$(document).ready(function(){
	var goToWhenSubmitted = '/test/English/ThankYou.aspx';
	setOnSubmitRedir(goToWhenSubmitted);
});
*/

// Use this function to add a dynamic URL for the OnSubmit-redirect. This function is automatically executed before save item.
function PreSaveAction(){
// Pass a dynamic redirect URL to the function by setting it here,
// for example based on certain selections made in the form fields like this:
	var mySelectVal = $(fields['MySelect']).find(':radio:checked').next().text(); 
	if(mySelectVal=='Option one'){
		var dynamicRedirect = '/test/English/YouSelectedOptionOne.aspx';
	}else if(mySelectVal=='Option two'){
		var dynamicRedirect = '/test/English/YouSelectedOptionTwo.aspx';
	}	
	
	// Call the function and set the redirect URL in the form-action attribute
	setOnSubmitRedir(dynamicRedirect);
	
	// This function must return true for the save item to happen
	return true;
}

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>

This script is by default setup with a “dynamic” redirect for “OK” based on the selection made in a “Choice-field” of type “Radio Buttons” with the options “Option one” and “Option two”.

The “OK” redirect can be set to a “static” value if you comment out the function “PreSaveAction()” and uncomment the “$(document).ready(…” function.

The cancel-redirect is set in the top pf the script in the variable “goToWhenCanceled”. The script modifies the “click” attribute of both cancel-buttons and adds this redirect.

Ask if something is unclear

Regards
Alexander

Identify content type to execute content type specific code

In another post i received a request on how to identify the content type in NewForm to execute “content type specific code”. Here’s a quick description of one method.

The method relies on a script, init_fields(), which loops trough all fields in the form and makes an object of all table rows and their HTML. This way all fields can be addressed by their FieldInternalName, returning the full HTML of that field.

The function init_fields() is a modified version of Erucy’s function for finding fields in a SharePoint form. My modified version uses FieldInternalName rather than DisplayName to locate the fields.

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 below uses the FieldInternalName of a specific field to ensure that the field is rendered – if so – it executes the code wrapped in that “if-statement”. The field used to identify the ContentType must reside only in that content type.

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="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
fields = init_fields();
/*
 This example shows how you can check what ContentType is used by checking if
 a field you know is in that specific ContentType is rendered
*/

// Check if the field with FieldInternalName of "OnlyInContentType1" is rendered
if(fields['OnlyInContentType1']!=undefined){
	alert("This is content type nr 1");
	// Execute any code that addresses the first content type
}

// Check if the field with FieldInternalName of "OnlyInContentType2" is rendered
if(fields['OnlyInContentType2']!=undefined){
	alert("This is content type nr 2");
	// Execute any code that addresses the second content type
}

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>

The code above does work in NewForm, DispForm and EditForm.

To get the “FriendlyName” of the content type in DispForm or EditForm you can use the script below. This script also enables you to hide the “Content type selector” from EditForm.

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">

// This example shows how you can get the "FriendlyName" of the ContentType
// You can optionally hide the "ContentType selector from EditForm"

// Get the name and hide the selector
var contentType = getContentFriendlyNameOptionalHide(true);
alert(contentType);

function getContentFriendlyNameOptionalHide(hide){
if(hide){
	$("select[id$='ContentTypeChoice']").parents('tr:first').hide();
}
	// EditForm
	var value = $("select[id$='ContentTypeChoice']").find('option:selected').text();
	// DispForm
	if(value==''){
		value = $("span[id$='InitContentType']").text();
	}
return value;
}
</script>

Ask if something is unclear.

Regards
Alexander

Preview metadata in list view on mouseover

12.09.2011 A new version is posted here.

30.07.2010 A major update of the script to tidy up the code and to support previewing in a image library. Please read trough the article to get the changes to the CEWP code. The solution is tested in IE 8, Firefox v3.6.8 and in Google Chrome v5.0.375.125.

22.06.2010 Small update in line 118 and 125 to prevent “star” to be appended to lookup columns.

23.03.2010 Updated the code for “Preview_DispForm_metadata.js”. This update fixed compatibility with folders (thanks to Deano for finding the bug). Added support for a mix of lists and document libraries in the same webpart page.

19.02.2010 Fixed a bug if two different document libraries were present in the same webpartpage. The file “Preview_DispForm_metadata.js” is updated. Thanks to Ben for finding the bug.

09.01.2010: Fixed a major performance issue when viewing only selected fields from the metadata. Replace the code for the file “Preview_DispForm_metadata.js” to get the latest fixes.

10.12.2009: Fixed a hard coded “hoverImg” in the code – thanks to Amy.


By request from some of my readers i have, with basis in a solution created by Paul Grenier and published on EndUserSharepoint, made a solution that preview’s metadata from a list item or a document on mouse over.

The script i used as basis previewed metadata from DispForm in a CEWP beside a calendar view.

This modification adapts it to present a “floating” pop-up on mouse over when hovering over a table row, a calendar item, or on a small image added before a selected field.

The original script, made by Paul Grenier, previewed the full form from DispForm. I have adapted it so that one can display the full form, or specify an array of columns to display.

This script can be used in plain list view, grouped list views and calendar views.

New in this version is that the ID column must be in the view (not true for calendar view). The column can be hidden in the script.

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.4.2.min. If you download another version, be sure to update the script reference in the sourcecode.

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

Add a CEWP below the list view and add the code – examples shown below the screen-shots.

Here are some screenshots and the CEWP code:
Plain list view – all fields
IMG

<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/Preview_DispForm_metadata.js"></script>

To hide the ID column, change the CEWP code like this:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/Preview_DispForm_metadata.js"></script>
<script type="text/javascript">
    hideIdColumn = true;
</script>

Plain list view – selected fields
IMG

<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/Preview_DispForm_metadata.js"></script>
<script type="text/javascript">
    hideIdColumn = true;
    arrOfFieldsToShow = ['MultilinePlainText','Responsible'];
</script>

“hoverImg” used
IMG

<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/Preview_DispForm_metadata.js"></script>
<script type="text/javascript">
    hideIdColumn = true;
    arrOfFieldsToShow = ['MultilinePlainText','Responsible'];
    hoverImg = '/_layouts/images/OPENDB.GIF';
    hoverImgDescription = 'Hover mouse over this image to preview the metadata'; // If left blank, no description is displayed in the pagetitle area
    prependHoverImageTo = 'LinkTitle'
</script>

Parameters explained:

  • hideIdColumn: true to hide the ID column. Defaults to false
  • arrOfFieldsToShow: Array of fields to show. Defaults to all fields.
    To have only a selection of fields, add to the array like this: [‘Title’,’MultilinePlainText,’Responsible’].
    To have only the value and not the label showing, add to the array like this: [‘MultilinePlainText|0’]
  • hoverImg: If you want to hover over an image and not the whole row, add the “src” to the image here. You must also set the parameter “prependHoverImageTo”.
  • prependHoverImageTo: A FieldInternalName to prepend the “hoverImg” to.
  • hoverImgDescription: A description that will be added to the page title area.

All parameters are optional.

Sourcecode for “Preview_DispForm_metadata.js” is found here

Note:

When new versions are released, they will be placed in a folder with the version number as label. Be sure to download the latest version.

If you are using a browser other than IE, right click the file and select “Save link as” or “Save linked content as…”.

Ask if something is unclear.

Regards
Alexander

Collect input from custom input fields and store in multiline plain text field

16.11.2009 Fixed an error found by Marc Verner, resulting in values returning “undefined”. This error var introduced by my previous update because i didn’t test it thoroughly…

I have added some code to show how to use this code with multiple fields. This code is commented out, but is found in lines 6, 10 and 54-63. Uncomment these lines and you are good to go with another field with FieldInternalName “MultilinePlain2”. I have also added an attribute “labelPosition”, value “above” or “before” to determine label position.

14.11.2009 Small update on alignment of the input field – thanks to Larry. There are now two options on alignment. the default is to have the label above the input-field. Comment out line 17 and activate line 19 to have the label before the input-field (note that a long label will fall behind the input-field).

I got a request that i thought was worth doing a post on. Its from Marc Verner and sounded like this:

Hey Alexander,
I currently have a MS Word based form that contains a 2 column by 10 row table where users provide up to 10 keycodes and their corresponding descriptions. I am hesitant to make 20 sharepoint variables to capture this since it will make a mess of the form – and I don’t need to query or report on these fields. Instead I’m looking for a possible solution for pre-populating a rich text field with a table template including column names. This way when a user creates a new item, they will see the familiar table and simply fill it in as per usual.
Not sure if its possible but you have really amazed me so far so figured I’d ask =)
Many thanks,
Marc

I do not like SharePoint’s rich text fields as the clutter the HTML-code to the non recognizable when editing. This solution is therefore based on generating some custom input fields and storing the result in a multi line text field of type “plain 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

You start with a standard multiline text field like this:
IMG

Add the script, and you end up with this:
IMG

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

And add this code:
You must replace any occurrence of “MultilinePlain” with your FieldInternalName

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
fields = init_fields();
// Array to create the input fileds from
var arr = ['Label 1','Long Label 2','Even longer Label 3','Label 4','Label 5'];
//var arr2 = ['Label 6','Long Label 7','Even longer Label 8','Label 9','Label 10'];

// Call the script with the array, and the FieldInternalName of the multiline text field
generateInputAndStoreInMultilineText(arr,'MultilinePlain','above',300);
//generateInputAndStoreInMultilineText(arr2,'MultilinePlain2','before',300);

function generateInputAndStoreInMultilineText(arrOfLabels,FieldInternalName,labelPosition,widthOfInputField){
if(widthOfInputField==undefined)widthOfInputField=250;
// Hide the multiline text field
$(fields[FieldInternalName]).find(".ms-formbody :input:last").hide().next().hide();
	var customInputFields = '';
	// Loop trough all "Labels" and create the input field
	$.each(arrOfLabels,function(idx,item){
		// Label position
		if(labelPosition=='above'){
			customInputFields += "<div id='customInput_" + idx + "' value='" + item + "' style='padding:2px'>" + item + "<br><input type='Text' style='width:100%;margin:0 13 0 0;'></div>";
		}else if(labelPosition=='before'){
			customInputFields += "<div id='customInput_" + idx + "' value='" + item + "' style='padding:2px;'>" + item + "<div style='text-align:right;margin: -17px 13px 0 0;'><input type='Text' style='width:" + widthOfInputField + "px'></div></div>";
		}
	});
	// Insert the custom input fields
	$(fields[FieldInternalName]).find('.ms-formbody').prepend(customInputFields);
	// Handle page refresh due to form validation, and preserve the values in the custom inputs
	$(document).ready(function(){
	// Read the values from the hidden multiline textfield
		if($(fields[FieldInternalName]).find(".ms-formbody :input:last").val()!=''){
			// Split the values
			var raw = $(fields[FieldInternalName]).find(".ms-formbody :input:last").val();
			var split = raw.split('n');
			// Insert the values in the correct "custom input"
			$(fields[FieldInternalName]).find(".ms-formbody div[id^='customInput_']").each(function(idx){
			var splitAgain = split[idx].split(': ');
				$(this).val(splitAgain[0]);
				$(this).find('input').val(splitAgain[1]);
			});
		}
	});
}

function PreSaveAction(){
var valToSave = '';
// Build the content to write to the hidden multiline field
$(fields['MultilinePlain']).find(".ms-formbody div[id^='customInput_']").each(function(){
	valToSave += $(this).val() + ": " + $(this).find('input').val() + "n";
});
// Write to multiline field
$(fields['MultilinePlain']).find(".ms-formbody :input:last").val(valToSave);

/*
// Field nr 2
var valToSave = '';
// Build the content to write to the hidden multiline field
$(fields['MultilinePlain2']).find(".ms-formbody div[id^='customInput_']").each(function(){
	valToSave += $(this).val() + ": " + $(this).find('input').val() + "n";
});
// Write to multiline field
$(fields['MultilinePlain2']).find(".ms-formbody :input:last").val(valToSave);
*/
return true; // Must return true for item to be saved
}

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>

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 script handles page refresh due to form validation, and preserves the values in the custom input fields (it reads them back from the hidden text field). The code can be used for both NewForm and for EditForm due to the same logic.

The values are stored in a proper format to present in DispForm and in list view’s like this:
IMG
IMG

Read here how to find the FieldInternalName of your field

Don’t hesitate to ask if all is not clear

Regards
Alexander

Move site actions to the left

21.02.2010: Updated the post with the code for floating the site action menu to the right on the screen (as requested by Larry).

This one proved a bit tricky because the site action menu is part of the master page.

See codeblock below for updated code. Please let me know if you find any bugs.


After i posted the solution to Move view selector to the left, i got a request from Charlie Epes for the same solution regarding the “Site Actions-menu”.

This is the default placement of the Site Actions-menu:
IMG

Here the menu is inserted after the last toplink (dynamic):
IMG


Here is how it’s done
Add a CEWP below the list view, and add this code (alter the location of the jQuery-scipt as needed)

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$("table.ms-bannerframe table:first td:last").after($("table.ms-bannerframe td:last"));
</script>

Code for floating the menu to the right (replace the code supplied above with this one):

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
// Site action float right
$(document).ready(function(){
	setTimeout(function(){
		siteActionFloatRight();
	},500);
});

function siteActionFloatRight(){
	var menuWidth = $("table.ms-siteaction").width();
	var doc = $(document).width();
	var win = $(window).width();
	var scr = $(window).scrollLeft();

	left = doc-win-scr+menuWidth;
	if(left<120){
		left=100;
	}
	// Move the site action menu to the new position
	$("table.ms-siteaction").css({'position':'absolute','top':0,'left':-left});	
}

// Handle resize and scroll
$(window).resize(function() {
	siteActionFloatRight();
}).scroll(function() {
	siteActionFloatRight();
});

// Make it adapt to changing document width due to expanding groups
$("td[class^='ms-gb']").click(function(){
	setTimeout(function(){
		siteActionFloatRight();
	},250);
});
</script>

Regards
Alexander

Move view selector to the left

06.02.2010 Added another method for floating the view selector on the right side of the page.


I got a request from “tecrms” that sounded like this:

As you know on all list views and document views, the view selector is on the right hand side of the menu bar. This can make it quite cumbersome for users looking at lists with many columns to change the view. A better option would be for the view selector to be on the left hand side and right hand side of the menu bar. I know I can move the view selector via SPD but would rather use a JavaScript options if one was available. Would this be something you would be interested in creating?

It’s often harder to think out the question than to actually solve the issue…

This is the default placement of the view-selector:
IMG

Here the selector is inserted after the “Settings-menu”:
IMG


Here is how it’s done
Add a CEWP below the list view, and add this code (alter the location of the jQuery-scipt as needed)

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$("td.ms-toolbar:last").insertBefore($("td.ms-toolbar[width='99%']"));
</script>

Use this code for a floating menu on the right side of the page:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
	viewMenuFloatRight();
});

function viewMenuFloatRight(){
	var top = $("td.ms-toolbar:last").offset().top+2;
	var menuWidth = $("td.ms-toolbar:last table").width()+15;
	var left = $(window).width() - menuWidth + $(window).scrollLeft();	
	// Position the menu
	$("td.ms-toolbar:last table").css({'position':'absolute','top':top,'left':left});
	// Paging
	$("td.ms-toolbar td[id='topPagingCellWPQ1'] table").css({'position':'absolute','top':top,'left':left-50});
}

// Handle resize and scroll
$(window).resize(function() {
	viewMenuFloatRight();
}).scroll(function() {
	viewMenuFloatRight();
});
</script>

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:

<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>

Sourcecode for the file “HTML_style_ToolTip.js”:

/* 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'> " + 
				displayText + " <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;
}

Save this as “HTML_style_ToolTip.js” and upload to your scriptlibrary as shown above.

Enjoy!

Regards
Alexander

Send E-mail with JavaScript

Note:
I’m far away from my safe “pure JavaScript” world here – if someone have any comments on this approach i will gladly listen!


In this article I will give an example of how to send e-mail (with CC, Bcc and HTML body) from SharePoint with JavaScript and the help of some server-side files (two variants of the aspx-page and a code-behind .cs file placed in the Layouts directory of your 12′ hive). This approach requires server access for placing the files.

I will first show you how to create a simple “contact-form”, secondly i will show you how to send the contents of a DispForm as a HTML-bodied email (in a follow-up post).

The method used passes the variables collected with javascript to the server-side file “SendMailBySessvars.aspx” or “SendMailNewWindow.aspx”. This page uses javascript to populate some hidden controls. The hidden controls is used to pass the variables to the server-side code as javascript cannot pass it’s variables directly. When the controls are populated, the server-side code is called to do the actual sending of the e-mail.

I will provide two options for sending the email:

  • The current page redirects to the “SendMailBySessvars.aspx” – sends the email and redirects back.
  • A new window is opened – the email is sent – and the window is closed.

The server-side files

In your SharePoint server – add these files to your 12’hive (C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12TEMPLATELAYOUTSSendMailWithJavascript)
IMG

The sourcecode for the files “SendMailBySessvars.aspx”, “SendMailNewWindow.aspx” and “SendMail.aspx.cs” is provided below. The file “sessvars.js” is found here.

SourceCode for “SendMailBySessvars.aspx” – used for sending mail in the current window

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SendMail.aspx.cs" Inherits="Enquiry" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<style>
.mailStatusMsg
{
	color:#666666;
	font-size:large;
	border:5px gray double;
	text-align:center;
}

</style>
<title>Send Mail</title>
</head>
<body>

<form id="formSendMail" runat="server">
	<div style="display:none">
		<asp:HiddenField ID="txtSMTP" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtSMTP_Port" runat="server"></asp:HiddenField>		
		<asp:HiddenField ID="txtEmailSubject" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtHtmlBody" runat="server"></asp:HiddenField>		
		<asp:HiddenField ID="txtFromEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtToEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtCCEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtBccEmail" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtNewWindow" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtShowSplash" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtRedirUrl" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtTimer" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtSuccessMsg" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtErrorMsg" runat="server"></asp:HiddenField>		
		<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click"/>
	</div>
</form>

<script type="text/javascript" src="sessvars.js"></script>
<script type="text/javascript">

if(sessvars.emailBySessvars!=undefined){
	if("<%=SendFunctionTriggered%>" != 1){
		document.getElementById('txtSMTP').value=sessvars.emailBySessvars.SMTP;
		document.getElementById('txtSMTP_Port').value=sessvars.emailBySessvars.SMTP_Port;
		document.getElementById('txtEmailSubject').value=sessvars.emailBySessvars.EmailSubject;
		document.getElementById('txtHtmlBody').value=sessvars.emailBySessvars.htmlBody;
		document.getElementById('txtFromEmail').value=sessvars.emailBySessvars.fromEmail;
		document.getElementById('txtToEmail').value=sessvars.emailBySessvars.toEmail;
		document.getElementById('txtCCEmail').value=sessvars.emailBySessvars.ccEmail;
		document.getElementById('txtBccEmail').value=sessvars.emailBySessvars.BccEmail;	
		document.getElementById('txtNewWindow').value="0";
		document.getElementById('txtShowSplash').value=sessvars.emailBySessvars.ShowSplash;
		document.getElementById('txtRedirUrl').value=sessvars.emailBySessvars.RedirUrl;
		document.getElementById('txtTimer').value=sessvars.emailBySessvars.RedirTimer;
		document.getElementById('txtSuccessMsg').value=sessvars.emailBySessvars.SuccessMsg;
		document.getElementById('txtErrorMsg').value=sessvars.emailBySessvars.ErrorMsg;
	
		// Clear sessvars 
		sessvars.$.clearMem();
		//if(confirm("Sessvars - send mail?")){
			document.getElementById('btnSubmit').click();
		//}
	}
}
</script>    
</body>
</html>

SourceCode for “SendMailNewWindow.aspx” – used for sending mail in new window

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SendMail.aspx.cs" Inherits="Enquiry" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<style>
.mailStatusMsg
{
	color:#666666;
	font-size:large;
	border:5px gray double;
	text-align:center;
}

</style>
<title>Send Mail</title>
</head>
<body>

<form id="formSendMail" runat="server">
	<div style="display:none">
		<asp:HiddenField ID="txtSMTP" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtSMTP_Port" runat="server"></asp:HiddenField>		
		<asp:HiddenField ID="txtEmailSubject" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtHtmlBody" runat="server"></asp:HiddenField>		
		<asp:HiddenField ID="txtFromEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtToEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtCCEmail" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtBccEmail" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtNewWindow" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtShowSplash" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtRedirUrl" runat="server"></asp:HiddenField>	
		<asp:HiddenField ID="txtTimer" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtSuccessMsg" runat="server"></asp:HiddenField>
		<asp:HiddenField ID="txtErrorMsg" runat="server"></asp:HiddenField>		
		<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click"/>
	</div>
</form>

<script type="text/javascript" src="sessvars.js"></script>
<script type="text/javascript">


if(window.opener!=undefined){
	if(window.opener.openInNewWindowAndEmail!=undefined){
		if("<%=SendFunctionTriggered%>" != 1){
			document.getElementById('txtSMTP').value=window.opener.openInNewWindowAndEmail.SMTP;
			document.getElementById('txtSMTP_Port').value=window.opener.openInNewWindowAndEmail.SMTP_Port;
			document.getElementById('txtEmailSubject').value=window.opener.openInNewWindowAndEmail.EmailSubject;
			document.getElementById('txtHtmlBody').value=window.opener.openInNewWindowAndEmail.htmlBody;
			document.getElementById('txtFromEmail').value=window.opener.openInNewWindowAndEmail.fromEmail;
			document.getElementById('txtToEmail').value=window.opener.openInNewWindowAndEmail.toEmail;
			document.getElementById('txtCCEmail').value=window.opener.openInNewWindowAndEmail.ccEmail;
			document.getElementById('txtBccEmail').value=window.opener.openInNewWindowAndEmail.BccEmail;	
			document.getElementById('txtNewWindow').value="1";
			document.getElementById('txtShowSplash').value=window.opener.openInNewWindowAndEmail.ShowSplash;
			document.getElementById('txtTimer').value=window.opener.openInNewWindowAndEmail.CloseWindowTimer;
			document.getElementById('txtSuccessMsg').value=window.opener.openInNewWindowAndEmail.SuccessMsg;
			document.getElementById('txtErrorMsg').value=window.opener.openInNewWindowAndEmail.ErrorMsg;
		
			//if(confirm("Window.opener - send mail?")){
				document.getElementById('btnSubmit').click();
			//}
		}else if("<%=SendFunctionTriggered%>" == 1){
			if(window.opener.openInNewWindowAndEmail.ShowSplash=="1"){
				var showSplashTime = "<%=redirTimer%>" * 1000; // Milliseconds
				setTimeout("self.close()", showSplashTime);
			}else if(window.opener.openInNewWindowAndEmail.ShowSplash=="0"){
				self.close();
			}
		}
	}
}
</script>    
</body>
</html>

SourceCode for SendMail.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net.Mail;

public partial class Enquiry : System.Web.UI.Page
{
public string SendFunctionTriggered = string.Empty;
public string UrlStatusFlagPrefix = string.Empty;
public string EmailSendStatus = string.Empty;
public int redirTimer = 0;

protected void Page_Load(object sender, EventArgs e)
{
// Do nothing
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
SendFunctionTriggered = "1";
SendMail(txtToEmail.Value, txtFromEmail.Value, txtCCEmail.Value, txtBccEmail.Value, txtEmailSubject.Value, txtHtmlBody.Value);
if (txtRedirUrl.Value.IndexOf("?") > 0)
{
UrlStatusFlagPrefix = "&";
}
else
{
UrlStatusFlagPrefix = "?";
}

if (msg == "Successful")
{
EmailSendStatus = UrlStatusFlagPrefix + "Email=Success";
}
else
{
EmailSendStatus = UrlStatusFlagPrefix + "Email=Failure";
}

if (txtNewWindow.Value == "1") // Open new window to handle send mail operation
{
if (txtShowSplash.Value == "1")
{
statusMsgDisplay();
}
}
else // Handle send mail operation in current window
{
if (txtShowSplash.Value == "1")
{
// Show status msg
statusMsgDisplay();
}
else
{
Response.Redirect(txtRedirUrl.Value + EmailSendStatus);
}
}
}

public void statusMsgDisplay()
{
redirTimer = Convert.ToInt32(txtTimer.Value);
string newString = string.Empty;
if (msg == "Successful")
{
newString = txtSuccessMsg.Value.Replace("{0}", Convert.ToString(redirTimer));
Response.Write(newString);
if (txtNewWindow.Value != "1")
{
Response.Write("<Meta http-equiv=’REFRESH’ content=’" + redirTimer + ";URL=" + txtRedirUrl.Value + EmailSendStatus + "’/>");
}
}
else
{
redirTimer = redirTimer + 3;
newString = txtErrorMsg.Value.Replace("{0}", Convert.ToString(redirTimer));
newString = newString.Replace("{1}",msg);
Response.Write(newString);
if (txtNewWindow.Value != "1")
{
Response.Write("<Meta http-equiv=’REFRESH’ content=’" + redirTimer + ";URL=" + txtRedirUrl.Value + EmailSendStatus + "’/>");
}
}
}

public string msg = string.Empty;
public string SendMail(string toList, string from, string ccList, string bccList, string subject, string body)
{
MailMessage message = new MailMessage();
SmtpClient smtpClient = new SmtpClient();

try
{
MailAddress fromAddress = new MailAddress(from);
message.From = fromAddress;
message.To.Add(toList);
if(ccList != null && ccList != string.Empty)
message.CC.Add(ccList);
if(bccList != null && bccList != string.Empty)
message.Bcc.Add(bccList);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = body;

smtpClient.Host = txtSMTP.Value;
smtpClient.Port = Convert.ToInt32(txtSMTP_Port.Value);
smtpClient.UseDefaultCredentials = true;
smtpClient.Send(message);
msg = "Successful";
}
catch (Exception ex)
{
msg = ex.Message;
}
return msg;
}
}
[/javascript]


Simple Contact form

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.

Sourcecode for the contact form:

&lt;button id=&quot;showContactForm&quot; onclick=&quot;javascript:toggleContactForm();&quot;&gt;Contact me&lt;/button&gt;
&lt;div id=&quot;contactForm&quot; style=&quot;display:none&quot;&gt;
&lt;table style=&quot;width: 500px&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; style=&quot;width:100px&quot;&gt;Your name&lt;span class=&quot;ms-formvalidation&quot;&gt; *&lt;/span&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;&lt;input id=&quot;customInputName&quot; type=&quot;text&quot; style=&quot;width: 300px&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign=&quot;top&quot; style=&quot;width:100px&quot;&gt;Your email&lt;span class=&quot;ms-formvalidation&quot;&gt; *&lt;/span&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;&lt;input id=&quot;customInputEmail&quot; type=&quot;text&quot; style=&quot;width: 300px&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td valign=&quot;top&quot; style=&quot;width:100px&quot;&gt;Message&lt;span class=&quot;ms-formvalidation&quot;&gt; *&lt;/span&gt;&lt;/td&gt;
&lt;td valign=&quot;top&quot;&gt;&lt;textarea id=&quot;customInputMessage&quot; rows=&quot;10&quot; style=&quot;width: 100%&quot;&gt;&lt;/textarea&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;2&quot; align=&quot;right&quot;&gt;
&lt;button onclick=&quot;javascript:emailBySessvars()&quot;&gt;Sessvars Send Email&lt;/button&gt;&amp;nbsp;
&lt;button onclick=&quot;javascript:openInNewAndEmail()&quot;&gt;New Window Send Email&lt;/button&gt;&amp;nbsp;
&lt;button onclick=&quot;javascript:toggleContactForm();&quot;&gt;Cancel&lt;/button&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/sessvars.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function toggleContactForm(){
$('#contactForm').find(&quot;:input:not(button)&quot;).each(function(){
	$(this).val('');
});
$('#showContactForm').toggle();
$('#contactForm').toggle();
}

function preSendCheck(){
var arrTovalidate = ['customInputName','customInputEmail','customInputMessage'];
$(&quot;div.ms-formvalidation&quot;).remove();
var preCheckOK = true;
$.each(arrTovalidate,function(){
	var field = $(&quot;#&quot; + this);
	if(field.val()==''){
		preCheckOK = false;
		field.parent().append(&quot;&lt;div class='ms-formvalidation'&gt;You must specify a value for this required field.&lt;/div&gt;&quot;)
	}
});
return preCheckOK ;
}

function emailBySessvars(){ // Current window redirect
var sendOK = preSendCheck();
if(sendOK ){
	var name = $(&quot;#customInputName&quot;).val();
	var email = $(&quot;#customInputEmail&quot;).val();
	var message = $(&quot;#customInputMessage&quot;).val();
		sessvars.emailBySessvars = {
		&quot;SMTP&quot;:&quot;insert your SMTP here&quot;,
		&quot;SMTP_Port&quot;:&quot;25&quot;,
		&quot;fromEmail&quot;:email,
		&quot;toEmail&quot;:&quot;insert the address to send the mail to here&quot;,
		&quot;ccEmail&quot;:&quot;&quot;,
		&quot;BccEmail&quot;:&quot;&quot;,
		&quot;EmailSubject&quot;:&quot;Contact form by Sessvars&quot;,
		&quot;htmlBody&quot;:&quot;Name: &lt;br&gt;&quot; + name + &quot;&lt;br&gt;Message:&lt;br&gt;&quot; + message,
		&quot;ShowSplash&quot;:&quot;1&quot;,
		&quot;RedirUrl&quot;:&quot;/test/English/Javascript/SendMailWithJavascript.aspx&quot;,
		&quot;RedirTimer&quot;:&quot;1&quot;,
		&quot;SuccessMsg&quot;:&quot;&lt;div class='mailStatusMsg'&gt;E-mail successfully sendt&lt;div style='font-size:small'&gt;Redirecting in {0} seconds&lt;/div&gt;&lt;/div&gt;&quot;,
		&quot;ErrorMsg&quot;:&quot;&lt;div class='mailStatusMsg'&gt;Error sending message&lt;div style='font-size:small'&gt;{1}&lt;br&gt;Redirecting in {0} seconds&lt;/div&gt;&lt;/div&gt;&quot;
		};
			window.location.href='/_layouts/SendMailWithJavascript/SendMailBySessvars.aspx';
	}
}

function openInNewAndEmail(){ // New window
var sendOK = preSendCheck();
if(sendOK){
	var name = $(&quot;#customInputName&quot;).val();
	var email = $(&quot;#customInputEmail&quot;).val();
	var message = $(&quot;#customInputMessage&quot;).val();
		openInNewWindowAndEmail = {
		&quot;SMTP&quot;:&quot;insert your SMTP here&quot;,
		&quot;SMTP_Port&quot;:&quot;25&quot;,
		&quot;fromEmail&quot;:email,
		&quot;toEmail&quot;:&quot;insert the address to send the mail to here&quot;,
		&quot;ccEmail&quot;:&quot;&quot;,
		&quot;BccEmail&quot;:&quot;&quot;,
		&quot;EmailSubject&quot;:&quot;Contact form by Window.opener&quot;,
		&quot;htmlBody&quot;:&quot;Name: &lt;br&gt;&quot; + name + &quot;&lt;br&gt;Message:&lt;br&gt;&quot; + message,
		&quot;ShowSplash&quot;:&quot;1&quot;,
		&quot;CloseWindowTimer&quot;:&quot;1&quot;,
		&quot;SuccessMsg&quot;:&quot;&lt;div class='mailStatusMsg'&gt;E-mail successfully sendt&lt;div style='font-size:small'&gt;Closing this window in {0} seconds&lt;/div&gt;&lt;/div&gt;&quot;,
		&quot;ErrorMsg&quot;:&quot;&lt;div class='mailStatusMsg'&gt;Error sending message&lt;div style='font-size:small'&gt;{1}&lt;br&gt;Closing in {0} seconds&lt;/div&gt;&lt;/div&gt;&quot;
		};
		newwindow=window.open('/_layouts/SendMailWithJavascript/SendMailNewWindow.aspx',
		'SendMail','location=no,menubar=no,resizable=no,scrollbars=no,titlebar=no,toolbar=no,width=300,height=125');
		toggleContactForm();
	}
}
&lt;/script&gt;

In the code for the contact form you have to insert your SMTP-server and the “toEmail”. This example form provides buttons for both methods of sending mail.

When sending the email you are presented with a “splash-screen” like this when using “sessvars.js” and redirect in the same page:
IMG

When using the sessvars.js redirect, you also get a “receipt” in the URL:
IMG

And like this when opening in a new window:
IMG

These “receipts” are based on the “SuccessMsg” and “ErrorMsg” specified in the contact form. The “placeholder” {0} and {1} in the message text are replaced with the time to close/redirect, and for “ErrorMsg” also the actual error from the “sendmail-code”.
IMG
In case of an error – the splash screen is displayed for 3 seconds longer than specified.

I will follow up this one with an example on how to send the contents of a DispForm as a HTML-bodied email, but all that is to it is to loose the “contact-form-message-field” and define the “htmlBody” in the “contact-form-code” to hold the HTML-content you want to send.

I am open for questions – and as i noted above: this one is outside my comfort zone and i appreciate feedback on the selected method and tips on how to make it better.

Regards
Alexander