About the author

Bart X. Tubalinal

Bart X. Tubalinal is a Sr. Consultant for a company based in the Chicagoland area. His primary focus is on the Microsoft technology stack, including: .NET, C#, SharePoint, InfoPath, Silverlight, Windows Presentation Foundation (WPF), Windows Workflow Foundation (WF), and ASP.NET. He has also dabbled a little in Project Server.

Though he doesn't have as much free time as he would like, when he does, he loves to hang out with friends, try different cuisines, and play with his dog, Tyson.

He also considers himself to be, pound for pound, one of the best developers there is.

Facebook ProfileTwitter: bart_tubalinal

RecentComments

Comment RSS

 

Microsoft FAST Search Server 2010 Installation Issue with Powershell Script

by Bart X. Tubalinal 10. March 2010 11:43

I am currently installing Microsoft FAST Search Server 2010 RC on my demo/development environment and ran into an issue running the post configuration Powershell script (found at C:\FastSearch\installer\scripts\psconfig.ps1). When I initially ran the script, it failed either because I didn’t supply the FQDN to my SQL Server machine (which is required) or because I may have fat-fingered the service account name or one of the associated passwords. Anyways, when I tried to re-run the script (this time making sure I entered the inputs correctly), I got an error that the configuration failed, specifically that ‘An error occurred while installing Resource store’. So I did a search both on the web and the Microsoft Connect newsgroups to see if there was anyone else that had this error but saw nothing. I checked the logs and found this (not the complete log file):

   1: 3/10/2010 4:53:51 PM Verbose Utility.Execute - "C:\FASTSearch\bin\ResourceStoreInstaller.exe" Output - (Mar 10, 2010 04:53:51 PM), Fast-installer, resourcestoreinstaller.exe, C:\Windows\system32\inetsrv\appcmd.exe SET config "ResourceStore/Config" /section:requestFiltering /+verbs.[verb='POST',allowed='true'] /commit:apphost - Applied configuration changes to section "system.webServer/security/requestFiltering" for "MACHINE/WEBROOT/APPHOST/ResourceStore/Config" at configuration commit path "MACHINE/WEBROOT/APPHOST"  
   2: 3/10/2010 4:53:51 PM Verbose Utility.Execute - "C:\FASTSearch\bin\ResourceStoreInstaller.exe" Output - (Mar 10, 2010 04:53:51 PM), Fast-installer, resourcestoreinstaller.exe, C:\Windows\system32\inetsrv\appcmd.exe SET config "ResourceStore/Config" /section:requestFiltering -requestLimits.maxAllowedContentLength:1073741824 /commit:apphost - Applied configuration changes to section "system.webServer/security/requestFiltering" for "MACHINE/WEBROOT/APPHOST/ResourceStore/Config" at configuration commit path "MACHINE/WEBROOT/APPHOST"  
   3: 3/10/2010 4:53:51 PM Verbose Utility.Execute - "C:\FASTSearch\bin\ResourceStoreInstaller.exe" Output - (Mar 10, 2010 04:53:51 PM), Fast-installer, resourcestoreinstaller.exe, C:\Windows\system32\inetsrv\appcmd.exe SET config "ResourceStore/Config" /section:httpRuntime -maxRequestLength:1024000 -executionTimeout:3600 /commit - Applied configuration changes to section "system.web/httpRuntime" for "MACHINE/WEBROOT/APPHOST/ResourceStore/Config" at configuration commit path "MACHINE/WEBROOT/APPHOST/ResourceStore/Config"  
   4: 3/10/2010 4:53:51 PM Warning Utility.Execute - "C:\FASTSearch\bin\ResourceStoreInstaller.exe" StdError - resourcestoreinstaller.exe - C:\Windows\system32\inetsrv\appcmd.exe SET config "ResourceStore/Config" /section:appSettings /+"[key='FileLimit',value='']" /commit - ERROR ( message:New add object missing required attributes. Cannot add duplicate collection entry of type 'add' with unique key attribute 'key' set to 'FileLimit'
   5: 3/10/2010 4:53:51 PM Warning Utility.Execute - "C:\FASTSearch\bin\ResourceStoreInstaller.exe" StdError -  . )  
   6: 3/10/2010 4:53:51 PM Warning Utility.Execute - Return code for binary "C:\FASTSearch\bin\ResourceStoreInstaller.exe" is not 0. This may indicate that binary didn't execute successfully
   7: 3/10/2010 4:53:51 PM Verbose Utility.Execute - Finished executing "C:\FASTSearch\bin\ResourceStoreInstaller.exe"
   8: 3/10/2010 4:53:51 PM Error InstallResourceStore - An error occurred while executing binary "C:\FASTSearch\bin\ResourceStoreInstaller.exe". Return code is not 0.
   9: 3/10/2010 4:53:51 PM Error Utility.WriteException - Exception -  : Exception - System.Management.Automation.RuntimeException: An error occurred while installing Resource store.

The exception is on line 9 but the important error is actually on line 4. Based on this line, I was able to deduce that what was happening was the resource installer was trying to add a key (FileLimit) in an appSettings section of a config file but couldn’t because the key already existed. Instead of just replacing the old key, it just causes the post configuration script to fail. Anyways, in order to fix it, I found the config file that it was attempting to update (there are a ton of config files for this app). The particular config file where it was failing is located at C:\FASTSearch\components\resourcestore\config\web.config. Sure enough, the FileLimit key was there. All I did was delete that key, re-ran the script again and presto, all done.

Anyways, just wanted to share this, to save others the headache I just ended up getting trying to figure out why that darn script wasn’t working correctly.

Technorati Tags: ,
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

SharePoint 2010 | FAST Search

Example: Using the SharePoint 2010 Silverlight Client Object Model and Excel Services REST API

by Bart X. Tubalinal 7. February 2010 05:20

NOTE: This code is based on the SharePoint 2010 Release Candidate version.

Download: ExcelChartViewerSL.zip (975.87 kb) 

I finally had a chance to put together a little sample of how to use the SharePoint 2010 Silverlight Client Object Model which I wanted to share. Now this example could have been just as easily done with jQuery and the Client OM for Javascript but I really didn't want to write another post on jQuery (I think everyone knows how much I like it) and instead, I wanted to show how much I like Silverlight and WPF as well J (so much so that I'm actually currently writing a Facebook desktop application in WPF).

In this example, I built a Silverlight app that can be used to display charts inside of an Excel workbook. The concept I had was simple, really. I wanted to take all charts contained in an Excel workbook located in a SharePoint document library and display them as navigational elements first (as thumbnails of the chart) and after one was selected, to display the entire chart itself. I thought this would be a good starting point to show Silverlight + SharePoint + Excel and an example that can be extended further for use by anyone. So this is the mockup for what I intended to build:

Figure 1 – Mockup

The first thing to do is to open Visual Studio 2010 and create a new Silverlight Application Project. The wizard will ask you if you want to add a Web project to the solution as well. For this example, it is not required. The project will contain two XAML files, an App.xaml and a MainPage.xaml. The App.xaml is for handling the application itself and the MainPage.xaml is for the main UI component of the application.

With MainPage.xaml, make sure to name the UserControl as this will later be used as part of some of the bindings defined in controls later. In this case, I named the control 'thisControl' (line 1). Then I defined the layout of the control by adding three grid row definitions to the LayoutRoot grid container (lines 8-12). All have been defined with a width of Auto so that each row will collapse if there is nothing inside of them. Then, I dropped an Image control and a TextBlock control in the xaml. The Image control, named 'imgMain', targets the second row of the grid container (line 37, Grid.Row="1") and the TextBlock control, 'tbStatus', targets the third row of the container (line 43, Grid.Row="2").

Look back at the Image control. In lines 40-41, I am defining a maximum height and width for the image by binding it to properties I defined in this MainPage user control class (MainPage.xaml.cs). The properties are MainImageMaxHeight and MainImageMaxWidth, both of which are ints. The maximum height and width has a default that I set (later) but can be modified by the user. Notice also that for each binding's ElementName, I specified the name I gave to the control itself, 'thisControl'. In line 38, I am binding the Source to a property called ID. Now this ID property isn't part of my MainPage user control class. It is actually a property of another class I defined called ExcelChart (also inside of the MainPage.xaml.cs) file. The ExcelChart class has two properties: ID (the url for the chart object) and Title. An instance of the ExcelChart class is what is used as the DataContext for the image, which you will see in the code.

For the thumbnails row, all I'm using is a ListBox control. This is an extremely versatile control. The first thing I want to make sure of is to make sure that the items in the listbox are presented horizontally rather than vertically as is the default. So in lines 16-21, I define the template used for the items panel (ItemsPanelTemplate) to use a StackPanel as the container with Orientation set to Horizontal. Then, I need to define how the actual items in the listbox will be displayed. For that, I defined the ItemTemplate of the listbox (lines 21-34). The template uses a two-row grid as the container. The first row contains a TextBlock with the chart's title and the second row contains an Image control that displays the chart. Notice the binding for the TextBlock's text uses the Title property and the Image source uses the ID property of the ExcelChart class.

The only other thing to pay attention to in the MainPage.xaml are the event handlers. There are only two events I care about, when the control gets loaded (line 5) and when the selection has changed on the list box (line 15).

Here is the full MainPage.xaml:

MainPage.xaml
    1 <UserControl x:Class="ExcelChartViewerSL.MainPage" Name="thisControl"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    5    Loaded="UserControl_Loaded" Height="Auto" Width="Auto">

    6 

    7     <Grid x:Name="LayoutRoot" Background="White">

    8         <Grid.RowDefinitions>

    9             <RowDefinition Height="Auto"/>

   10             <RowDefinition Height="Auto"/>

   11             <RowDefinition Height="Auto"/>

   12         </Grid.RowDefinitions>

   13 

   14         <ListBox Name="lbCharts" Grid.Row="0" BorderBrush="Transparent" HorizontalAlignment="Center"

   15                 SelectionChanged="lbCharts_SelectionChanged">

   16             <ListBox.ItemsPanel>

   17                 <ItemsPanelTemplate>

   18                     <StackPanel Orientation="Horizontal"/>

   19                 </ItemsPanelTemplate>

   20             </ListBox.ItemsPanel>

   21             <ListBox.ItemTemplate>

   22                 <DataTemplate>

   23                     <Grid>

   24                         <Grid.RowDefinitions>

   25                             <RowDefinition Height="Auto"/>

   26                             <RowDefinition Height="Auto"/>

   27                         </Grid.RowDefinitions>

   28                         <TextBlock Text="{Binding Title}" FontWeight="Bold" HorizontalAlignment="Center" />

   29                         <Image Source="{Binding ID}" Grid.Row="1"

   30                               MaxWidth="250" MaxHeight="250"

   31                               Margin="3,2,3,2" HorizontalAlignment="Center"/>

   32                     </Grid>

   33                 </DataTemplate>

   34             </ListBox.ItemTemplate>

   35         </ListBox>

   36 

   37         <Image Name="imgMain" Grid.Row="1"

   38               Source="{Binding ID}"

   39               Margin="0, 10, 0, 0" HorizontalAlignment="Center"

   40               MaxHeight="{Binding ElementName=thisControl, Path=MainImageMaxHeight}"

   41               MaxWidth="{Binding ElementName=thisControl, Path=MainImageMaxWidth}"/>

   42 

   43         <TextBlock Name="tbStatus" Grid.Row="2" HorizontalAlignment="Left" TextWrapping="Wrap" Text="" Visibility="Collapsed"/>

   44 

   45     </Grid>

   46 </UserControl>

   47 

 

Now take a look at MainPage.xaml.cs (shown below). In lines 22-26 is where I define the simple ExcelChart class with my two properties, ID and Title. In the main page class, I defined three properties (lines 34-36), WorkbookLocation, MainImageMaxWidth, and MainImageMaxHeight. The MainImageMaxWidth/Height I already discussed. The WorkbookLocation is used to specify which workbook to get the charts from.

In the UserControl_Loaded event handler (starting at line 45), the first thing I want to make sure of is that the WorkbookLocation is set. At the very least, that needs to be specified. If not, show an error message and stop. If it is specified, we then call the BeginLoad() method to start processing.

In the BeginLoad method (lines 61-68), I use the SharePoint client OM to request the workbook file. The client OM is new for SharePoint 2010. If you haven't already heard, the difference with the client OM and the server OM is that with the client OM, the objects have to be explicitly loaded. In other words, I can't just start trying to access properties of a SharePoint object as those properties won't be available right away. So in this case, I have this _wkbkFile object (of type Microsoft.SharePoint.Client.File) I defined as a field of my MainPage class. Before I can do anything with this object, I need to load it by explicitly asking the ClientContext object to load it (and execute a query) for me (lines 65-67). Note that with the Silverlight OM, the queries have to be done asynchronously.

When you call ExecuteQueryAsync, it expects two callbacks, one for if the query succeeds and one for if the query fails. The callback I defined for the failure is between line 76-88. If the query failed, then I just display a message to the user about the failure. An important thing to remember here is that when the query is called and is executing, it is executing on a different thread. It is not executing on the UI thread. The implication here is that in order to update the TextBlock text to display the status message, I need to make sure I do that on the UI thread. In order to do this, we use Dispatcher.BeginInvoke() to wrap the call that updates the text and changes the TextBlock's visibility.

The succeeded callback (_wkbkFile_LoadSucceeded) simply calls the LoadWorkbookFeed() method (lines 90-99). In SharePoint 2010, Excel Services has added the ability to expose objects contained in an Excel workbook via RESTful services. In this case, I create a string (wkbkRestUrl) to the Excel REST service that will return to me all the charts in a particular workbook (line 93). Then, I use a System.Net.WebClient object to request that URL. The WebClient also makes the request asynchronously so I have to provide a callback function that should be executed when the request completes (wcFeedReader_OpenReadCompleted).

When you call this Excel REST service the response is going to be in ATOM format. In wcFeedReader_OpenReadCompleted (lines 101-134), I use an XDocument object to load up the response that comes back from the REST service. I then use LINQ to XML (lines 116-122) to get an IEnumerable<ExcelChart> collection of all entry objects. Finally, I set the ItemsSource property of my ListBox (lbCharts) to my 'entries' collection, select the first chart, and set the DataContext of my imgMain image to the selected ExcelChart object. Again, since I am now updating something with the UI and because I am currently executing on a different thread than the UI thread, I need to make sure to wrap the code that updates the UI with a call to Dispatcher.BeginInvoke().

Here's the full MainPage.xaml.cs:

MainPage.xaml.cs

   19 namespace ExcelChartViewerSL

   20 {

   21 

   22     public class ExcelChart

   23     {

   24         public string ID { get; set; }

   25         public string Title { get; set; }

   26     }

   27 

   28     public partial class MainPage : UserControl

   29     {

   30         private const string EXCEL_REST_URL = "/_vti_bin/ExcelRest.aspx/";

   31         private const string MODEL_CHART_URL = "/Model/Charts/";

   32         private const string NS_ATOM = "http://www.w3.org/2005/Atom";

   33 

   34         public string WorkbookLocation { get; set; }

   35         public int MainImageMaxWidth { get; set; }

   36         public int MainImageMaxHeight { get; set; }

   37 

   38         private Microsoft.SharePoint.Client.File _wkbkFile;

   39 

   40         public MainPage()

   41         {

   42             InitializeComponent();

   43         }

   44 

   45         private void UserControl_Loaded(object sender, RoutedEventArgs e)

   46         {

   47             //make sure the web part was actually configured with a workbook location.

   48             if (string.IsNullOrEmpty(WorkbookLocation))

   49             {

   50                 tbStatus.Text = "Please configure at least the workbook location. Init Params Available: " +

   51                     "workbookLocation(string), mainImageMaxHeight(int), mainImageMaxWidth(int)";

   52 

   53                 tbStatus.Visibility = Visibility.Visible;

   54                 return;

   55             }

   56 

   57             //start the loading of the workbook file

   58             BeginLoad();

   59         }

   60 

   61         private void BeginLoad()

   62         {

   63             //first, use the clientcontext object to request the workbook file

   64             _wkbkFile = ClientContext.Current.Web.GetFileByServerRelativeUrl("/sites/adventureworksbi" + "/" + this.WorkbookLocation);

   65             ClientContext.Current.Load(_wkbkFile);

   66 

   67             ClientContext.Current.ExecuteQueryAsync(_wkbkFile_LoadSucceeded, _wkbkFile_LoadFailed);

   68         }

   69 

   70         private void _wkbkFile_LoadSucceeded(object sender, ClientRequestSucceededEventArgs e)

   71         {

   72             //file load succeeded. start loading the workbook REST feed

   73             LoadWorkbookFeed();

   74         }

   75 

   76         private void _wkbkFile_LoadFailed(object sender, ClientRequestFailedEventArgs e)

   77         {

   78             //file loading failed. show the error

   79             //Dispatcher.BeginInvoke is used because this is currently not executing on the UI thread

   80             Dispatcher.BeginInvoke(delegate()

   81             {

   82                 this.tbStatus.Text = "Error message: " + e.Message

   83                     + "\nWorkbook file: " + WorkbookLocation

   84                     + "\nCode: " + e.ErrorCode.ToString();

   85 

   86                 this.tbStatus.Visibility = Visibility.Visible;

   87             });

   88         }

   89 

   90         private void LoadWorkbookFeed()

   91         {

   92             //the feed url format is: http://{server/sitecollection}/{site}/_vti_bin/ExcelRest.aspx/{workbooklocation}/model/charts

   93             string wkbkRestUrl = ClientContext.Current.Url + EXCEL_REST_URL + WorkbookLocation + MODEL_CHART_URL;

   94 

   95             //use a web client object to request the workbook REST feed

   96             WebClient wcFeedReader = new WebClient();

   97             wcFeedReader.OpenReadCompleted += new OpenReadCompletedEventHandler(wcFeedReader_OpenReadCompleted);

   98             wcFeedReader.OpenReadAsync(new Uri(wkbkRestUrl));

   99         }

  100 

  101         void wcFeedReader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)

  102         {

  103             //the response sent back will be ATOM. load the response in an XDocument first.

  104             XDocument doc;           

  105             using (Stream s = e.Result)

  106             {

  107                 doc = XDocument.Load(s);

  108             }

  109 

  110             //ATOM is the default namespace in the response.

  111             //we need to prepend this when referring to any elements or attributes of the document

  112             XNamespace nsAtom = XNamespace.Get(NS_ATOM);

  113 

  114             //use LINQ to XML to get all 'entry' objects in the feed

  115             //with each 'entry' element, create an instance of our ExcelChart class (defined above)

  116             var entries =

  117                 from entry in doc.Root.Descendants(nsAtom + "entry")

  118                 select new ExcelChart()

  119                 {

  120                     ID = entry.Element(nsAtom + "id").Value,

  121                     Title = entry.Element(nsAtom + "title").Value

  122                 };

  123 

  124             //remember that the REST feed request was started on a different thread.

  125             // we need to use Dispatcher.BeginInvoke here to update the UI thread.

  126             Dispatcher.BeginInvoke(delegate()

  127             {

  128                 this.lbCharts.ItemsSource = entries;

  129                 if (this.lbCharts.Items.Count > 0) this.lbCharts.SelectedIndex = 0;

  130 

  131                 this.imgMain.DataContext = this.lbCharts.SelectedItem;

  132             });

  133 

  134         }

  135 

  136         private void lbCharts_SelectionChanged(object sender, SelectionChangedEventArgs e)

  137         {

  138             this.imgMain.DataContext = this.lbCharts.SelectedItem;

  139         }

  140     }

  141 }

  142 

 

Lastly, I need to edit the App.xaml.cs. There's not much to explain here. I'm just retrieving the initparams that is passed by the Silverlight host object and using it to set up my application.

App.xaml.cs (Application_Startup)

   27         private void Application_Startup(object sender, StartupEventArgs e)

   28         {

   29             //Load up any init parameters from the silverlight web part host.

   30             IDictionary<string, string> parms = e.InitParams;

   31 

   32             string workbookLocation = parms.ContainsKey("workbookLocation") ? parms["workbookLocation"] : string.Empty;

   33             int mainImageMaxHeight = parms.ContainsKey("mainImageMaxHeight") ? int.Parse(parms["mainImageMaxHeight"]) : 400;

   34             int mainImageMaxWidth = parms.ContainsKey("mainImageMaxWidth") ? int.Parse(parms["mainImageMaxWidth"]) : 640;

   35 

   36             //Create our main user control (MainPage) and set it up as the app's main UI.

   37             MainPage mainPage = new MainPage()

   38             {

   39                 WorkbookLocation = workbookLocation,

   40                 MainImageMaxHeight = mainImageMaxHeight,

   41                 MainImageMaxWidth = mainImageMaxWidth

   42             };

   43 

   44             this.RootVisual = mainPage;

   45         }

 

After the project is built, then all you need to do is drop the XAP file into the ClientBin directory (c:\program files\common files\microsoft shared\web server extensions\14\templates\layouts\clientbin). I actually created a subdirectory structure (DeviantPoint\ExcelChartViewerSL) under clientbin to store my xap for this application. Then, drop a Silverlight web part (found under Media and Content) and configure it to point to the new XAP file.

Figure 2 – Add a Silverlight Web Part

 

Figure 3 – Configure the web part to point to the XAP

 

Figure 4 – Configuring the appearance

 

Figure 5 – Configuring other settings, which contains the Initialization Parameters passed to the Silverlight application

(Full Initialization Parameters: workbookLocation=AnalyticsReports/AW Charting Samples.xlsx,mainImageMaxHeight=500,mainImageMaxWidth=800)

So that's it. It was pretty simple to build, actually. It probably took me about an hour or so to get it all working the way I expected it to. Here's a screenshot of the Silverlight web part with my Silverlight app:

Figure 6 – Silverlight web part for displaying Excel charts


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Excel Services | LINQ | REST | SharePoint Development | SharePoint 2010 | Silverlight

What I've learned about the Visio Services API ... so far

by Bart X. Tubalinal 5. February 2010 04:26

Ok, so I’ve played around with Visio Services and created diagrams linked to data. Here's what I've learned so far: there is no way to dynamically create a Visio diagram. What I mean is,  the Visio Services API won’t allow you to dynamically add shapes to a diagram. The shapes have to be on the diagram already when you publish the diagram. You also cannot modify any of the properties of the diagram or any of the diagram shapes’ properties through the Visio Services API. You can’t even dynamically link a row from your data source to a shape already on the diagram. The link from row to shape must be already defined prior to publishing.  

So what can you do with the API? From what I can tell, there’s really only a few things:  

  1. You can read the linked data of any shape in your diagram. This is the data coming from the data source.
  2. You can highlight or select any shape.
  3. You can change the view (which page is shown) and zoom level of the diagram.
  4. You can add an overlay. There are two types of overlays you can add here: a text overlay or an image overlay (note that when you’re looking at a workflow visualization, it uses this image overlay technique). Actually, I think you can technically create a third type of overlay (if the diagram is rendered w/ Silverlight as opposed to PNG). I think you can create a very limited XAML overlay that will be placed inside of a Canvas. That’s because the overlaying capabilities of the API uses createFromXaml() to create the other types of overlays (image and text). 

So that’s what I’ve learned as I messed around with Visio Services. If anyone finds out anything else or if any of what I say is incorrect, let me know. So if you're looking for a way to create a dynamic diagram, maybe the best way to accomplish that is through Silverlight.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

SharePoint 2010 | Visio Services

SharePoint 2010 Managed Metadata Columns and Metadata Navigation Settings

by Bart X. Tubalinal 16. November 2009 19:05

Ok, here's another one I don't get. I created a new Team Site. I added a few test documents to the Shared Documents document library and tagged a few of the documents with some managed keywords:

I go into the library settings to verify that the Managed Keywords column is of type 'Managed Metadata':

I want to use the Managed Keywords column to drive metadata navigation. I go into the metadata navigation settings for the library:

The description for the navigation hierarchies clearly states that a column of type Managed Metadata field can be used for the navigation hierarchies. Yet I don't see my Managed Keywords column in the list of Avaiable Hierarchy Fields. So, of course, it doesn't show up in my navigation tree:

I'm not sure if this is a bug, if the description in the metadata navigation settings is incorrect, or if there's some configuration setting I'm missing. But it sure would be nice if that worked. That's going to help the users a heck of a lot if it works the way I think it's supposed to.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

SharePoint 2010 | Metadata Navigation

Can't Edit Document Library form in SharePoint 2010

by Bart X. Tubalinal 16. November 2009 18:06

NOTE: I posted this about an hour ago but for some reason, it got deleted.

One of the features I looked most forward to working with in SharePoint 2010 is the ability to customize a list's add/edit forms in InfoPath. I created a very simple custom list and the ability to edit those forms was as easy as advertised. However, when I created a document library with all the default settings and without adding any columns, I got the following error:

The following is the full error text:

The SharePoint list form can't be customized with InfoPath because fields of an unsupported data type are marked as required, or because fields are corrupted. In SharePoint, try deleting the columns or editing the column properties to remove the required

Is this supposed to work for document libraries or is the ability to edit these forms in InfoPath 2010 limited to lists only? Like I said, I kept all the default settings and didn't add any additional columns to the document library so if this functionality is supposed to work, I would have assumed it would have worked at the very least in this scenario. But if it truly isn't supposed to work with document libraries in the first place, why does the command to edit the library's forms appear in the ribbon at all?

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

SharePoint 2010

T-SQL Function for Getting Business Dates Between a Given Range

by Bart X. Tubalinal 28. October 2009 14:25

Here's a really simple T-SQL function for getting a list of business dates (Monday - Friday) that fall within a given date range. For example, say I wanted to find the business dates between the dates 10/21/2009 - 10/30/2009. This function will return the following results:

10/21/2009
10/22/2009
10/23/2009
[10/24/2009 is skipped]
[10/25/2009 is skipped]
10/26/2009
10/27/2009
10/28/2009
10/29/2009
10/30/2009

I just thought this function might be helpful for others since I couldn't find anything else out there that someone else had written to accomplish this (easy as it is). There are plenty of T-SQL scripts that return the number of business days between a date range, I just couldn't find one that actually returned the business dates.

Here's the script:

CREATE FUNCTION BusinessDatesInDateRange
(
    @BeginDate DATETIME@EndDate DATETIME
)

RETURNS @BusinessDates TABLE (BusinessDate DATETIME)
AS    BEGIN 
        DECLARE @CurrentDate DATETIME         
        SET @CurrentDate = @BeginDate        

        WHILE (@CurrentDate <= @EndDate
        BEGIN 
            -- 1: Sunday 7: Saturday 
            IF DATEPART(WEEKDAY, @CurrentDate) <> 1 AND DATEPART(WEEKDAY, @CurrentDate) <>
            BEGIN 
                INSERT INTO @BusinessDates(BusinessDate) VALUES (@CurrentDate); 
            END             

            SET @CurrentDate = DATEADD(D, 1, @CurrentDate)             
        END

    RETURN 
    END

GO

Sample call to execute:

select * from dbo.BusinessDatesInDateRange('10/21/2009', '10/30/2009');

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

SQL

Custom SharePoint Designer workflow action for extracting InfoPath attachment fields

by Bart X. Tubalinal 6. June 2009 04:08

I've been meaning to post this for at least a month but I've been so busy with work that I've had no time to sit down and write this until now. But better late than never, I guess.

A little more than a year ago, I developed a browser-enabled InfoPath form that was used on a public-facing MOSS site so that site visitors could submit their photographs to the organization's yearly photo contest. Along with capturing the photo metadata (title, location, date, etc), one of the fields on the form was for the photo itself, captured through the use of the attachment control. The photo contest reviewers wanted to be able to have a quick and easy way to review the photos and the photo metadata so the original thought was to submit the photo to a document library and use property promotion to display the photo along with the metadata. Unfortunately, we quickly found out that the attachment control could not be promoted to a property. So I wrote a web service instead that would accept this form, extract out the attachment, and save the attachment directly into a picture library (and copy the photo metadata as well). That way, the users were able to see the photo and its metadata as soon as they opened the library.

A few months ago, someone again approached me with similar requirements. They were building a form that would have an attachment field that they'd need to extract to put into another library. Well, that was enough right there to make me realize that I needed to build something that would enable users to build these types of solutions themselves. I didn't want to have to keep writing things over and over to support these types of requirements. I also wanted to remove myself out of the process; they were already at 90% of the entire solution since they were building these forms already, they just needed the last 10% of being able to extract the attachment.

So what I ended building instead was a new workflow activity that could be used in SharePoint Designer as a workflow action. Basically, the action can be used as part of a workflow created in SharePoint Designer that will allow the user to add a step in their workflow for extracting out the attachment and saving it somewhere else. When the action is added to the SPD workflow, it looks like the following:

The 'attachment field name' is where the user specifies the name of the attachment control field in the InfoPath form. The link 'the item' is the SharePoint list item this action should work against. This is going to typically be the current item. The 'document library' is where you want the item to be stored to and the 'filename' parameter is the filename to save the attachment as (this can be driven dynamically as well from metadata of the item or some variable). The sentence '(use attachment name instead: Yes)' actually gives you the opportunity to use the actual filename of the file that was attached, rather than having to specify the filename yourself. When a user attaches a document to an InfoPath form, part of what is stored is the actual file's filename. Though that is not available through SharePoint, it can be extracted out by code, which I do inside of the custom action. By specifying 'Yes' for this field, this indicates the action to ignore the filename parameter and use the attachment's filename instead. The workflow designer can also specify whether or not the file should overwrite any existing file in the document library with the same filename. Finally, when the attachment has been extracted and saved, the action returns the item's new id which can be bound to a variable in the SPD workflow.

As an example of how this works, I created a sample New Hire InfoPath Form. The form contains an attachment field for an employee photo. The forms are submitted to my 'New Hire Forms' document library. Here is a sample of the form as it's been filled out:

Now, let's say that as part of this scenario, I want to give others the ability to be able to reuse that employee photo for other purposes (who knows what for, just go along with the example :)). But other people shouldn't be allowed to look at this form because it could potentially hold sensitive information. I need to move this photo out of this form and into another, less-restricted library. So I created a 'Team Photos' Picture Library for this purpose. Now, all I have to do is create a workflow to do the photo extraction. I can create a workflow and attach it to my New Hire Forms document library and configure it to start automatically when a new item is added. Then, I can configure my new workflow as follows:

I have three actions here. The first action is my custom extraction action. I configured it to pull the photo from the 'employeePhoto' field using the current item in the New Hire Forms document library. I save this photo to the Team Photos picture library (and instead of specifying a filename, I'll just use the attachment's filename). I will overwrite the picture if it already exists. Finally, I store the id of the newly added item in the Team Photos library to the workflow variable 'new item id'.

The second action is actually an Update List Item action. I use this action to grab the last name of the employee (from the New Hire Forms item) and save it to the description field of the item I just saved in the picture library. That's why saving the id is important because you can use it to reference to later or make cross references to (which I'll get into in a second). The following is the configuration of this action:

Obviously, I could have created a workflow variable that was a concatenation of the first name, last name, department, etc and used that to fill out the description but this is just for demonstration purposes.

Lastly, the third action is again an Update List Item action. With this action, I update the current item I'm executing this workflow against so that I can add a cross-reference to the photo that I just extracted and stored somewhere else. One of the columns in the New Hire Forms document library is a lookup column called Employee Photo. I configured the lookup column to point to the Team Photos picture library with the referencing being the ID of the picture item. Then, I just configured the action in my workflow as follows:

That's it for the workflow. Finally, when it runs, here's what I get:

In my New Hire Forms library, you can see the workflow has finished executing and there is a link under Employee Photo to the photo that was extracted. And here's the Team Photos picture library with the extracted photo:

 

So, that's pretty much to it. I think from this example, it's easy to see the value of taking some time and really thinking about coming up with custom workflow activities. Custom workflow activities exposed as SharePoinw Designer workflow actions can really enable your users to build their own solutions, possibly in ways you wouldn't have imagined yourself. That's normally how I try to envision solutions. When someone asks me to build something, I ask myself, can I build something else that will allow them to create their own solution now and in the future.

I attached the SharePoint solution file (.wsp) below as well as the VS2008 project files.

In the future, if I see there's enough interest (through comments), I can go into a discussion of the code.

DeviantPointWorkflowActivities.wsp (7.20 kb)   - Once this solution has been deployed, you need to activate the DeviantPoint Custom Workflow Activities web application feature. Repeat - web application feature, not site collection, not site.

DeviantPoint.SharePoint.Workflow.zip (499.49 kb)

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

SharePoint Designer Custom Workflow Activity - WTF

by Bart X. Tubalinal 2. April 2009 09:05

I was writing a custom workflow activity for SharePoint Designer today (a pretty cool custom activity, if I do say so myself, which I'll post in a few days) and on my custom activity, one of the settable fields I have happens to be the last word in the sentence:  

So I went to go set the field and this is what I get:


Whenever I went to set the field, the hover action over the activity added a drop down button to the end, thereby making the field impossible to set. Anyways, I'm just going to change the sentence but I thought it was pretty funny and wanted to share it.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Using the jQuery UI Dialog widget for confirmation windows

by Bart X. Tubalinal 12. March 2009 09:09

In our web applications, we often have the need to confirm with the user whether or not they want to proceed with an action they attempted to take. For instance, we might have a delete button on our form that responds to a user click by deleting a record in the database. Before we actually do the delete, we want to double-check with the user first. JavaScript has a confirm(msg) function that will display a standard dialog window that you can use to determine whether or not to continue with an action. The standard dialog window looks like the following (in IE): 

The standard confirm window is not very flexible. First, you only get two buttons (and no more), Ok and Cancel, and you can't change the text of either button. Second, you can't change the title on the title bar. You also can't change the question mark icon inside of the dialog. If you need something more flexible, you're going to have to create your own modal overlay window and recreate the functionality that confirm() gives you. Fortunately, jQuery UI has a dialog widget that will get you most of the way there:

 

As you can see, this dialog window definitely doesn't look like the standard confirm. First, I have more than two buttons and with different text. I also have a different title. It can be resized and repositioned. Also, although you can't see it, this dialog window can have the same visual effects (like applying semi-transparent overlays on everything underneath the window) applied to it that can be applied to other html elements by using jQuery. This would not be possible with the standard confirm. I won't bore you with the details of how to set this up. The documentation on the jQuery site sufficiently explains that. What I want to concentrate on is showing you how to make the jQuery dialog widget behave exactly like the standard JavaScript confirm.

When using the standard confirm, all processing stops until the user clicks on either Ok or Cancel in the window. That means that if the button was supposed to post back to the server, the postback won't occur until a selection is made. Usually, we only go ahead with the postback if the Ok button was clicked. This is typically handled by adding something similar to the OnClientClick event handler on our button:

<asp:Button ID="Button1" runat="server" Text="JavaScript" OnClick="Click" OnClientClick="return confirm('Dude, are you sure?');" />

If the user clicked the Ok button, true would be returned by the confirm(msg) function. If the user selected Cancel, false would be returned. Returning false in OnClientClick will effectively cancel the rest of the event processing (i.e., the event handler for the OnClick event won't be triggered).

Now, for the jQuery dialog, this is how I have the button:

<asp:Button ID="Button2" runat="server" Text="jQuery" OnClick="Click" OnClientClick="showjQueryDialog();return false;" />

I call a client-side function showjQueryDialog() which, amazingly enough, handles showing my jQuery dialog (pre-configured in the document ready event handler). After the call to showjQueryDialog(), I go ahead and just return false. The reason why I have to return false here is because, unlike the confirm() function, the browser doesn't stop processing the rest of the client-side script just because the dialog widget is opened. So we have to manually stop it. Now this raises an issue. So if we always return false, how will our event handler for the OnClick event ever be executed? In order for that event handler to execute, we will need to do the postback ourselves. There are a couple of ways to handle this but this is the approach I take:

1. Create a hidden field on the form (called hdnBtnPostback) who's value will be the exact postback function call I need to make in order to emulate the same postback that would occur had the button processing continued. This value can be set in the Page_Load() of the ASP.NET page. But how do we know what the exact postback function call should be? Fortunately for us, that is one of the methods available from the ClientScriptManager object. So the following code will do the trick:

 

this.hdnBtnPostback.Value = Page.ClientScript.GetPostBackEventReference(Button2, string.Empty);

 

This is will generate the exact same call to the __doPostBack() JavaScript function that is generated by the button. 

2. In the event handler for my dialog's Ok button click, all I have to do then is get the value of this hidden field and pass it to the JavaScript eval() function. This will effectively execute the postback and the event handler for the OnClick event will be processed: 

    1    function showjQueryDialog() {

    2 

    3       $("#dialog").dialog("open");

    4    }

    5 

    6    //document on ready.

    7    $(function(){

    8       $("#dialog").dialog({

    9          autoOpen: false,

   10          modal:true,

   11          buttons : {

   12             "Yes" : function() {              

   13                $(this).dialog("close");

   14                eval($("#<%= hdnBtnPostback.ClientID %>").val());

   15             },

   16             "No" : function() {

   17                $(this).dialog("close");

   18             },

   19             "Maybe": function() {

   20                $(this).dialog("close");

   21                //what should we do when "Maybe" is clicked?

   22             }        

   23          }

   24       });

   25    });

The event handler for the Yes button in the dialog are on lines 12-15. Line 14 is where we actually do the postback manually. 

As you can see, it is quite easy to replace the standard confirm dialog and make it function in the same way. All that is needed is a little elbow grease :).

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

ASP.NET | jQuery | JavaScript

Creating a SharePoint breadcrumb control with drop down menus

by Bart X. Tubalinal 3. February 2009 14:05

While there have plenty of things that people don't like about Windows Vista, one of the features I do like and I think is underappreciated is the new breadcrumb:

Unfortunately in SharePoint, the breadcrumbs don't work like this. There are no submenus. Lucky for us, it's pretty easy to create a breadcrumb that functions this way. Here's how:

Creating the web control

The first part we'll need is a web control that will render the markup. The web control I created is simple and straightforward. Only two public properties are available: SiteMapProvider (string) and NodeSeparator (string). The SiteMapProvider property is used to specify the named site map provider from the web.config file to use to build the breadcrumb. The NodeSeparator property is used to specify the character(s) to use to separate each item in the breadcrumb (like the sideway triangles in the screenshot above). By default, this is set to the '>' character. Also, this property will only be used if the breadcrumb item doesn't have any sub-items; if it does, then a clickable image like the one above will be displayed instead. Lastly, the breadcrumb's submenus will only go one level deep (like Vista's). So there won't be any "submenus of submenus".

The rendering logic takes place in the RenderContents(HtmlTextWriter) method. First, we get an instance of the SiteMapProvider object that has the same name as the one specified in the control's SiteMapProvider property. Then, using the provider, we traverse our way up the site map from the current page (specified by the SiteMapProvider.CurrentNode property) until we get to the top of the site map. While we traverse up, we will collect the nodes that we passed in a Stack<SiteMapNode> collection:

            SiteMapProvider provider = GetSiteMapProvider();

 

            Stack<SiteMapNode> nodes = new Stack<SiteMapNode>();

 

            SiteMapNode current = provider.CurrentNode;

            while (current != null)

            {

                nodes.Push(current);

                current = current.ParentNode;

            }

 

Once we've reached the top, we then pop the nodes out of the stack. Each node will be represented as a list item (li) in an unordered list (ul). If the node has any subitems, then we will render a clickable image and unordered list that is a child of the list item:

            while (nodes.Count > 0)

            {

                SiteMapNode node = nodes.Pop();

                sb.AppendFormat("<li class='dp-breadcrumbitem'><a href='{0}' title='{1}'>{1}</a>", node.Url, node.Title);

 

                //why not use SiteMapNode.HasChildNodes? see: http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/37d10f92-140f-4ce8-b71c-388163721737/

                if (node.ChildNodes.Count > 0)

                {

                    sb.Append("<img src='/_layouts/images/marr.gif' class='dp-breadcrumbitemimage'/>");

 

                    sb.AppendFormat("<ul id='dp-submenu-{0}' class='ms-topNavFlyOuts dp-breadcrumbsubmenu'>", node.Key);

                    foreach (SiteMapNode subNode in node.ChildNodes)

                    {

                        sb.AppendFormat("<li class='dp-breadcrumbsubmenuitem'><a href='{0}' title='{1}' class='dp-submenulink'>{1}</a></li>", subNode.Url, subNode.Title);

                    }

                    sb.Append("</ul>");

                }

                else

                {

                    if (nodes.Count > 0) sb.AppendFormat("<span class='dp-breadcrumbseperator'>{0}</span>", nodeSeparator);

                }

                sb.Append("</li>");

            }

 

This is the typical html markup that is rendered by the breadcrumb control:

<ul class='dp-breadcrumb'>

    <li class='dp-breadcrumbitem'><a href='link' title-'Item 1'>Item 1</a> <img src='path_to_image' />

        <ul class='ms-topNavFlyOuts dp-breadcrumbsubmenu'>

            <li class='dp-breadcrumbsubmenuitem'><a href='link' title='Sub Item 1' class='dp-submenulink'>Sub Item 1</a></li>

            <li class='dp-breadcrumbsubmenuitem'><a href='link' title='Sub Item 2' class='dp-submenulink'>Sub Item 2</a></li>

        </ul>

    </li>

    <li class='dp-breadcrumbitem'><a href='link' title-'Item 2'>Item 2</a> <img src='path_to_image' />

        <ul class='ms-topNavFlyOuts dp-breadcrumbsubmenu'>

            <li class='dp-breadcrumbsubmenuitem'><a href='link' title='Sub Item 3' class='dp-submenulink'>Sub Item 3</a></li>

            <li class='dp-breadcrumbsubmenuitem'><a href='link' title='Sub Item 4' class='dp-submenulink'>Sub Item 4</a></li>

        </ul>

    </li>

</ul>

 

That is pretty much it for the web control. The next parts we need to build are the CSS and the JavaScript.

CSS and JavaScript

I won't bore you with the details of the CSS since it's available in the zip file below but the most important things with the CSS are: making sure the breadcrumb items are displayed inline and making sure the submenu uses absolute positioning and has a z-index that will place it on top of any other element that is going to be on the page.

Now for the UI magic to happen, we need a little client-side code. Here again, I use my new favorite client-side library, jQuery. The client script primarily consists of three event handlers: an event handler for the click event on the image, an event handler for a submenu item's hover event, and an event handler used to handle clicks anywhere else on the document.

The click event for the image is used to show/hide the corresponding submenu. It will also make sure that no other menu is visible besides the one that corresponds to the image that was clicked. Finally, it will toggle an appropriate image to use, depending on whether or not the submenu is visible or hidden:

    //add the event handler for the click on the image

    $("img.dp-breadcrumbitemimage").click(function(e){   

        e.stopPropagation();

 

        var theImage = $(this);

 

        var left = this.offsetLeft + 12;

        var top = this.offsetTop + 12;

 

        //get the submenu corresponding to the image.           

        var submenu = theImage.next("ul.dp-breadcrumbsubmenu");

 

        //iterate over all the submenus in this breadcrumb and hide any that isn't the target submenu.

        $("ul.dp-breadcrumbsubmenu").each(function(idx){           

            if (this.id != submenu.attr("id")){

                $(this).hide();

                $(this).prev("img.dp-breadcrumbitemimage").attr({src:"/_layouts/images/marr.gif"});

            }

        });

 

        //if the target submenu is visible, hide it. if it's invisible, show it.

        //also change the image that is being displayed.

        if(submenu.is(":visible"))

        {

            theImage.attr({src : "/_layouts/images/marr.gif"});

            submenu.slideUp();

        }

        else

        {

            theImage.attr({src : "/_layouts/images/menu2.gif"});

            submenu.css("position", "absolute").css("top", top).css("left", left).slideDown();

        }       

    });

The hover event handler for each submenu item will take care of making sure the item is highlighted properly. The highlighting we will use is the same highlighting used by the top navigation menu:

    //add a hover event for the items in the submenu so that they are highlighted.

    $("li.dp-breadcrumbsubmenuitem").hover(function(){

        $(this).addClass("ms-topNavFlyOutsHover");

    },

    function(){

        $(this).removeClass("ms-topNavFlyOutsHover");   

    });

Lastly, the click event handler for the document will make sure that if the user clicks outside of the breadcrumb, any visible submenu will be hidden:

    //add a click handler for the entire page so that when the user clicks outside of the breadcrumb, any visible menu will be hidden.

    $(this).click(function(){

        $("ul.dp-breadcrumbsubmenu").slideUp();

        $("img.dp-breadcrumbitemimage").attr({src:"/_layouts/images/marr.gif"});

    });

 

Putting it all together

So now that we've built the components, it's time to put it all together. First, add the breadcrumb.css file and breadcrumb.js file in a document library or folder in the SharePoint site collection. You also need to place the jQuery javascript library in a document library/folder (note: I used jQuery version 1.2.6 for this).

Second, you need to deploy the assembly 'DeviantPoint.SharePoint.Web.UI.dll' to the Global Assembly Cache (GAC) and then reset IIS.

Third, in order to be able to use the web control we developed, you need to add an entry into the SafeControls section of your web.config file:

      <SafeControl Assembly="DeviantPoint.SharePoint.Web.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d767c3b2d2145e42" Namespace="DeviantPoint.SharePoint.Web.UI.WebControls.Navigation" TypeName="*" Safe="True" />

Lastly, you need to modify your site collection's master file by first registering our custom assembly:

<%@ Register Tagprefix="DeviantPoint" Namespace="DeviantPoint.SharePoint.Web.UI.WebControls.Navigation" Assembly="DeviantPoint.SharePoint.Web.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d767c3b2d2145e42" %>

Then you need to add a reference to the css and javascript files we are using:

    <!-- reference to the breadcrumb css -->

    <link href="/Style Library/Breadcrumb.css" type="text/css" rel="stylesheet"/>

 

    <!-- add the reference to the two jquery libraries -->

    <script src="/scripts/jquery-1.2.6.min.js" type="text/javascript" language="javascript"></script>

    <script src="/scripts/Breadcrumb.js" type="text/javascript" language="javascript"></script>   

Note that in this case, I put 'Breadcrumb.css' in the default Style Library document library. I put the javascript files in a folder I created with SharePoint designer called scripts. Also, make sure to place these lines right before the closing 'head' tag in the master file.

Lastly, we need to place the breadcrumb control in an appropriate spot on the master page where we'd like the breadcrumb to appear:

              <asp:ContentPlaceHolder id="PlaceHolderGlobalNavigationSiteMap" runat="server">

                <!-- DEVIANTPOINT breadcrumb -->

                <DeviantPoint:Breadcrumb ID="bcGlobal" runat="server" SiteMapProvider="GlobalNavSiteMapProvider"></DeviantPoint:Breadcrumb>

              </asp:ContentPlaceHolder>

In this case, I actually replaced the default global breadcrumb that comes out of the box with my own breadcrumb. I also used the GlobalNavSiteMapProvider because that site map provider will have all of the nodes for the site collection.

Results

Here are some screenshots of the new breadcrumb in action:

 

 

See? Not too difficult!

Files

In the zip file below, you'll find the assembly that needs to be deployed to the GAC, Breadcrumb.cs, breadcrumb.css, breadcrumb.js, and deviantpoint.master. Deviantpoint.master is just the out of the box master with all the changes to the master file I specified above. You will need to download jQuery v. 1.2.6 yourself.

DeviantPoint_Breadcrumb.zip (11.12 kb)

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Currently rated 4.8 by 4 people

  • Currently 4.75/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

JavaScript | jQuery | SharePoint | SharePoint Development