Changes between Version 2 and Version 3 of EggCookingTutorialTrac0.11


Ignore:
Timestamp:
Jun 3, 2007, 11:11:51 AM (8 years ago)
Author:
khundeen
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • EggCookingTutorialTrac0.11

    v2 v3  
    274274== Aftermath ==
    275275
    276 Now that you have added a basic template for your plugin let's add the final twist, putting some static content like a stylesheet and an image. Continue to [wiki:EggCookingTutorialTrac0.11#]
    277 
     276Now that you have added a basic template for your plugin let's add the final twist, putting some static content like a stylesheet and an image. Continue to next section to cook high-end egg.
     277
     278= Cooking high-end eggs =
     279
     280Now you have pretty neat plugin already but let's add final twist and serve some static content like stylesheet and image.
     281
     282== Important thing to check ==
     283
     284First step is to ensure that your ''trac.ini'' doesn't have ''htdocs_location'' set otherwise Trac can't serve static data.
     285
     286== More directories ==
     287
     288Since we don't have enough directories in our simple plugin let's make few more:
     289{{{
     290./helloworld-plugin/helloworld/htdocs/
     291./helloworld-plugin/helloworld/htdocs/css/
     292./helloworld-plugin/helloworld/htdocs/images/
     293}}}
     294
     295== Style is everything ==
     296
     297We want to use our own stylesheet to give some color to our fine content. For that we need cascaded stylesheet.
     298
     299Create ''helloworld.css'' in ''./helloworld-plugin/helloworld/htdocs/css/'':
     300{{{
     301#!text/css
     302div.helloworld h1 {
     303        color: red;
     304}
     305}}}
     306
     307== Image tells more than thousand words ==
     308
     309Images are always nice.
     310
     311Put small image named ''helloworld.jpg'' in ''./helloworld-plugin/helloworld/htdocs/images/''.
     312
     313Note: Since it's not practical to show jpg contents here you should find one image by yourself somewhere.
     314
     315== Egg grows ==
     316
     317Even natural eggs doesn't grow Python eggs does.
     318
     319Modify ''setup.py'' to include our static data:
     320{{{
     321#!python
     322from setuptools import find_packages, setup
     323
     324# name can be any name.  This name will be used to create .egg file.
     325# name that is used in packages is the one that is used in the trac.ini file.
     326# use package name as entry_points
     327setup(
     328    name='Trachelloworld', version='1.1',
     329    packages=find_packages(exclude=['*.tests*']),
     330    entry_points = """
     331        [trac.plugins]
     332        helloworld = helloworld
     333    """,
     334    package_data={'helloworld': ['templates/*.html',
     335                                 'htdocs/css/*.css',
     336                                 'htdocs/images/*']},
     337)
     338}}}
     339
     340== Tell it to Trac too ==
     341
     342Trac doesn't know where our fine stylesheet and image is located. So you have to tell it to Trac.
     343
     344Add the following code at the tail in file ''helloworld.py'' which
     345implements {{{get_htdocs_dir()}}} to tell the static data path information for this plugin
     346with identical prefix 'hw'.
     347{{{
     348#!python
     349    def get_htdocs_dirs(self):
     350        """Return a list of directories with static resources (such as style
     351        sheets, images, etc.)
     352
     353        Each item in the list must be a `(prefix, abspath)` tuple. The
     354        `prefix` part defines the path in the URL that requests to these
     355        resources are prefixed with.
     356
     357        The `abspath` is the absolute path to the directory containing the
     358        resources on the local file system.
     359        """
     360        from pkg_resources import resource_filename
     361        return [('hw', resource_filename(__name__, 'htdocs'))]
     362}}}
     363
     364== Remember to load stylesheet ==
     365
     366To make Trac to load our stylesheet you need to modify ''process_request'' method starting from line 24 to following:
     367{{{
     368#!python
     369    def process_request(self, req):
     370        data = {}
     371        add_stylesheet(req, 'hw/css/helloworld.css')
     372        # This tuple is for Genshi (template_name, data, content_type)
     373        # Without data the trac layout will not appear.
     374        return 'helloworld.html', data, None
     375}}}
     376Note that prefix path 'hw/' specified by {{{get_htdocs_dirs()}}} should be used.
     377
     378And also import {{{add_stylesheet()}}} at the beginning of ''helloworld.py''.
     379{{{
     380#!python
     381from trac.web.chrome import INavigationContributor, ITemplateProvider, \
     382        add_stylesheet
     383}}}
     384
     385== Complete version of code ==
     386The whole of final code is here:
     387{{{
     388#!python
     389# Helloworld plugin
     390import re
     391
     392from genshi.builder import tag
     393
     394from trac.core import *
     395from trac.web import IRequestHandler
     396from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
     397
     398class HelloworldModule(Component):
     399    implements(INavigationContributor, ITemplateProvider, IRequestHandler)
     400
     401    # INavigationContributor methods
     402    def get_active_navigation_item(self, req):
     403        return 'helloworld'
     404
     405    def get_navigation_items(self, req):
     406        yield ('mainnav', 'helloworld',
     407               tag.a('Hello World', href=req.href.helloworld()))
     408
     409    # IRequestHandler methods
     410    def match_request(self, req):
     411        return re.match(r'/helloworld(?:_trac)?(?:/.*)?$', req.path_info)
     412
     413    def process_request(self, req):
     414        data = {}
     415        add_stylesheet(req, 'hw/css/helloworld.css')
     416        # This tuple is for Genshi (template_name, data, content_type)
     417        # Without data the trac layout will not appear.
     418        return 'helloworld.html', data, None
     419
     420    # ITemplateProvider methods
     421    # Used to add the plugin's templates and htdocs
     422    def get_templates_dirs(self):
     423        from pkg_resources import resource_filename
     424        return [resource_filename(__name__, 'templates')]
     425   
     426    def get_htdocs_dirs(self):
     427        """Return a list of directories with static resources (such as style
     428        sheets, images, etc.)
     429
     430        Each item in the list must be a `(prefix, abspath)` tuple. The
     431        `prefix` part defines the path in the URL that requests to these
     432        resources are prefixed with.
     433
     434        The `abspath` is the absolute path to the directory containing the
     435        resources on the local file system.
     436        """
     437        from pkg_resources import resource_filename
     438        return [('hw', resource_filename(__name__, 'htdocs'))]   
     439}}}
     440
     441== Back to images ==
     442
     443We need to add our image to template to see it.
     444
     445Our new ''helloworld.cs'':
     446{{{
     447#!text/html
     448<!DOCTYPE html
     449    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
     450    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
     451<html xmlns="http://www.w3.org/1999/xhtml"
     452      xmlns:py="http://genshi.edgewall.org/"
     453      xmlns:xi="http://www.w3.org/2001/XInclude">
     454  <xi:include href="layout.html" />
     455  <head>
     456    <title>Helloworld</title>
     457  </head>
     458
     459  <body>
     460    <div id="ctxtnav" class="nav"></div>
     461
     462    <div id="content" class="helloworld">
     463      <h1>Hello World!</h1>
     464      <img src="${href.chrome('/hw/images/helloworld.png')}" />
     465    </div>
     466  </body>
     467</html>
     468}}}
     469
     470== Compilation and deployment ==
     471
     472Now you should be familiar with both, so make an egg and deploy it.
     473
     474Click and see... Hello world! with your pretty own image.
     475
     476== Aftermath ==
     477
     478Now you have successfully completed nice simple plugin that uses it's own template and serves some static data.
    278479
    279480[[TagIt(khundeen)]]