Archive

Posts Tagged ‘jQuery’

Adding an image uploader to the Publishing Image site column

January 6, 2012 12 comments

Click here to download the WSP

Click here to download the Source

Mission
To add a much needed feature to the Publishing Image site column, which is the ability to upload an image from your computer when adding a page or roll up image on a publishing page.
The current SharePoint functionality is that you must upload your image to the image library first, then you can edit your page and select the uploaded image, not very user friendly.

Solution
Use jQuery to add an upload button that then opens a SharePoint dialog in which you can upload an image to the image library. Once uploaded successfully you click continue and insert your new image.

Here is my solution structure

So first lets look at the SiteScripts module that adds our JavaScript reference and initializes it.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Location="ScriptLink"
ScriptBlock="
function loadImageUploaderScript(src) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
var url = window.location.toString();
url = typeof(L_Menu_BaseUrl) != 'undefined' ? L_Menu_BaseUrl :
url.substr(0, url.indexOf('/_layouts'));
script.src = url + src;
head.appendChild(script);
}
_spBodyOnLoadFunctionNames.push(
'loadImageUploaderScript(\'/Style Library/js/publishingImageUploader.js\')');
" Sequence="120">
</CustomAction>
</Elements>

Now lets look at the publishingImageUploader.js
The script checks that we are on the AssetImagePicker window first, it then creates a input button, shortens the “Select Image” textbox and appends our button. It then attaches a click event.

$(function () {
if (window.location.href.indexOf("AssetImagePicker.aspx") > 0) {
var uploader = $("<input id='uploader' type='button' value='Upload image' />");
$(".ms-assetimagedialog-longtextbox").width("300px");
$("[id$=_assetSelectedImage_PickerLaunchButton]").parent().append(uploader);

uploader.click(function () {
publishingImageUploader();
});
}
});

function publishingImageUploader() {
var dialogOptions = SP.UI.$create_DialogOptions();
var url = window.location.href;
dialogOptions.url = url.substr(0, url.lastIndexOf("/_layouts/")+10) +
"PublishingImageUploader.aspx";
dialogOptions.width = 750;
dialogOptions.height = 200;
dialogOptions.dialogReturnValueCallback = Function.createDelegate(null,
CloseCallback);
SP.UI.ModalDialog.showModalDialog(dialogOptions);
return false;
}

function CloseCallback(strReturnValue, url) {
$("[id$=_assetSelectedImage_AssetUrlInput]").val(url);
}

The click event opens our PublishingImageUploader.aspx shown below, which is in the layouts folder and opened in a SharePoint dialog.

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI"
Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" %>
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="PublishingImageUploader.aspx.cs"
Inherits="PublishingImageUploader.Layouts.PublishingImageUploader"
DynamicMasterPageFile="~masterurl/default.master" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead"
runat="server">
<script type="text/javascript">
function CloseUploader() {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK,
'<%=ImageUrl %>');
}
</script>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<h3>Upload image</h3>
<input type="file" id="ImageFile" runat="server" />
<input type="button" id="Upload" value="Upload" onserverclick="UploadImage"
runat="server" />
<asp:panel id="ClosePanel" visible="false"  runat="server">
<asp:Literal id="Message" runat="server" />
<input type="button" id="close-button" value="Continue"
onclick="CloseUploader()" />
</asp:panel>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle"
runat="server">
Upload image
</asp:Content>

<asp:Content ID="PageTitleInTitleArea"
ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
Upload image
</asp:Content>

Now our codebehind looks like this

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Publishing;

namespace PublishingImageUploader.Layouts
{
public partial class PublishingImageUploader : LayoutsPageBase
{
public string ImageUrl { get; set; }

protected void UploadImage(Object sender, EventArgs args)
{
var pubWeb = PublishingWeb.GetPublishingWeb(SPContext.Current.Web);
var folder = pubWeb.ImagesLibrary.RootFolder;
var file = folder.Files.Add(string.Format("{0}/{1}", folder.Url,
ImageFile.PostedFile.FileName), ImageFile.PostedFile.InputStream, true);
ImageUrl = file.ServerRelativeUrl;
Message.Text = string.Format("Image {0} was uploaded successfully!", file.Name);
ClosePanel.Visible = true;
}
}
}

So the above uploads our image to SharePoint on click and then shows a success message and a continue button, it also sets the ImageUrl property which is used in our dialog callback function so that the uploaded image url is added to the “Select image” textbox on close.

Note: dependant on the global jQuery WSP, get it here: https://simonovens.wordpress.com/2011/11/14/sandbox-sharepoint-online-jquery-jquery-ui-wsp-package/

See it in action

Click here to download the WSP

Click here to download the Source

SharePoint Online jQuery & jQuery UI WSP package

November 14, 2011 3 comments

Click here to download the jQuery sandbox WSP

With SharePoint online client side scripting really leads the way in which alot of solutions will be built, so bringing in the powerful library jQuery into your toolkit you will get much more out of the Solutions you build.

While there are a few solutions to get jQuery onto SharePoint Online the approach I have implemented here is a soution that adds jQuery and jQuery UI to all pages across the Site Collection using the Google API libraries which hosts the jQuery 1.6.4, jQuery 1.8.16, jQuery UI css start theme 1.8.13
(note: I will try and keep this package up to date with new releases of jQuery so if you see me slacking then give me a reminder).

To achieve this we cannot just add it to the CustomAction ScriptSrc or else it will just prepend a /_layouts/ to our absolute path.
You can use the ~SiteCollection token as shown below if you want to host it yourself but having it Google hosted it has advantages as talked about here and you would need to add the theme images and css files into a module in your package if self hosted.

<CustomAction
ScriptSrc=”~SiteCollection/Style Library/Scripts/jquery-ui-1.8.12.custom.min.js
Location=”ScriptLink” />

Solution
The solution is to load the scripts using the CustomAction ScriptBlock as follows:

<CustomAction
Location=”ScriptLink
ScriptBlock=”
            function loadjQueryScripts(src) {         
                      if (window.location.href.indexOf(‘AssetPortalBrowser.aspx’) > 0) return;
                      var head = document.getElementsByTagName(‘head’)[0];         
                      var script = document.createElement(‘script’);         
                      script.type = ‘text/javascript’;          
                      script.src = src;          
                      head.appendChild(script); 
            }

            function loadUIElements(){
                      if (window.location.href.indexOf(‘AssetPortalBrowser.aspx’) > 0) return;
                      var head = document.getElementsByTagName(‘head’)[0];
                      var cssNode = document.createElement(‘link’);
                      cssNode.type = ‘text/css’;
                      cssNode.rel = ‘stylesheet’;
                      cssNode.href = ‘https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/start/jquery-ui.css&#8217;;
                      cssNode.media = ‘screen’;
                      head.appendChild(cssNode);
            }
            _spBodyOnLoadFunctionNames.push(‘loadjQueryScripts(\’https://&#8230;./jquery.min.js\’)’);
            _spBodyOnLoadFunctionNames.push(‘loadjQueryScripts(\’https://&#8230;./jquery-ui.min.js\’)’);
            _spBodyOnLoadFunctionNames.push(‘loadUIElements()’);
Sequence=”101“>
</CustomAction>

So as you can see above we are using the _spBodyOnLoadFunctionNames function to fire off our functions once the page has loaded, which in turn adds our jQuery libraries to the head tag.

Another benefit of having a global jQuery package is that you do not have to do any jQuery.js checking and/or registering in any of your other solutions that would use jQuery, just ensure you have this dependency installed.

It would be nice to see Microsoft build these options into their products, as products like DNN now have the option to tick a box to enable hosted jQuery. I am sure Microsoft wouldnt use the Google hosted libraries though :)

One thing to remember is that you should use the ExecuteOrDelayUntilScriptLoaded(yourFunctionName/plugin initialization, ‘sp.js’) if you use this package as you may recieve an error if you use the traditional jQuery $(function(){});
I believe this is due to the order the _spBodyOnLoadFunctionNames loads the jQuery.

Here is an example of a solution I built that requires jQuery being added to my Office 365 trial which simply changes the “more information” button to open in a nice popup rather then pushing the page down with a bad layout.

My takeaways from the Anaheim SharePoint 2010 Conference

October 15, 2011 Leave a comment

No I am not talking about the CHEAP fast food joints in the states that played on my wallet to get the biggest burger and drink for a ridiculously cheap price when compared to New Zealand.
I am sharing the sessions that I got something from so here is the list:

  1. Keynote
  2. SharePoint online Overview – Mark Kashman
  3. Out of the sandbox and into the cloud: Build your next SharePoint app on Azure – Andrew Connell
  4. Integrating SharePoint Social features into your Windows Phone 7 application – Todd Baginski
  5. SharePoint workflow best practises – Keenan Newton
  6. Developing SharePoint applications and HTML5 and jQuery – Ted Pattison
  7. Search Engine Optimization on a SharePoint 2010 Internet Site – Daniel Haywood
  8. Application lifecycle Management: Automated builds and testing for SharePoint projects – Chris O’Brien & Mike Morton
  9. Customising Content publishing approval workflows – Robert Bogue
  10. Branding SharePoint online Sites – Randy Drisgill & John Ross
  11. Deep Dive on SharePoint Ribbon Development & Extensibility. – Chris O’Brien & Andrew Connell
  12. Advance BI Visualization using Visio services. – Christopher Hopkins & A.J Briant

Keynote
The big things that came out of the keynote was the announcement that the next release to the cloud will include BCS, which should be released sometime end of this year I believe.

We were given a good demo of a full replicated failover of a 15 server farm that had a whopping 14 terabytes of data and how fast it happened, the only thing here was that the VM host they used had 80 cores with 1 terabytes of ram…..now that’s some computing power!

Also they mentioned the fact that the Microsoft SharePoint development team has increased dramatically and that they see the future of SharePoint to be big and are putting alot of focus into make it bigger and better. I know this seems obvious being their 3rd biggest seller, but its good to hear it coming from Microsoft’s mouth.

SharePoint online Overview – Mark Kashman

This was a basic intro into the cloud.  Demoing adding webparts that where utilising jQuery, and showing that it is basically the same as you see in the foundation version. 

He did demo the new BCS that is coming in the new year. You will be able to connect to webservices to allow the two way connection to your external data.

Out of the sandbox and into the cloud: Build your next SharePoint app on Azure – Andrew Connell

This was a great session by AC basically showing a good alternative to creating SharePoint applications in the cloud.
Using Azure as our data storage we can have full control on how we handle the data meaning no limitations on the structure of the data and accessing this data from various sites. Add the power of Microsoft’s Data Entity framework and WCF you can easy create your application that your SharePoint Online webparts can consume.

This would be a good option if you find yourself too limited by the site lists and what you can achieve with SharePoint Online. Also it gives greater flexibility for complex data and data relationships, meaning happier developers.

Integrating SharePoint Social features into your Windows Phone 7 application – Todd Baginski

Todd showcased a nice windows 7 phone application surfacing the social media data from SharePoint, using the OOTB SharePoint services and RSS feeds.

He also demoed the new push notification service available in mango. These are what you see in your home tiles showing you the number of new emails you have for example.
The notification service is hosted in the cloud and you as an application developer send a request to this service which then sends out the message to all phones subscribe to it (ie they have your application and have accepted to receive these messages). One caveat is that there is no guarantee that the message will make it to all phones.
Todd mentioned that it is complicated plumbing to get this to work, requiring a service to react to an event, which then sends a message to the notification service which in turn invokes an event on your phone application to which you can respond to by putting a count on your apps tile for example.
Todd’s push notification demo failed to appear on his phone and he did mentioned that when testing give it sometime before you blame your code as it can take a while for the push notification to send the message.

SharePoint workflow best practises – Keenan Newton

The main nugget I got from this was the idea of building custom actions developed in Visual Studio, which means you can get the best out of building workflows in SharePoint Designer but if you need it you have the power of custom code, in the form of a custom action, to give you exactly what you want.

Developing SharePoint applications and HTML5 and jQuery – Ted Pattison

One of my favourites. First Ted started with jQuery basics which almost made me leave but I knew he would dive deeper.
He demoed the jQuery templating engine that I have been using for over a year now so good to see others are using it in the wild. 
He demoed the library datajs which gives you a nice wrapper to easily post/put/delete data using OData services, I have yet to see why you would use this over the jQuery ajax library though.

He then moved onto HTML5 which I was amazed how clean and powerful it is. HTML5 has very readable tags like Nav, Article, Footer and so on which makes it nice to layout your HTML and it makes life easier for screen readers and so on.  Unfortunately its early days so not a lot of browsers support it, which means if you use it you will have to use a lot of fall back methods. Sure there are libraries that make this easy but the extra work required would have to be weighed up. I would say if its an internal web app and you can control the browser then go for HTML 5 otherwise it may not be the time yet to go all out.

One thing I see from this is that with HTML5 JavaScript  is going to be the main development language used,  just look at the ability to access the database straight from JavaScript, LocalStorage, web workers and web sockets….all i can say is awesome and bring it on!

Search Engine Optimization on a SharePoint 2010 Internet Site – Daniel Haywood

Daniel started with a good video on SEO to show how it all works, which showed the basics and that is that content is king and links from other high ranking sites give you a better ranking. But what I didnt know was that some search engines will ignore some links if you are using those sites that are designed to just provide a simple link back to your site, so if you pay for any of these type of sites then you maybe wasting your money.

He showed how you can use web master tools to see how well you are setup SEO wise, and how this tool can help you make your site better for search engines. It gives you info on how google sees your site, what keywords are being used to find your site and so on.

He also showed Waldeks custom field controls which basically give you the ability to add keywords, title and description to each page for use in SEO, very useful.

Application lifecycle Management: Automated builds and testing for SharePoint projects – Chris O’Brien & Mike Morton

My other favourite session. Chris and Mike showed how easy it is to set up continuous deployments that include the WSPs using Visual Studio. Also showed the workflow you use for continuous deployments and where you would call out to PowerShell to install the WSPs. They covered the fact that you can set it so that broken builds can not be checked in, instead they get shelved until the solution builds.
This was a really good session for me as in my current project we are using continuous deployments and while it was painful to begin with it has been an eye opener into how useful it is in a project with multiple developers.

Another cool thing they covered is Coded UI Tests which I like very much!  Basically it allows to record clicks (for example clicking a jQuery accordion) and then selecting the assertion (for example the accordion element should have a different class/style or certain text should appear. Once completed it will generate the code into your test class which can then be run by your continuous deployments. Very quick and easy to create, which is good considering some integration tests I had to write took alot of time.
One question was does this replace all other unit and integration tests and the answer was depends on your needs. Obviously more coverage is better so I see Coded UI tests great for the jQuery and other UI related testing, so I will start trying them out in the wild.

Customising Content publishing approval workflows – Robert Bogue

Robert showed that there is a bug with setting the approval status in a SharePoint Designer workflow on a pages library, it gives a message saying something around “file being checked out”, something I had previously encountered.  To get around this you create a custom action in visual studio to set the approval status, so yes a workaround needed!

Unfortunately for him he had a demo melt down and everything he tried to do to recover failed him, it was almost unbelievable the issued that all came together…poor guy.

Branding SharePoint online Sites – Randy Drisgill & John Ross

Randy and John showed basic branding starting from overriding CSS to using custom MasterPages. Good thing I got from this is not much is different from using foundation version, so life is good.

Deep Dive on SharePoint Ribbon Development & Extensibility. – Chris O’Brien & Andrew Connell

Chris and AC showed the different control options you can have in the ribbon, eg flyout buttons and so on.
They advised to always use your own custom group instead of adding to or changing an existing group as the idea of the ribbon is that it does not change, so buttons are always where you would expected them.

They talked about contextual menus, like the one used on media webpart, and the options for the contextual menu which are global and focused. Note contenxtual menus are not available to create in the sandbox.
Global means if you have multiple instances of the same webpart whatever action you do in the ribbon it will apply it to all the instances added.
Focused means the action you do in the ribbon will only apply to the webpart that is in focus, ie clicked on, this is how the media webpart is setup.
Both require working with OO JavaScript, and as AC said it is hard going.
In regards to focused contextual menus they both agreed that the complexity and plumbing of OO javascript to get this working may not be worth the trouble. Part of me is happy to hear this as I did look into how the media webpart works so I could do something similar and found it very hard, but the other part of me thinks why does it have to be so hard. Lets hope some smart cookie out there creates some wrappers to make it easier.

Advance BI Visualization using Visio services. – Christopher Hopkins & A.J Briant

Christopher and A.J had a very nice demo that used visual diagrams connected to a datasource, then published to sharepoint. I was impressed with the visual presentation of data, for example they had a map of the US and it displayed the businesses staff distribution and sales per state all in a nice visual diagram. I would enjoy looking at this rather then some excel spread sheet or lame old pie charts.
Also impressed on how easy it is to wire up using the Visio UI.

One failure was when he tried to use the diagram auto generatation in Visio and it failed to do anything, always a worry to see. Though they did mention that the auto genration will not always give good results anyway, so it sounds like the advice is to go straight to building up your custom diagram using the shapes provided.

That wraps up an excellent conference, networking and meeting some great people, talking and learning from the legends of SharePoint and learning some new areas of the product that is set to be in every organisation and keep us all busy for many years to come!

Mix the following ingredients jQuery AJAX, jQuery templating, SharePoint REST api and apostrophes?

February 28, 2011 Leave a comment

The mission:
I wrote a jquery plugin to get events from a calendar list on another site using the Sharepoint 2010 REST api.
So I thought the best approach was to use the $.getJSON() function to get the events as a javascript object, that way I could feed it into the jquery templating engine.

All went well until a tester used the dreaded apostrophe in an event title (surely we sorted this on out years ago:)).
What this meant is that the json object that was returned had an escape charactor in it, which according to the ecma v1 standards (reference: http://bclary.com) is the way to go:

Escape Sequence Code Point Value Name Symbol
\’ \u0027 single quote

Unfortunately the jQuery $.getJSON() failed.
Actually this is just a wrapper for the $.ajax() function which also failed.

The answer:
Use the dataFilter to override the jquery library and strip the escape ecma standard so that we can get our response back.

Here is the plugin:

;(function ($) {

    $.events = {
        VERSION: “0.1″,
        defaults: {
            url: “/eventshub/_vti_bin/ListData.svc/Events“,
            success: function (data, element) { 
                $(“#EventsTemplate”).tmpl(data.d).appendTo(element);
                element.accordion(); //note: dependency on jquery UI
            },
            template : ‘<script id=”EventsTemplate” type=”text/x-jquery-tmpl”>’ +
                            ‘{{each results}}’ +
                                ‘<h3>’ +
                                    ‘<a href=”#”>{{html Title}} ${$.events.formatDate(StartTime)}</a>’ +
                                ‘</h3>’ +
                                ‘<div>’ +
                                    ‘{{html Description}}’ +
                                    ‘<br /><a href=”${Path}/DispForm.aspx?ID=${Id}” target=”_blank”>-full event details-</a>’ +
                                ‘</div>’ +
                            ‘{{/each}}’ +
                        ‘</script>’
            },
            formatDate : function(date){  //note: dependency on dataTimeParser.js
              return new Date(parseInt(date.substr(6))).format(“d mmm”); 
           },
           title : function(url){
                return url.substr(url.indexOf(“, “) + 2); 
            },                
            url : function(url){
                return url.substr(0, url.indexOf(“,”)); 
            }
    };

    $.fn.extend({
        events: function(settings){

            settings = $.extend({}, $.events.defaults, settings);
           
            return this.each(function(){
                var $this = $(this);
                $(“head #EventsTemplate”).remove();
                $(“head”).append(settings.template);
                var url = settings.url + “?$filter=StartTime ge datetime’” + new Date().format(“yyyy-mm-dd’T’HH:mm:ss”) + “‘”;
                $.ajax({
                    url: url,
                    dataType: ‘json’,
                    success: function(data){
                                if ($.isFunction(settings.success)) settings.success(data, $this);
                              },
                    dataFilter: function(data, type){
                                    return data.replace(/\\’/g, “‘”); // fix for escaped apostrophes in the feed 
                             } 
                    });
            });
        }
    });

})(jQuery);

We can use it in a webpart or usercontrol like so:

<script type=”language/javascript” src=”https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js”></script&gt;
<script type=”language/javascript” src=” https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js”></script>
<script type=”language/javascript” src=”{ path to your javascript }/jquery.tmpl.min.js”></script>
<script type=”language/javascript” src=”{ path to your javascript }/events.jquery.js”></script> <– our plugin above –>
<script type=”language/javascript”>

$(“.events”).events();

</script>

<div class=”events” />

Resources used:
jspec, a test suite for jquery, was used to write a series of unit tests.
Using firebug we can use the NET tab to get the json response to add as our test feed which is known as a test fixture.
This way we can override the url property in the plugin and give it our test data.
This gives us the abilty to have a number of possible scenarios both good and bad ensuring we have covered all the bugs testers may find (well maybe all :))

Follow

Get every new post delivered to your Inbox.