Archive for January, 2010

jQuery Blogging Part Deux


28 Jan
No Gravatar

This is a continuation of my previous post on enhancing the SharePoint Blog user interface with jQuery. In that sample I demonstrated how to use jQuery along with a customized Content Query Web Part in order to create a nice accordion effect for recent blog comments. In this example I will take things further and demonstrate:

  • How to include the most recent blog posts using jQuery to create a nice scrolling effect
  • Use the concepts introduced by Mark Miller for creating a Scripting Resource Center
  • How to change the look and feel of your jQuery components by using jQuery themes
  • Finally I will use the jQuery Dynamic List Filter and MOSS Filter web parts to create a dynamic page for searching posts and comments
  • I’ll also use the ChartPart web parts and some SPD workflows to create some graphs to visualize information about the blog

The completed blog home page looks like the image below. Please check the following screen cast to see it in action. Note that some of the more dynamic effects aren’t visible in the video due to the fact that Camtasia Studio seems to consume a lot of resources. You can see them in the video attached to the previous blog post. http://www.screencast.com/users/JasonMacKenzie/folders/Default/media/7e067f8b-af00-4a69-aae0-59c2fc41a198

Blog Scrolling

The first effect I wanted to achieve was to create a scrolling list of recent blog posts. In order to achieve this I used the Content Query Web Part along with the Scrollable plugin from jQuery Tools. The vertical scrolling requires the HTML to be output in the following structure:

<div id="actions">
<a class="prevPage">&laquo; Back</a>
<a class="nextPage">More pictures &raquo;</a>
</div>
<!-- root element for scrollable -->
<div class="scrollable vertical">
<!-- root element for the items -->
<div class="items">
<!-- first item. can contain anything -->
<div>
<!-- image -->
<img src="http://farm1.static.flickr.com/_m.jpg" />
<!-- title -->
<h3>1. Barcelona Pavilion</h3>
<!-- content -->
<p>
The Pavilion was not only a pioneer ...
</p>
</div>
<!-- second item (and so on) -->
<div>
...
</div>
</div>
</div>

So, as in the last post I’ll create a custom item template in ItemStyles.xsl in order to achieve this effect. I won’t go into to detail explaining this as y0u can read my previous post for the mechanics of it. I’ll post the template in it’s entirety for you to use:

<xsl:template name="ScrollableBlogPosts" match="Row[@Style='ScrollableBlogPosts']" mode="itemstyle">
<xsl:variable>
<xsl:call-template>
<xsl:with-param select="'ImageUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable>
<xsl:call-template>
<xsl:with-param select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable>
<xsl:call-template>
<xsl:with-param select="@Title"/>
<xsl:with-param select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable>
<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
</xsl:variable>
<xsl:if test="count(preceding-sibling::*)=0">
<div></div>
<style>
<xsl:text disable-output-escaping="yes"&gt
.vertical {position:relative; overflow:hidden; height: 665px; width: 650px; border-top:1px solid #ddd; }
.items {position:absolute; height:20000em; margin: 0px;}
.items div {margin:2px 0; padding:2px;}
.items img {float:left;margin-right:20px; height:180px; width:240px;}
.items h3 {margin:0 0 5px 0; font-size:16px;color:#456; font-weight:normal;}
#actions {width:100%px;margin:30px 0 10px 0;}
#actions a {font-size:11px; cursor:pointer; color:#666;}
#actions a:hover {text-decoration:underline;color:#000;}
.disabled {visibility:hidden;}
.nextPage {float:right;}
</xsl:text>
</style>
<div>
<a>Previous</a>
<a>More Blog Posts</a>
</div>
<a></a>
<xsl:text disable-output-escaping="yes">
<!-- root element for scrollable -->
&lt;div&gt;
<!-- root element for the items -->
&lt;div&gt;
</xsl:text>
</xsl:if>
<div><div><strong><a style="font-size:medium;color:gray" href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}">
<xsl:value-of select="@Title"></xsl:value-of></a></strong></div><xsl:value-of select="@Body" disable-output-escaping="yes"></xsl:value-of>
Posted at <xsl:value-of select="ddwrt:FormatDateTime(string(@PubDate) ,1033 ,'dd-MM-yyyy')" />
Posted By: <xsl:value-of select="@Author"></xsl:value-of> |
<a style="font-size:x-small;color:black" href="{$SafeLinkUrl}#Comments" target="{$LinkTarget}" title="{@LinkToolTip}">
Comments</a>
<hr style="color:white;border-bottom:1px solid black;"></hr>
</div>
<xsl:if test="count(following-sibling::*)=0">
<xsl:text disable-output-escaping="yes">
&lt;/div&gt;
&lt;/div&gt;
</xsl:text>
</xsl:if>
</xsl:template>

The next thing we’ll need to do is modify out CEWP to contain the jQuery to handle the scrolling. I will include all the script that is included in order to make our prototype function properly. The relevant script is in red. Note the easing function – for those that read my posts I’m sure you recognize that I did not come up with that on my own. All those algorithms are from the jQuery Easing plugin and you can simply copy and paste them in order to change the easing effect.

<script src="/sprc/Resources%20%20jQuery/jquery-1.3.2.min.js"></script>
<script src="/sprc/Resources%20%20jQuery/jquery.tools.min.js"></script>
<script src="/sprc/Resources%20%20jQuery/jquery-ui-1.7.1.min.js"></script>
<link rel="stylesheet" href="/sprc/Resources%20%20jQuery/jquery-ui-themes-1.7.1/excite-bike/jquery-ui.css">
<script>
$(document).ready(function(){
$("#accordion").accordion(
{ autoheight: false}
);
// initialize scrollable
$("div.scrollable").scrollable({
vertical:true, size: 1,easing: 'custom', speed: 1000
})
jQuery("#dialog").dialog({
bgiframe: true, autoOpen: false, modal: true, show: 'slide'
});
$("#demo img[title]").tooltip('#demotip');
});
// custom easing called "custom"
$.easing.custom = function (x, t, b, c, d) {
if (t==0) return b;
if (t==d) return b+c;
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
}
function PopulateText(textToShow, title)
{
document.getElementById("dialog").innerHTML = textToShow;
document.getElementById("dialog").title = title;
}
</script>

Scripting Resource Center

Following Mark’s advice I created a Scripting Resource Center to centrally host all jQuery related files as well as a wiki for all things SharePoint. I have download the latest versions of jQuery – 1.2.6 +, recent versions of jQuery UI, jQuery Tools as well as all the jQuery UI themes:

Changing Look and Feel

jQuery themes make it extremely easy to change the look of your jQuery components. See the screencast for the specific look but in a nutshell all you need to do is change the theme name in your CEWP. I’m quite pleased with the fact that the theme that works for me is called excite-bike. For some reason the name makes me happy.

<link rel=”stylesheet” href=”/sprc/Resources%20%20jQuery/jquery-ui-themes-1.7.1/excite-bike/jquery-ui.css”> to
<link rel=”stylesheet” href=”/sprc/Resources%20%20jQuery/jquery-ui-themes-1.7.1/redmond/jquery-ui.css”>

Personalized View and Dynamic List Filtering

I added a page where a user can view all blog posts along with their own comments. This uses the Filter web parts that are part of MOSS Enterprise Edition. The important thing to note here is that you need to set the Select Value to Provide to SharePoint profile value for current name and then select “Name” from the drop down.

Adding dynamic filtering could not be easier thanks to Jaap Vossers solution. This requires jQuery 1.2.6 so I installed that into the Resource Center and then it’s just a matter of placing the script in a CEWP. In my view this dramatically improves the user experience.

Charting and Real-Time Data

For the last piece of the puzzle I want to provide some charts on the home page that would show in (near) real time some of the activity on the blog. For this I downloaded the ChartPart solution from CodePlex and begged my administrator to install it :) It is incredibly easy to configure and it renders really slick looking charts.

Everything else was accomplished with a few custom lists and a 2 step workflow called Activity Tracker on the Posts list.

I created 2 lists – Comment Counter and Post Comment Counter.

Comment Counter contains 3 columns – Title, Comment Poster (person) and Comment Count (number).

Post Comment Counter contains 2 columns – Post Subject and Comment Count (number).

Below is a shot of the workflow in SPD

Both steps are essentially the same and the process goes like this:

  1. If the current user has a an entry already in the Comment Count list then get the current comment count, increment the count by 1 and then update their list item.
  2. If the user has no item in the Comment Count list then create a new item for them with a Comment Count of 1.

The second step is essentially the same except we are looking to see if an item with the same subject as the current post the user is commenting on exists. If so increment by 1, otherwise create a new item for that Blog Post with a Comment Count of 1.

We can then create views and easily hook the charts up to those views.

And that is it. Going through this process has been extremely educational for me as it relates to integrating jQuery with SharePoint and I can say with certainty that our users are very impressed by the new pizazz we’re adding to their intranet. It also made it clear how many resources there are available and what you can do when you combine them into a holistic solution.

Please feel free to send me any comments or questions.

VN:F [1.9.21_1169]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.21_1169]
Rating: +2 (from 2 votes)

JQuery and SharePoint Blogging Sample


13 Jan
No Gravatar

It’s been a while since I posted due to a change in careers.  I have become an independent SharePoint consultant and am loving the change.

Reading my favourite (IT) site, EndUserSharepoint and all the interesting examples of what the authors are doing with SharePoint has gotten me very excited about the possibilities of integrating JQuery with SharePoint to create some very slick user interfaces.  I want to some highlights of this latest prototype because it touches on a lot of different areas.

Firstly the shoutouts:

Heather Solomon for her blog on Customizine the CQWP
Michael Hofer for rolling up blog comments with the CQWP
Everyone at EUSP

So without further ado here’s a quick video of what the prototype looks like.  Prototype

So the first thing I did was create a new site based on the Blog template, added a few posts and made a few of my typically dim comments.  I actually added a column on the comments list called Highlight which we’ll use later. 

I added a CQWP to my page and you’ll notice that there is no way to roll up blog comments from the UI.  A little research led me to Michael’s blog above.  So configuring the CQWP to roll up blog posts and then exporting it, modifying the server template property from 301 to 302 and reimporting it did the trick.  Keep in mind that if you modify the CQWP in the UI after words you’re going to have to go through that process again.

While we’re on the subject of modifying the webpart we might as well add the extra fields we’ll need to the CommonViewFields property in our webpart. Essentially this makes the fields available to use when modifying the XSL a little later.  For more information please read Heather Solomon’s post above.

<property name=”CommonViewFields” type=”string”>Body, Text;Title,Text;Highlight,Boolean</property>

Moving along….I wanted to get a  nice accordion effect with the results which naturally led me toward the jQuery accordion.  For those that haven’t used it, it really could not be simpler.  Add a reference to the right jquery libraries, format the HTML and away we go.  Actually in the interest of clarity, here are all the jquery references and code required for this sample.  I’ll explain them as we go:

Simply place this all into a Content Editor Web Part (this definitely is not a best practice but for the purposes of this article we’ll leave it like this).

  <script type=”text/javascript” src=”http://jqueryui.com/latest/jquery-1.3.2.js”></script>
  <script type=”text/javascript” src=”http://jqueryui.com/latest/ui/ui.core.js”></script>
  <script type=”text/javascript” src=”http://jqueryui.com/latest/ui/ui.accordion.js”></script>
<script type=”text/javascript” src=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js”></script>
<link rel=”stylesheet” href=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/ui-lightness/jquery-ui.css” type=”text/css”>

<script type=”text/javascript”>
  $(document).ready(function(){
    $(“#accordion”).accordion(
{
    autoheight: false
}
);
jQuery(“#dialog”).dialog({
      bgiframe: true, autoOpen: false,  modal: true, show: ‘slide’
    });

  });

  function PopulateText(textToShow, title)
  {
        document.getElementById(“dialog”).innerHTML = textToShow;
        document.getElementById(“dialog”).title = title;
  }

 </script>

The appropriate HTML formatting for the accordion looks like this:

<div id=”accordion”>
    <h3><a href=”#”>First header</a></h3>
    <div>First content</div>
    <h3><a href=”#”>Second header</a></h3>
    <div>Second content</div>
</div>

Since we’ll need to control the HTML output we’ll turn to our friend the itemstyles.xsl file.  It’s located in the style library which is easy enough to find in SPD:

Again, for the mechanics of creating new templates etc. please refer to Heather’s blog post.  She’s far more articulate that your resident troglodyte here.  Anywhoo…we’ll create a new template and this is really where the magic happens.  The first challenge I had was that I needed to have a <div id=”accordion”></div>  block surrounding the CQWP.  But, obviously this output will be rendered for each item. 

However with the following check we can ensure that the following output is generated only for the first item.  I’ll explain the code snippet in red later – it’s not germane to this discussion.  So essentially on the first match we’re going to spit out <div id=”accordion”> and then everything else will be contained with in that div.

 <!–If this is the first match let’s put a header on it–>
  <xsl:if test=”count(preceding-sibling::*)=0″>
   <div id=”dialog” title=”Comment”>
    <p>
     <xsl:value-of select =”@Body” disable-output-escaping=”yes”/>
    </p>

   </div>
   <xsl:text disable-output-escaping=”yes”>&lt;div id=accordion &gt;</xsl:text>
  </xsl:if>

Of course then at the end of the template will put the following check it to render the closing tag on the last match:

  <!–If this is the last match we’ll put a footer on the end to close off the html–>
  <xsl:if test=”count(following-sibling::*)=0″>
   <xsl:text disable-output-escaping=”yes”>&lt;/div&gt;</xsl:text>
  </xsl:if>

The next step we want to do is make sure that only the list items or comments that have Highlight checked are rendered.

A very simple check like so makes that happen:  <xsl:if test=”@Highlight=’True’”> …put everything you want rendered in here  </xsl:if>

Now – you’ll notice in the video that when you click the more button for each item a nice jquery modal dialog pops up with the body of the comment.  Here’s how that was accomplished.

That snippet in red above is the container that will be required to store the text we want to show in the jQuery dialog so we’re going to need to come up with a way to dynamically populate this.

So in our XSL we will do the following – comments inline:

       <tr valign=”top”>
        <td><strong>Details</strong></td>
        <td valign=”bottom”>

<!–The users will click an image with the word “More” on it in order to show the comment body.  We wrap the image in an <a> tag and then in the click event we set the dialog properties (height, width etc.) and then we open the dialog.

However on the mousedown event (prior to the onclick) we render some script that will call the PopulateText function and pass in the comment Body (@Body).  When the dialog opens it will display the right text. 

–>   
<a href=”#” onclick=”jQuery(‘#dialog’).dialog(‘option’,'show’ , ‘slide’);jQuery(‘#dialog’).dialog(‘option’,'height’ , 300);jQuery(‘#dialog’).dialog(‘option’, ‘width’, 500);jQuery(‘#dialog’).dialog(‘open’); return false”>
   <xsl:attribute name=”onmousedown”>
   <xsl:text>javascript:PopulateText(“</xsl:text>
   <xsl:value-of select =”@Body” disable-output-escaping=”yes”/>
   <xsl:text>”, “Comment”);</xsl:text>
   </xsl:attribute>
   <img border=”0″ src=”/SiteCollectionImages/Moreicon.gif”></img>
   </a>
     </td>
       </tr>

In order to change the them for your accordion and dialog all you need to do is change the link to the theme css file (<link rel=”stylesheet” href=”http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/ui-lightness/jquery-ui.css” type=”text/css”>).

And that is how I created some nice effects for Blog Posts using the CQWP and jQuery.   I hope you enjoy, get some ideas and provide me with some feedback.

Jason

For reference sake the entire XSL template is below:

<xsl:template name=”HighlightedBlogComments” match=”Row[@Style='HighlightedBlogComments']” mode=”itemstyle”>
  <xsl:variable name=”SafeLinkUrl”>
            <xsl:call-template name=”OuterTemplate.GetSafeLink”>
                <xsl:with-param name=”UrlColumnName” select=”‘LinkUrl’”/>
            </xsl:call-template>
        </xsl:variable>
  <xsl:variable name=”SafeImageUrl”>
            <xsl:call-template name=”OuterTemplate.GetSafeStaticUrl”>
                <xsl:with-param name=”UrlColumnName” select=”‘ImageUrl’”/>
            </xsl:call-template>
        </xsl:variable>
  <xsl:variable name=”LinkTarget”>
            <xsl:if test=”@OpenInNewWindow = ‘True’” >_blank</xsl:if>
        </xsl:variable>
 
 <!–If this is the first match let’s put a header on it–>
  <xsl:if test=”count(preceding-sibling::*)=0″>
   <div id=”dialog” title=”Comment”>
    <p>
     <xsl:value-of select =”@Body” disable-output-escaping=”yes”/>
    </p>
   </div>
   <xsl:text disable-output-escaping=”yes”>&lt;div id=accordion &gt;</xsl:text>
  </xsl:if>
  <!–Only show the records where the HighLight Column has been checked–>
  <xsl:if test=”@Highlight=’True’”>
   <h4>
    <a href=”#”>
     <xsl:value-of select=”@Title”/>
    </a>
   </h4>
   <div height=”350″>
    <p>
     <font size=”1″>
      <table>
       <tr valign=”top”>
        <td><strong>Author</strong></td>
        <td><xsl:value-of select=”@Author”/></td>
       </tr>
       <tr valign=”top”>
        <td><strong>Posted On</strong></td>
        <td><xsl:value-of select=”@Created”/></td>
       </tr>
       <tr valign=”top”>
        <td><strong>Details</strong></td>
        <td valign=”bottom”>
   

   <a href=”#” onclick=”jQuery(‘#dialog’).dialog(‘option’,'show’ , ‘slide’);jQuery(‘#dialog’).dialog(‘option’,'height’ , 300);jQuery(‘#dialog’).dialog(‘option’, ‘width’, 500);jQuery(‘#dialog’).dialog(‘open’); return false”>
   <xsl:attribute name=”onmousedown”>
   <xsl:text>javascript:PopulateText(“</xsl:text>
   <xsl:value-of select =”@Body” disable-output-escaping=”yes”/>
   <xsl:text>”, “Comment”);</xsl:text>
   </xsl:attribute>
   <img border=”0″ src=”/SiteCollectionImages/Moreicon.gif”></img>
   </a>
  

   </td>
       </tr>
      </table>
     </font>
    </p>
   </div>
  </xsl:if>
  <!–If this is the last match we’ll put a footer on the end to close off the html–>
  <xsl:if test=”count(following-sibling::*)=0″>
   <xsl:text disable-output-escaping=”yes”>&lt;/div&gt;</xsl:text>
  </xsl:if>
 </xsl:template>

VN:F [1.9.21_1169]
Rating: 8.8/10 (4 votes cast)
VN:F [1.9.21_1169]
Rating: +1 (from 3 votes)

Intelligence Among Us

it's there…use it.