Creating a jQuery Extension

jQuery extensions are the most fundamental piece to the jQuery library.  When you create functions that build on jQuery, you should always ask yourself if your function or group of functions would be valuable as a reusable jQuery extension.

Learning to create a jQuery extension is relatively simple. It is all about encapsulating your functions into a larger object that prevents them from interfering with each other.

Creating Our jQuery Work Space

Before we can begin creating the meat of the jQuery extension we’ll need to set up our work space, which is where all of our jQuery goodness will go. I usually begin by naming my jQuery extension and creating a shell where all of my functionality will go:

(function (p) {
 p.fn.Talk = function (settings) {
 // Saving Settings
 var customSettings = $.extend({

 }, settings);

 // Methods
 methods = {

 };
})(jQuery);

This will be the basic layout of the Talk jQuery extension we’ll be creating.  More on the Methods & Settings we’ll be setting up are below.

Creating Extension Settings

The best way to store data and pass data to your jQuery extension is to use a group of settings defined in the beginning of the application and then extend them with variables passed to the jQuery extension.

Now lets fill our talk extension with some useful settings. I’ve chosen to use message, backcolor, forecolor, and bordercolor for my group of settings.

var customSettings = $.extend({
 message: "What's Up?",
 backcolor: "#F8F8F8",
 forecolor: "#666",
 bordercolor: "#DCDCDC",
 }, settings);

Now, you’ll notice that I’m using the $.extend() method. If you’ve never used this before, essentially what it does is tak the array provided and merge it with the existing default settings, overwriting the default values if a message, backcolor, forecolor, or bordercolor is provided.

To pass settings to our jQuery extension, we would simply provide an array similar to the one we’ve defined above:

$('#TalkBox').Talk( { bordercolor: 'red', backcolor: 'blue' } );

Applying this settings to our extension will overwrite the default color and change the text color to blue and the back color to blue. While this will undoubtedly make for an ugly message, it serves as a good example.

Creating Extension Functions

Now, this is where the meat of our application goes. We have our framework laid out and our settings prepped, so lets create our functions.  First, we’ll say Hi, then output the user’s message, and finally say Goodbye.  Pretty simple, but this is only an example.

Before we output our message, lets do a simple variable to hold our message container and save the object we’re outputting to ($(this)) for easy access in our functions.

var talkBox = $(this);
var containerOpen = "<div style='background-color:" + customSettings['backcolor'] +
 ";color:" + customSettings['forecolor'] + ";border: 1px solid " +
 customSettings['bordercolor'] + ";padding: 10px; margin: 5px;'>";
 var containerClose = "</div>";
Now that we have that settled, lets add our functions to output the three messages we'll be using in this jQuery extension.
 // Methods
 methods = {
 SayHi: function () {
 talkBox.append(containerOpen + "Hello!" + containerClose);
 },
 SayMessage: function () {
 talkBox.append(containerOpen + customSettings['message'] + containerClose);
 },
 SayBye: function () {
 talkBox.append(containerOpen + "Goodbye!" + containerClose);
 }
 };

Finally, We’ll need to execute these functions.  To do so, you simply call them from the ‘methods’ array like so:

// Outputting Messages
 methods['SayHi']();
 methods['SayMessage']();
 methods['SayBye']();

Put It All Together

Well, that’s all there is to it. if you’ve followed the steps above, you’ve created your very own jQuery Extension!  Now to make it easier on you, I’ve put it all together below:

(function (p) {
 p.fn.Talk = function (settings) {
 // Saving Settings
 var customSettings = $.extend({
 message: "What's Up?",
 backcolor: "#F8F8F8",
 forecolor: "#666",
 bordercolor: "#DCDCDC",
 }, settings);
var talkBox = $(this);
var containerOpen = "<div style='background-color:" + customSettings['backcolor'] +
 ";color:" + customSettings['forecolor'] + ";border: 1px solid " +
 customSettings['bordercolor'] + ";padding: 10px; margin: 5px;'>";
 var containerClose = "</div>";
// Methods
 methods = {
 SayHi: function () {
 talkBox.append(containerOpen + "Hello!" + containerClose);
 },
 SayMessage: function () {
 talkBox.append(containerOpen + customSettings['message'] + containerClose);
 },
 SayBye: function () {
 talkBox.append(containerOpen + "Goodbye!" + containerClose);
 }
 };
 // Outputting Messages
 methods['SayHi']();
 methods['SayMessage']();
 methods['SayBye']();
 }
 })(jQuery);

More Information

The jQuery website is always a great help.  I have to give credit to them for outlining the process so well on their site and teaching me how to create jQuery extensions. For more information, you can visit the page below.  They have more detailed information on do’s and don’ts and the process of creating an extension.

http://docs.jquery.com/Plugins/Authoring#Getting_Started

Thanks for reading! Feel free to submit comments/suggestions below!

jQuery – Prevent a User From Leaving a Page with Unsaved Data

It’s pretty common to see the age old message ‘Are you sure you want to leave this page? Any unsaved data will be lost’ and for good reason, its useful. jQuery makes creating a message that prevents users from leaving the page pretty easy.

I recently had to implement a message just like this and to do so, I implemented the code below. The key to setting up a function like this is the onbeforeunload command

Message

First, I created my message:

 var warnMessage = 'You have unsaved changes on this page.';

Change Event

Then, I set up an event to watch controls for changes and a boolean to save the change state:

 var formModified = new Boolean();
 formModified = false;
 $('input:not(:button,:submit),textarea,select').live('change', function () {
     formModified = true;
 });

Submit Event

Now that we have something to set the formModified to true, we need a function to set it back to false once the save button has been clicked (You can modify this to use any selector you wish):

 $('input:submit').live('click', function (e) {
     formModified = false;
 });

onbeforeunload Window Event

Finally, we need to set up a function to run when onbeforeunload is fired. Our function will return our message if any fields have been changed without clicking the submit button first.

 window.onbeforeunload = function () {
     if (formModified != false) return warnMessage;
 }

Complete Code

Here’s the completed code you’ll need:

 // Capturing when the user modifies a field
 var warnMessage = 'You have unsaved changes on this page.';
 var formModified = new Boolean();
 formModified = false;
 $('input:not(:button,:submit),textarea,select').live('change', function () {
     formModified = true;
 });
 // Checking if the user has modified the form upon closing window
 $('input:submit').live('click', function (e) {
     formModified = false;
 });
 window.onbeforeunload = function () {
     if (formModified != false) return warnMessage;
 }

And that’s all you’ll need to do, pretty simple right? Oh, make sure that you’ve included a link to the jQuery library (1.4 or above) in your project as well or jQuery won’t work. It may seem obvious but you have to cover all your bases right?

As always if you find a mistake or have any suggestions for improvements let me know!

Custom Rich Text Editor Styles in SharePoint 2010

A common request to have in SharePoint 2010, especially externally facing installations, is to have custom Styles available in the menu.

Thankfully, SharePoint 2010 makes this extremely easy. The key is the prefix attached to your styles. SharePoint will interpret any style beginning with ms-rteElement-[custom name] as a markup style and it will interpret anything starting with ms-rteStyle-[custom name] as a Style. However, you are able to change this prefix, but we’ll start out by creating some new styles using the default ‘ms-rte’

First, the differences between the two:

Markup Styles (ms-rteElement):

  • Will wrap the currently selected area in the specified tag (See below)
  • Applied style to newly created tag

Styles (ms-rteStyle):

  • Applies your custom class to the currently selected element
  • Will not add additional markup

Getting Started

Now that we’ve discussed the differences between them, lets talk about how to implement them. To start, make sure you have a stylesheet already linked on your SharePoint master page. Once that’s ready, follow the steps below.

Continue reading

SharePoint 2010 Client Object Model – ECMA Script Get List Fields

I was working on a project that required me to dynamically build a grid based on a SharePoint list using client side JavaScript and naturally, I needed a way of retrieving the fields (columns) of the list. Some research revealed the best way to do this use the SharePoint client object model.

Before we write any code lets make sure that everything we’ll need is ready when our code executes. So, lets wait for the sp.js script to load before we execute our function. We can do that with this snippet of code:

function getFields() {
 // waiting until the core.js is loaded
 ExecuteOrDelayUntilScriptLoaded(retrieveAllFields, 'sp.js');
 }

Now that we’re sure our code will work, lets write it. First, we’ll need to build the client context query in our retrieveAllFields function.

function retrieveAllListsAllFields() {
 // Getting List Title
 var listTitle = 'TestList';
// Building environment
 var clientContext = new SP.ClientContext.get_current();
 var oWebsite = clientContext.get_web();
// Getting all Fields in default view
 this.list = oWebsite.get_lists().getByTitle(listTitle);
 var defaulViewGUID = '{YOUR GUID}';
 var defaultview = list.getView(defaulViewGUID); // Default GUID
 this.listFields = defaultview.get_viewFields();
 clientContext.load(this.list);
 clientContext.load(this.listFields);
// Getting Detailed Information on the Fields
 var collList = oWebsite.get_lists();
 this.listInfoArray = clientContext.loadQuery(collList,
 'Include(Title,Fields.Include(Title,InternalName,FieldTypeKind))');
// Executing Query
 clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded),
 Function.createDelegate(this, this.onQueryFailed));
 }

Now that we have our query ready to go. Let’s create our logic to process our list fields.

function onQuerySucceeded() {
// Setting Site URL
 $("#jqListURL").val(_spPageContextInfo.webServerRelativeUrl);
for (var i = 0; i < this.listInfoArray.length; i++) {
 var oList = this.listInfoArray[i];
 var collField = oList.get_fields(); // Getting All Fields From the List
 var listTitle = oList.get_title()
 if (listTitle == this.list.get_title()) {
 var fieldEnumerator = collField.getEnumerator();
 var textInfo = "";
 // Looping through all fields 
   while (fieldEnumerator.moveNext()) {
     var oField = fieldEnumerator.get_current();
     var internalName = oField.get_internalName();

 // Checking to see if the field is in the current view
     var viewFieldEnumerator = listFields.getEnumerator();
     while (viewFieldEnumerator.moveNext()) {
       var currentFieldTitle = viewFieldEnumerator.get_current(); // Getting Title
 var itemTitle = oField.get_title();
       var type = oField.get_fieldTypeKind();
       textInfo = listTitle + " - " + currentFieldTitle + " " + itemTitle + " " + type + " " + internalName;
     }
   }
 // Adding Info
   $(".testDIV").append(textInfo);
  }
}

And you’re done! You’ll notice that my code gets the fields in the current view and compares them to the fields returned in the list query.  This way, you’re not getting back every single field in the list schema (including the ugly hidden ones).

As always, if you spot and error or have a suggestion for an improvement let me know and I’ll update my post.

-Max

SharePoint Run with Elevated Privileges Best Practices

Running code in SharePoint with elevated privileges can be risky. It’s always important to make sure you’re using it appropriately. I did a quick Google search and found a great list best practices when using it. You can find the list Here.

The post offers a great alternative to running with elevated privileges. Instead, impersonate the SHAREPOINT\system account and use it to instantiate new SPSite and SPWeb objects. Check out the code below. (Courtesy of Soumya Dasari)

 var user = SPContext.Current.Web.AllUsers[@"SHAREPOINT\SYSTEM"];
 var superToken = user.UserToken;
 using (var site = new SPSite(SPContext.Current.Web.Url, superToken))
 {
    // This code runs under the security context of the SHAREPOINT\system
 // for all objects accessed through the "site" reference. Note that it's a
 // different reference than SPContext.Current.Site.
    using(var elevatedWeb = site.OpenWeb())
    {
       // Perform actions as SYSTEM here
    }
 }

jQuery CAML Query – lists.asmx Web Service

So, recently I’ve embarked on a project to create a client side jQuery grid. To do this, I started out by creating a simple table from list data return from a CAML query to the list.asmx web service.

To get me started, I used Jan Tielen’s blog post Here. His example works perfectly accept you’ll need to modify one line of code to make it fully cross-browser compatible.

Change this:

$(xData.responseXML).find(“z\\:row”).each(function() {

to this:

$(xData.responseXML).find(“z\\:row, row”).each(function() {
Continue reading

InfoPath 2010 – Validating the Attachments Field

InfoPath 2010 has its ups and downs. For the most part it makes things extremely easy. However, you’ll still run into the occasional roadblock while working with InfoPath forms.

I recently ran into one such roadblock. The issue was being able to apply validation rules to the attachments field. To my surprise, InfoPath does not let you select the Attachments field to apply rules, making it a challenge apply validation on attachment fields. Also, if you go into the advanced view and select the repeating ‘:attachmentURL’ field inside of the Attachments group and apply formatting to that field it just doesn’t work.

So, I had to come up with a custom solution. Now, given one of the major advantages of using InfoPath in the first place is not having to use any code behind, I didn’t want to have to add custom code to my form.

My solution involves 3 steps:

1.) Create a field in addition to the attachments field. In my case, I called the field I created Attachment Validation.

2.) Drop your field onto the form and remove the borders and background. Then set the default text to ‘Attachments:’

InfoPath 2010 Attachments Field Validation

3.) Finally, lets apply some validation to this field. Right click the field on your form and select Rules > Manage Rules.

In my case, I needed to make sure there was at least one attachement. So, I counted the :attachmentURL instances and checked if there were more than 0. To do this, I used a custom expression:

Now with all of that complete you will have a separate field that validates the attachments field and if there are no attachments, the text in the left hand column will be surrounded in the standard red dashed border.

InfoPath 2010 Validation on Attachments Field

NOTE:

To get to the ‘:attachmentsURL’ field you need to create the validation make sure you go into Advanced View of the fields.

InfoPath 2010 Attachments :attachmentURL field advanced view

Follow

Get every new post delivered to your Inbox.