Changeset 3313

Show
Ignore:
Timestamp:
03/05/08 06:26:47 (9 months ago)
Author:
Blackhex
Message:

ScreenshotsPlugin:

  • Port of r3303 - r3309 to 0.11.
  • Documentation for [[Screenshot()]] macro.
  • Minor fixes in wiki macro CSS style.
  • Fixed display of macro when SCREENSHOTS_VIEW is not granted.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • screenshotsplugin/0.10/tracscreenshots/api.py

    r3161 r3313  
    103103            return row 
    104104 
    105     def _format_screenshot(self, screenshot): 
    106         #screenshot['author'] = wiki_to_oneliner(screenshot['author'], self.env) 
    107         #screenshot['name'] = wiki_to_oneliner(screenshot['name'], self.env) 
    108         #screenshot['description'] = wiki_to_oneliner(screenshot['description'], 
    109         #  self.env) 
    110         screenshot['width'] = int(screenshot['width']) 
    111         screenshot['height'] = int(screenshot['height']) 
    112         screenshot['time'] = pretty_timedelta(screenshot['time']) 
    113         return screenshot 
    114  
    115105    def get_screenshot(self, cursor, id): 
    116106        # Get screenshot from database. 
     
    125115            screenshot['versions'] = self.get_screenshot_versions(cursor, 
    126116              screenshot['id']) 
    127             return self._format_screenshot(screenshot) 
     117            return screenshot 
    128118        else: 
    129119            return None 
     
    136126 
    137127        # Append components and versions. 
    138         screenshot['components'] = self.get_screenshot_components(cursor, 
    139           screenshot['id']) 
    140         screenshot['versions'] = self.get_screenshot_versions(cursor, 
    141           screenshot['id']) 
    142         return self._format_screenshot(screenshot) 
     128        if screenshot: 
     129            screenshot['components'] = self.get_screenshot_components(cursor, 
     130              screenshot['id']) 
     131            screenshot['versions'] = self.get_screenshot_versions(cursor, 
     132              screenshot['id']) 
     133            return screenshot 
     134        else: 
     135            return None 
    143136 
    144137    def get_screenshot_components(self, cursor, id): 
  • screenshotsplugin/0.10/tracscreenshots/core.py

    r3304 r3313  
    88from trac.web.chrome import Chrome, add_stylesheet, add_script 
    99from trac.web.clearsilver import HDFWrapper 
    10 from trac.util import Markup, format_datetime, TracError 
     10from trac.util import format_datetime, pretty_timedelta, TracError 
    1111from trac.util.html import html 
    1212 
     
    120120        req.hdf['screenshots.has_tags'] = self.env.is_component_enabled( 
    121121          'tracscreenshots.tags.ScreenshotsTags') 
    122         #req.hdf['screenshots.has_tags'] = self.config.get('components', 
    123         #  'tracscreenshots.tags.screenshotstags') == 'enabled' 
    124122        return template, content_type 
    125123 
     
    167165                height =  int(req.args.get('height') or 0) 
    168166 
    169                 self.log.debug(self.formats) 
    170  
    171167                # Check if requested format is allowed. 
    172168                if not format in self.formats: 
     
    183179 
    184180                    if format == 'html': 
     181                        # Format screenshot attributes. 
     182                        screenshot['time'] = pretty_timedelta(screenshot['time']) 
     183 
    185184                        # Prepare data dictionary. 
    186185                        data['screenshot'] = screenshot 
  • screenshotsplugin/0.10/tracscreenshots/htdocs/css/screenshots.css

    r3309 r3313  
    5050  display: inline-block; 
    5151  margin: 1em; 
     52  margin-top: 0.5em; 
    5253  padding: 0em; 
    5354  font-size: 75%; 
     
    5859span.thumbnail-left 
    5960{ 
     61  margin-left : 0em; 
    6062  float: left; 
    6163} 
     
    6365span.thumbnail-right 
    6466{ 
     67  margin-right: 0em; 
    6568  float: right; 
    6669} 
  • screenshotsplugin/0.10/tracscreenshots/wiki.py

    r3309 r3313  
    99from trac.util.html import html 
    1010from trac.util.text import to_unicode 
     11from trac.util.datefmt import format_datetime 
    1112 
    1213from trac.wiki import IWikiSyntaxProvider, IWikiMacroProvider 
     
    1617class ScreenshotsWiki(Component): 
    1718 
    18     screenshot_macro_doc = "" 
     19    screenshot_macro_doc = """Allows embed screenshot image in wiki page. 
     20First mandatory argument is ID of the screenshot. Number or image attributes 
     21can be specified next: 
     22 
     23 * {{{align}}} - Specifies image alignment in wiki page. Possible values are: 
     24   {{{left}}}, {{{right}}} and {{{center}}}. 
     25 * {{{alt}}} - Alternative description of image. 
     26 * {{{border}}} - Sets image border of specified width in pixels. 
     27 * {{{class}}} - Class of image for CSS styling. 
     28 * {{{description}}} - Brief description under the image. Accepts several 
     29   variables (see bellow). 
     30 * {{{format}}} - Format of returned image or screenshot behind link. 
     31 * {{{height}}} - Height of image. Set to 0 if you want original image height. 
     32 * {{{id}}} - ID of image for CSS styling. 
     33 * {{{longdesc}}} - Detailed description of image. 
     34 * {{{title}}} - Title of image. 
     35 * {{{usemap}}} - Image map for clickable images. 
     36 * {{{width}}} - Width of image. Set to 0 if you want original image width. 
     37 
     38Attribute {{{description}}} displays several variables: 
     39 
     40 * {{{$id}}} - ID of image. 
     41 * {{{$name}}} - Name of image. 
     42 * {{{$author}}} - User name who uploaded image. 
     43 * {{{$time}}} - Time when image was uploaded. 
     44 * {{{$file}}} - File name of image. 
     45 * {{{$description}}} - Detailed description of image. 
     46 * {{{$width}}} - Original width of image. 
     47 * {{{$height}}} - Original height of image. 
     48 
     49Example: 
     50 
     51{{{ 
     52 [[Screenshot(2,width=400,height=300,description=The $name by $author: $description,align=left)]] 
     53}}}""" 
    1954 
    2055    """ 
     
    5388    def render_macro(self, req, name, content): 
    5489        if name == 'Screenshot': 
     90            # Check permission. 
     91            if not req.perm.has_permission('SCREENSHOTS_VIEW'): 
     92               return html.div('No permissions to see screenshots.', 
     93               class_ = 'system-message') 
     94 
    5595            # Get database access. 
    5696            db = self.env.get_db_cnx() 
     
    165205        description = description.replace('$file', 
    166206          to_unicode(screenshot['file'])) 
    167         description = description.replace('$time', screenshot['time']) 
     207        description = description.replace('$time', format_datetime( 
     208          screenshot['time'])) 
    168209        description = description.replace('$author', screenshot['author']) 
    169210        description = description.replace('$description', 
  • screenshotsplugin/0.11/tracscreenshots/core.py

    r3271 r3313  
    66from trac.core import * 
    77from trac.mimeview import Context 
    8 from trac.config import Option 
    9 from trac.web.chrome import add_stylesheet, add_script 
     8from trac.config import Option, ListOption 
     9from trac.web.chrome import add_stylesheet, add_script, format_to_oneliner, \ 
     10  pretty_timedelta 
    1011from trac.util.html import html 
    1112from trac.util.text import to_unicode 
     
    4243    # Configuration options. 
    4344    mainnav_title = Option('screenshots', 'mainnav_title', 'Screenshots', 
    44       'Main navigation bar button title.') 
     45      doc = 'Main navigation bar button title.') 
    4546    metanav_title = Option('screenshots', 'metanav_title', '', 
    46       'Meta navigation bar link title.') 
     47      doc = 'Meta navigation bar link title.') 
    4748    path = Option('screenshots', 'path', '/var/lib/trac/screenshots', 
    48       'Path where to store uploaded screenshots.') 
    49     ext = Option('screenshots', 'ext', 'jpg png', 
    50       'List of screenshot file extensions that can be uploaded. Must be' 
     49      doc = 'Path where to store uploaded screenshots.') 
     50    ext = ListOption('screenshots', 'ext', 'jpg,png', 
     51      doc = 'List of screenshot file extensions that can be uploaded. Must be' 
    5152      ' supported by PIL.') 
    52     formats = Option('screenshots', 'formats', 'raw html jpg png', 
    53       'List of allowed formats for screenshot download.') 
     53    formats = ListOption('screenshots', 'formats', 'raw,html,jpg,png', 
     54      doc = 'List of allowed formats for screenshot download.') 
    5455    default_format = Option('screenshots', 'default_format', 'html', 
    55       'Default format for screenshot download links.') 
    56     default_components = Option('screenshots', 'default_components', 'none', 
    57       'List of components enabled by default.') 
    58     default_versions = Option('screenshots', 'default_versions', 'none', 
    59       'List of versions enabled by default.') 
     56      doc = 'Default format for screenshot download links.') 
     57    default_components = ListOption('screenshots', 'default_components', 'none', 
     58      doc = 'List of components enabled by default.') 
     59    default_versions = ListOption('screenshots', 'default_versions', 'none', 
     60      doc = 'List of versions enabled by default.') 
    6061 
    6162    # IPermissionRequestor methods. 
    6263 
    6364    def get_permission_actions(self): 
    64         return ['SCREENSHOTS_VIEW', 'SCREENSHOTS_FILTER', 'SCREENSHOTS_ADMIN'] 
     65        view = 'SCREENSHOTS_VIEW' 
     66        filter = ('SCREENSHOTS_FILTER', ['SCREENSHOTS_VIEW']) 
     67        admin = ('SCREENSHOTS_ADMIN', ['SCREENSHOTS_FILTER', 
     68          'SCREENSHOTS_VIEW']) 
     69        return [view, filter, admin] 
    6570 
    6671    # ITemplateProvider methods. 
     
    167172 
    168173                # Check if requested format is allowed. 
    169                 if not format in self.formats.split()
     174                if not format in self.formats
    170175                    raise TracError('Requested screenshot format that is not' 
    171176                      ' allowed.', 'Requested format not allowed.') 
     
    247252                result = reg.match(filename) 
    248253                if result: 
    249                     if not result.group(2).lower() in self.ext.split()
     254                    if not result.group(2).lower() in self.ext
    250255                        raise TracError('Unsupported uploaded file type.') 
    251256                else: 
     
    448453                      ' at least one.', 'No screenshots renderer enabled') 
    449454 
     455                # Get all available components and versions. 
     456                components = [self.none_component] + api.get_components( 
     457                  context.cursor) 
     458                versions = [self.none_version] + api.get_versions( 
     459                  context.cursor) 
     460 
    450461                # Get enabled components and versions from request or session. 
    451462                enabled_components = self._get_enabled_components(context.req) 
    452463                enabled_versions = self._get_enabled_versions(context.req) 
     464                if 'all' in enabled_components: 
     465                    enabled_components = [component['name'] for component in 
     466                    components] 
     467                if 'all' in enabled_versions: 
     468                    enabled_versions = [version['name'] for version in 
     469                    versions] 
     470 
     471                self.log.debug(enabled_components) 
     472 
     473                # Filter screenshots. 
    453474                screenshots = api.get_filtered_screenshots(context, 
    454475                  enabled_components, enabled_versions) 
     
    462483                # Fill data dictionary. 
    463484                self.data['id'] = screenshot_id 
    464                 self.data['components'] = [self.none_component] + \ 
    465                   api.get_components(context) 
    466                 self.data['versions'] = [self.none_version] + \ 
    467                   api.get_versions(context) 
     485                self.data['components'] = components 
     486                self.data['versions'] = versions 
    468487                self.data['screenshots'] = screenshots 
    469488                self.data['href'] = context.req.href.screenshots() 
     
    509528 
    510529    def _get_enabled_components(self, req): 
    511         # Check if session is initialized. 
    512         if not req.session.has_key('enabled_components'): 
    513             req.session['enabled_components'] = str(self.default_components \ 
    514               .split()) 
    515  
    516         # Return enabled components from session. 
    517         return eval(req.session.get('enabled_components')) 
     530        if req.perm.has_permission('SCREENSHOTS_FILTER'): 
     531            # Return existing filter from session or create default. 
     532            if req.session.has_key('enabled_components'): 
     533                components = eval(req.session.get('enabled_components')) 
     534            else: 
     535                components = self.default_components 
     536                req.session['enabled_components'] = str(components) 
     537        else: 
     538            # Users without SCREENSHOTS_FILTER permission uses 
     539            # 'default_components' configuration option. 
     540            components = self.default_components 
     541        self.log.debug('enabled_components: %s' % (components,)) 
     542        return components 
    518543 
    519544    def _get_enabled_versions(self, req): 
    520         # Check if session is initialized. 
    521         if not req.session.has_key('enabled_versions'): 
    522             req.session['enabled_versions'] = str(self.default_versions \ 
    523               .split()) 
    524  
    525         # Return enabled versions from session. 
    526         return eval(req.session.get('enabled_versions')) 
     545        if req.perm.has_permission('SCREENSHOTS_FILTER'): 
     546            # Return existing filter from session or create default. 
     547            if req.session.has_key('enabled_versions'): 
     548                versions = eval(req.session.get('enabled_versions')) 
     549            else: 
     550                versions = self.default_versions 
     551                req.session['enabled_versions'] = str(versions) 
     552        else: 
     553            # Users without SCREENSHOTS_FILTER permission uses 
     554            # 'default_versions' configuration option. 
     555            versions = self.default_versions 
     556        self.log.debug('enabled_versions: %s' % (versions,)) 
     557        return versions 
  • screenshotsplugin/0.11/tracscreenshots/htdocs/css/screenshots.css

    r3140 r3313  
    2121  display: inline; 
    2222} 
     23 
     24/* Wiki [[Screenshot()]] macro styles. */ 
     25span.thumbnail > a > img 
     26{ 
     27  display: inline; 
     28  border-color: #b00; 
     29  border-style: solid; 
     30  margin: 0em; 
     31  padding: 0em; 
     32} 
     33 
     34span.thumbnail > a 
     35{ 
     36  display: inline-block; 
     37  border: 0px none; 
     38  margin: 0.2em; 
     39  padding: 0em; 
     40} 
     41 
     42span.thumbnail > span.description 
     43{ 
     44  display: inline-block; 
     45} 
     46 
     47span.thumbnail, span.thumbnail-left, span.thumbnail-right 
     48{ 
     49  display: inline-block; 
     50  margin: 1em; 
     51  margin-top: 0.5em; 
     52  padding: 0em; 
     53  font-size: 75%; 
     54  text-align: center; 
     55  vertical-align: middle; 
     56} 
     57 
     58span.thumbnail-left 
     59{ 
     60  margin-left: 0em; 
     61  float: left; 
     62} 
     63 
     64span.thumbnail-right 
     65{ 
     66  margin-right: 0em; 
     67  float: right; 
     68} 
  • screenshotsplugin/0.11/tracscreenshots/wiki.py

    r3140 r3313  
    44 
    55from trac.core import * 
     6from trac.config import Option 
     7from trac.wiki.formatter import format_to_html, format_to_oneliner 
     8from trac.web.chrome import add_stylesheet, add_script, format_datetime 
    69from trac.util.html import html 
    7  
    8 from trac.wiki import IWikiSyntaxProvider 
     10from trac.util.text import to_unicode 
     11 
     12from trac.wiki import IWikiSyntaxProvider, IWikiMacroProvider 
    913 
    1014from tracscreenshots.api import * 
    1115 
    1216class ScreenshotsWiki(Component): 
     17 
     18    screenshot_macro_doc = """Allows embed screenshot image in wiki page. 
     19First mandatory argument is ID of the screenshot. Number or image attributes 
     20can be specified next: 
     21 
     22 * {{{align}}} - Specifies image alignment in wiki page. Possible values are: 
     23   {{{left}}}, {{{right}}} and {{{center}}}. 
     24 * {{{alt}}} - Alternative description of image. 
     25 * {{{border}}} - Sets image border of specified width in pixels. 
     26 * {{{class}}} - Class of image for CSS styling. 
     27 * {{{description}}} - Brief description under the image. Accepts several 
     28   variables (see bellow). 
     29 * {{{format}}} - Format of returned image or screenshot behind link. 
     30 * {{{height}}} - Height of image. Set to 0 if you want original image height. 
     31 * {{{id}}} - ID of image for CSS styling. 
     32 * {{{longdesc}}} - Detailed description of image. 
     33 * {{{title}}} - Title of image. 
     34 * {{{usemap}}} - Image map for clickable images. 
     35 * {{{width}}} - Width of image. Set to 0 if you want original image width. 
     36 
     37Attribute {{{description}}} displays several variables: 
     38 
     39 * {{{$id}}} - ID of image. 
     40 * {{{$name}}} - Name of image. 
     41 * {{{$author}}} - User name who uploaded image. 
     42 * {{{$time}}} - Time when image was uploaded. 
     43 * {{{$file}}} - File name of image. 
     44 * {{{$description}}} - Detailed description of image. 
     45 * {{{$width}}} - Original width of image. 
     46 * {{{$height}}} - Original height of image. 
     47 
     48Example: 
     49 
     50{{{ 
     51 [[Screenshot(2,width=400,height=300,description=The $name by $author: $description,align=left)]] 
     52}}}""" 
     53 
    1354    """ 
    1455        The wiki module implements macro for screenshots referencing. 
    1556    """ 
    16     implements(IWikiSyntaxProvider) 
    17  
    18     # [screenshot] macro attributes regular expression. 
    19     attributes_re = re.compile('(align|border|width|height|alt|title|longdesc|' 
    20       'class|id|usemap|format)=(.+)') 
     57    implements(IWikiSyntaxProvider, IWikiMacroProvider) 
     58 
     59    # [screenshot] macro id regular expression. 
     60    id_re = re.compile('^(\d+)($|.+$)') 
     61 
     62    # [[Screenshot()]] macro attributes regular expression. 
     63    attributes_re = re.compile('(align|alt|border|class|description|format|' \ 
     64      'height|id|longdesc|title|usemap|width)=(.*)') 
     65 
     66    # Configuration options. 
     67    default_description = Option('screenshots', 'default_description', 
     68      '$description', 'Template for embended image description.') 
    2169 
    2270    # IWikiSyntaxProvider 
     71 
    2372    def get_link_resolvers(self): 
    2473        yield ('screenshot', self._screenshot_link) 
     
    2776        return [] 
    2877 
    29     # Internal functions 
    30  
    31     def _screenshot_link(self, formatter, ns, params, label): 
    32         if ns == 'screenshot': 
     78    # IWikiMacroProvider 
     79 
     80    def get_macros(self): 
     81        yield 'Screenshot' 
     82 
     83    def get_macro_description(self, name): 
     84        if name == 'Screenshot': 
     85            return self.screenshot_macro_doc 
     86 
     87    def expand_macro(self, formatter, name, content): 
     88        if name == 'Screenshot': 
     89            # Check permission. 
     90            if not formatter.req.perm.has_permission('SCREENSHOTS_VIEW'): 
     91               return html.div('No permissions to see screenshots.', 
     92               class_ = 'system-message') 
     93 
    3394            # Create request context. 
    3495            context = Context.from_request(formatter.req)('screenshots-wiki') 
     
    41102            api = self.env[ScreenshotsApi] 
    42103 
    43             # Get macro arguments and screenshot. 
    44             arguments = params.split(',') 
    45             screenshot_id = int(arguments[0]) 
     104            # Get macro arguments. 
     105            arguments = content.split(',') 
     106 
     107            # Get screenshot ID. 
     108            try: 
     109               screenshot_id = int(arguments[0]) 
     110            except: 
     111                 raise TracError("Missing screenshot ID in macro arguments.") 
     112 
     113            # Try to get screenshots of that ID. 
    46114            screenshot = api.get_screenshot(context, screenshot_id) 
    47115 
    48             # Return macro content 
     116            # Build and return macro content. 
    49117            if screenshot: 
    50118                # Set default values of image attributes. 
    51                 attributes = {'alt' : screenshot['description'], 
    52                               'format' : 'html'} 
     119                attributes = {'align' : 'none', 
     120                              'border' : '1', 
     121                              'format' : 'raw', 
     122                              'width' : screenshot['width'], 
     123                              'height' : screenshot['height'], 
     124                              'alt' : screenshot['description'], 
     125                              'description' : self.default_description} 
    53126 
    54127                # Fill attributes from macro arguments. 
     
    58131                    if match: 
    59132                        attributes[str(match.group(1))] = match.group(2) 
    60                 if attributes.has_key('width'): 
    61                     if attributes['width'] == '0': 
    62                         attributes['width'] = screenshot['width'] 
    63                 if attributes.has_key('height'): 
    64                     if attributes['height'] == '0': 
    65                         attributes['height'] = screenshot['height'] 
    66133                self.log.debug('attributes: %s' % (attributes,)) 
    67134 
     135                # Format screenshot description from template. 
     136                attributes['description'] = self._format_description(context, 
     137                  attributes['description'], screenshot) 
     138 
     139                # Make copy of attributes for image tag. 
     140                img_attributes = {'align' : 'center', 
     141                                  'style' : 'border-width: %spx;' % ( 
     142                                    attributes['border'],)} 
     143                for attribute in attributes.keys(): 
     144                    if attribute not in ('align', 'border', 'description', 
     145                      'format'): 
     146                        img_attributes[attribute] = attributes[attribute] 
     147 
     148                # Add CSS for image. 
     149                add_stylesheet(formatter.req, 'screenshots/css/screenshots.css') 
     150 
    68151                # Build screenshot image and/or screenshot link. 
    69                 screenshot_href = formatter.href.screenshots(screenshot['id']) \ 
    70                   + '?format=%s' % (attributes['format'],) 
    71                 if attributes.has_key('width') and attributes.has_key('height'): 
    72                     image = html.img(src = formatter.href.screenshots( 
    73                       screenshot['id'], width = attributes['width'], height = 
    74                       attributes['height'], format = 'raw'), **attributes) 
    75                     return html.a(image, href = screenshot_href, title = 
    76                       screenshot['description']) 
    77                 else: 
    78                     return html.a(label, href = screenshot_href, title = 
    79                       screenshot['description']) 
     152                image = html.img(src = formatter.req.href.screenshots( 
     153                  screenshot['id'], width = attributes['width'], height = 
     154                  attributes['height'], format = 'raw'), **img_attributes) 
     155                link = html.a(image, href = formatter.req.href.screenshots( 
     156                  screenshot['id'], format = attributes['format']), title = 
     157                  screenshot['description']) 
     158                description = html.span(attributes['description'], class_ = 
     159                  'description') 
     160                thumbnail_class = 'thumbnail' + ((attributes['align'] == 'left') 
     161                  and '-left' or (attributes['align'] == 'right') and '-right' 
     162                  or '') 
     163                thumbnail = html.span(link, ' ', description, class_ = 
     164                  thumbnail_class, style = "width: %spx;" % ( 
     165                  int(attributes['width']) + 2 * int(attributes['border'],))) 
     166                return thumbnail 
     167            else: 
     168                return html.a(screenshot_id, href = 
     169                  formatter.req.href.screenshots(), title = content, 
     170                  class_ = 'missing') 
     171 
     172    # Internal functions 
     173 
     174    def _screenshot_link(self, formatter, ns, params, label): 
     175        if ns == 'screenshot': 
     176            # Get screenshot ID and link arguments from macro. 
     177            match = self.id_re.match(params) 
     178            if match: 
     179                screenshot_id = int(match.group(1)) 
     180                arguments = match.group(2) 
     181            else: 
     182                # Bad format of link. 
     183                return html.a(label, href = formatter.href.screenshots(), 
     184                  title = params, class_ = 'missing') 
     185 
     186            # Create request context. 
     187            context = Context.from_request(formatter.req)('screenshots-wiki') 
     188 
     189            # Get database access. 
     190            db = self.env.get_db_cnx() 
     191            context.cursor = db.cursor() 
     192 
     193            # Get API component. 
     194            api = self.env[ScreenshotsApi] 
     195 
     196            # Try to get screenshots of that ID. 
     197            screenshot = api.get_screenshot(context, screenshot_id) 
     198 
     199            # Return macro content 
     200            if screenshot: 
     201                return html.a(label, href = formatter.href.screenshots( 
     202                  screenshot['id']) + arguments, title = 
     203                  screenshot['description']) 
    80204            else: 
    81205                return html.a(arguments[0], href = formatter.href.screenshots(), 
    82206                  title = params, class_ = 'missing') 
     207 
     208    def _format_description(self, context, template, screenshot): 
     209        description = template.replace('$id', to_unicode(screenshot['id'])) 
     210        description = description.replace('$name', screenshot['name']) 
     211        description = description.replace('$file', 
     212          to_unicode(screenshot['file'])) 
     213        description = description.replace('$time', format_datetime(to_datetime( 
     214          screenshot['time'], utc))) 
     215        description = description.replace('$author', screenshot['author']) 
     216        description = description.replace('$description', 
     217          screenshot['description']) 
     218        description = description.replace('$width', to_unicode( 
     219          screenshot['width'])) 
     220        description = description.replace('$height', to_unicode( 
     221          screenshot['height'])) 
     222        self.log.debug(description) 
     223        return format_to_oneliner(self.env, context, description) 
     224