Friday, November 18, 2011

Replicating the Text Editor Functionality Programmatically

I was developing a custom webpart which has custom properties viz. a people picker, a textbox to type a question and another to type the answer.


As, I was using the EditorPart and the PeoplePicker control, I was unable to group the People Picker property with the other two properties. I would get the People Picker at the top of the webpart property pane, and the other two at the bottom of the properties pane under the custom group "My Properties". Any blogger who knows how to group your custom properties can please post the related url. Thanks in advance.

Thus, I created two more additional textboxes to capture the question and the answer, and was in high spirits of having completed my task.When I demonstrated this "cool" webpart to my product owner, he casually added that the answer textbox needs to have a pop-up Text Editor, as you see in any OOTB textboxes which help you build content. Thats when the real problem started. 

I was expecting Microsoft to give me a "SPLinkBuilderXXX" kind of a control which gives me this functionality straightaway, just as the PeoplePicker class. I was very happy to find on MSDN that there did exist a class called "TextZoomBuilder" class, which to my dismay was marked "Obsolete" :(.

I found that MS uses an input button which calls a javascript function in javascript:MSOPGrid_doBuilder, and passes the arguments - '_layouts/1033/zoombldr.aspx', the id of the control to which the value needs to passed, and the properties of the pop-up window.

When I tried to replicate this, I found that SharePoint (the ASP.NET runtime engine) appends dynamic Guids to all the controls on a page to prevent them from getting duplicated. Thus, we cannot get the ClientId of the control at runtime in the code-behind. It appears this is achieved by SharePoint using the 'ContentToolPart' which is an internal sealed class.
I am very thankful to Tony Bierman who posted Leveraging Custom Property Builders in SharePoint Web Parts, a wonderful article in 2006. The workaround being to place a hidden form field on the page to which you can get the zoombldr.aspx page to post the data back to, and then use a Javascript function which simulates the 'Apply' button click action of the webpart properties pane to post the value back to your textbox.

However, when I tried to implement it in SharePoint 2010, I got lot of Javascript errors. I found that we need to use the name of ApplyButton directly. The code which worked for me was - 

 string key = "applyFunction";
                StringBuilder embeddedScriptFormat = new StringBuilder("<script language=jscript>function ApplyProperties(){\n");
                embeddedScriptFormat.Append("document.forms[MSOWebPartPageFormName].MSOTlPn_Button.value = 'apply';\n");
                embeddedScriptFormat.Append("document.forms[MSOWebPartPageFormName].elements['ctl00$MSOTlPn_EditorZone$MSOTlPn_AppBtn'].click();\n");
                embeddedScriptFormat.Append("}\n");
                embeddedScriptFormat.Append("</script>\n");
                if (!Page.ClientScript.IsClientScriptBlockRegistered(key))
                {
                    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), key, embeddedScriptFormat.ToString());
                }


One more trick up your sleeve as a SharePoint developer.

Friday, November 11, 2011

Custom Pagelayout with custom user controls causes a page crash

So this was an issue that we were facing a couple of days back and really had a tough time solving it, thanks to the wierd behaviour of SharePoint.

The Issue:

Ok, as any other project in SharePoint would do we were using custom pagelayouts for our content pages. However, one of the layouts has a user control which would push a couple of webparts into the different webpart zones of layout. This page layout would crash when it gets applied to any page in the site.
Applying Custom Page layout

Investigations:

As is common in most of the issues in SharePoint, the ULS wouldnt give a clue. We used to get wierd error messages viz. Unknown class for webpartzone 'xyz', div tag is not a valid tag etc.

The interesting part was that trying to debug wouldnt even hit the breakpoint in any of the pages.

Thus, we turned to the only resort for any developer, Google :)

Cause:

We found that SharePoint would introduce two error webparts into the pagelayout while deploying the solution. This could be checked by going to the edit properties of the pagelayout in the master pages and pagelayouts gallery of the site collection. Scrolling down to the end of the page and selecting the option to 'Open the page in Webpart maintenance mode'.
Link to Webpart Page Maintenance Link at the bottom

Now the question is from where have these errorwebparts come from? Obviously, no sane developer would do that.

Root Cause:

It was obvious that SharePoint was pushing these, but why? A lot of googling ultimately pointed the issue. As I understand SharePoint expects the '<ZoneTemplate></ZoneTemplate>' tags to be defined within the Webpartzone tags, failing to which it injects these webparts when your custom code tried to insert webparts into the webpartzone.

Resolution:

Well the first step in trying to resolve this was to remove the error webparts from the custom pagelayout, and checking if the issue is gone. Having confirmed that, we added the '<ZoneTemplate></ZoneTemplate>' tags at all places in the page before the closing tage of the webpartzone.

Well abracadabra............. the problem is gone :)

Hope this helps you in solving your problem too.