A More Flexible Set of Container Panels


Note this article is based on mojoPortal content management system version 2.3.6.6 or higher.

Rationale

Over time we have seen more and more need for better control over markup rendering for various reasons. Support for Artisteer was one of them since it needed specific CSS classes and additional markup in various places to match their exported html templates. Then newer versions of Artisteer keep introducing little changes over time, CSS classes changed from mixed case to lower case for example, so skins designed with older versions need different CSS classes than with newer versions. Also the emergence of HTML 5 and the goal to be able to provide a good experience for mobile devices and smart phones are other things pushing the need for more control over the markup rendered.

It would be nice to be able to use the newer HTML 5 structural elements if we want to, and it would be really great if we can provide a truly optimized experience for smart phone browsers. When we started off with supporting Artisteer we implemented it making the fewest changes we could and over time we've had to code in different things for different cases and different versions of Artisteer.

After stepping back a bit and looking at the problem as a whole and considering both our changing needs with different versions of Artisteer and our goals for HTML 5 and mobile it seemed clear that we need a more flxible way of doing things than what we have done in the past. So to that end I did some thinking about how to improve on the techniques we were already using and take it to the next level, and came up with a set of Panel controls that allow us to manage many aspects of the rendering from the theme.skin file.

What Do We Need Our Container Panels To Do?

We need to be able to control the element used, so instead of rendering as a div it could be configured to render as a section or article (new elements introduced in HTML 5).

We need to be able to control what CSS classes are rendered on the container element.

We need the ability to optionally inject some extra unsemantic markup into the top and bottom of the container element if needed for styling (ie for Artisteer support).

For Artisteer we even need to be able to use different CSS classes and extra markup if the content is in a side column rather than center.

We also would like to be able to not even render the container element but only render the contents inside it. Since not all designs need that many levels of nested containers, it would be nice to be able to leave out some of that markup.

The Solution Flexible Panels

So we implemented  a set of new Panel controls:
BasePanel
OuterWrapperPanel
InnerWrapperPanel
OuterBodyPanel
InnerBodyPanel
EmptyPanel

BasePanel inherits from the regular <asp:Panel which renders as a div by default, but we've modified it to support the needs identified above.
All of the other panels inherit from BasePanel and currently have no additional functionality than that provided by BasePanel.
The idea is that we don't use BasePanel directly, but instead we use the sub classes which have been named by the context in which they should be used. So each of the sub class panels has the functionality of the BasePanel, but we can configure those features separately for each type of panel using the theme.skin file. For example these properties shown here with their default values can all be configured separately for each panel type:

<portal:OuterBodyPanel runat="server"
RenderId="true"
Element="div"
ExtraCssClasses=""
RenderContentsOnly="false"
LiteralExtraTopContent=""
LiteralExtraBottomContent=""
DetectSideColumn="false"
SideColumnxtraCssClasses=""
SideColumnLiteralExtraTopContent=""
SideColumnLiteralExtraBottomContent=""
/>

This example shows an example configuration for Artisteer 2.4 up to 3.0

<portal:OuterBodyPanel runat="server"
   Element="div"
   ExtraCssClasses="art-postcontent"
   RenderContentsOnly="false"
   DetectSideColumn="true"
   SideColumnxtraCssClasses="art-blockcontent"
   SideColumnLiteralExtraTopContent="<div class='art-blockcontent-tl'></div><div class='art-blockcontent-tr'></div><div class='art-blockcontent-bl'></div><div class='art-blockcontent-br'></div><div class='art-blockcontent-tc'></div><div class='art-blockcontent-bc'></div><div class='art-blockcontent-cl'></div><div class='art-blockcontent-cr'></div><div class='art-blockcontent-cc'></div><div class='art-blockcontent-body'>"
   SideColumnLiteralExtraBottomContent="</div><div class='cleared'></div>"
   />
  
Previously the needed CSS classes and all that extra markup had to be hard coded in C#, but now you can see that if the needed extra markup changes for the next version of Artisteer, we will be able to change it easily from the theme.skin file.

Using the New Panels

Perhaps the easiest way to show how the new panels are used is with an example, this is the HtmlModule.ascx file using the old markup without the new flexible panels.

<%@ Control language="c#" Inherits="mojoPortal.Web.ContentUI.HtmlModule" CodeBehind="HtmlModule.ascx.cs" AutoEventWireup="false" %>

<portal:ModulePanel ID="pnlContainer" runat="server">
<portal:mojoPanel ID="mp1" runat="server" ArtisteerCssClass="art-Post" RenderArtisteerBlockContentDivs="true">
<mp:CornerRounderTop id="ctop1" runat="server" EnableViewState="false" />
<portal:ModuleContainer ID="pnlWrapper" runat="server"  CssClass="art-Post-inner panelwrapper htmlmodule">
<portal:ModuleTitleControl id="Title1" runat="server" EditUrl="/Modules/HtmlEdit.aspx" EnableViewState="false" />
<portal:mojoPanel ID="MojoPanel1" runat="server" ArtisteerCssClass="art-PostContent">
<portal:mojoRating runat="server" ID="Rating" Enabled="false" />
<div class=" modulecontent">
<portal:SlidePanel id="divContent" runat="server" EnableViewState="false" EnableSlideShow="false" class="slidecontainer"></portal:SlidePanel>
<portal:FacebookLikeButton ID="fbLike" runat="server" Visible="false" />
</div>
<div class="modulefooter"></div>
</portal:mojoPanel>
<div class="cleared"></div>
</portal:ModuleContainer>
<mp:CornerRounderBottom id="cbottom1" runat="server" EnableViewState="false" />
</portal:mojoPanel>
</portal:ModulePanel>

and this is the new implementation using the new set of panels:

<%@ Control language="c#" Inherits="mojoPortal.Web.ContentUI.HtmlModule" CodeBehind="HtmlModule.ascx.cs" AutoEventWireup="false" %>

<portal:OuterWrapperPanel ID="pnlOuterWrap" runat="server">
<mp:CornerRounderTop id="ctop1" runat="server" EnableViewState="false" />
<portal:InnerWrapperPanel ID="pnlInnerWrap" runat="server"  CssClass="panelwrapper htmlmodule">
<portal:ModuleTitleControl id="Title1" runat="server" EditUrl="/Modules/HtmlEdit.aspx" EnableViewState="false" />
<portal:OuterBodyPanel ID="pnlOuterBody" runat="server">
<portal:mojoRating runat="server" ID="Rating" Enabled="false" />
<portal:InnerBodyPanel ID="pnlContent" runat="server" CssClass="modulecontent">
<portal:SlidePanel id="divContent" runat="server" EnableViewState="false" EnableSlideShow="false" class="slidecontainer"></portal:SlidePanel>
<portal:FacebookLikeButton ID="fbLike" runat="server" Visible="false" />
</portal:InnerBodyPanel>
<portal:EmptyPanel id="divFooter" runat="server" CssClass="modulefooter" SkinID="modulefooter"></portal:EmptyPanel>
</portal:OuterBodyPanel>
<portal:EmptyPanel id="divCleared" runat="server" CssClass="cleared" SkinID="cleared"></portal:EmptyPanel>
</portal:InnerWrapperPanel>
<mp:CornerRounderBottom id="cbottom1" runat="server" EnableViewState="false" />
</portal:OuterWrapperPanel>

We will be working through existing features and changing to the new approach. For those of you who have already implemented your own custom features, the old way will still work, so it is not mandatory to change to the new way of doing things. But if you want to be able to take advantage of the benefits provided by these controls, it may be worthwhile for you to revisit your current custom features.

This will be especially important as we work on our goal for a mobile optimized experience, and if you want to make your own features have the same possibilities for optimization it would be a good idea to follow the new approach. We can currently use a different skin for mobile devices, and these abilities will make it possible to control more of the experience by the skin configuration. Using a different skin will probably be only a part of our mobile solution, but the more control we have from the skinning end of things the better.

Last Updated 2011-05-21 by Joe Audette