1,485 articles and 10,297 comments as of Thursday, April 8th, 2010

Friday, March 12, 2010

Real World Project: Transparent Overlays for SharePoint Interface Enhancement

A note from Mark Miller: If you’ve ever worked with Christina Wheeler, you know from the beginning she is a perfectionist. NOTHING gets released until it has been tested, retested, written, tweaked and then started all over again because it wasn’t EXACTLY right. What you see in this article is how painstakingly thorough she is when documenting a solution.

We could all learn a little just by following her example. Thank you, Christina.

Introduction

I have a client that wanted to convert their outdated HTML district website to an external facing SharePoint portal. The client was brand new to SharePoint and brought me in to build an external facing portal using MOSS 2007 Enterprise. After setting up the new farm it was time to brand the site and create content. The one thing I had the client do before I started branding the site was have them send me references to sites they liked along with a list of elements they liked about the sites.

Overview

The first thing the client wanted was randomly rotating pictures on the main page of the site. To accomplish this I decided to use the SharePoint Ad Rotator. The second thing the client wanted was a rounded corners transparent overlay to display information for News and Events. In order to achieve this I used jQuery and SharePoint web services. For the layout of this page, I created a custom master page and style sheet to get the zones and styling the way I wanted it to be for the client’s site.


Solution

All scripts/solutions will be stored in a central library with the CEWP pointing to the solution. For this solution I used a central repository that the client already had called the “Utilities” document library but I recommend implementing a Scripting Resource Center based on Mark Miller’s recommendation.

Step 1. Downloads: To make it easier, I have provided downloads for the JavaScript and overlay image files that are used for this project. You will have to download and create your own background images as the files I have are property of the client.

Step 2. SharePoint Ad Rotator: Download and install the SharePoint Ad Rotator from CodePlex. Once the web part solution has been installed you will need to activate it in the Site Collection Features.


Step 3. Photo Library: Now create a Photo Library to store the images for the SharePoint Ad Rotator. Make sure the images are the exact size you want them to display as on the page. For this project my images are sized at 790×600 pixels.

Step 4. SharePoint Ad Rotator Properties: Next step is to add the SharePoint Ad Rotator web part to the page and change the Query List Name property to point to my photo library.


Now that the main page rotating photos are in place it’s time to add the rounded corners transparent overlay with text.

Step 5. HTML page & CSS file: Create a blank HTML page and a blank CSS file. I named my HTML file JQuerySPOverlay.htm and named my CSS file JQuerySPOverlay.css. Once created load these files into your central repository.

Note: You can also create a plain text (JQuerySPOverlay.txt) file instead of a HTML file to store your code.


Step 6. Content Editor Web Part: Add a CEWP to your page and point it to your JQuerySPOverlay.htm or JQuerySPOverlay.txt file.  For those who have been using jQuery for awhile then you know that most solutions begin with adding a hidden CEWP to the bottom of the page. For this solution we cannot hide the web part and instead need change the ‘Chrome Type’ from Default to None.




Step 7. Create SharePoint List: Create a SharePoint custom list to contain the content for the overlay. I named my list “Overlay Items List”.

  • Title (Single line of text): Title of the item.
  • Link (Single line of text): Column to hold the URL for the item.
  • Order (Choice): Column used for sorting the items.
  • Category (Choice): Column for the category to break apart which section the link will belong to.


  • Order choice options


  • Category choice options


  • Now input your data into the SharePoint list. Enter the Link value ‘none’ for items you do not want to have a href.


Step 8. Edit the HTML Page: Since the files are now stored in SharePoint you can open your HTML, CSS, and JS central repository files through SharePoint Designer.

HTML Code

The first thing we’ll do is layout the div’s for the overlay along with the heading text.

<div class="wrap">
 <div id="slideshow"></div>
	<div id="callout">
		<div id="callout-content">
            <div class="columnL">
                <!-- left COLUMN CONTENT -->
                <h2>HVRSD News</h2>
          </div>
             <div class="columnR">
                <!-- right COLUMN CONTENT -->
                <h2>HVRSD Events</h2>
			</div>
      </div>
           <div id="callout-btm"></div>
 	</div>
</div>

CSS Code

Below are the CSS settings used for this project to create the transparent overlay with rounded corners.

Note: I am working in a resolution of 1440×900 therefore you may need to adjust the positioning and sizing if you are working in a smaller resolution.

body
{
	background: #ffffff;
	margin: 0;
	padding: 0;
	font: 10px normal Arial, Helvetica, sans-serif;
}
.clear
{
	clear: both;
}
/* This is the area of the SharePoint Ad Rotator. Adjust these settings to the size of
your images */
#slideshow
{
	position: relative;
	width: 790px;
	height: 600px;
	z-index:0;
}
.wrap
{
	position: absolute;
	margin: 0px;
	overflow: hidden;
	top: 150px;
	z-index: 0;
}
#callout
{
	background-image: url("/Utilities/Images/callout_top.png");
	background-repeat: no-repeat;
	background-position: left top;
	position: absolute;
	padding-top: 18px;
	padding-bottom: 0px;
	padding-left: 0px;
	padding-right: 0px;
	margin: 0px;
	width: 617px;
	display: block;
	color: #ffffff;
	top: 400px;
	left: 160px;
}
#callout #callout-content
{
	background-image: url("/Utilities/Images/callout_repeat.png");
	background-repeat: repeat-y;
	background-position: left top;
	padding-top: 10px;
	padding-bottom: 2px;
	padding-left: 10px;
	padding-right: 10px;
	margin: 0px;
	width: 617px;
	height: 90px;
}
#callout #callout-btm
{
	background-image: url("/Utilities/Images/callout_btm.png");
	padding-top: 0px;
	padding-bottom: 18px;
	padding-left: 0px;
	padding-right: 0px;
	margin: 0px;
	width: 617px;
	background-repeat: no-repeat;
	background-position: left top;
}
#callout #callout-content H2
{
	padding-top: 0px;
	padding-bottom: 0.25em;
	padding-left: 0px;
	padding-right: 0px;
	margin: 0px;
	color: #ffffff;
	font-size: 1.2em;
}
#callout #callout-content P
{
	padding-top: 0.25em;
	padding-bottom: 0.25em;
	padding-left: 0px;
	padding-right: 0px;
	margin: 0px;
}
#callout #callout-content HR
{
	border-top-style: none;
	border-bottom: #ffffff 1px dashed;
	border-left-style: none;
	border-right-style: none;
	padding-top: 1px;
	padding-bottom: 0px;
	padding-left: 0px;
	padding-right: 0px;
	background-color: transparent;
	margin: 3px 0px;
	height: 1px;
}
#callout #callout-content .columnA
{
	background-image: url("/Utilities/Images/callout_repeat.png");
	background-repeat: repeat-y;
	background-position: left top;
	background-color: #000000;
	width: 617px;
}
#callout #callout-content .columnL
{
	padding-top: 0px;
	padding-bottom: 0px;
	padding-left: 8px;
	border-right: #ffffff 1px solid;
	padding-right: 8px;
	margin: 0px;
	width: 320px;
	float: left;
}
#callout #callout-content .columnR
{
	border-left: #ffffff 1px solid;
	padding-top: 0px;
	padding-bottom: 0px;
	padding-left: 8px;
	padding-right: 8px;
	margin: 0px 0px 0px -1px;
	width: 240px;
	float: left;
}
#callout #callout-content .btm-links
{
	text-align: right;
	padding-top: 6px;
	padding-bottom: 0px;
	padding-left: 0px;
	padding-right: 0px;
	margin: 0.65em 0px 0px 8px;
	display: block;
	float: none;
	clear: both;
	font-weight: bold;
}
#callout #callout-content a:link
{
	color: #ffffff;
	text-decoration: none;
}
#callout #callout-content a:visited
{
	color: #ffffff;
	text-decoration: none;
}
#callout #callout-content a:hover
{
	color: #ffffff;
	text-decoration: underline;
}
#callout #callout-content a:active
{
	color: #ffffff;
	text-decoration: none;
}
#callout #callout-content .btm-links a:link
{
	color: #ffcc1a;
	text-decoration: none;
}
#callout #callout-content .btm-links a:visited
{
	color: #ffcc1a;
	text-decoration: none;
}
#callout #callout-content .btm-links a:hover
{
	color: #ffffff;
	text-decoration: none;
}
#callout #callout-content .btm-links a:active
{
	color: #ffcc1a;
	text-decoration: none;
}

JavaScript Setup

  • Add a reference to your jQuery library files and CSS file to the top of your html page.
<script type="text/javascript">
if(typeof jQuery=="undefined"){
var jQPath="/Utilities/js/";
document.write("<script src='",jQPath,"jquery-1.4.min.js' type='text/javascript'><\/script>");
}
</script>
<script src="/Utilities/js/jquery.SPServices-0.5.2.min.js"></script>
<!-- styling -->
<link rel="stylesheet" type="text/css" href="/Utilities/css/jQuerySPOverlay.css" />

jQuery and SharePoint Web Services

This project uses Marc D. Anderson’s jQuery Library for SharePoint Web Services. This library abstracts SharePoint’s Web Services and makes them much easier to use. I highly recommend using this library because it’s clean, readable, and simplifies coding. Also, I suggest looking at the normal version if you want to understand the workings of the library but use the minified version for production use.

For a better understanding of  jQuery with SharePoint Web Services read Marc D. Anderson’s article “A jQuery Library for SharePoint Web Services (WSS 3.0 and MOSS): Part 2 – How Does It Work?

  • Now add this script below your CSS reference.
<script type="text/javascript">
$(document).ready(function() {
$().SPServices({
operation: "GetListItems",
async: false,
listName: "Overlay Items List",
CAMLQuery: "<Query>" +
"<OrderBy><FieldRef Name='Order0' Ascending='TRUE'/></OrderBy>" +
"</Query>",
CAMLViewFields: "<ViewFields>" +
"<FieldRef Name='Title' />" +
"<FieldRef Name='Link' />" +
"<FieldRef Name='Category' />" +
"</ViewFields>",
CAMLRowLimit: 0,
completefunc: processResult
});
});
</script>

This function is attached to the jQuery document ready event. In this function the listName element is set to get items from the SharePoint list named “Overlay Items List”.

Note: You can either use the text name of the list or the GUID for the list.

The OrderBy element is set to the field name for the sorting column and the ViewFields element contains the fields we want to pull data from. For this project I am pulling the Title, Link, and Category fields.

Note: When you wish to query or display a field with a space in the name use _x0020_ instead of the space.

<FieldRef Name="Sort_x0020_Order"/>

The jQuery function has a complete parameter which points to the processResult JavaScript function. In the processResult function, a loop is created over every row element (in the namespace z). In the original JavaScript I used the .find method to locate all notes with the tag name of z:row.

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

This worked fine in Internet Explorer and Firefox but Safari and Chrome returned 0 results. I found a nice work around from Mike Hacker for this z:row issue that I used to fix the browser problem. Marc also expanded Mike Hacker’s workaround to check for ItemCount up front so you don’t have to use getElementsByTagNameNS function in IE if no rows returned legitimately.

  • Now add the processResult function to process the result along with the z:rows loop.
function processResult(xData, status) {
var rows;
if (xData.responseXML.getElementsByTagName("z:row").length==0)
{
rows = xData.responseXML.getElementsByTagNameNS('*', 'row');
}
else
{
rows = xData.responseXML.getElementsByTagName("z:row");
} 
  • Next we need to add the .each() method for the rows. The two variables being declared are: catValue (Category field) and getLink (Link field). You will need to update the catValue if/else statements if you are using different categories.
jQuery(rows).each(function() {
var catValue = $(this).attr("ows_Category");
var getLink = $(this).attr("ows_Link");
if (catValue == "News"){
if (getLink == "none")
{
var leftHtml = "<p>" + $(this).attr("ows_Title") + "</p><hr>";
$("div.columnL").append(leftHtml);
$("div.columnL hr").each(function(i){this.id = "LeftHR" + i ; });
}
else {
var leftHtml = "<p><a href=" + $(this).attr("ows_Link") + ">" + $(this).attr("ows_Title") + "</a></p><hr>";
$("div.columnL").append(leftHtml);
$("div.columnL hr").each(function(i){this.id = "LeftHR" + i ; });
}
$("#LeftHR1").remove();
}
else if (catValue == "Events"){
if (getLink == "none")
{
var rightHtml= "<p>" + $(this).attr("ows_Title") + "</p><hr>";
$("div.columnR").append(rightHtml);
$("div.columnR hr").each(function(i){this.id = "RightHR" + i ; });
}
else {
var rightHtml= "<p><a href=" + $(this).attr("ows_Link") + ">" + $(this).attr("ows_Title") + "</a></p><hr>";
$("div.columnR").append(rightHtml);
$("div.columnR hr").each(function(i){this.id = "RightHR" + i ; });
}
$("#RightHR1").remove(); 
}
});
}
</script>

The client also wanted the horizontal rule to only display between the rows and not display below the last item. In order to accomplish this I first appended the <hr> to the HTML.

var rightHtml= "<p><a href=" + $(this).attr("ows_Link") + ">" + $(this).attr("ows_Title") + "</a></p><hr>";
$("div.columnR").append(rightHtml);

Then I had to assign an incremental ID to each <hr> element.

$("div.columnR hr").each(function(i){this.id = "RightHR" + i ; });

Next, I used the IE Developer Toolbar to figure out which generated <hr> I needed to remove and then added code to remove the <hr> by ID.
$("#RightHR1").remove();  

Here is the full html.

<script type="text/javascript">
if(typeof jQuery=="undefined"){
var jQPath="/Utilities/js/";
document.write("<script src='",jQPath,"jquery-1.4.min.js' type='text/javascript'><\/script>");
}
</script>
<script src="/Utilities/js/jquery.SPServices-0.5.2.min.js"></script>
<!-- styling -->
<link rel="stylesheet" type="text/css" href="/Utilities/css/jQuerySPOverlay.css" />
<script type="text/javascript">
$(document).ready(function() {
$().SPServices({
operation: "GetListItems",
async: false,
listName: "Overlay Items List",
CAMLQuery: "<Query>" +
"<OrderBy><FieldRef Name='Order0' Ascending='TRUE'/></OrderBy>" +
"</Query>",
CAMLViewFields: "<ViewFields>" +
"<FieldRef Name='Title' />" +
"<FieldRef Name='Link' />" +
"<FieldRef Name='Category' />" +
"</ViewFields>",
CAMLRowLimit: 0,
completefunc: processResult
});
});
function processResult(xData, status) {
var rows;
if (xData.responseXML.getElementsByTagName("z:row").length==0)
{
rows = xData.responseXML.getElementsByTagNameNS('*', 'row');
}
else
{
rows = xData.responseXML.getElementsByTagName("z:row");
} 
jQuery(rows).each(function() {
var catValue = $(this).attr("ows_Category");
var getLink = $(this).attr("ows_Link");
if (catValue == "News"){
if (getLink == "none")
{
var leftHtml = "<p>" + $(this).attr("ows_Title") + "</p><hr>";
$("div.columnL").append(leftHtml);
$("div.columnL hr").each(function(i){this.id = "LeftHR" + i ; });
}
else {
var leftHtml = "<p><a href=" + $(this).attr("ows_Link") + ">" + $(this).attr("ows_Title") + "</a></p><hr>";
$("div.columnL").append(leftHtml);
$("div.columnL hr").each(function(i){this.id = "LeftHR" + i ; });
}
$("#LeftHR1").remove();
}
else if (catValue == "Events"){
if (getLink == "none")
{
var rightHtml= "<p>" + $(this).attr("ows_Title") + "</p><hr>";
$("div.columnR").append(rightHtml);
$("div.columnR hr").each(function(i){this.id = "RightHR" + i ; });
}
else {
var rightHtml= "<p><a href=" + $(this).attr("ows_Link") + ">" + $(this).attr("ows_Title") + "</a></p><hr>";
$("div.columnR").append(rightHtml);
$("div.columnR hr").each(function(i){this.id = "RightHR" + i ; });
}
$("#RightHR1").remove(); 
}
});
}
</script>
<div class="wrap">
<div id="slideshow"></div>
<div id="callout">
<div id="callout-content">
<div class="columnL">
<!-- left COLUMN CONTENT -->
<h2>HVRSD News</h2>
</div>
<div class="columnR">
<!-- right COLUMN CONTENT -->
<h2>HVRSD Events</h2>
</div>
</div>
<div id="callout-btm"></div>
</div> 
</div>

Conclusion

In all honesty, I didn’t start using jQuery for SharePoint until after I saw Mark Miller’s presentations at SharePoint Saturday Philly in 2009. Since then I’ve been extremely addicted and have been able to accomplish more of what my clients want without having to write custom web parts. Thank you Mark, I owe it all to you for introducing me to jQuery!

Guest Author: Christina Wheeler

Christina Wheeler is a Senior SharePoint Consultant for Summit 7 Systems and Founder of CM Portal Solutions, LLC based in Malvern, PA. With over 10 years of experience in the industry, Christina has a background in graphic design, web development, custom development, and has been working with SharePoint since May 2005. Christina has a strong passion for technology and photography who enjoys sharing and learning with the community.

 

Please Join the Discussion

20 Responses to “Real World Project: Transparent Overlays for SharePoint Interface Enhancement”
  1. eric says:

    Holy crap, great article! Definately will be referencing this in the near future.

  2. Shalin Parmar says:

    Overwhelmed by the article……need to read it time and time again…….Excellent work Christina!

  3. Paul says:

    I cant explain how much I appreciate this article. By the way great job at SP Boston.

  4. Derek says:

    Excellent article Christina, Mark is right to call you a perfectionist!

  5. Christina Wheeler says:

    Thank you!!!! I truly appreciate the great feedback and support!

  6. Greg says:

    HS! There are SO many goodies in this post. I will have to go back at it this WE to get into all the steps and details.
    Seems like a solid, well built solution.
    Thanks for sharing!

    Greg

    PS: Mark, Have you convinced Christina to record webcasts?

  7. FYI — On the z:row piece, this should work in all browsers:

    $(xData.responseXML).find(&quot;[nodeName=z:row]&quot;)

    M.

  8. Varin says:

    Was it a publishing or collaboration portal?

  9. Manrike says:

    Hi, Christina…

    I only wish to say thank you for your GREAT article! Is excellent! Well done!

    Please, keep your good work!

    Best regards,

    Manrike

  10. Jeff says:

    HS! Fantastic article Christina, thank you! Minor typo #8 “stored in SharePoint.”

    Any idea if something similar could be done with with DVWP and XSLT?

    Maybe use XSLT to do the HTML rendering and list data pull but then overlay Java Script for the animation? Probably a tangent away from this whole model because Ad Rotator wouldn’t even be included. Curious for your opinion please. Some MOSS systems I’ve had push back on CodePlex .WSP … so at times I must work natively even if more cumbersome. =]

    This post was so awesome it makes mine look like crayon scribble.

  11. akram says:

    Very Cool,
    Step by Step.

    This is the real End User SharePoint Article, where non-Developers can work around.

    Great work “Christina”. Thanks

    Hope to see similar step by step articles from you.

  12. Christina Wheeler says:

    Varin, it is a collaboration portal.

    Jeff,

    Typo, what typo…I don’t see any typo? :) Thanks for that, it’s been updated. Also, you make a good point about some companies not trusting WSP files from Codeplex. I’ll work on an alternative DVWP solution and if I get it working I’ll document it for a follow up article.

    BTW…love your crayon scribble comment! :-)

    Thanks,

    Christina

  13. Badir McCleary says:

    This Article is amazing!!

  14. This is a fantastic article. Thank you so much for sharing it and I am looking forward to reading more of your posts.

  15. Eric M says:

    Great work and great to work with…

  16. PrashanthSpark says:

    Thats Really great work. I would love to try once those stuff

Trackbacks

Check out what others are saying about this post...
  1. Real World Project: Transparent Overlays for SharePoint Interface Enhancement (EUSP)…

    Introduction I have a client that wanted to convert their outdated HTML district website to an external…

  2. [...] Note: The script in wrapwebparts2007.html that tests for and writes the reference to the jQuery library is borrowed from Christina Wheeler’s post “Transparent Overlays for SharePoint Interface Enhancement.” [...]

  3. [...] Note: The script in spuiguy_collapsible_web_parts_in_zone_2007.html that tests for and writes the reference to the jQuery library is borrowed from Christina Wheeler’s post “Transparent Overlays for SharePoint Interface Enhancement.” [...]




Notify me of comments to this article:


Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!