After updating a custom theme for CS2008, support for widgets can be added.

Community Server 2008 provides built-in support for extending Dynamic Theme Configuration to support selecting custom widgets to be displayed within a theme.  CS2008 includes widgets for showing post lists, user lists, group lists, tag clouds, custom HTML (including viewer support for videos, images, and audio), as well as external widgets from Google, Widgetbox, and Springwidgets.  Here's a short example of using widgets in CS2008:

 

Adding support for widgets in a custom theme is simple--it requires only two steps:  (1) Add the Dynamic Configuration property for each "column" of widgets and (2) Add Chameleon controls to the theme to render the widget "column".

 

Adding Widget Dynamic Configuration Properties

Widget support in CS2008 is implemented as an extension to Dynamic Configuration support in themes.  For each set (or column) of widgets in a theme, a new <property /> node needs to be added to the theme's theme.config file.

The following <property /> node identifies a column of widgets:

<property
   id="myWidgetColumn"
   text="Widgets"
   dataType="Custom"
   controlType="CommunityServer.Controls.ContentFragmentsCustomControl, CommunityServer.Controls"
   />

In this example, the id ("myWidgetColumn") is the unique name for this column of widgets (this will be used later when we want to render this column of widgets in the theme), the text identifies this widget column, the dataType identifies that widgets will be stored as custom data (they're actually stored as XML), and the controlType identifies the built-in Dynamic Configuration control that renders the widget editor:

Example of the Widget Dynamic Configuration Control

This <property /> node can be added within any existing <propertyGroup /> or <propertySubGroup /> node in the theme's theme.config file.  A full discussion of the theme.config file is beyond the scope of this article, but browsing around an existing theme.config file should provide enough pointers to add a widget column.

A <property /> node identifying the dataType and controlType mentioned above must be added for each unique list/column of widgets that will be included in the theme.

Once the <property /> nodes are added to the theme.config file, users are able to select their desired widgets.  The next step is actually rendering them somewhere in the theme...

 

Adding Chameleon Controls to Render Widget Dynamic Configuration Properties

Community Server 2008 provides Chameleon controls to render widgets.  Widgets are identified as ContentFragments in Chameleon and the following Chameleon controls can be used to interact with ContentFragments:

  • <CSControl:ContentFragment />
    Renders the content/body of a ContentFragment.
  • <CSControl:ContentFragmentData />
    API-related single value control that renders a property on a ContentFragment, such as: OrderNumber, FragmentName, FragmentDescription, FragmentHeader, or FragmentMoreUrl.
  • <CSControl:ContentFragmentList />
    List control that renders the list/column of widgets for a single configuration property (as defined in the theme's theme.config file).
  • <CSControl:ContentFragmentPropertyComparison />
    Condition control providing support for comparing two properties of a ContentFragment.
  • <CSControl:ContentFragmentPropertyValueComparison />
    Condition control providing support for comparing a property of a ContentFragment to a static value.

These controls can be included in any page, master page, or user control in a theme.

The most simple inclusion would be the default <CSControl:ContentFragmentList /> control:

<CSControl:ContentFragmentList Property="myWidgetColumn" runat="server" />

This would render the body/content of each ContentFragment configured for the property with id "myWidgetColumn" within <li> tags in an <ul> list.

As with other Chameleon controls, the formatting of ContentFragments can be customized by defining custom formatting templates on the list control.  The following is the standard format for ContentFragment lists rendered in the Hawaii theme:

<CSControl:ContentFragmentList runat="server" Property="myWidgetColumn">
  <ItemTemplate>
    <CSControl:ContentFragment runat="server">
      <LeaderTemplate>
        <div class="CommonContentBox">
          <CSControl:ContentFragmentData Property="FragmentHeader" runat="server" Tag="H4" CssClass="CommonContentBoxHeader" />
          <div class="CommonContentBoxContent">
      </LeaderTemplate>
      <TrailerTemplate>
          </div>
        <CSControl:ContentFragmentData ResourceName="ViewMore" LinkTo="More" runat="server" Tag="Div" CssClass="CommonContentBoxFooter" />
        </div>
      </TrailerTemplate>
    </CSControl:ContentFragment>
  </ItemTemplate>
</CSControl:ContentFragmentList>

Note the custom formatting of the <ItemTemplate /> of the <CSControl:ContentFragmentList /> and the customizations of the rendering of the <CSControl:ContentFragment /> to define a custom <LeaderTemplate /> and <TrailerTemplate />.  In this example, the <LeaderTemplate /> is used to render the ContentFragment's header and the <TrailerTemplate /> is used to render the ContentFragment's "view more" link if it is defined.

The control templates can be adjusted to fit the look/feel/markup of any custom theme.

 

Additional Options

There are a few additional notes and considerations when adding support for widgets to a theme: Setting Default and Filtering Selectable Widgets.

Setting Defaults for Widget Dynamic Configuration Properties

When shipping a custom theme, it is useful to include a default set of widgets for each column of widgets supported by the theme.  The easiest way to add default widgets is to

  1. Define the widget <property /> node and add the supporting Chameleon controls to the theme as described above.
  2. Use the theme configuration page for the theme to select and configure the widgets that you want to include by default and save the theme changes.
  3. When your widgets are properly defined, use the export feature of the theme configuration page to get the sharable XML version of your configuration data.
  4. Locate the <property /> node in this XML file with the id matching the id given to each widget column.
  5. For each <property /> node relating to a widget column in the XML export file, copy the contents of the <value /> node (<![CDATA[... blah ... ]]>) and paste it into a <defaultValue /> node within the <property /> node defining the widget column in the theme's theme.config file.

The final result should look like:

<property id="myWidgetColumn" text="Widgets" dataType="Custom" controlType="CommunityServer.Controls.ContentFragmentsCustomControl, CommunityServer.Controls">
  <defaultValue>
    <![CDATA[
      <contentFragments>
        <contentFragment type="CommunityServer.Controls.SiteUrlContentFragment, CommunityServer.Controls" id="2df9ece8-fe74-46c6-b82a-a42a65664fe8" configuration="fragmentTitle=Shortcuts&amp;controlpanel=False&amp;blogAdmin=False&amp;mediaAdmin=True&amp;user_List=False&amp;post_NotRead=False&amp;forumSubscriptions=False&amp;usersOnline=False&amp;forumModeration=False&amp;hub_create=False&amp;allGroups=False&amp;groupAdmin=False&amp;customLinks=&amp;listCssClass=CommonSidebarList" />
        <contentFragment type="CommunityServer.Controls.TagCloudContentFragment, CommunityServer.Controls" id="2b1a7190-3b89-4a19-985c-eaf6c41e993d" configuration="applicationType=MediaGallery&amp;ignoreFilterTags=False&amp;maximumTags=25&amp;minimumPostsPerTag=0&amp;filterTags=&amp;fragmentTitle=Tags&amp;tagCloudCss=CommonSidebarTagCloud&amp;tagCss=CommonTag6%2cCommonTag5%2cCommonTag4%2cCommonTag3%2cCommonTag2%2cCommonTag1&amp;showTagCounts=False&amp;noTagsText=No+Tags+Found&amp;linkTo=ContextualTagBrowser" />
      </contentFragments>
    ]]>
  </defaultValue>
</property>

This will set the default set of widgets used by a new installation of the theme as well as the set of widgets used after clicking the "Restore Defaults" button on the theme configuration page.

Filtering the Available Widgets for a Widget Dynamic Configuration Property

If a column of widgets is only going to be shown in a blog, why show forums-related widgets in the widget drop-down?

CS2008 supports filtering the widget drop-down list by application type.  To add an application-type-based filter to a widget dynamic configuration property, add the applicationTypes attribute to the <property /> in the theme.config file defining the widget column.  The value of this attribute is a comma-separated list of the application types for which associated widgets should be listed. For example,

<property
   id="myWidgetColumn"
   text="Widgets"
   dataType="Custom"
   controlType="CommunityServer.Controls.ContentFragmentsCustomControl, CommunityServer.Controls"
   applicationTypes="Forum,Weblog"
   />

would only allow blog- and forum-related widgets to be selected for this widget list/column.

Note that when filtering widgets by application type, widgets that do not identify an associated application type will always be included in the list of available widgets--this includes the "Generic Content", "Google Gadget" and other application-generic widgets.

 

In my next article covering CS2008, I'll talk about implementing custom widgets.

Questions? Please ask in the comments.