wiki:EggCookingTutorial/AdvancedEggCooking2

Cooking high-end eggs

Now that you have a working version of a plugin already, let's add a final twist and serve some static content like a stylesheet and an image.

Important thing to check

First step is to ensure that your trac.ini doesn't have htdocs_location set, otherwise Trac can't serve static data.

More directories

We will need a few more directories for the files that we will add:

./helloworld-plugin/helloworld/htdocs/
./helloworld-plugin/helloworld/htdocs/css/
./helloworld-plugin/helloworld/htdocs/images/

Style is everything

We want to use our own stylesheet to give some color to our content. For that we need cascading stylesheets.

Create helloworld.css in ./helloworld-plugin/helloworld/htdocs/css/:

div.helloworld h1 {
        color: red;
}

Image tells more than thousand words

Images enhance the look and feel of your site. Put small image named helloworld.jpg in ./helloworld-plugin/helloworld/htdocs/images/.

Egg grows

Even natural eggs doesn't grow Python eggs does.

Modify setup.py to include our static data:

from setuptools import setup

PACKAGE = 'TracHelloworld'
VERSION = '0.1'

setup(name=PACKAGE,
      version=VERSION,
      packages=['helloworld'],
      entry_points={'trac.plugins': '%s = helloworld' % PACKAGE},
      package_data={'helloworld': ['htdocs/css/*.css', 'htdocs/images/*.jpg',
                                   'templates/*.cs']},
)

Tell it to Trac

Trac doesn't know where our stylesheet and image is located, so you have to tell it to Trac.

Add the following code at the tail in file helloworld.py, which implements get_htdocs_dir() to tell the static data path information for this plugin with identical prefix 'hw':

    def get_htdocs_dirs(self):
        """Return a list of directories with static resources (such as style
        sheets, images, etc.)

        Each item in the list must be a `(prefix, abspath)` tuple. The
        `prefix` part defines the path in the URL that requests to these
        resources are prefixed with.

        The `abspath` is the absolute path to the directory containing the
        resources on the local file system.
        """
        from pkg_resources import resource_filename
        return [('hw', resource_filename(__name__, 'htdocs'))]

Remember to load stylesheet

To make Trac to load our stylesheet you need to modify process_request method starting from line 23 to following:

    def process_request(self, req):
        add_stylesheet(req, 'hw/css/helloworld.css')
        return 'helloworld.cs', None

Note that prefix path 'hw/' specified by get_htdocs_dirs() should be used.

And also import add_stylesheet() at the beginning of helloworld.py:

from trac.web.chrome import INavigationContributor, ITemplateProvider, \
        add_stylesheet

Complete version of code

The whole of the Python code is here:

# Helloworld plugin

from trac.core import *
from trac.web.chrome import INavigationContributor, ITemplateProvider, \
        add_stylesheet
from trac.web.main import IRequestHandler
from trac.util import escape, Markup

class UserbaseModule(Component):
    implements(INavigationContributor, IRequestHandler, ITemplateProvider)

    # INavigationContributor methods
    def get_active_navigation_item(self, req):
        return 'helloworld'

    def get_navigation_items(self, req):
        yield 'mainnav', 'helloworld', Markup('<a href="%s">Hello</a>',
                self.env.href.helloworld())

    # IRequestHandler methods
    def match_request(self, req):
        return req.path_info == '/helloworld'

    def process_request(self, req):
        add_stylesheet(req, 'hw/css/helloworld.css')
        return 'helloworld.cs', None

    # ITemplateProvider methods
    def get_templates_dirs(self):
        """Return a list of directories containing the provided ClearSilver
        templates.
        """
        from pkg_resources import resource_filename
        return [resource_filename(__name__, 'templates')]

    def get_htdocs_dirs(self):
        """Return a list of directories with static resources (such as style
        sheets, images, etc.)

        Each item in the list must be a `(prefix, abspath)` tuple. The
        `prefix` part defines the path in the URL that requests to these
        resources are prefixed with.

        The `abspath` is the absolute path to the directory containing the
        resources on the local file system.
        """
        from pkg_resources import resource_filename
        return [('hw', resource_filename(__name__, 'htdocs'))]

Back to images

We need to add our image to the template to see it.

Our new helloworld.cs:

<?cs include "header.cs" ?>
<?cs include "macros.cs" ?>

<div id="content" class="helloworld">
 <h1>Hello world!</h1>
 <img src="<?cs var:chrome.href ?>/hw/images/helloworld.jpg" />
</div>

<?cs include "footer.cs" ?>

Compilation and deployment

Now you should be familiar with both, so make an egg and deploy it.

Click and see "Hello world!" with your chosen image.

Aftermath

Now you have successfully completed a simple plugin that uses its own template and serves some static data.

Last modified 7 months ago Last modified on Jan 25, 2016, 9:26:16 PM

Attachments (2)

Download all attachments as: .zip