Changes between Version 2 and Version 3 of EggCookingTutorialTrac0.11


Ignore:
Timestamp:
Jun 3, 2007 11:11:51 AM (7 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)]]