James Shaw's Blog

Hi-tech and Real Estate Entrepreneur

Search

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Customizing Sharepoint 2007: Quick Post

Thursday, 17 July 2008 09:29 by jshaw

In my 1st technical post I'd like to share how I implemented a delicious-like feature in a Sharepoint site (called "Quick Post") that lets users post a file or Url to a Sharepoint document library with one click of a button on any page of the site; the user can tag each post just like with delicious, and the site has tag cloud and searching-by-tags features for users to find info later; the user will get suggestions on existing tags when he tags. 

The following is a screen shot of the pop-up window after the user clicks on the Quick Post button in the site:  



The type just gives the user a choice on one of the two different document libraries.  The location is a toggle between the ASP.NET FileUpload control for file and TextBox control for Url, using Javascript.  

With this custom UI, the user is able to post a file or Url to the document library without leaving the page he's on, and in one screen (unlike the built-in multiple Sharepoint pages for adding a file or Url, and any tags in the tag field of the document library); the custom UI also has tag suggestion to maximize tag reuse :).

The Pop-up Window

The pop-up window you see in the screen shot is a DHTML window (which is better than a browser window because of pop-up blocker).  I'm all for re-using others' code as much as possible :), so for the pop-up window I used and would recommend this 3rd party widget.  Just include the 3rd party widget in your page that pops up the window (in our case the master page since the QuickPost button needs to show up everywhere):

    <link rel="stylesheet" href="http://devcentral/_vti_bin/windowfiles/dhtmlwindow.css" type="text/css" />   
    <script type="text/javascript" src="http://devcentral/_vti_bin/windowfiles/dhtmlwindow.js">
   
    </script>

and have the button click call the following javascript function:

        var quickPostWin = null;
       
        function openQuickPostWindow ()
        {
            quickPostWin = dhtmlwindow.open("quickPostBox",
                                            "iframe",
                                            "http://devcentral/Pages/QuickPost.aspx",
                                            "Quick Post",
                                            "width=650px,height=400px,resize=1,scrolling=1,center=1",
                                            "recal");                       

            if (quickPostWin.onclose == null)
            {
                quickPostWin.onclose=function(){ //Run custom code when window is being closed (return false to cancel action):
                    return true;
                }
            }               
           
        }

The content inside the window comes from a ASP.NET user control (.ascx).  The easiest way I found to develop custom pages in Sharepoint is to develop it in Visual Studio (so you take advantage of the designer support, code-behind, etc), and host it in a Sharepoint web part: a page viewer web part to host .aspx, or like in this case, a 3rd party smart part web part to host .ascx; the page shown in the DHTML window (http://devcentral/Pages/QuickPost.aspx) is just a Sharepoint page with one smart part web part that hosts a .ascx.  Sharepoint still has some way to go in terms of its integration with Visual Studio for development, and this is kind of a stopgap until MSFT builds the functionality of developing custom pages for Sharepoint right into Visual Studio.

AJAX functionality

As seen in the screen shot, Quick Post provides suggestions as the user starts typing in tags, just like delicious.  To add AJAX functionality like this, I used the AJAX Control Toolkit from codeplex; it contains quite a few extenders to ASP.NET controls to add AJAX to your web page, and in this case I used the auto-complete extender to the tags text box.

To use AJAX Control Toolkit in Sharepoint, make sure to reference it and include the ScriptManager in the page.  Since in our case we want AJAX functionality in every page (as in most cases I think), I just put the following in the master page:

<%@ Register Tagprefix="ajaxToolkit"
             Namespace="AjaxControlToolkit"
             Assembly="AjaxControlToolkit, Version=3.0.11119.26320,
             Culture=neutral, PublicKeyToken=28f01b0e84b6d53e" %>

...

    <ajaxToolkit:ToolkitScriptManager ID="ScriptManager1" runat="server" />

Here I'm using AJAX Control Toolkit's implementation of the ScriptManager rather than the one in ASP.NET AJAX, as the former is supposed to be more efficient at sending the javascript down to the client.

The auto-complete extender itself is pretty straight-forward as documented: in my implementation, the web-service responding to the user key strokes in the tags text box just iterates over all records in the document library, extracts and parses the tags from the comma-separated tag field (using Sharepoint API's), and return the tags matching the given prefix.

There's perhaps one tricky thing in the web service.  In our Sharepoint site, the user is free to create sub-sites, and those sub-sites can contain library items with tags as well, so to make sure we capture all existing tags from all sites in this site collection, you need to make sure either every user has the permission to iterate over all sites, or elevate the privilege in the web service code somehow, .e.g, by impersonating a user that for sure has permission to do it:

            SPUser wssAccount = null;
            using (SPSite siteCollection = new SPSite("http://devcentral"))
            {
                // need to impersonate to iterate over all sub-sites
                wssAccount = siteCollection.OpenWeb().AllUsers["corp\\dcentral_wss_svc"];
            }
           
            using (SPSite impersonatedSiteCollection = new SPSite("http://devcentral", wssAccount.UserToken))
            {
               // iterate over all sites, get all the tags, and return matching tags

               ...

            }

The above will also do the trick any time your custom code using the Sharepoint API's needs to run in elevated privilege mode.

Storing Url in a Document Library

Sharepoint document libraries can have multiple content types, and when it does, the user can choose which content type it is when adding a record to a document library.  There's a "Link to a Document" content type that's well suited for storing Url's in a document library; in fact it can store link to another document as well.  For our Sharepoint site, however, we just need to support storing Url's.  

It's however not well documented how to add a document link programmatically, as I had to do for our custom UI.  When a user adds a document link to a document library, what happens behind the scenes is that Sharepoint actually creates an aspx file on the fly that does nothing more than redirecting to the document link Url you give, and it's the aspx file that's stored in the document library, just like a document stored in the document library.  A rather convoluted way to store links in my opinion, but that's the way the document link content type works.

After bugging him about it, Cliff Green from MSFT wrote up how to programmatically add a document link to a document library in his blog :).  Essentially you have a aspx template file that you read into memory each time you add a document link to a document library, after filling in the Url in the template file in-memory.

Conclusion

In this blog post, I've hopefully covered how to have custom pages in Sharepoint (leveraging Visual Studio designer), adding AJAX to your page, and how to have Url's in a document library.  In future posts I will share more customizations I've done in Sharepoint.  Hope this has been a useful read :).

Tags: ,
Categories: Tech
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

TechEd 2008

Friday, 6 June 2008 13:51 by jshaw

TechEd 2008 just finished.  It was a blast!  I enjoyed it a lot.  Microsoft did a great job throwing a fairly smooth event, given the number of attendees, and pampering of the attendees, including a night at the Universal Studio.  See my picture with the Simpsons there:

Look.  They even provided bean bags for us to sleep on when we are exhausted from the conference:

The sessions themselves were about 1/3 bad, 1/3 good, and 1/3 excellent.  I have to give MS credit for trying to get feedback; I heard from one of the speakers that they have a monitor that constantly shows the bottom rated speakers who probably won't be invited back next year.  I also noticed a pattern of the MS speakers there: they are all PM's rather than developers.  Hmm...  Even most of the staff manning the product booths were PM's.  I asked one of them why there's no developers; he said that they'd rather work and finish the product.  Do you believe that?  :).

The excellent sessions I attended were (in case you want to view their videos online): "Asynchronous ASP.NET", "Silverlight Tips", and "ASP.NET AJAX Extensions Deep Dive" by Jeff Prosise, "ASP.NET Performance Black Belt" by Steven Smith, and "SEO for Developers" by Nathan Buggia.  I only went to the sessions based on the topic, and Jeff's sessions always overflowed.  Apparantly a lot of people went to sessions based on the speaker :).

These sessions are also good to check out: "IIS 7 Security and Tuning" by Ruslan Yakushev, "Silverlight Controls" by Karen Corby, "REST web services using WCF" by Jon Flanders, and "Optimizing Javascript and IE" by Cyra Richardson. 

At the conference, I was really impressed by Silverlight's capabilities and felt that it's really going to disrupt the web space.  I attended a BofF session (i.e., a peer discussion among TechEd attendees w/o MS) on Silverlight vs AJAX, and as people started listing out the pro's and con's of AJAX and Silverlight, it became clear that RIA like Silverlight is the superior solution and the next step of evolution in web development; AJAX is really an intermediate stage towards richer content/easier development (Google is solving ease of development with GWT, but there are just things you can't do with AJAX that you can do with Silverlight/plugin-type of model).  The one major drawback is searchability (Plugin model is still a black box that search engines can't crawl), but like Nathan said, it's something that all search engines are trying to crack and find a solution of. 

With all the talk about Silverlight, I also felt a bit deja vu.  In my college years Java applet was all the hype of the day, and, except more advanced graphics and a declarative model, it pretty much has everything Silverlight has (including a bridge with Javascript/Browser DOM).  Java applets didn't take off for some reason (non-ubiquitous broadband?).  It seems like we're going back full circle to a plugin-model of web development like Flex/Flash and Silverlight. 

I also saw an interesting book at the conference store and couldn't resist buying it:

I've skimed through it and think it's a pretty candid assessment of Microsoft today; it's written by a well-know Microsoft analyst Mary Jo Foley.  Check it out!

Overall it was a great experience for my 1st time at a Microsoft conference.  The MS people were friendly technical enthusiasts who seem genuinely passionate about technology, and I felt right at home talking to them :). 

The Perfect Laptop

Monday, 18 February 2008 12:39 by jshaw

I really gotta get in the habit of writing blogs...

Recently I just bought a new personal laptop, to replace my venerable IBM Thinkpad T41.  Thought it'd be good to share my experience:

Originally I was just going to buy the latest Thinkpad (T60 at the time); seemed like a logical choice.  I was at the same time upgrading my work laptop to a T60p; good thing I waited to see how it is before buying one for my personal use.  The laptop was heavier than T41, freezes half of the time whenever I undock and bring it back from sleep, or whenever I dock.  It was terrible.  A lot of my co-workers also had the same problem, and the IBM service rep on-site did his best (including putting a jumper on one of the docking station pins and some software option) but the freeze still happened.  Nowadays I just use it like a desktop, i.e., always having it docked and remoting to it from another laptop when I need to access it, which totally defeats the purpose of having a laptop.  It seems that since the acquisition by Lenovo the quality of thinkpad just went way down...

I then started looking for another brand for my personal laptop.  In the end I settled for a macbook (BTW I bought it from ecomelectronics; probably the cheapest place for it).  Still getting used to it; there has been lots of little things that annoyed me, like the extra small screws that need a special screw driver to open to install more memory, and the stupid bootcamp download from apple website that expires as soon as you run it (since it's part of Leopard and they don't want people using the beta one; why don't they just disable the link on their website if it's not meant to be used?).  What frustrated me the most was that the drivers bootcamp installs for Vista by default conflict and whenever you play music (or game) it skips.  It cost me quite a few hours before finally finding a solution (see Smaels' 1st post on the page).

Overall I'm just disappointed at the quality of laptops (and electronics in general) nowadays.  Seems like companies just try to rush to market without doing enough QA; these 2 scenarios are so basic (docking and undocking a laptop; playing music after installing Vista on a macbook) that I'm apalled to see that Lenovo and Apple released their products without covering them.

For now I'm fine with the macbook.  It's still not as good as my old T41 (where everything just works as expected), but probably the best laptop experience I'll get.  One good thing about owning a macbook for a software developer is that you can test your web app on all 3 major browsers (IE, Firefox and Safari).