Forums

Control Layout Customization Issues

  • 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.

    1. You can change the markup globally in /Utility/{Content,Footer,Header}Fragments.
    2. 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.
    3. 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.


    --
    --Jeff (ATGi)
  • The changes to theming in Telligent Community 5.0 were geared towards improving end-user customization support and enhancing upgradability.

    1. All themes are based on the same set of standard markup.  This enables widgets to be theme-generic and their markup to be predictable for custom CSS.
    2. All widgets are self-contained pieces of end-user functionality.  A widget may correspond relatively directly with a Chameleon control (forms, for example), but is generally a larger set of functionality (a formatted list of posts).  Configuration options are geared towards end-users and are should not be technical or include styling (raw CSS) options.
    3. Any variation from core themes should be implemented as new widgets.  This approach clearly identifies where customizations branch from core functionality.
    4. All of the core widgets are based on a set of core/generic markup and style rules.  Any customization (adding additional wrapping HTML, reordering, etc) is performed using markup translations which are regex-based.  Although XSLT could be used (assuming all markup in all widgets--including 3rd party widgets--is well-formed), it wouldn't provide significantly different functionality.
    5. Since core widgets customization is stored as meta-data, it can be interpreted in future versions against changes in markup/control functionality without requring theme-level review of changes.  This will allow the produce to add new features more easily while enabling customers to upgrade without a long review and test cycle.  After adjusting to the new approach, our internal services team was able to save significant amounts of time over the old approach.... with the added benefit of eased upgrading.

    Allowing for an ASCX-based override file is almost exactly the same as copy-and-pasting an existing widget.  Most core widgets are a class and an ASCX.  The class identifies the name of the widget and its configuration options.  If you were customizing the ASCX, you would most likely also want to adjust the configuration options... or, more generally, branching from the core implementation/markup should be a complete branch (class+ASCX).

     

    Ben Tiedt's Blog

  • In general, we're recommending *not* creating new physical themes.  The goal is to manage theme customization completely through the UI (and not by manually editing the themes/ folder) for the vast majority of sites.  

    There is still a little ways to go to accomplish this goal (customization of header/footers, adding of images/css/scripts, etc), but hopefully you can see the benefits of this change of direction.  

    Ben Tiedt's Blog

  • Thanks for the reply Ben. I can see there are definitely significant strides toward a more customizable system in the new version. Some of them that you outline are going to make my life as a developer working with Telligent Community much easier, but I feel like you haven't really addressed my core concern - that I can't change the layout of a particular control for an individual theme without creating a new control and ASCX.  If the class+ASCX are really that tightly coupled, then I would say that the ASCX should be an embedded resource within the CS.Controls.dll and I shouldn't be able to change it at all. My goal is to change small bits of the HTML without needing to create and compile a new control. Without full control of the layout of every single part of every single control in the widget then embedding the ASCX seems foolish. So I am back to asking why can't I just substitue one layout for another?

    As far as Regular Expressions and XSLT being the same in this case, I just can't see it. It is much easier to select an element by a specific attribute (xpath) than to create a generic regex that I know will match and is maintainable. Would you suggest that I start using regexs to find elements in my DOM versus a call to getElementById()?

    When you say thay you don't recommend creating a new theme do you mean a new theme like the 'generic' directory, or a new theme like 'fiji'. I can understand that generic is just what it is named - the generic base. But I can't see that I wouldn't want to replace fiji with my own theme that uses the default layouts from the fiji theme. It makes it much easier to upgrade because that is then a copy over the existing and a merge into the new theme that has been created.

    --
    --Jeff (ATGi)
  • The class and ASCX represent the meta-data and implementation.  If the meta-data (configuration options, description) changed in a future version but the implementation (because it was overridden) did not keep up, the two would get out-of-sync.  Additionally, there is no guarantee that future versions of the core widgets will use ASCX controls.  Versioning the ASCX effectively versions the widget (and branches from Core), so, personally, I think it makes sense to make that versioning/branching complete and manage the class file seperately as well. The core ASCX files exist currently to aid in core development and show examples of widget implementations. 

    I'll try to divide the issues you're raising int two categories:

    Customizing Individual Widget Markup

    All widgets are based on a set of core/shared markup and style rules.  The style guide and theme translations will be published soon to the public wiki. 

    The markup/style guide was designed to be generic (and was not designed with any of the Evolution Platform themes in mind) and reusable, providing the ability to target individual pieces of content via CSS selectors to specific markup formats, specific widgets, and specific pages. 

    When implementing the out-of-the-box themes, we implemented markup translations to adjust the standard markup to meet the styling needs of the specific theme when CSS alone was not sufficient.  Although HTML is structured, strict enforcement of that structure is not required by browsers... all major browsers still make sense of 'tag soup'... so it would be difficult to require that all markup served from the Telligent Evolution Platform be completely well-formed (a requirement to use XSLT).  Without wellformedness, we're left with a stream of text... and regular expression-based replacements made sense.  We used this technique to implement the OOTB themes and it worked relatively well.  The ideal translation would be full CSS-style selector support (similar to jQuery), but implementing that complex of a rule engine when full parsing of the document is not required seemed excessive. 

    So.. issue #1.  How can customizations best adjust markup?  Options:

    1. Don't.   Try to use the base style/markup formats.  This will be easier when the style guide is published (we're waiting to document the translations before publishing the style guide... since the OOTB themes implement adjustments)
    2. Create new widgets.  This requires versioning from core, but provides full control over the rendered markup and style output.
    3. Use a markup translation.  Currently, this requires a new physical theme to be created based on the "generic:" theme.  This will enable allow greater customization of the theme, but also makes upgrading *slightly* more difficult.
    4. Edit the existing ASCX.  I wouldn't recomment this as it would make upgrading difficult (since upgrades would likely overwrite any changes made to the core ASCX... and we're not really guarenteeing that future versions of the core widgets will use ASCX controls)
    5. ... something else... we're still working on ways to make this easier.

    Customizing the Layout/Header/Footer of Themes

    Currently, the only way to customize the layout or add/remove header/footer fragments is to create a new theme.  Ideally, these options would be enabled through the front UI, but this has not yet occured.

    If a new theme is required (header, footer, translations, configuration need to be customized), I'd strongly suggest basing the new theme on the generic theme (as the Fiji and Evolution2 themes do).  This will enable the custom theme to use the OOTB widgets and a quick export-from-Fiji/Evolution2 and import-into-the-new-theme will result in a working base theme. 

    When a new theme is created, however, I'd degrade the upgrade effort from "easy" (drop in the new DLLs/files and your customized site based on core themes and core widgets just works) to "relatively easy" (drop in the new DLLs/files , restore your custom theme's folder and header, footer, content fragments, review, and correct any issues).

    This is another area we're still working on improving.  Ideally, even when making header, footer, translation, etc changes, a new physical theme would not be required... and a customized theme could still exist as a new theme selection, but support full import, export, etc functionality.

    Issue #2 -- When/how should I create a new physical theme?

    1. *Only* when the header, footer, translations, or configuration options must be adjusted should a new theme be created.  If at all possible, try to use one of the OOTB themes.
    2. If a new theme is created, base it on the generic theme (similar to the OOTB themes).  This will enable an *easier* upgrade path (though not as easy as using one of the built-in themes).
    3. When creating a new theme, export the defaults for the core theme and import them into the new theme... this will provide a good basis for the content of the new theme while changes are being made
    4. ... in the future, we will further minimize the needs to create a new physical theme.

    Ben Tiedt's Blog

  • This is some great information. Thanks for the time that you put in here. 

    On Issue #1, I have some comments:

    1. Don't, doesn't always work for me (but might more often than I think). There are some things where working with the CSS on the default markup just isn't going to give me enough control over the presentation.
    2. Create new widgetsI think you have won me over to the fact that I need to create a new control-ASCX combo if there are any changes I want to make. I understand your arguments of versioning and that they ASCXs might disappear in a future version.
    3. Use a markup translationI don't want to sound like I am against the idea of using the markup translations in the theme.config. I like that idea, and if you had provided me a jQuery like interface in there instead of regular expressions I would have thought something like "awesome - this is just like jQuery" and moved on. I only suggest XSLT because it was the next most obvious to me. I understand the issues of validation. As it stands, I still feel like regexs are just so much lipstick on a pig for this application.
    4. Edit the existing ASCX. If you say this isn't a good idea, I am fine with that, it just seemed like a good place to start so I based my arguments off of it.
    5. ... something else... I want to lobby for jQuery like syntax in the markup translations. That would make things easy/familiar for the theme developer, with a bit more work on your end.

    Issue #2

    I operate in a world where the basic layout of a theme is almost always going to be customized, so I think that point #2 under Issue #2 is what applies to my development efforts. Although the features of version 5 have decreased the need for that on some of the simpler solutions that I have implemented in the past.

    --
    --Jeff (ATGi)
  • Ben, I would love to leave OOTB physical themes as is. In general I support this direction with new CS UI, basically this is what we did for our customers and I already mentioned some details Also with those atomic filters we were able to support CF in any layout, including

    But this CF/CF+ascx approach requires rock solid OOTB themes. For example, as a Telligent Partner I'm working with non-English customers hence need to take care about localization. Recently I reported 460+ bugs in multi-language support in Fuji/Evolution2 themes and Control Panel. So what do you think customers should do about it? Fix it now? Wait for next service release? I don't know what kind of software testing process you guys using but it definitely need some improvements.

  • It would be nice to have a subfolder inside of a theme folder (like fiji) that contains a directory structure similar to the utitlity/ContentFragments folder that can be used for overriding. Forexample, look in theme folder for the .ascx for the fragement, if not there, then use the default fragement located directly in the utitlity/ContentFragments folder.

    This could be done easily as soon as the SDK comes out.

    ~Paul Knopf

    Blog, services and more at Adept Web Studios

  • PKnopf

    It would be nice to have a subfolder inside of a theme folder (like fiji) that contains a directory structure similar to the utitlity/ContentFragments folder that can be used for overriding. Forexample, look in theme folder for the .ascx for the fragement, if not there, then use the default fragement located directly in the utitlity/ContentFragments folder.

    This could be done easily as soon as the SDK comes out.

    I am actually writing some bits that will do exactly this. I will be publishing to CodePlex sometime tomorrow and I will update this thread once I have.

    John Bledsoe

    Sr. Software Specialist - ATGi

  • John Bledsoe

    I am actually writing some bits that will do exactly this. I will be publishing to CodePlex sometime tomorrow and I will update this thread once I have.

    Sweet! Thanks for this!

    How are you doing it without the sdk? inheriting and then overriding?

    ~Paul Knopf

    Blog, services and more at Adept Web Studios

  • Module is implemented and available at http://tccontrolurlresolver.codeplex.com/.

    As for how I took control of the location of controls without touching the SDK (or any TC5 code for that matter), the secret is in an ASP.NET component called the Virtual Path Provider. Whenever the ASP.NET system asks for a virtual path (such as "~/Utility/HeaderFragments/Core/SiteBanner.ascx"), the virtual path provider is called to retrieve a virtual file for the path. The standard provider used by ASP.NET just maps the specified path to a physical disk location. The provider I implemented uses the base provider, but examines current Community Server context to determine the current theme and to systematically search for an alternate file.

    Incedentally, a virtual path provider can be used for all sorts of applications, such as retrieving control markup from assembly resources or a database. It is a nifty tool to have in your ASP.NET toolbox.

    Please direct any specific questions or discussion about the project to the CodePlex project forum. Or you can keep them on this thread, if that will make you happy. Smile

    John Bledsoe

    Sr. Software Specialist - ATGi

  • Even a few years later, this remains a really interesting and useful discussion.  Ben, I appreciate you taking the time to address these questions - it's a service to the entire community.  It's nice to see this level of transparency over the thinking behind the design process.

  • Because this thread is still active, I'd like to point out that we've addressed many of these issues in Evolution 6.  Specifically:

    1.  Widgets are now fully defined in the control panel and can be fully editable.

    2.  Language resources (for localization) are now stored with the widget.

    3.  Evolution 6 provides a set of initial widgets that can be edited and customized to meet specific needs.  These widgets can be imported/exported and shared on the marketplace.

    4.  Widgets in Evolution 6 can be versioned to render differently for different themes.

    5.  Headers and footers in Evolution 6 are now fully editable using a similar UI as page editing.

    6.  Widgets in Evolution 6 make use of the Platform API (an expansion of the REST API in previous versions) to ensure upgrade safety.

    Ben Tiedt's Blog