in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

helloitsliam's blog

  • Blog URL Changing!!

    Well what can I say. After hosting my blog here for the past year I thought it was time to move it to a SharePoint based blog (as this is the technology I focus on). I want to thank Dustin and the team for all the efforts they have put in to restore the system back to how it was. For me personally the amount of effort involved in putting a year's worth of blog posts back onto the community server will take too much time. Now I have a SharePoint based blog it is easier to post all my images and posts here. Keep an eye over the next few weeks or so and all the old posts should be back!!! I will be keeping this blog to host any of the posts I can get back, but my new stuff will now be at the new blog address below.

    I am also testing the CKS:EBE (Community Kit for SharePoint: Enhanced Blog Version) here as well. So check back soon to see my newly skinned blog!! A big thanks to Vince and the CKS:EBE Team for this. :-)

    The new blog link is: http://www.helloitsliam.com

    If you wish to subscribe to the blog please remember to use: http://feeds.feedburner.com/helloitsliam that way if I move it again it will still work. :-)

  • MOSS2007 – JavaScript Item Menus Part 3 (Real World)

    One of the things I have been asked recently has been to do with changing the “Email Link To” menu item. Sometimes this link works, sometimes it doesn’t. Before we can look at changing it let’s take a look at the code that is used to create this link. The code block can be found within the “AddSendSubMenu” function within the “CORE.JS” file. Here is the code block in full:

    Now let’s step through it line by line. The first line:

    This line is used to check that the current user has the correct permissions, i.e. Permission to the document or item. Next we simply populate the local variable “strDisplayText” with the globally declared variable from the top of the “CORE.JS”.

    Now we get to the interesting bits. Each list and library when viewed within the standard pages such as “AllItems.aspx” can be accessed via JavaScript by using some built in functions. One of these is “GetAttributeFromItemTable”. This function is actually called from the “INIT.JS” file; along with a few more that you will see further down the code. This code line is connecting to the table and grabbing the “URL”, which in reality is the direct link to the document or item.

    Once we have the actual link then we find the root URL (the server URL) using a built in property of the list item which is referred to as CTX.

    Once we have the root URL it is then chopped up slightly, so we have the length, and location of the relevant slashes. The local variable “fileUrl” is also declared at this point, this is used later on.  Now we populate the local variable by concatenating the root URL and the variable called “currentItemUrl” which is actually populated previously from the item table.

    Now we have the new variable “fileUrl” populated and ready to use, the next variable to get populated is the “serverFileRedir”. This is used to hold any redirection page that is needed as part of the menu item link.

    Now that we have all the variables populated the next few lines of code simply build the menu item. The “strAction” variable contains the action that will happen when the relevant menu item is pressed. In this case it calls another function that exists within the “INIT.JS” file. This function simply encodes the relevant URL and does a “window.location” redirect. Notice also in the code we pass auto populate the body of the email with the newly populated variable “fileUrl”.

    Next an image is assigned to the menu item. The images used for this are stored here:

    C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\IMAGES

    Now we put it all together using a built in function called “CAMOpt” which exists within the “CORE.JS”. The syntax for this is shown below but let me explain it here:

    CAMOpt({menu or parent menu item}, {display name variable}, {code action variable}, {image variable})

    Notice that in this example the first parameter is set as “sm”. This is the ID of the “Send To” menu item on the main item menu. Some of the functions refer to the variable called “m”. This is the main menu itself and gets populated from the function called “CreateMenuEx”. In one of the last posts we looked at creating nested menun items. To achieve this we made use of this method. Last but not least it assigns a global ID to the menun item. Thisn is great as you can then create custom CSS styles that map direct to the menu item.

    So now we have stepped through the code let’s modify it slightly. One of the errors you sometimes get is caused by the fact that the JavaScript URL Encodes the path before it adds it to the body of the email. An example of this is when the main server URL gets encoded also and makes the link unusable from an email client but works in the browser.

    http://intranet%2Elabs%2Elocal/StaffDirectory/Team%20Documents/DemoDoc1.docx

    By modifying the code we could make sure that the first part of the URL does not get encoded. The URL would then look as below:

    http://intranet.labs.local/StaffDirectory/Team%20Documents/DemoDoc1.docx

    To make this work we need to add the following line(s) into the code:

    Notice that in this line we are calling a built in function called “UnescapeProperly” around the “httpRootWithSlash” variable and then we are using the “EscapeProperly” around the “currentItemUrl”, both of these functions are called from the “INIT.JS”. Both of these functions simply replace any spaces or special characters with their HTML (ASCII) equivalent. Next we need to tweak the link that is rendered into the body of the email. The first variable “NewEmailLength” simply grabs the item table value called “DREF”. This is used to get the relative location of the item or document. The second variable takes the current item URL and substrings the length from the previous variable which leaves us with the actual name of the file plus the extension. The idea behind this was so the subject would read: “Emailing Document Link: {Document Name}“. The “NewEmailBody” variable is populated by the variable we created earlier called “fileUrlNonEscaped”.

    You will also notice that the action variable is calling a function called “CreateMailMessage”. This is a simple function that just does a “window.location” redirect for the email. The function is:

    Once it all together when you access the link the email now renders as:

    As you can see by using lots of the inbuilt functions you are able to change the way that the default menu items or new menu items work within MOSS2007. As a side not I have just noticed that fellow MVP Ishai Sagi has posted his findings on what all the variables are used for from within the “itemTable”. Check his post here:

    http://www.sharepoint-tips.com/2007/05/meanings-of-variables-in-context-menus.html

    Hope this helps. Wink
  • MOSS2007 - DoD 5015.2 Certified

    MOSS2007 has passed it's certification for compliance with level DoD 5015.2. This means that soon you will be able to install an add-in that will bring the world of "records management compliance" closer to the MOSS2007 world. You can read an article about this using the link below:

    http://www.cmswire.com/cms/records-management/microsoft-delivers-on-dod-50152-cert-promise-001323.php

    Big shout to the Microsoft Guys for this!!! Party!!!

  • MOSS2007 – JavaScript Item Menus Part 2 (Real World Examples)

    In the last article we looked at hiding existing menu items and also adding new sub menu items. In this article we will look at adding our own custom menus and sub menu items within the same framework as before. We will use the same code as last time but build on it slightly. The objective now is to create a new menu at the same level as the “Send To” menu and then add some sub menu items. For this example the sub menu items will simply link to external website addresses. To start with let’s modify the code as shown below:

    This code block will add the relevant menus we described above. When you now access the UI the menu items should be shown as below:

    We could enhance this slightly further also by adding a simple hierarchy of menu items. In the real world you probably wouldn’t do this as it can be quite complex to use and administer. The code needs to be changed as below:

    This will then render as below:

    With a little extra JavaScript and a little creativity you can create very complex menu structures with different events that are fired based on the link clicked. The above examples are just some of the things you can do with it. Big Smile

  • MOSS2007 – JavaScript Item Menus Part 1 (Real World Examples)

    I have had quite a few emails recently about ways of either hiding, showing, adding or modifying the item level menu items that appear within lists and document library. In this post I thought I would examine what you can do and what the best approach would be (in my opinion anyway). Firstly the bulk of the menu items are drawn from the “CORE.JS” file that resides in the “12” hive.

    C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS\1033

    This file is a few thousand lines long so can be slightly cumbersome to work with. However the easiest way to find what you are after is to look at the name of the menu item you wish to change in UI and use this to search through the “CORE.JS”. For example I want to hide the “Send To” menu on all document libraries. To do this I would simply search the “CORE.JS” for the text “Send To”.

    Notice when I do it highlights the variable called “L_Send_Text”.

    Now call we have to do is search for that variable and hey presto we have found the function that is called when creating the menus.

    So using this example let’s look at completely hiding the send to menu items. This is quite a simple request but has to be done in a certain way. There are really a couple of ways of doing this. They are:

    1.       Comment out the functions that are called within the CORE.JS

    2.       Use a content editor web part and add this to the relevant pages (all of them)

    3.       Use inline script within the Master Page

    Option 1 will work well, however where possible it is not best to modify the underline files when modifying MOSS2007. Option 2 is a favourite of mine but is very hard to maintain unless you are building custom list definitions for all your content. Also it is very hard to ensure that the web part is added to every list or library. Option 3 is the best option here, simply adding the functions as inline script code will mean that any page that calls this function will automatically call the function in the Master Page, not the CORE.JS.

    So let’s take option 2 for now just so we can see how this option works. The steps to take are:

    1.       Comment out the “AddSendSubMenu” in the CORE.JS

    2.       Add Content Editor Web Part to the “AllItems.aspx” page for the relevant list or library

    3.       Add the “AddSendSubMenu” function to the Content Editor Web Part

    To comment out the function simply use the following at the beginning and the top of the function.

    Now we need to add the content editor web part to the relevant pages. We will open up a document library for this and select the “Edit Page” option from the site actions menu. Once the page is edit mode press the “Add a Web Part” button.

    Now we need to select the “Content Editor Web Part” to the page.

    Once it is on the page press the “Open Tool Pane” link within the web part and then press the “Source Editor” button. When the dialog opens add the following code:

    Once this added, if you select the item menu the “Send To” menu items will not appear.

    Ok, so not everyone will want to hide functionality but the principle is the same for each menu item. I have worked on a few projects where the “DELETE” menu item has either been moved or removed from the item menu and the list or library menu bar. So let’s look at adding it back but only the email link menu item. To do this we will change the code that exists in the content editor web part to be the following:

    When we now run the page the menu should then render as below:

    Let’s say we wanted to have an external process run from the menu item when we click a custom link. For example we might want to send the document to another system for processing or even copy the document somewhere else. This can be done quite easy by creating a new menu item and making the link a custom “aspx” page that contains our custom code. For this example we will simply pass a few query strings to custom page. To begin with let’s modify our code slightly.

    Now when we load the page it should render as below:

    I won’t show the code for the other page here, as you can really do whatever you want. The URL that we constructed in the JavaScript should now look as below:

    http://intranet.labs.local/StaffDirectory/_layouts/custompages/QueryStringExample.aspx?FileID=2&FileURL=http%3A%2F%2Fintranet%2Elabs%2Elocal/StaffDirectory/Team%20Documents/DemoDoc1.doc

    Notice that the variables that we created have now been populated. As you can see without knowing lots of complex c# or VB.Net you can create highly customisable menus within MOSS2007.

  • MOSS2007 – My "HttpHandler" more work!!

    Hi, everyone. Hope you are all well. Since my last post on the Http Handler I am writing, I have not been able to fix the issue I get with the constant looping within the code and lack of attaching the “PreInit” method to the page. Crying However it works really well for normal team sites and site collections, well basically Windows SharePoint Services (WSS). I have had a little more time to work on this and have decided to expand it slightly. My original idea behind this was to simply change the master page upon loading the page and overwrite any master page selections done via the UI. Now however it has changed to the following:

    1.       Overwrite Master Page selections done through the UI

    2.       Show different Master Pages based on Group Membership to the sites

    3.       Show different Master Pages based on the URL that is used to access the site

    For a project I am working on this is a key requirement for an Intranet / Extranet solution. Firstly the code I used before is the same but now has a few changes. The first change is that I am capturing the current site collection URL and checking this against an “AppSettings” in the “Web.Config” file. If this matches then I move onto the next code block. If the code fails the test then it must be coming in from one of the other Alternate Access Mapping (AAM) URL’s and then applies a “defaultGuest.master” page.

    ActualURL = site.Url.ToString();

     

    if (ActualURL.ToString() == InternalSCURL.ToString())

    {

          {Code here to check the user group membership}

    }

    else

    {

    page.MasterPageFile = "/_catalogs/masterpage/defaultGuest.master";

    }

    The second change is that I am now checking the group membership of the current user, by using the inbuilt method:

    site.IsCurrentUserMemberOfGroup

    I am not looping through the groups, I already know that anyone who is an Owner or Member belongs to the “Members” group and should get Master Page one and anyone else should get Master Page 2. Once I have worked out what membership the current user has I then apply the relevant master page. As I know that all the groups in the various sites will have the following format “{Site Title} {Group Name}” I can simply check using the following code and concatenate the “site.Title” and the custom variable “siteGroup” together as shown below.

    bool isMember;

    string siteGroup = " Members";

     

    isMember = site.IsCurrentUserMemberOfGroup(site.Groups[site.Title.ToString() + siteGroup.ToString()].ID);

     

    if (isMember == true)

    {

    page.MasterPageFile = "/_catalogs/masterpage/defaultMember.master";

    }

    else

    {

    page.MasterPageFile = "/_catalogs/masterpage/defaultReader.master";

    }

    The master pages simply have been edited to display the name of the master page as part of the title, so Member, Reader or Guest. With this code in place and the enabled I get the following:

    1.       User Accessing site using Extranet URL Only

     

    2.       User (Member) using Internal URL

     

    3.       User (Reader) using the Internal URL

     

    With a little more code and a nice interface (which I am working on) you are able to map user groups, URL’s and master pages all together to create a simple system for managing look and feel across your Windows SharePoint Services (WSS) Sites.

  • MOSS2007 - Where are my content types being used?

    Recently someone emailed me asking if there was a way to find out what content types various lists and libraries were using in MOSS2007. After a little investigation I decided to write some C# code. If you take a look at the object model you will notice that you have hierarchy that you can traverse down to find this information. In the code I have used I am using the following:

    SPSite Class – The root Site (Portal)

    SPWeb Class – To get details about the current site (Portal)

    SPWebCollection Class – List all sub sites that exist at the current parent site (Portal)

    SPListCollection Class – List all the Lists and Libraries within the various sites under the portal

    SPContentTypeCollection Class – List all the content types that are associated with the selected list

     

    As you can see there is a very nice structure available for us to traverse down. The code is not the most elegant and has no error handling and I am sure there are better ways to write it but you get the idea. I created a test console application for this to simply output to the screen. Anyway the code:

    SPSite siteCollection;

    SPWeb webSite;

    static void Main(string[] args)

    {

    GetCurrentMOSSContext(args[0].ToString());

    }

    static void GetCurrentMOSSContext(string PortalURL)

    {

    siteCollection = new SPSite(PortalURL.ToString());

          webSite = siteCollection.AllWebs["/"];

     

          System.Console.WriteLine(webSite.Url.ToString());

    }

     

    static void GetAllSubSitesListsAndContentTypesUnderContext()

    {

    SPWebCollection subSites = siteCollection.AllWebs;

     

    for (int i = 0; i < subSites.Count; i++)

    {

    System.Console.WriteLine(“...” + subSitesIdea.Title.ToString() + “ – Site”);

     

                SPListCollection lists = subSitesIdea.Lists;

                for (int j = 0; j < lists.Count; j++)

    {

    System.Console.WriteLine(“......” + lists[j].Title.ToString() + “ – List”);

     

                      SPContentTypeCollection types = lists[j].ContentTypes;

                      for (int k = 0; k < types.Count; k++)

                      {

    System.Console.WriteLine(“.........” + types[k].Name.ToString() + “ – Content Type”);

                      }

    }

    }

    }

     

    As you can see the code is very simple and works like a treat. Be aware that this code only works for root site collections. You would need to change it to make it work when trying to check a site collection that had the following format of URL: http://[Server]/[Sites]/[Site]

    Once it is run the output is simliar to this:

    http://intranet.labs.local

    ....Document Center - Site

    ........Announcements - List

    ............Announcement - Content Type

    ............Folder - Content Type

    ........Documents - List

    ............Document - Content Type

    ............Folder - Content Type

    ........Master Page Gallery - List

    ............Master Page - Content Type

    ............Folder - Content Type

    ........Tasks - List

    ............Task - Content Type

    ............Folder - Content Type

     

    Anyway hopefully you get the idea. Big Smile

  • MOSS2007 – Business Data Catalog using BDCMetaMan

    Hi everyone, hope everyone is well. I am back doing a million different things for all those projects I work on. Recently I have been working with the Business Data Catalog (BDC), specifically for use with Oracle. I wanted to share with you how this works by using the BDC MetaMan tool. This is a great tool for generating the XML file(s) needed for the BDC. You can visit the website below to get a copy.

    http://www.bdcmetaman.com/default.aspx

    It comes in a developer version you can try for free or you could purchase the professional version, this would be my recommendation! J

    So let’s look at how we can get Oracle data into MOSS2007. Firstly my environment is set up as one Virtual Machine with the following software:

    1.       Windows 2003 Standard R2

    2.       Active Directory

    3.       SQL Server 2005

    4.       Oracle Express 10g

    5.       Microsoft Office SharePoint Server  2007 (Enterprise)

    6.       Microsoft Office 2007 Enterprise

    7.       Visual Studio 2005

     

    The Oracle server has a sample HR database that comes with it that I will use for this demonstration. So firstly let’s open up BDCMetaMan. To do this simply access the “BdcMetaMan.Application.exe” from the program files directory shown below.

    Once this has loaded it should look as below:

    Firstly you need to configure the output locations and the Shared Service Provider locations. To do this simply press the “Configuration” menu and select either of the following options:

    If we select the “XML Output File” option first it should let you select the location for this file. This XML file is the physical file that you need to load into MOSS2007 after you have created it.

    You must also now select the “MOSS SSP” option and change to suit your environment. In mine I have used a host header within a Web Application called “SSP.LABS.LOCAL” so my settings are as below:

    Before we can continue we must select the output format from the dropdown box.

    Now that we have saved these settings we can now connect to our database and start creating the output file. To start this press the “Connect to data source” button and select the relevant option that you need. In this demonstration we will use Oracle.

    Once you have selected the Oracle option a dialog will appear asking for server details and security details as shown below:

    My settings are shown below:

    Once you have completed these details and press connect you should then be presented with something similar to the below:

    Obviously for this demonstration there are not many tables at all. Now we have our Oracle tables exposed to us here we can now start to create the relevant connections. To do this, simply drag the relevant table from the left tree structure onto the design surface on the right.

    Once it is dragged onto the design surface it should render the fields as a table.

    Now if you take a look at the left structure at the bottom of the application you can see that it has started to build the required XML structure. These can be renamed to suit what you need for your own system.

    To change the name of an item simply right click on an element and select the “Edit” option.

    Once you select the “Edit” option you are presented with a dialog that asks for the following details:

    To change any element of this simply overtype it or select a new value from the dropdown lists. My completed dialog is shown below:

    Once you have saved this the left navigation should then display the new names. By default you will notice that by adding the table to the design surface that is generates a single method called “GetEMPLOYEES”. This is the base one that we will use but we also need a method that we search for values of the employees. This means we will need to add an ID Enumerator. To do this right click on the “GetEMPLOYEES” method and select the “Edit” option. The following window should appear:

    You can see from the windows that we can simply press the “Add ID Enumerator” button and this will add the relevant method.

    Once you have accepted this the window should then look as below:

    What you will see here is the fields that are available for this method. By default an ID Enumerator only has the primary key field, but you can add more fields if you wish. I have added all the fields.

    You will also see you can add actions that will appear on the item once it is exposed within MOSS2007. From the actions windows we can either create our own or add one of the predefined list shown below:

    The actions are simple menu items that appear next to a selected field, similar to the menu that appears on a list item within MOSS2007. We will add a custom one that is basically the email one but we will add some different fields. To do this select the “Create Custom Action” button and complete the window as below:

    Now that we have created the custom action we can now look at associating other tables with the employee list. To do this we will need to drag the relevant table to the design surface as shown before. For this demonstration we will use the “Departments” table.

    Once we have this on the design surface we will also add an ID Enumerator method. The full method list should look as below:

    Now we need to associate the two tables together so we can create almost like a master and detail view within MOSS2007. To do this simply right click on the “Employees” table and select the “Add Association” menu item.

    It doesn’t matter which field you right click on for this as the next dialog window allows you to select the relevant fields. In the new windows you need to select the following:

    1.       Parent Table

    2.       Parent Field to use for Linking

    3.       Child Table

    4.       Child Field to use for Linking

     

    My settings are shown below:

    Once this is set your design surface should look as below:

    Now we have created all the methods we need we can simply output this file and then import into MOSS2007. To do this press the little green arrow next to the output type item on the main screen. Once this outputted you will get prompted as below. Select the “NO” option.

    Now we are ready to import this definition into MOSS2007. To do this simply select the “SSP Administration Site” tab, and then press the “Load SSP Administration Web Site”. The SSP Site should then load within the application.

    Now we need to press the “Import Application Definition” from the Business Data Catalog menu items. The window should then load as below:

    All we need to do is browse to our newly outputted file and press the import button. Once it has been imported it should then redirect you to the page to show you the relevant methods and fields you have access to. If you experience any errors on import, in my experience this is due to the tables not having corresponding primary and foreign keys within the tables of the database. So we have created our XML file, imported it and are now ready to use this inside MOSS. For the purposes of the demonstration I already have a definition that I will use. This definition uses the Job history and employee table instead of the departments table one. It will still give us the same effect.

    So to continue we need to launch our portal and add some web parts to our page. In this demonstration I have created a new web part page and added this to the navigation. Once your page is loaded change it to “Edit” mode and select the “Add a Web Part” button. From the list select the “Business Data List” web part.

    Once the web part is on the page, press the “Open Tool Pane” link. This will load the properties for the web part into the right hand pane. From the properties window press the address book icon next to the “type” field.

    The following window will load.

    In this demonstration I am selecting the “Job_History” method as the main table to expose first. Once this is done and you apply these changes it should render the web part as below:

    As you can see it is really easy to expose database content through using the Business Data Catalog. Using BDCMetaMan is the easiest way to build all your methods, actions and all the interfaces you need for the Business Data Catalog. Go get a copy and give a try!! In the next post we will look at joining the data together within the MOSS2007 UI. Big Smile

  • Great Team-Based Development Document on MOSS2007

    Hi just been reading a post on Mart Muller's blog about a document on the MSDN site talking about Team-based development with MOSS2007. You can read the document from the link below.

    http://msdn2.microsoft.com/en-us/library/bb428899.aspx

    Happy Reading. Thanks to Mart for posting this link.

  • MOSS2007 – "HttpHandler" Investigation

    I have recently been trying to develop an “HttpHandler” that will change the “Master Page” for the portal and sites on the fly based on various parameters. I am hoping that I will be able to validate the user and the zone they are coming from and display different master pages accordingly. My first idea was to create a new class library and override the “PageBaseType” within the “Web.Config”. This would have worked except that any pages that already have “Inherits” statements don’t work. This solution would involve having to change the “inherits” for each and every page in the site, something I am not about to do. My next approach was to create an “HttpHandler” that simply would override the “Page_PreInit” method and change the master page. I read various articles to work out what the code would be and also the best approach to doing this.

    http://ryanfarley.com/blog/archive/2004/06/16/788.aspx

     

    http://weblogs.asp.net/soever/archive/2006/11/14/SharePoint-2007_3A00_-using-the-masterpage-from-your-site-in-custom-_5F00_layouts-pages.aspx

     

    http://www.lnbogen.com/OverrideOnPreInitOnAPageWithMasterPage.aspx

     

    http://msdn.microsoft.com/msdnmag/issues/04/06/ASPNET20MasterPages

     

    http://staff.develop.com/ballen/blog/PermaLink.aspx?guid=09befce7-f48e-4555-891c-13818fd75a56

     

    http://odetocode.com/Articles/450.aspx

     

    http://www.sharepointblogs.com/dwise/archive/2007/01/08/SingleMasterPage.aspx

     

    After reading the articles above I decided to structure the code as follows:

    public void Init(HttpApplication context)

    {

    context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);

    }

    void context_PreRequestHandlerExecute(object sender, EventArgs e)

    {

    HttpApplication httpApp = sender as HttpApplication;

     

    if (httpApp != null)

    {

    Page page = httpApp.Context.CurrentHandler as Page;

                   

    if (page != null)

    {

    page.PreInit += new EventHandler(page_PreInit);

    }

    }

    }

    void page_PreInit(object sender, EventArgs e)

    {

    Page page = sender as Page;