Turbo twitter Bootstrap theming for Plone using Diazo

When building a new Plone theme based on twitter Bootstrap without modifying core templates you have to do a lot of xsl-styling. Hopefully this article can help you getting started.

Building a diazo theme

You should have basic knowledge of how to build a diazo theme in Plone. So you will have a file called rules.xml and hopefully your bootstrap javascript and css code already plugged into Plone resource registries. An installable Plone product is available here.

Read more about bootstrap css-classes and javascript components.

Content Views

Transforming the edit-bar is not very hard, following rule provides a really good working solution.

../../_images/bootstrapeditbar.png

Mark active tab in content views

<xsl:template match="//ul//@class[contains(., 'selected')]">
    <xsl:attribute name="class">
        <xsl:value-of select="." /> active
    </xsl:attribute>
</xsl:template>

<xsl:template match="//ul//@class[contains(., 'contentActions')]">
    <xsl:attribute name="class">nav nav-tabs</xsl:attribute>
</xsl:template>

Rebuild contentActionsMenu and integrate it into new

The code below will transform your .contentActionMenus in your #edit-bar into following bootstrap dropdowns:

../../_images/bootstrapaddnew.png
<xsl:template match="//ul[@id='contentActionMenus']//li">
    <li>
    <xsl:attribute name="class">dropdown pull-right</xsl:attribute>
        <a>
            <xsl:attribute name="class">dropdown-toggle</xsl:attribute>
            <xsl:attribute name="data-toggle">dropdown</xsl:attribute>
            <xsl:attribute name="href"><xsl:value-of select="." /></xsl:attribute>
            <!-- TODO: Include something like dl/dt/a/span/@class[not( contains(.,'arrow'))] -->
            <xsl:value-of select="dl/dt/a/span[1]" />
        </a>
        <ul>
            <xsl:attribute name="class">dropdown-menu</xsl:attribute>
            <xsl:for-each select="dl/dd/ul/li">
                <xsl:if test="@class='actionSeparator'">
                    <li><xsl:attribute name="class">divider</xsl:attribute></li>
                </xsl:if>

                <xsl:copy-of select="." />
            </xsl:for-each>
        </ul>
    </li>
 </xsl:template>

Form Buttons

I’ve decided to use btn-danger for all remove and delete buttons and btn-primary for primary submit buttons.

../../_images/bootstrapbuttons.png
<xsl:template match="//input[@type[contains(., 'submit') or contains(., 'button')]]">
    <input>
        <xsl:copy-of select="attribute::*[not(name()='class')]" />
        <xsl:attribute name="class"><xsl:value-of select="@class" /> btn
            <xsl:if test="@name[contains(., 'delete') or contains(., 'Remove')]">btn-danger</xsl:if>
            <xsl:if test="@name[contains(., 'save') or contains(., 'Save') or contains(., 'RenameAll')]">btn-primary</xsl:if>
        </xsl:attribute>
    </input>
</xsl:template>

Tables

By applying additional classes, you’ll get nice bootstrap tables.

../../_images/bootstraplistingtable.png
<xsl:template match="//table[@class[contains(., 'listing')]]">
    <table>
        <xsl:copy-of select="attribute::*[not(name()='class')]" />
        <xsl:attribute name="class">table-striped table-bordered table-hover table <xsl:value-of select="@class" /></xsl:attribute>
        <xsl:apply-templates />
    </table>
</xsl:template>

ListingBar

listingBar was tricky to transform, of course it would be easier to just customize the listingBar viewlet, but if you don’t want to touch Plone’s templates, you can use the xsl-transformations below.

../../_images/bootstrappagination.png
<xsl:template match="//div[@class='listingBar']">
    <div>
        <xsl:copy-of select="attribute::*[not(name()='class')]" />
        <xsl:attribute name="class"><xsl:value-of select="@class" /> pagination</xsl:attribute>
        <ul>
            <xsl:if test="span[@class='previous']/a">
                <li>
                    <xsl:copy-of select="span[@class='previous']/a" />
                </li>
            </xsl:if>
            <xsl:for-each select="*[not(contains(@class, 'previous')) and not(contains(@class, 'next'))]">
                <xsl:choose>
                    <xsl:when test="child::a and not(child::text())">
                    <li>
                        <xsl:copy-of select="./a[text()]" />
                    </li>
                    </xsl:when>
                    <xsl:when test="child::a and child::text()">
                        <xsl:if test="position() = last()">
                        <li>
                            <xsl:attribute name="class">disabled</xsl:attribute>
                            <a>
                                <xsl:attribute name="href">#</xsl:attribute>
                                <xsl:copy-of select="text()" />
                            </a>
                        </li>
                        </xsl:if>
                        <li>
                            <xsl:copy-of select="./a[text()]" />
                        </li>
                        <xsl:if test="position() = 1">
                        <li>
                            <xsl:attribute name="class">disabled</xsl:attribute>
                            <a>
                                <xsl:attribute name="href">#</xsl:attribute>
                                <xsl:copy-of select="text()" />
                            </a>
                        </li>
                        </xsl:if>
                    </xsl:when>
                    <xsl:when test="name()='span' and not(child::a)">
                        <li>
                            <xsl:attribute name="class">active</xsl:attribute>
                            <a>
                                <xsl:attribute name="href">#</xsl:attribute>
                                <xsl:copy-of select="text()" />
                            </a>
                        </li>
                        </xsl:when>
                    <xsl:when test="@href">
                        <li>
                            <a>
                                <xsl:attribute name="href"><xsl:value-of select="@href" /></xsl:attribute>
                                <xsl:copy-of select="text()" />
                            </a>
                        </li>
                    </xsl:when>
                    <xsl:otherwise>
                        <li>
                            <xsl:attribute name="class">disabled</xsl:attribute>
                            <a>
                                <xsl:attribute name="href">#</xsl:attribute>
                                <xsl:copy-of select="text()" />
                            </a>
                        </li>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
            <xsl:if test="span[@class='next']/a">
                <li>
                    <xsl:copy-of select="span[@class='next']/a" />
                </li>
            </xsl:if>
        </ul>
    </div>
</xsl:template>

Comments

comments powered by Disqus