Adventures In Theming: Overriding A Stock Viewlet

This is the sixth post in a short series about the ideas, trials and tribulations of my first theme product. I’ll be posting the whole story in one place when the series is complete.

I Forgot The Footer! (Overriding Stock Viewlets)

I’ve managed to get all of the styling nailed down. Here’s what it looks like now:

Looking Good.... But wait!

Looking Good.... But wait!

So here’s what’s different: The extra viewlets are gone. I’ve added in all of the background images. I’ve styled the portlets. It’s become obvious that I’m going to have to do some more specific customization of the calendar portlet, but that’s not a big deal right now.

You may have been wondering what I did with the search viewlet that’s normally up in the right hand corner. In this screenshot, you can see I opted to use the search portlet instead… and yeah, that was my plan all along. :)

In addition, I’ve added my own copy of the modern plone logo, with a transparent background. I accomplished this by putting a file called "logo.jpg" into /src/my.theme/my/theme/skins/my_theme_custom_images.

Here’s the CSS as it stands now:

src/my.theme/my/theme/browser/stylesheets/main.css

/* Stylesheet for the 'My Theme' Plone theme */

body {
    background-color: #cfd8e5;
}

#siice_header #main {
    height: 90px;
}

#my_header #left_side {
    float: left;
    clear: left;
    height: 90px;
    width: 50%;
    background-image: url("++resource++my.theme.images/left_background.png");
    background-repeat: no-repeat;
}

#my_header #right_side {
    float: right;
    clear: right;
    height: 90px;
    width: 50%;
    background-repeat: no-repeat;
    background-position: right;
    background-image: url("++resource++my.theme.images/right_background.png");
}

#my_header #personal_bar_sections {
    clear: both;
}

#my_header #personal_bar {
    float: right;
    clear: right;
}

#my_header #sections {
    float: left;
    clear: left;
}

#my_header #crumbtrail {
    clear: both;
}

#my_header #personal_bar_sections {
    background-image: url("++resource++my.theme.images/tabs_background.png");
    height: 20px;
    background-repeat: repeat-x;
    background-color: #b7c4c8;
    border-bottom: 1px solid #93a7ac;
    background-position: top;
}
/************* Override Plone Styles **********/

/* Logo */
#portal-logo {
    float: right;
    padding-right: 5px;
}

/* Site Actions */
#portal-siteactions {
    float: left;
}

#portal-siteactions li a, #portal-siteactions li a:hover, #portal-siteactions li a:active, #portal-siteactions li a:visited {
    border: 0px;
    color: #5f8dd3;
    background-color: transparent;
}

/* Top Sections */
#portal-globalnav {
    padding: 0px;
    font-size: 110%;
}

#portal-globalnav li.selected a {
    color: #000000;
    background-color: transparent;
    border: none;
}

#portal-globalnav li.plain a {
    color: #000000;
    background-color: transparent;
}

/* get rid of the left border for the first tab, the index page */
#portaltab-index_html {
    border: 0px !important;
}

#portal-globalnav li {
    border: 0px;
    border-left: 1px solid #000000;
}
#portal-globalnav li a {
    border: 0px;
    color: #000000;
    background-color: transparent;
    margin: 0px;
}

/* Personal Bar */
#portal-personaltools {
    padding: 0px;
    padding-right: 1em;
    background-color: transparent;
    border: 0px;
}

/* Bread Crumbs Nav */
#portal-breadcrumbs {
    background-color: #b7c4c8;
    border-bottom: none;
}

#portal-breadcrumbs a {
    color: #4b93ff;
}

/* "Green" action tabs */
.contentViews li a {
    background-color: #e3f4d7;
}

/* Portlets */
.portletHeader, .portletFooter, .portletItem, .portlet {
    border: 0px !important;
}

.portletHeader {
    text-transform: none;
    font-size: 110%;
}

.portletHeader, .portletFooter {
    background-color: #b5c3d7 !important;
}

.portletItem {
    background-color: #dfe5ee;
}

.portletHeader a, .portletFooter a, .portletItem a {
    border: 0px;
}

/* Page Body */
.documentContent {
    border: 1px #447821 solid;
}

Considering the amount of CSS that Plone uses, this isn’t that much to override. I’m sure if I was delving deepter into the content area it might be a little more cumbersome, but it looks like the core theme is pretty well built for utilizing CSS to it’s fulllest.

A nice bonus of this layout: it works with large fonts. I haven’t tested it in Internet Explorer or Safari yet, but I can hit ctrl-+ over and over with no ill effects. w00t!

You’ll notice, of course, that I’ve missed the portal footer, the bit just above the colophon at the bottom of the page. I styled it in my mockup but have neglected to give it any attention in my theme product. Now is the time.

I don’t like the idea of just slapping a background on the div around the footer via CSS. I like my styles to be flexible, and if the font size got beyond a certain point, the text would exceed the height of the background. That’s just messy. There’s also the chance that I may need to put some static content inside of the portal footer that I don’t want overriden by any user-configurable options. Examples include a special copywright notice or link to a help center.

Normally, this isn’t a big deal. In my application, however, I may have people with the Manager role running around on the sites that use this theme that aren’t under my jurisdiction.

What this all means is that I need a new viewlet to replace the portal footer viewlet. Luckily, executing such a task is easier than explaining why I need to do it :).

Anyway, overriding a viewlet can be accomplished entirely in ZCML if you want. The same goes for viewlet managers, in theory at least. But, if you need it, you have the option to produce a class that can give you more flexibility.

The Theme Reference has a good overview of what you need to do. Here’s what my <browser:viewlet> tag looks like:

src/my.theme/my/theme/browser/configure.zcml

...
  <browser:viewlet
        name="plone.footer"
        for="*"
        manager="plone.app.layout.viewlets.interfaces.IPortalFooter"
        template="footer.pt"
        permission="zope.Public"
        layer=".interfaces.IThemeSpecific"
        />
...

With this configuration, I just had to drop a footer.pt file into my browser directory and bickety-bam, my footer shows up!

Note that I made sure to specify a layer so my override will only be enabled when my theme is in effect.

I took a look at the footer template that comes with Plone to be sure nothing special was happening. No worries there, so in my footer.pt, I was free to code it how I wished. I did borrow the date/time stuff to display the copywright year, however. Clever!

For the sake of illustration, in my examples here I’ve pulled the full copywright from Plone’s storck footer template. Here’s what it looks like:

src/my.theme/my/theme/browser/footer.pt

<div id="my_footer">
    <div id="my_copywright">
        <p>
    <span i18n:translate="description_copyright" tal:omit-tag="">
    The
    <span i18n:name="plonecms" tal:omit-tag="">
        <a href="http://plone.org" i18n:translate="label_plone_cms">Plone<sup>&reg;</sup> CMS &mdash; Open Source Content Management System</a>
    </span>
    is
    <acronym title="Copyright" i18n:name="copyright" i18n:attributes="title title_copyright;">&copy;</acronym>
    2000-<span i18n:name="current_year"
               tal:omit-tag=""
               tal:define="now modules/DateTime/DateTime"
               tal:content="now/year" />
    by the
    <span i18n:name="plonefoundation" tal:omit-tag="">
        <a href="http://plone.org/foundation" i18n:translate="label_plone_foundation">Plone Foundation</a></span>
    et al.
    </span>
</p>

<p>
    <span i18n:translate="description_trademark" tal:omit-tag="">
    Plone<sup>&reg;</sup> and the Plone logo are registered trademarks of the
        <span i18n:name="plonefoundation" tal:omit-tag="">
            <a href="http://plone.org/foundation" i18n:translate="label_plone_foundation">Plone Foundation</a></span>.
    </span>

    <span i18n:translate="description_license" tal:omit-tag="">
    Distributed under the
        <span i18n:name="license" tal:omit-tag="">
            <a href="http://creativecommons.org/licenses/GPL/2.0/" i18n:translate="label_gnu_gpl_licence">GNU GPL license</a></span>.
    </span>
</p>
    </div>
    <div id="my_footer_shadow"></div>
</div>
<br />

Here’s what I added to my existing CSS file to make the footer look like it does in my original design:

src/my.theme/my/theme/browser/stylesheets/main.css

...
#my_footer {
    border-top: 2px solid #a9dd89;
        background-color: #d2dce2;
    background-image: url("++resource++my.theme.images/footer_background.png");
    height: 32px;
    background-repeat: repeat-x;
    background-position: top;
    clear: both;
}

#my_footer #my_copywright {
    text-align: center;
}

#my_footer #my_footer_shadow {
    background-image: url("++resource++my.theme.images/footer_shadow.png");
    border-top: 2px #879ba3 solid;
    height: 10px;
    background-repeat: repeat-x;
    background-position: top;
    clear: both;
}
...

A quick note about my background images

Each of my gradient backgrounds are much larger than they need to be height-wise, and the color of the last row of pixels is the same as the background color of the element they’re in the background of. This helps to ensure that the text can stretch to a severe degree, either in amount or font-size, and the gradient still looks good.

With the new CSS added, here’s what it looks like:

Ah, that's much better

Ah, that's much better

So almost everything is done! All that’s left is some cleanup and testing.

Advertisements
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s