Tuesday, 28 August 2012

Show Special Characters in XSLT WebParts.

Are you are working with XSLT WebParts (eg: People Search Core Results WebPart) and the special characters like ä, ë, é, ö, etc are getting replaced with a question mark (?) or a Square Box ? Let's change that then:

So basically the encoding of the XSLT is set to "iso-8859-1" by default and we will have to change it to "utf-8." Here is how to change the encoding: Find in your XSL file, the following line:
<xsl:output method="xml" indent="no" encoding="iso-8859-1"/>
view raw encode.xsl hosted with ❤ by GitHub

and change it to:
<xsl:output method="xml" indent="no" encoding="utf-8"/>
view raw decode.xsl hosted with ❤ by GitHub

Now all the special characters should be visible perfectly.

Monday, 27 August 2012

Paging in SharePoint JavaScript Client Object Model

Paging can be of great help when you want to improve the performance of your code especially when you are working on front-end development and want to reduce the page response time. Let us see how can be implement paging when working with the JavaScript Client Object Model.

var listItems; // The list of retrieved items.
var query; // For paging, reuse the same query object.
var targetList; // The list from which to retrieve items.
var clientContext;
function runCode() {
clientContext = new SP.ClientContext();
targetList = clientContext.get_web().get_lists().getByTitle('Announcements');
query = new SP.CamlQuery();
//Specifying the RowLimit will determine how many items will be fetched in one call to the server.
query.set_viewXml("<View><ViewFields><FieldRef Name='Title'/></ViewFields><RowLimit>2</RowLimit></View>");
listItems = targetList.getItems(query);
clientContext.load(listItems);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded() {
var message = "Titles, two at a time:\n";
var listEnumerator = listItems.getEnumerator();
while (listEnumerator.moveNext()) {
message += "\nTitle=" + listEnumerator.get_current().get_item("Title")
}
alert(message);
//Gets the id of the last element from the returned collection along with the query.
var position = listItems.get_listItemCollectionPosition();
//Position will be null if all the items in the collection are fetched and there are no more items to be fetched.
if (position != null) {
//If more items are to be fetched, make a second call to the server and fetch the next group of items.
query.set_listItemCollectionPosition(position);
listItems = targetList.getItems(query);
clientContext.load(listItems);
//Call the same function recursively until all the items in the current criteria are fetched.
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
}
function onQueryFailed(sender, args) {
alert('Request failed. \nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace());
}
//Call the function after the sp.js is loaded.
ExecuteOrDelayUntilScriptLoaded(runCode, "sp.js");
view raw paging.js hosted with ❤ by GitHub

The important parts to note in this code are the RowLimit element in the CAML query and the SP.ListItemCollection.get_listItemCollectionPosition(); property. Please have a look at the comments to know more details about the individual lines of code.

The ListItemCollectionPosition.pagingInfo determines the id of the last item fetched along with the filter and sorting criteria. It specifies information, as name-value pairs, required to get the next page of data for a list view.

Tuesday, 21 August 2012

RegisterClientScriptBlock for SharePoint Sandbox Solutions

So we had this requirement where we had to check if a script was already loaded on the page before we push it. So my natural choice was to use the RegisterClientScriptBlock method. But this being a Sandbox solution, like always, things were much more difficult than they initially appeared.

The code executed without throwing any error so I thought I was good to go but the script was not getting registered and also the IsClientScriptBlockRegistered method was not doing its job. So after some searching around, I found the following page which explained my scenario:
http://blog.a-dahl.dk/post/Sharepointe28093Where-is-my-Page-object.aspx

So turns out that sandbox solutions runs in a "sandbox" mode with separate context and no access to the rest of the page. So to my huge disappointment, the ClientScriptManager class was out of bounds. Now it was up to me to figure out a workaround for this issue.

So I thought, why not push some good old JavaScript to the page to check the loading of the script? The challenge before me was that since I was pushing the script from server side to the page, the code would be executed before my DOM was loaded. Also, I could not use any jQuery here because it was included in my script which was to be checked and  loaded. So 1) I had to make sure that my code would get executed only after the page was loaded and  2) I had to do it using pure JavaScript.

The first problem could have been solved by using window.load = function( ) {} but due to the function's browser incompatibility, I decided against it. Thankfully, SharePoint provides an Out of the Box mechanism called _spBodyOnLoadFunctionNames in which we can push functions to be executed when the body tag of the document completes loading.
Being using jQuery very heavily in the past, using pure JavaScript was also an exciting challenge which was fun to do. So after about an hour of fiddling with this issue, I managed to put together a function which would check if a script with the particular id was loaded and if not, then only load it on the page. Here is my SandboxRegisterClientScriptBlock function:

public static void SandboxRegisterClientScriptBlock(string scriptId, string scriptUrl,Page page)
{
//Add script control.
HtmlGenericControl addJscript = new HtmlGenericControl("script");
addJscript.Attributes.Add("type", "text/javascript");
//Checks if the script is already loaded and if not, load it.
addJscript.InnerHtml = @"function CheckScriptAndLoad() {
//Check if script is loaded. Return true if yes, else return false.
var isScriptLoaded = function (scriptId) {
if (document.getElementById(scriptId) != null) {
return true;
}
else {
return false;
}
}
//If script is not loaded, create a DOM script element with specified script id and url.
if (!isScriptLoaded('" + scriptId + @"')) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.id = '" + scriptId + @"';
script.src = '" + scriptUrl + @"';
document.body.appendChild(script);
}
}
_spBodyOnLoadFunctionNames.push('CheckScriptAndLoad');";
page.Controls.Add(addJscript);
}