Setting up multiple calendars for meeting room bookings & prevent double booking

31. March 2009 16:57 by Eric in calendar, Event Handlers  //  Tags: ,   //   Comments (3)

A common usage for Sharepoint is meeting room bookings.

This article will provide one way of elegantly handling this scenario with some simple configuration but then we'll take it a step further by getting under the hood of WSS and adding some validation so that a room can not be double booked.

 

Add a calendar

Firstly we need to add the calendar list we are going to use.

On the parent page of where the calendar will reside use the site actions menu to create a new Calendar.

 

Give the calendar a descriptive name such as Book Meeting Rooms.

 

Add a new column

From the calendar settings choose "Create column" under the Columns options.

Name this column "Meeting Room" of type "Choice" and add some entries for each meeting room name.

 

This column will be used as a filter so that users can select a specific meeting room view.

 

Create Views

From the settings menu on the calendar choose create view.

 

Click Calendar View.

Name your view after one of the meeting rooms and add filtering criteria as below.

 

Repeat these steps until you have created a view for all Meeting Rooms.

Now the user can select which room they would like to see the availability for by selecting from the view drop down list in the top right of the calendar page.

 

One last touch - Displaying the room name in Month View.

When you are in month view by default the Title of the entry is visible.

  

The calendar month view only displays the title column by default.

In week view and day view you can select a second column to be displayed but in month view for some strange reason this is not possible.

The trick is to create a new calculated column that is a combination of the fields you would like to see.

In this example the Meeting room name followed by the title in a column I have called Summary.

 Then go into the calendar view and select Summary as the Month View Title.

 Now the month view displays the meeting room as well as the title

  

 Stay tuned for part 2 where we get technical and look at event handlers in Sharepoint!!

 

How to Prevent Duplicate Bookings in a Sharepoint Calendar List

We recently had a customer request a feature addition to the Calendar List.  The feature they wanted to add would prevent the user from being able to book a meeting room for a time in which the meeting room was already used.  For more information on adding a Meeting Room column, see the previous article.  For example, we have made a booking for the Earth Room on 25/9/08 at 4:00pm:

 

 

Attempting to create a new item on 25/9/08 from 4:30pm to 5:00pm can be done:

 

 This 'How To' will show you how to prevent this from happening.


Create an Event Listener
1.     Open Visual Studio and create a new class library project.
2.     Add a reference to Microsoft.Sharepoint.dll (the dll can be found in %Program Files%\Common Files\Microsoft Shared\web server extensions\12\ISAPI on the the server running WSS).
3.     Add a new code file and name it PreventDoubleBooking.cs.

 

 4.     In PreventDoubleBooking.cs, add the following code:

using System;
using Microsoft.SharePoint;


namespace Webcoda.WSS.Calendar.Events
{
    class PreventDoubleBooking: SPItemEventReceiver
    {
        /// <summary>
        /// This event is triggered when the user adds a new item
        /// </summary>
        /// <param name="properties"></param>
        public override void ItemAdding(SPItemEventProperties properties)
        {
            //Our query string variable
            string strQuery = null;

            try
            {
                //Get the Sharepoint site instance
                using (SPWeb oWebsite = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
                {
                    
                    //Get the collection of properties for the Booking item
                    SPListItemCollection collItems = oWebsite.Lists[properties.ListTitle].Items;

                    //Get the Calendar List that we will be querying against
                    SPList calendar = oWebsite.Lists[properties.ListId];

                    //Get the internal name of the fields we are querying. 
                    //These are required for the CAML query
                    string start_internal = collItems.List.Fields["Start Time"].InternalName;
                    string end_internal = collItems.List.Fields["End Time"].InternalName;
                    string MeetingRoom_Internal = collItems.List.Fields["Meeting Room"].InternalName;

                    //Get the query string parameters
                    string start_str = properties.AfterProperties[start_internal].ToString();
                    string end_str = properties.AfterProperties[end_internal].ToString();
                    string MeetingRoom_str = properties.AfterProperties[MeetingRoom_Internal].ToString();

                    //Construct a CAML query
                    SPQuery query = new SPQuery();

                    //Create the CAML query string that checks to see if the booking we are attemping
                    //to add will overlap any existing bookings
                    strQuery = string.Format(@"

    <Where>
    
        <And>
            <Or>
            
                <Or>
                    <And>
                       <Leq>
                          <FieldRef Name='EventDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                       </Leq>

                       <Gt>
                          <FieldRef Name='EndDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                       </Gt>
                    </And>

                    <And>
                       <Lt>
                          <FieldRef Name='EventDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                       </Lt>

                       <Geq>
                          <FieldRef Name='EndDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                       </Geq>
                    </And>
                </Or>
                
                <Or>
                    <And>
                       <Leq>
                          <FieldRef Name='EventDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                       </Leq>

                       <Geq>
                          <FieldRef Name='EndDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                       </Geq>
                    </And>

                    <And>
                       <Geq>
                          <FieldRef Name='EventDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                       </Geq>

                       <Leq>
                          <FieldRef Name='EndDate' />
                          <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                       </Leq>
                    </And>
                </Or>
                
            </Or>
        
            <Eq>
                <FieldRef Name='Meeting_x0020_Room' />
                <Value Type='Choice'>{2}</Value>
            </Eq>
            
        </And>
        
    </Where>
    <OrderBy>
        <FieldRef Name='EventDate' />
    </OrderBy>
", start_str, end_str, MeetingRoom_str);

                    //Set the query string for the SPQuery object
                    query.Query = strQuery;

                    //Execute the query against the Calendar List
                    SPListItemCollection existing_events = calendar.GetItems(query);
                    
                    //Check to see if the query returned any overlapping bookings
                    if (existing_events.Count > 0)
                    {
                        //Cancels the ItemAdd action and redirects to error page
                        properties.Cancel = true;

                        //Edit the error message that will display on the error page
                        properties.ErrorMessage += "This booking cannot be made because of one or more bookings in conflict. <BR><BR>";

                        //Here you can loop through the results of the query
                        //foreach (SPListItem oListItem in existing_events)
                        //{
                        //   ....
                        //}

                        properties.ErrorMessage += "Please go back and schedule a new time.";
                    }
                    
                }
            }
            catch (Exception ex)
            {
                //Cancels the ItemAdd action and redirects to error page
                properties.Cancel = true;

                //Edit the error message that will display on the error page
                properties.ErrorMessage = "Error looking for booking conflicts: " + ex.Message;
            }
          
        }

        /// <summary>
        /// This event is triggered when the user edits an calendar item
        /// </summary>
        /// <param name="properties"></param>
        public override void ItemUpdating(SPItemEventProperties properties) {

            string strQuery = null;

            try {

                //Get the Sharepoint site instance
                using (SPWeb oWebsite = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl)) {

                    //Get the collection of properties for the Booking item
                    SPListItemCollection collItems = oWebsite.Lists[properties.ListTitle].Items;

                    //Get the Calendar List that we will be querying against
                    SPList calendar = oWebsite.Lists[properties.ListId];

                    //Get the internal name of the fields we are querying. 
                    //These are required for the CAML query
                    string start_internal = collItems.List.Fields["Start Time"].InternalName;
                    string end_internal = collItems.List.Fields["End Time"].InternalName;
                    string MeetingRoom_Internal = collItems.List.Fields["Meeting Room"].InternalName;
                    string guid_internal = collItems.List.Fields["GUID"].InternalName;

                    //Get the query string parameters
                    string start_str = properties.AfterProperties[start_internal].ToString();
                    string end_str = properties.AfterProperties[end_internal].ToString();
                    string MeetingRoom_str = properties.AfterProperties[MeetingRoom_Internal].ToString();
                    string guid_str = properties.AfterProperties[guid_internal].ToString();

                    //Construct a CAML query
                    SPQuery query = new SPQuery();

                    //Create the CAML query string that checks to see if the booking we are attemping
                    //to change will overlap any existing bookings, OTHER THAN ITSELF
                    strQuery = string.Format(@"

    <Where>
        <And>
        
            <And>
                <Or>
                
                    <Or>
                        <And>
                           <Leq>
                              <FieldRef Name='EventDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                           </Leq>

                           <Gt>
                              <FieldRef Name='EndDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                           </Gt>
                        </And>

                        <And>
                           <Lt>
                              <FieldRef Name='EventDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                           </Lt>

                           <Geq>
                              <FieldRef Name='EndDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                           </Geq>
                        </And>
                    </Or>
                    
                    <Or>
                        <And>
                           <Leq>
                              <FieldRef Name='EventDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                           </Leq>

                           <Geq>
                              <FieldRef Name='EndDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                           </Geq>
                        </And>

                        <And>
                           <Geq>
                              <FieldRef Name='EventDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{0}</Value>
                           </Geq>

                           <Leq>
                              <FieldRef Name='EndDate' />
                              <Value Type='DateTime' IncludeTimeValue='TRUE'>{1}</Value>
                           </Leq>
                        </And>
                    </Or>
                    
                </Or>
            
                <Eq>
                    <FieldRef Name='Meeting_x0020_Room' />
                    <Value Type='Choice'>{2}</Value>
                </Eq>
                
            </And>
        
            <Neq>
                <FieldRef Name='GUID' />
                <Value Type='GUID'>{3}</Value>
            </Neq>
        
        </And>
        
    </Where>
    
    <OrderBy>
        <FieldRef Name='EventDate' />
    </OrderBy>
", start_str, end_str, MeetingRoom_str, guid_str);

                    //Set the query string for the SPQuery object
                    query.Query = strQuery;

                    //Execute the query against the Calendar List
                    SPListItemCollection existing_events = calendar.GetItems(query);

                    //Check to see if the query returned any overlapping bookings
                    if (existing_events.Count > 0) {

                        //Cancels the ItemAdd action and redirects to error page
                        properties.Cancel = true;

                        //Edit the error message that will display on the error page
                        properties.ErrorMessage += "This booking cannot be made because of one or more bookings in conflict. <BR><BR>";

                        //Here you can loop through the results of the query
                        //foreach (SPListItem oListItem in existing_events)
                        //{
                        //   ....
                        //}

                        properties.ErrorMessage += "Please go back and schedule a new time.";
                    }

                }
            } catch (Exception ex) {

                //Cancels the ItemAdd action and redirects to error page
                properties.Cancel = true;

                //Edit the error message that will display on the error page
                properties.ErrorMessage = "Error looking for booking conflicts: " + ex.Message;
            }

        }

        
    }
}

Register Assembly into GAC

We want the WSS server to call our event code instead of the built-in code that allows us to make a double booking.  In order for our new events to be available to the WSS server, we need to register our assembly into the GAC.  For this to happen, the assembly being registered must be strongly typed and signed. 

1.    To do this, follow the instructions here:  http://www.dotnetspider.com/resources/1620-Strong-Naming-And-Installing-Assembly-into-GAC.aspx.  Once you have added the Key File into the project, your solution should look similar to this:

 

 2.    When you get to the “Installing Assembly into the GAC” section, instead of running the gacutil.exe command line utility, you can simply drag your compiled project assembly into the GAC:

 

Register Events

Now that the assembly is registered into the GAC, we still need to register the events in the WSS Server.  To do this, we can use a tool called EventHandlerExplorer.  Download, source code, and demo instructions can be found here:  http://www.u2u.info/Blogs/Patrick/Lists/Posts/Post.aspx?ID=1547.  

1.    Once you’ve downloaded the tool, run the EventHandlerExplorer.exe on the WSS server.  In the “Enter URL for the site collection you want to explore” field, type the URL of your Sharepoint site, then click “Explore”.  If you get an “Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))” error, then you are probably not running the EventHandlerExplorer app in the context of a Site Collection Administrator account. On the WSS Server, go to Central Administration -> Application Management -> Site Collection Administrators and add yourself as the Secondary site collection administrator. Be sure that you add yourself to the correct site collection.  Alternatively, run the EventHandlerExplorer as the person who is listed as a Site Collection Administrator (right-click on EventHandlerExplorer.exe -> Run as...).

 

 

If you get through without an “Access is dened…” error, you should be able to expand your site, then subsite until you get to the List that contains your Calendar.  In our case, we have a subsite called “Sandbox” and the List containing the Calendar is called “Book Meeting Room”.  So, we would expand the Sandbox tree, then expand the Lists tree node to expose the “Items” node and “Event Handlers” node.

 

To see which events are registered for that list, you must double-click the “Event Handlers” node.  At this point, however, you probably won’t have any events registered and therefore double-clicking will do nothing.

With the Book Meeting Room node highlighted, click the Load Assembly button, and then select the .dll we’ve created.  Then, in the Class drop down, select PreventDoubleBooking.  For sequence, type “0”.  I think this only comes into play if you want to have multiple delegates for the same event, but I’m not 100% sure.  And finally, for Event Type, select ItemAdding.  The values you selected should look like this:

 

Then click the “Add Handler” button.  Once that event has been registered, change the Event Type to ItemUpdating, then click the “Add Handler” button again.  Even though you just registered two events, the Event Handlers node doesn’t show a “plus” sign next to it, indicating it has child nodes.  This is because you must first double-click the Event Handlers node which will then show the “plus” sign.  Expand this node to see the two Events you just registered.

 

Testing Our Code

That’s it!  You’re finished!  Now let’s test our changes.  To test our code, we’re going to book a meeting room for an hour at 4pm on 26/9 and then try to book the same meeting room at 4:30pm.

 

 But look what happens when we try to add the booking at 4:30pm for the same meeting room on the same day.

 

An error is generated and the booking is not made!

 

Download 

You can download the entire project here:  Webcoda_PreventDuplicateBookings.zip (5.41 mb)

 

More Information

Any changes to the code you make will require you to recompile the assembly, reinstall your assembly into the GAC, and finally reregister your events.  If you would like to change the query used in the sample code, a tool that may help is U2U Caml Query Builder which can be found here:  http://www.u2u.info/Blogs/karine/Lists/Posts/Post.aspx?ID=12.  To get familiar with the Microsoft.SharePoint namespace, here is a link to the documentation you will need:  http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.aspx.

Also, here is a link to “Getting Started with Programmatically Customizing a SharePoint Web Site in Visual Studio”:  http://msdn.microsoft.com/en-us/library/ms479423.aspx.

How to customize a Sharepoint theme

31. March 2009 16:29 by sashashev in reskining  //  Tags: , ,   //   Comments (0)
In this article, we are going to explore how to modify an existing Sharepoint theme.  This process is pretty straight forward and this article provides a few tips and tricks along the way.  Please note this process requires some previous CSS experience.

Copy the theme directory you want to customize

 

1.    Navigate to THEMES folder:  %Program Files%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES.  Copy theme folder you want to modify and rename the copied folder.  Here, we copied the BREEZE2 folder and renamed it to DERWENT.

 

Update the copied files with the new theme information

2.     Navigate into the new theme folder and rename the .INF to the name of the new theme.  Here we renamed BREEZE2.INF to DERWENT.INF.

 

 3.     Open the INF that was just renamed and update all the entries with the new name of your theme.  A global search and replace (Ctrl+H in most editors) will take care of this easily for you.  Here we changed all the Breeze2 entries to Derwent.

 

 4.    Next, we need to add the new theme into the XML file so that Sharepoint knows it exists.  To do this, we are going to edit the SPTHEMES.XML file located in C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033.   Add the following <Templates> entry into the XML file:

For now, leave the <Thumbnail> and <Preview> tags as they are, we will get to these later.  They simply specify which images will show up when the user is previewing a theme.  Since we don’t have a screenshot of our new theme yet, we do not have anything to put here.  Your XML file should look similar to the one below:

Make CSS changes to the theme

5.    Next, we are going to edit the theme.css style sheet located in the new theme folder (for example, C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES\DERWENT\theme.css).

This is where all of the hard work comes in.  In order to work more efficiently, it is a good idea to save a couple of the Sharepoint pages locally (File -> Save As… from IE, select Webpage, complete (*.htm;*.html) for Save as type).  

 

This will allow you see the CSS changes on a local page without have to perform an iisreset (See Step 6) on the server.

For the pages I saved locally, the .htm files seemed to link to “Derw1011-65001.css” style sheet instead of the expected theme.css file.  It turns out the “Derw1011-65001.css” is actually a copy of the theme.css style sheet.  (The “65001” in the filename comes from the codepage setting in the .INF file).  So when you save a page locally, it will also save the “Derw1011-65001.css” file since the .htm file links to this file.  Edit the “Derw1011-65001.css” file locally and once you’re happy with the changes, copy the contents of this CSS file into the theme.css file located on the server (after making a backup, of course).

Microsoft has provided some documentation (http://msdn.microsoft.com/en-us/library/ms438349.aspx) on the CSS classes used in core.css which shares some common CSS classes with theme.css, however I found it easier to examine the CSS information using IE Web Developer or Firebug.

Force Sharepoint to recognize changes

6.    Now that you finished with your CSS changes, you need to perform an iisreset from the command prompt in order for the Sharepoint server to recognize the changes.   

To do this, start the command prompt (Start -> Run… -> type cmd -> Enter).

   Type iisreset, then hit enter. 

Note: be careful performing this command on a server in a production environment as it will sever any active connections to all of the websites being hosted on the server.

Apply customized theme to site

7.    Next, we are going to apply the newly created theme.  Open a browser and navigate to the Sharepoint page that you want to apply the new theme to.  Click Site Actions -> Site Settings.

 Once in Site Settings, click “Site Theme” from the Look and Feel section:

This will bring up a list of all available themes that you can apply to the site.  You should see the theme we added in the previous steps.  Below, you can see the Derwent theme we added in the example:

Highlight the theme you added, and click apply. 

Update preview image

8.    Notice the Preview image shown to the left of the list of themes.  You will still see the preview image of the copied theme.

In order to update that image with a preview of our own theme, we need to grab a screenshot of our new theme and add it to the proper location.

Navigate to the home page of the site you changed the theme for.  In our example, we would navigate to the My Home page.

Take a screenshot of this page and resize it to about 350 x 230 pixels using your favorite image editor (i.e. SnagIt). 

Save the screenshot in a standard format (.gif, .jpg, or .png).


9.    Next, we need to add the image to the Sharepoint server so that the image will appear when a user is attempting to select a theme.

Copy the screenshot image you created in Step 8 into %Program Files%\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES.  Here you can see I’ve named my screenshot Derwent_Preview.gif:

 10.     Repeat Step 4, updating the <Preview> and <Thumbnail> attributes in the SPTHEMES.XML file with the new name of your preview image, as shown below:

11.     Repeat Step 6 to complete the changes on the Sharepoint server.

12.    Next, we need to see our changes on the Sharepoint site.  Repeat Step 7 to navigate to the Site Themes Settings Page.

Notice that the image you just created isn’t showing up in the preview?  In order to see the changes you just made to the theme, you must first apply another theme (any theme listed - it doesn’t matter which one), and then reapply the new theme. This is required to see ANY changes you have made to theme, if you already have the theme applied.

Tips for Installing MOSS 2007 (3.0) on Windows Server 2008

31. March 2009 16:17 by sashashev in Server Configuration  //  Tags: ,   //   Comments (0)

Slipstream MOSS 3.0 Service Pack 1

At the time this article was written, Microsoft has only released a version of the MOSS 3.0 installer package without integrating the already available MOSS 3.0 SP1.  When you attempt to install MOSS 3.0 using the installer package on the Windows Server 2008, you will get an error from the Program Compatibility Assistant stating that a service pack is required in order to install WSS 3.0.  To circumvent this, we need to slipstream the SP1 bits into the MOSS 3.0 installer files.  Basically, this involves extracting the SP1 EXE files into the Upgrades folder of the MOSS 3.0 installer files.  Then, running the MOSS 3.0 installation should work.

How To

Matt Hester has compiled information on this issue and come out with a very helpful screencast which takes the user through a step-by-step process of slipstreaming SP1 into the installation.  Before beginning this video, make sure you have a local copy of the MOSS 3.0 installation files as we will need to add files to the Upgrades folder.  The screencast can be found here:

http://blogs.technet.com/matthewms/archive/2008/02/15/screencast-how-to-install-office-sharepoint-server-2007-on-windows-server-2008.aspx.

Error Using SharePoint Products and Technologies Configuration Wizard

After installing MOSS 3.0, you should be taken to the SharePoint Products and Technologies Configuration Wizard.  After specifying the Database Server, Database Name, Database Account, and Database Password, you may encounter an error stating “Internet Information Service is not installed. You must have Internet Information Service installed in order to use the Sharepoint Products and Technologies Configuration Wizard.”  If you receive this error, read the following two sections.

Error Source

If you used the Add Roles Wizard to install IIS 7.0 (as we did in Matt Hester’s How To),  we were given the default installation containing a minimum set of role services. We will need additional IIS 7.0 role services, such as IIS6 Metabase which provides a legacy interface to applications requiring IIS 6 backward compatibility.

Install Additional Features

We can use the following script to install available feature packages, namely IIS-Metabase.  Running the following script will give us the full IIS 7.0 installation, which installs all available feature packages.  If there are feature packages you do not need, you should change the script to install only the packages you require.

Code Snippet:

Excerpted from:

http://technet.microsoft.com/en-us/library/cc730716.aspx

Administrator Privileges in Windows Server 2008

31. March 2009 16:14 by sashashev in Server Configuration  //  Tags: ,   //   Comments (0)
By default, you do not have Administrative privileges if you're logged on as a user (other than the built-in Administrator account) even if this user was added to the local Administrators group on the machine (this is a new security feature in Windows Server®2008 with-IIS 7.0, called LUA).

Make sure to either log-on as the built-in Administrator account, or explicitly invoke applications as the built-in Administrator as needed, using the "runas" cmd-line tool. For example, to launch notepad.exe you could run this command: "runas /user:administrator notepad.exe".

You will be prompted for the password of the Administrator account. It is useful to have a cmd-box shell that is already elevated, by running "runas /user:administrator cmd.exe".

Every application you run from that cmd-box will be elevated as well, and you will not need to use the "runas" syntax from that cmd-box.

Excerpted from:

http://learn.iis.net/page.aspx/126/how-to-use-metabase-compatibility-with-iis-7/

Access denied entering Shared Services

31. March 2009 16:12 by sashashev in Shared Services  //  Tags: , ,   //   Comments (0)

There are 2 types of Access Denied errors when trying to access Shared Services.

This first solution deals with not being able to access Shared Services at all and No 2 deals with being able to get in but when you click on anything like "User Profiles and Properties" you get Access Denied.

 1.

If this happens to you go to Site Collection Administrators in Application Management in Central Admin.

Change both or just the secondary administrators in here to your user for the Shared Service site collection.

I found this solution here:

http://social.technet.microsoft.com/forums/en-US/sharepointadmin/thread/f73c76be-714a-4d00-9a05-786a17c03bca

 

2.

 



Assign yourself lot's of permissions. Go on. You know you deserve it!

Uploading Images in Sharepoint Content made easier.

31. March 2009 16:04 by sashashev in CMS, Third Party Tools  //  Tags: , ,   //   Comments (0)

For anyone who has ever had to edit content in Sharepoint and asked themselves why is it so hard to insert an image, this is for you.

By default to insert an image into a wiki or blog for example, you have to do something like upload images to a Sharepoint picture library and link to image by copying and pasting a URL to the Image. 

 

Does Microsoft know what year this is?

Anyway there is a Solution but it requires a little effort. The telerik MOSS editor which also comes in free lite version.

 

See - http://www.telerik.com/products/sharepoint/radeditor.aspx

Uing the RAD editor you can browse to image folders directly while editing content and create folders for storing images on the fly.

A few gotchas to watch:

Make sure you follow the installation instructions that come with the download package as the online instructions seem to be out of date.

You need to have either AJAX or .Net 3.5 installed on the server.

You dont need to edit the masterpages as the instructions say you do.

To modfiy properties of the editor you need to modify the ListConfigFile.xml located in
/Program Files/Common Files/Microsoft Shared/web server extensions/wpresources/RadEditorSharePoint/5.2.3.0__1f131a624888eeed/Resources/

(ListConfig as opposed to Config.xml as most content is kept in Lists. Lists, Wikis, Blogs, etc. are Sharepoint Lists)

Missing items in “Site Actions” menu

31. March 2009 15:58 by sashashev in CMS  //  Tags: , , ,   //   Comments (0)
If you are expecting to see more items in your “Site Actions” menu such as the “Navigation” menu item then you probably need to activate “Office Sharepoint Server Publishing” from Site Settings > Site Features .

Before

After

The new menu items that appear allow you to control Navigation and add and edit CMS pages.

You may also notice you have different items in your top menu which is another topic that we will discuss when we talk about Sharepoint navigation.

Creating custom landing pages in SharePoint Part 1 - TheTable of Contents Webpart

The mission: Create a default landing page for each publishing site to aid in navigation.

The landing page should contain 2 sections.

  1. A section that lists all sites directly below the site you are on (1 level)
  2. A section that lists all the pages in the pages folder.
To pretty things up we may want to show images and/or descriptions for sites and pages.
The images and descriptions should be pulled from the image and description field the user enters when creating the new subsite or page.

Method No 1- Using the Table Of Contents Webpart

Note: Please read conclusion of this article to see why this solution didn't meet my requirements.

An obvious place to start is to see what we can do using the built in Web Part purpose built for our task.

The table of contents webpart provides a quick an easy method to display a Table of Contents. (Believe it or not)

It has cool features such as..

  1. Pick from which level to start the TOC
  2. Style your TOC 
  3. How many levels to show


More on the TOC web part can be found here and here

As we want this page to be a template with the contents starting from the current site we use SharePoint Designer.

Page templates reside in the same folder as Masterpages. 

_catalogs >  masterpage

  

To keep things seperated I have created 2 subfolders. Custom > Layouts and my new layout page is called WelcomeTOC.aspx.

I created this page by making a copy of one of the existing Welcome Pages.(I can't remember which but any layout will do)

I then added a TableOfContentsWebPart into the first WebpartZone. I'm not sure whether you need the ZoneTemplate tags.

<ZoneTemplate>
<PublishingWebControls:TableOfContentsWebPart runat="server" 
Description="" 
NoDefaultStyle="" 
AllowZoneChange="True" 
ViewContentTypeId="" 
AllowHide="True" 
ChromeType="None" 
UseSQLDataSourcePaging="True" 
AllowRemove="True" 
Dir="Default" 
AllowConnect="True" 
PageSize="-1" 
HelpMode="Modeless" 
Title="Table of Contents" 
PartOrder="1" 
ID="g_c8cdaea8_bb45_4983_afc7_bfcd74aa22dd" 
MissingAssembly="Cannot import this Web Part." 
FrameType="None" 
IsVisible="True" 
DetailLink="" 
ZoneID="TopColumnZone" 
ConnectionID="00000000-0000-0000-0000-000000000000" 
PartImageSmall="" 
PartImageLarge="" 
HelpLink="/_layouts/help.aspx" 
ShowWithSampleData="False" 
ExportMode="All" 
IsIncludedFilter="" 
HelpUrl="/_layouts/help.aspx" 
DataSourceID="" 
IsIncluded="True" 
ExportControlledProperties="True" 
FrameState="Normal" 
AllowEdit="True" 
AllowMinimize="True" 
SuppressWebPartChrome="False" 
AnchorLocation=""
__MarkupType="vsattributemarkup"
__WebPartId="{C8CDAEA8-BB45-4983-AFC7-BFCD74AA22DD}"
WebPart="true"
Height=""
Width=""
LevelsToShow="1"
DisplayColumns="2"
Level1Style="Vertical with descriptions">
<DataFields>
</DataFields>
<SampleData>
<Levels>
<Level LevelNumber="1" Path="/Site1" Title="Site 1" BeginColumn="true">
<Item LevelNumber="1" Path="/Page1" Title="Page 1" />
<Item LevelNumber="1" Path="/Page2" Title="Page 2" />
<Item LevelNumber="1" Path="/Page3" Title="Page 3" />
</Level>
<Level LevelNumber="1" Path="/Site2" Title="Site 2" BeginColumn="true">
<Item LevelNumber="1" Path="/Page1" Title="Page 1" />
<Item LevelNumber="1" Path="/Page2" Title="Page 2" />
<Item LevelNumber="1" Path="/Page3" Title="Page 3" />
</Level>
</Levels>
</SampleData><Xsl>
<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime" exclude-result-prefixes="xsl cmswrt x"> 
<xsl:import href="/Style%20Library/XSL%20Style%20Sheets/Header.xsl" /> 
<xsl:import href="/Style%20Library/XSL%20Style%20Sheets/LevelStyle.xsl" /> 
<xsl:import href="/Style%20Library/XSL%20Style%20Sheets/TableOfContentsMain.xsl" /> </xsl:stylesheet></Xsl>
</PublishingWebControls:TableOfContentsWebPart>
</ZoneTemplate>

The important thing to note here is the

AnchorLocation="" attribute.
This sets the starting location of our links to the current site.
Customising the layout

Customising the layout is similar to customising the layout for other web parts such as the RSS reader or Custom Query web part. You need to do some XSLT.

You can edit 3 files

  • Header.xsl
  • LevelStyle.xsl
  • TableOfContentsMain.xsl

These files reside in Style Library > XSL Style Sheets

  

You can read more info here -

http://panvega.wordpress.com/2009/02/11/customizing-styles-of-table-of-contents-webpart-toc/#more-920

 

Conclusion

Basically you can alter the layout but the TOC web part is very limited as it only outputs the @Title, @Description, @LevelNumber and@Path.

This is OK if you just want some basic text but this won't cover our needs to display a possible image for each site or page listed.

A neat trick for verifying this is to add the following to your XSLT transformation in the LevelStyle.xsl file.

This will output the raw XML in between the <rawdata> tags.

That way you can see all the data you have to play with. I suspect this will work in the other xsl files in Sharepoint.

   <xsl:template name="ShowAll" match="Level[@LevelTemplate='ShowAll']">
  <rawdata>
    <xsl:copy-of select="*"/>
    </rawdata>
</xsl:template>

When you view the source of your page you will something like..

<rawdata>
<Item Description="I am happy to announce " LevelNumber="1" Path="/News/Pages/mypage.aspx" Title="Title of my page"></Item>
</rawdata>

Further reading:
Customizing Styles of Summary Links, Table of Contents, and Content Query Web Parts

Webcoda, SharePoint Consultants & Web Development

SharePoint Development Sydney is a crack team of SharePoint Consultants and SharePoint Developers.

We can't tell you their names or show their faces on TV but if you need a SharePoint job done right, call them on +61 2 9370 3602 or email us at info@sharepointsydney.com.au

Persecuted by the Government and shunned by society they developed their SharePoint skills in back streets and labor camps where other programmers wouldn't dare to tread. 

During a trek through the Himalayas they stumpled upon the fabled Mossy Yak who shared his SharePoint knowledge of how to attain Nirvana through a series of Workflows and Event Handlers. Their mission is to spread this knowledge through-out the world to bring peace, harmony and document version control to all .

 

Month List