I have been reviewing Telligent Communinty 5 for a couple days now and I have some issues with the current implementation of
ExternallyImplemented{Content,Footer,Header}FragmentBase classes/controls. To give some context - I work for a Telligent partner and my main responsibility here is to customize CS for our clients. When we customize CS we almost always create a new theme, so that is where I started working with TC 5. There are some really neat bits here, but it seems like one major thing was overlooked/rushed/just not done right.
There is no easy way to change the markup that is rendered
for a particular theme. I can see three ways to change the output of a control.
- You can change the
markup globally in /Utility/{Content,Footer,Header}Fragments.
- You can write a new control that is basically a cut-and-paste copy of the current one, but points to a different .ascx file.
- You can use
regular expressions in the <MarkupTranslations> section of theme.config
to rearrage the output of the controls.
The first option is reasonable but makes
upgrades more difficult and will not allow per theme control customization.
The second option will work, but is really a hack and will be unmaintainable as things are upgraded. Using regular expressions to write HTML is entirely unacceptable. I don't know
if that decision was rushed, but it regex's are, at best, an unreliable method
for manipulating HTML. I can see two solutions that would address these
problems.
Summary:
To create a new theme in TC5 you either have to do things that will make your site a pain to upgrade, or abandon the idea of different themes having different layout, or mess with regular expressions just to write HTML.
One Solution:
Use XSLT in the <MarkupTranslations> section of the
theme.config. We are working with structured data here, so why not use a tool
that is meant to manipulate it? That way it is unimportant if the id attribute or the class attribute on a control is rendered first. With the regex approach, this is very important and must be carefully controlled. A potential issue is that all pages/control markup would be
required to validate for this to work.
Second (better) solution:
Allow theme authors to specify the control template they
want to use to render the fragment control in theme.config. This is almost
there already. Here I am using the SiteBanner HeaderContentFragment as an example.
What is currently in theme.config:
<HeaderFragment
type="CommunityServer.Controls.HeaderFragments.WelcomeMessage,
CommunityServer.Controls" />
What could solve this problem:
<HeaderFragment
type="CommunityServer.Controls.HeaderFragments.WelcomeMessage,
CommunityServer.Controls"
controlSource="~/my/path/to/the/control.ascx" />
With the following additions to the code in
CommunityServer.Components.ExternallyImplementedHeaderFragmentBase:
public string UserControlUrl { get return _userControlUrl;
set _userControlUrl = value; }
And the following implementation of LoadHeaderFragments in
CommunityServer.Components.ThemeConfiguration:
private void LoadHeaderFragments(XmlNode parentNode)
{
foreach (XmlNode
node in parentNode.ChildNodes)
{
if
(((node.Name == "HeaderFragment") &&
(node.Attributes["type"] != null)) &&
!string.IsNullOrEmpty(node.Attributes["type"].Value))
{
try
{
Type type =
Type.GetType(node.Attributes["type"].Value);
if
(type != null)
{
IHeaderFragment item = Activator.CreateInstance(type) as
IHeaderFragment;
if
(item != null)
{
if
((node.Attributes["controlSource"] != null)) &&
!string.IsNullOrEmpty(node.Attributes["controlSource"].Value)
item.UserControlUrl
= node.Attributes["controlSource"].Value;
this._headerFragments.Add(item);
}
}
continue;
}
catch
{
continue;
}
}
}
}
I understand that by choosing to look at HeaderFragments things are a bit simplified over the generic control fragments, but the same concepts apply and should be able to be implemented. The current implementation has basically broken the whole workflow for customizing a CS site. Please tell me that this is at least on the radar for things that need to be changed in the next release.