All posts tagged Control Adapters

iGoogle UI for SharePoint 2010 – Part Four: Control Adapters

Series Content

  1.     Part One – Overview, Concept,  HTML Structure & jQuery Basics
  2.     Part Two – Dragging, Dropping,  Sorting and Collapsing
  3.     Part Three – Saving WebPart states using Cookies
  4.     Part Four – Control Adapters – Current Article
  5.     Part Five – SharePoint 2010 Integration
  6.     Part Six – Bringing it all together
  7.     Bonus – Saving WebPart States using the Client Object Model

Overview

In Part Four we will take the take a look at how we will create our widgets in SharePoint 2010.  As the title of this post mentions we are going to use what is known as a Control Adapter.  This Post will outline what they are, how they work, and how we are going to use them in this series.  There will also be a code snippet to explain how we can use it.

Control Adapters

Rather than try to explain these myself I thought it would be easier to grab a snippet from a Microsoft Article which i think does a great job of explaining what and how they work from an architectural level and in more detail than I could probably achieve :) .

At their core, control adapters are simply a way of providing different renderings for controls without actually modifying the controls themselves. Because control adapters are designed to provide alternate renderings for different clients, you specify control adapter mappings in a .browser file, which is where associations between User Agent strings and browser capabilities are defined. The control adapter class itself must inherit from the System.Web.UI.Adapters.ControlAdapter, which is an abstract base class that looks much like the Control base class, with events for Init, Load, PreRender, and Unload, as well as a virtual Render method.

The next step to use a control adapter is to derivatively bind your adapter to a specific control.  To do this you use a Browser Definition File Schema which is found in the App_Browsers folder of the IIS WebSite you are using.

How are we going to use Control Adapters?

Now we know what a control adapter is, what do we need them for?  Well, if we are going to have our WebPart rendering like we have built in the previous three post then we will need to use a Control Adapter to do the hard work for us.  WebParts can be placed onto a SharePoint 2010 Page in many ways.  They can be either added to content inline using the rich content editor, they can be added directly into a page layout or masterpage, or (the most common way) is that they can be placed into a WebPart zone.  It is this final method that we are going to use to modify the rendering of our WebParts.

A basic WebPart Control Adapter Code looks like this:

using System.Web.UI;
using System.Web.UI.WebControls.WebParts;

namespace LifeInSharePoint.iGoogle.Common.ControlAdapters
{
    public class WebPartRenderControlAdapter : System.Web.UI.Adapters.ControlAdapter
    {
        protected override void Render(HtmlTextWriter writer)
        {
            WebPartZone wpz =
                Control as WebPartZone;
            if (wpz != null)
            {
                // Render the WebPartZone
                writer.Indent++;
                // Render the web parts
                if (wpz.WebParts.Count > 0)
                {
                    WebPartCollection wpColl = new WebPartCollection(wpz.WebParts);
                    foreach (WebPart wp in wpColl)
                    {
                        wp.RenderControl(writer);
                    }
                }
                writer.Indent--;
                writer.WriteLine();
            }
        }
    }
}

As you can see from the code above we have a class which inherits from System.Web.UI.Adapters.ControlAdapters.  We first get a reference to the current WebPartZone on the Adapter.  If this is not null then we can start to override the WebPart rendering.  We then check how many WebParts exist in the current WebPartZone that we are in and if there are some then we create a new WebPartCollection object with all the WebParts in the current zone.

WebPartCollection wpColl = new WebPartCollection(wpz.WebParts);

We can then loop through each WebPart in the collection and render the WebPart control.   This alone will remove all the tables for each WebPart rendered in a WebPartZone.  The final step to get this basic Control Adapter working is to update the compact.browser file stored (in my case) in the inetpub > webapp > App_Browsers > compact.browser file.

We need to add a single line into the <controlAdapters> node to register our new custom adapter.

  <browser refID="default">
    <controlAdapters>
		<adapter controlType="System.Web.UI.WebControls.WebParts.WebPartZone" adapterType="LifeInSharePoint.iGoogle.Common.ControlAdapters.WebPartRenderControlAdapter, LifeInSharePoint.iGoogle, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4077a3c2ee13ed4a" />
    </controlAdapters>
  </browser>

Save this file and ensure that the dll is in the GAC and then the control adapter should work.  One thing that is important to know about Control Adapters is that when they are in use they will by default process EVERY WebPart on the site.  For our implementation however we want to be able to choose which WebParts are rendered as our widgets.  To do this we will place some logic into our control adapter which will check the title of the WebPartZone to ensure it contains the text “iGoogle” and only process WebParts that are contained within those specific zones.  Another piece of logic that we need to place into our zones is that we only want our rendering to process WebParts when the page is in the Display mode and not in Edit mode.  The code below shows the updated adapter with the new pieces of logic included.

using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebPartPages;
using WebPart = System.Web.UI.WebControls.WebParts.WebPart;
using WebPartZone = System.Web.UI.WebControls.WebParts.WebPartZone;

namespace LifeInSharePoint.iGoogle.Common.ControlAdapters
{
    public class WebPartRenderControlAdapter : System.Web.UI.Adapters.ControlAdapter
    {
        protected override void Render(HtmlTextWriter writer)
        {
            WebPartZone wpz =
                Control as WebPartZone;
            if (wpz != null)
            {
                SPWebPartManager swpm = (SPWebPartManager)SPWebPartManager.GetCurrentWebPartManager(wpz.Page);
                bool inDisplayMode = !swpm.GetDisplayMode().AllowPageDesign;
                if (inDisplayMode && wpz.DisplayTitle.Contains("iGoogle"))
                {
                    // Render the WebPartZone
                    writer.Indent++;
                    // Render the web parts
                    if (wpz.WebParts.Count > 0)
                    {
                        WebPartCollection wpColl = new WebPartCollection(wpz.WebParts);
                        foreach (WebPart wp in wpColl)
                        {
                            wp.RenderControl(writer);
                        }
                    }
                    writer.Indent--;
                    writer.WriteLine();
                }
                else
                {
                    // If we are not editing the page --> render the web part as usual.
                    base.Render(writer);
                }
            }
        }
    }
}

As you can now see we have first added a line to get a reference to the current WebPartManager on the page which will enable use to get the state of the page and check if we are in display or edit mode.

    SPWebPartManager swpm = (SPWebPartManager)SPWebPartManager.GetCurrentWebPartManager(wpz.Page);

We are then able to set a boolean value to the state of the page.

    bool inDisplayMode = !swpm.GetDisplayMode().AllowPageDesign;

The final step is to wrap a new if statement around the render code which will control when the table removal is processed.

                if (inDisplayMode && wpz.DisplayTitle.Contains("iGoogle"))
                {
                    //Old code to go here
                }
                else
                {
                    // If we are not editing the page --> render the web part as usual.
                    base.Render(writer);
                }

When this code is run only WebPartZones with the iGoogle text value in the title will be rendered.

Adding the Widget Code Wrapper

Now that we have the basics sorted for our Control Adapter we now need to wrap our widget code around the render control and this can be done like it would be done in a normal WebPart.  We need to add the following code and replace it within the foreach loop around for each WebPart.

                        writer.WriteLine();
                        writer.Write("<div id='" + wp.ID + "' class='widget'>");
                            writer.Write("<div class='widget-head'>");
                                writer.Write("<a class='collapse'>collapse</a>");
                                writer.Write("<h3>" + wp.Title + "</h3>");
                                writer.Write("<a class='remove'>remove</a>");
                                writer.Write("<a class='edit'>edit</a>");
                            writer.Write("</div>");
                            writer.Write("<div class='widget-edit'>");
                            writer.Write("<input type='text' type='text' class='iColorPicker' id='color" + wp.ID + "' />");
                                writer.Write("<div class='clearfix'></div>");
                            writer.Write("</div>");
                            writer.Write("<div class='widget-content'>");
                                wp.RenderControl(writer);
                            writer.Write("</div>");
                        writer.Write("</div>");

Those who have been following the previous three posts will recognize the HTML from above.  I have use the writer object to inject the HTML and have also ensured that the ID of my widget wrapper div is generated from the current WebPart ID – (wp.ID), and the title of the WebPart is injected into the <H3> tag.

Summary

That wraps up part four of the iGoogle series.  The next post will be to integrate the code above into a SharePoint 2010 solution and include some of the extra pieces such as CSS to enable the this solution to come to life.  The final code for this Control Adapter is shown below.  Thanks for reading and all the positive feedback is greatly appreciated.

using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint.WebPartPages;
using WebPart = System.Web.UI.WebControls.WebParts.WebPart;
using WebPartZone = System.Web.UI.WebControls.WebParts.WebPartZone;

namespace LifeInSharePoint.iGoogle.Common.ControlAdapters
{
    public class WebPartRenderControlAdapter : System.Web.UI.Adapters.ControlAdapter
    {
        protected override void Render(HtmlTextWriter writer)
        {
            WebPartZone wpz =
                Control as WebPartZone;
            if (wpz != null)
            {
                SPWebPartManager swpm = (SPWebPartManager)SPWebPartManager.GetCurrentWebPartManager(wpz.Page);
                bool inDisplayMode = !swpm.GetDisplayMode().AllowPageDesign;
                if (inDisplayMode && wpz.DisplayTitle.Contains("iGoogle"))
                {
                    // Render the WebPartZone
                    writer.Indent++;
                    // Render the web parts
                    if (wpz.WebParts.Count > 0)
                    {
                        WebPartCollection wpColl = new WebPartCollection(wpz.WebParts);
                        foreach (WebPart wp in wpColl)
                        {
                            writer.WriteLine();
                            writer.Write("<div id='" + wp.ID + "' class='widget'>");
                            writer.Write("<div class='widget-head'>");
                            writer.Write("<a class='collapse'>collapse</a>");
                            writer.Write("<h3>" + wp.Title + "</h3>");
                            writer.Write("<a class='remove'>remove</a>");
                            writer.Write("<a class='edit'>edit</a>");
                            writer.Write("</div>");
                            writer.Write("<div class='widget-edit'>");
                            writer.Write("<input type='text' type='text' class='iColorPicker' id='color" + wp.ID + "' />");
                            writer.Write("<div class='clearfix'></div>");
                            writer.Write("</div>");
                            writer.Write("<div class='widget-content'>");
                            wp.RenderControl(writer);
                            writer.Write("</div>");
                            writer.Write("</div>");
                        }
                    }
                    writer.Indent--;
                    writer.WriteLine();
                }
                else
                {
                    // If we are editing the page --> render the web part as usual.
                    base.Render(writer);
                }
            }
        }
    }
}

writer.WriteLine();
writer.Write(“<div id=’” + wp.ID + “‘ class=’widget’>”);
writer.Write(“<div class=’widget-head’>”);
writer.Write(“<a class=’collapse’>collapse</a>”);
writer.Write(“<h3>” + removeFixedTitle(wp.Title) + “</h3>”);
writer.Write(“<a class=’remove’>remove</a>”);
writer.Write(“<a class=’edit’>edit</a>”);
writer.Write(“</div>”);
writer.Write(“<div class=’widget-edit’>”);
writer.Write(“<input type=’text’ type=’text’ class=’iColorPicker’ id=’color” + wp.ID + “‘ />”);
writer.Write(“<div class=’clearfix’></div>”);
writer.Write(“</div>”);
writer.Write(“<div class=’widget-content’>”);
wp.RenderControl(writer);
writer.Write(“</div>”);
writer.Write(“</div>”);

iGoogle UI for SharePoint – Part One : Overview, Concept, HTML Structure & Jquery Basics

iGoogle---Part-One

Series Content

  1.     Part One – Overview, Concept,  HTML Structure & jQuery Basics – Current Article
  2.     Part Two – Dragging, Dropping,  Sorting and Collapsing
  3.     Part Three – Saving WebPart states using Cookies
  4.     Part Four – Control Adapters
  5.     Part Five – SharePoint 2010 Integration
  6.     Part Six – Bringing it all together
  7.     Bonus – Saving WebPart States using the Client Object Model

Overview

This is the first in a series of posts which will explain how to create an iGoogle style interface for SharePoint 2010.  More and more clients are asking for an iGoogle or BBC Homepage style homepage for their intranets and out of the box in SharePoint 2010 there is no method to do this.  While you can drag and drop webparts in “Edit Mode” in a WebPart page, end user however is stuck on where to place their webparts on the page.  This series will aim to provide a mechanism where end users are able to take control of their page and make the SharePoint experience more personal.

There are many sites on the internet which have the ability to drag and drop components around the page and save their locations for your next visit.  Some of the most well known examples of this interface are:

iGoogle – http://www.google.com/ig?hl=

BBC Homepage – http://www.bbc.co.uk/

Both these sites give you the ability to drag and drop various widgets around the page.  You can also close widgets you do not want to see and minimise others to maximise space on the page.  This is the kind of interface that we are going to create for use in SharePoint using jQuery and some C# code.

The Plan

First, let’s list exactly what we’ll be creating here and what features it will have:

  • The interface will contain several widgets (WebParts).
  • Each widget can be collapsed and removed via controls on the page.
  • The widgets can be sorted into an unlimited number of columns.
  • WebParts will be have their rendering controlled via a control adapter which will modify their look and feel.
  • Widgets will have their location and states saved using cookies.
  • Creating a simple Visual Studio 2010 solution to deploy an example.

This post will provide an overview of what we are planning to build as well as getting some development environments configured for your own personal demos.

Getting Started

To get started in this post we will be creating a demo environment to ensure that the Javascript, HTML and CSS are all working together for use in future posts.  Initially we will not be touching SharePoint as it is not necessary at this stage.  Firstly we will need to create a base HTML template that will load a specific CSS stylesheet, images and Javascript libraries.

HTML

Below is the base HTML that will be used in our initial demo.  We have a wrapper div that surrounds three div columns called “Left”, “Middle” and “Right”.  Within each column is the widget HTML that will be used to wrap each WebPart.  Each widget has a wrapper div as well as a header and body content divs.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

	<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame. Remove this if you use the .htaccess -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />

	<title>Life In SharePoint - Drag and Drop - Part One</title>

	<link rel="stylesheet" type="text/css" media="all" href="css/style.css" />

</head>	

<body>

	<div class='wrapper'>

		<div class='column' id='left'>
			<div class='widget' id='111'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 1</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color111' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
			<div class='widget' id='2'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 2</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color2' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
		</div>		

		<div class='column' id='middle'>
			<div class='widget' id='3'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 3</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color3' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
			<div class='widget' id='4'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 4</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color4' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
		</div>		

		<div class='column' id='right'>
			<div class='widget' id='5'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 5</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color5' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
			<div class='widget' id='6'>
				<div class="widget-head">
					<a class='collapse'>collapse</a>
					<h3>Widget title 6</h3>
					<a class='remove'>remove</a>
					<a class='edit'>edit</a>
				</div>
				<div class="widget-edit">
					<input type='text' type="text" class="iColorPicker" id='color6' />
					<div class='clearfix'></div>
				</div>
				<div class="widget-content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem orci, ornare at malesuada a, pulvinar lobortis neque. Integer et felis vel augue suscipit vestibulum id nec nulla.</p>
				</div>
			</div>
		</div>
	</div>
	<div id='toolbox-wrapper'>

		<div id='toolbox-controls'>
			<div class='badge'></div>
			<p class="slide"><a href="#" class="btn-slide">Toolbox</a></p>
			<p class="reset"><a href="#" class="btn-reset">Reset Widgets</a></p>
		</div>
		<div class='column' id='toolbox'>

		</div>
		<div style='clear:both;'></div>
	</div>	

	<!-- Load the jQuery Libraries -->
	<script src="js/jquery-1.6.2.min.js" type="text/javascript"></script>
	<script src="js/jquery-ui-1.8.16.custom.min.js" type="text/javascript"></script>
	<script type="text/javascript" src="js/iColorPicker.js"></script>
	<script type="text/javascript" src="js/jquery.cookie.js"></script>
	<script type="text/javascript" src="js/jquery.corner.js"></script>
	<!-- script file to add your own JavaScript -->
	<script type="text/javascript" src="js/script.js"></script>	

</body>
</html>

As you can see the HTML is very simple but at the moment it will not look very attractive.  We have each of the widgets in their own Div and in the header we have three images which will be our “buttons” to control each widget.  On the left we have the collapse icon, next we have the edit icon and finally we have the remove icon.  Underneath the header we have an edit panel which will contain in this example some colour selections for the header bar which will be hidden in the css shown below.  So the next task is to now style the page and make it look neater.

CSS

The CSS is fairly simple and will be used for the SharePoint implementation.  We start with a global reset of the page to ensure that all DOM elements are reset.

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center,dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed,  figure, figcaption, footer, header, hgroup,  menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%;	font: inherit; vertical-align: baseline; } article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {	display: block;} body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } 

/** Base Body Styles **/
body{ background:#ddd; color:#000; font:14px Arial, Helvetica, "Trebuchet MS", sans-serif;}

h1,h2,h3,h4,h5,h6{ font-weight:bold; }
h1{ font-size:30px;}
h2{ font-size:24px;}
h3{ font-size:18px;}
h4{ font-size:14px;}
h5{ font-size:12px;}
h6{ font-size:10px;}

a{ text-decoration:none; }
a:active, a:visited { color: #607890; }
a:hover { color: #036; }

.wrapper
{
	clear:both;
}

.column
{
	float:left;
	width:300px;
	margin:10px;
	min-height:100px;
}

.column .widget {
	border:1px solid #ddd;
	margin:5px;
	width:288px;
	float:left;
	background-color:#fff;
}

.widget-head
{
	background-color:#60b51c;
	padding:5px;
	margin:5px 5px 5px 5px;
	height:20px;
}

.widget-head h3
{
	float:left;
    padding: 0 5px;
	color:#fff;
	font-family: verdana, arial;
	font-weight:normal;
	font-size:1em;
}

.widget-head a.remove  {
    float: right;
    display: inline;
    background: url(../images/controls.png) no-repeat -14px 0;
    width: 14px;
    height: 14px;
    margin: 3px 4px 0px 0;
    text-indent: -9999em;
    outline: none;
}  

.widget-head a.edit  {
    float: right;
    display: inline;
    background: url(../images/controls.png) no-repeat -28px 0;
    width: 14px;
    height: 14px;
    margin: 3px 4px 0px 0;
    text-indent: -9999em;
    outline: none;
}  

.widget-head a.collapse  {
    float: left;
    display: inline;
    background: url(../images/controls.png) no-repeat 0;
    width: 14px;
    height: 14px;
    text-indent: -9999em;
    margin: 3px 0 0px 4px;
    outline: none;
}
.widget-edit
{
	background-color:#efefef;
	border:1px solid #ddd;
	padding:5px;
	margin:0px 5px 5px 5px;
	display:none;
}
.widget-edit ul
{

}
.widget-edit ul.colors li {
    width: 20px;
    height: 20px;
    border: 1px solid #EEE;
    float: left;
    display: inline;
    margin: 0 5px 0 0;
    cursor: pointer;
	background-color:red;
}  

.widget-content
{

	padding:5px;
}
.widget-placeholder
{
	border:2px dashed #999;
	margin:5px;
	width:283px;
	float:left;
}

#toolbox-wrapper
{
	clear:both;
	width:900px;
	margin:10px;
}

#toolbox-controls
{
	float:left;
}

#toolbox
{
	background-color:#fff;
	padding:5px;
	width:930px;
	min-height:auto;
	margin:0px;
	margin-top:-1px;
	border:1px solid #ddd;
	float:left;
	position:relative;
}

#toolbox .widget
{
	float:left;
}

#toolbox .widget-content, #toolbox .widget-head .collapse, #toolbox .widget-head .remove, #toolbox .widget-head .edit
{
	display:none;
}

.badge {
	background-image: url('../images/badge.png');
	width:20px;
	height:17px;
	float:right;
	color:#fff;
	padding-top:4px;
	text-align:center;
	font-size:10px;
	font-weight:bold;
	position:absolute;
	z-index:10;
	margin-left:-5px;
	font-family:verdana;
}

.slide {
                margin: 5px 5px 0px 0px;
                background-color:#fff;
                float:left;
                color:#fff;
				border:1px solid #ddd;
				position:relative;
}

.slide a, .slide a:active, .slide a:visited
{
                float:left;
                color:#fff;
                padding: 5px;
				margin:5px;
				background-color:#187069;
}

.reset a, .reset a:active, .reset a:visited
{
                float:left;
                color:#fff;
                padding: 5px;
				margin:5px;
				background-color:#082167;
}

.reset {
				margin: 5px 5px 0px 5px;
                background-color:#fff;
                float:left;
                color:#fff;
				border:1px solid #ddd;
				position:relative;
}

The CSS helps style the page into three even columns and each of the widgets are styled with some buttons and styled headers.

Javascript

To provide the cool functionality, we will need to get the latest jQuery libraries and jQuery plugins. We will also create our own custom javascript file which we will be used to store our script.  The versions that we are using are below with links to download them.

Our own script.js file at this stage will contain only a couple of lines of code to test that jQuery is working;

jQuery(document).ready(function(){
	alert('Jquery is Working');
});

Images

The images for the close and collapse buttons we will use a simple sprite which has a close, max and min symbols on it.

Live Demo

A live demo of the base structure can be found here.

Summary

In this post we have outlined what we will be covering and have managed to get a demo environment working for the next phase.  We will add some jQuery functionality and make our page come alive in the next posts.  I hope this post has been useful and please leave some comments about what you would like to see in future posts.