Beispiel #1
0
 def _render_icon(self, formatter, name, size):
     if not name:
         return
     size = size.upper()[0] if size else 'S'
     name = name.lower()
     if any(x in name for x in ['*', '?']):
         #noinspection PyArgumentList
         return ShowIcons(self.env)._render(formatter, 2, name, size, True,
                                            self.icon_limit)
     else:
         loc = self.icon_location(size)
         return tag.img(src=formatter.href.chrome(loc[0], '%s.png' % name),
                        alt=name,
                        style="vertical-align: text-bottom")
Beispiel #2
0
 def _format_smiley(self, formatter, match, fullmatch=None):
     #noinspection PyArgumentList
     loc = Icons(self.env).icon_location()
     return tag.img(src=formatter.href.chrome(loc[0], self.smileys[match]),
                    alt=match,
                    style="vertical-align: text-bottom")
Beispiel #3
0
 def render(self, context, mimetype, content, filename=None, url=None):
     if url:
         return tag.div(tag.img(src=url, alt=filename), class_='image-file')
Beispiel #4
0
    def expand_macro(self, formatter, name, content):
        args = None
        if content:
            content = stripws(content)
            # parse arguments
            # we expect the 1st argument to be a filename (filespec)
            args = [
                stripws(arg)
                for arg in self._split_args_re.split(content)[1::2]
            ]
        if not args:
            return ''
        # strip unicode white-spaces and ZWSPs are copied from attachments
        # section (#10668)
        filespec = args.pop(0)

        # style information
        attr = {}
        style = {}
        link = ''
        # helper for the special case `source:`
        #
        from trac.versioncontrol.web_ui import BrowserModule
        # FIXME: somehow use ResourceSystem.get_known_realms()
        #        ... or directly trac.wiki.extract_link
        try:
            browser_links = [
                res[0] for res in BrowserModule(self.env).get_link_resolvers()
            ]
        except Exception:
            browser_links = []
        while args:
            arg = args.pop(0)
            if self._size_re.match(arg):
                # 'width' keyword
                attr['width'] = arg
            elif arg == 'nolink':
                link = None
            elif arg.startswith('link='):
                val = arg.split('=', 1)[1]
                elt = extract_link(self.env, formatter.context, val.strip())
                elt = find_element(elt, 'href')
                link = None
                if elt is not None:
                    link = elt.attrib.get('href')
            elif arg in ('left', 'right'):
                style['float'] = arg
            elif arg == 'center':
                style['margin-left'] = style['margin-right'] = 'auto'
                style['display'] = 'block'
                style.pop('margin', '')
            elif arg in ('top', 'bottom', 'middle'):
                style['vertical-align'] = arg
            else:
                match = self._attr_re.match(arg)
                if match:
                    key, val = match.groups()
                    if (key == 'align' and
                            val in ('left', 'right', 'center')) or \
                        (key == 'valign' and
                            val in ('top', 'middle', 'bottom')):
                        args.append(val)
                    elif key in ('margin-top', 'margin-bottom'):
                        style[key] = ' %dpx' % _arg_as_int(val, key, min=1)
                    elif key in ('margin', 'margin-left', 'margin-right') \
                             and 'display' not in style:
                        style[key] = ' %dpx' % _arg_as_int(val, key, min=1)
                    elif key == 'border':
                        style['border'] = ' %dpx solid' % _arg_as_int(val, key)
                    else:
                        m = self._quoted_re.search(
                            val)  # unquote "..." and '...'
                        if m:
                            val = m.group(1)
                        attr[str(key)] = val  # will be used as a __call__ kwd

        if self._quoted_re.match(filespec):
            filespec = filespec.strip('\'"')
        # parse filespec argument to get realm and id if contained.
        parts = [
            i.strip('\'"')
            for i in self._split_filespec_re.split(filespec)[1::2]
        ]
        realm = parts[0] if parts else None
        url = raw_url = desc = None
        attachment = None
        interwikimap = InterWikiMap(self.env)
        if realm in ('http', 'https', 'ftp', 'data'):  # absolute
            raw_url = url = filespec
            desc = url.rsplit('?')[0]
        elif realm in interwikimap:
            url, desc = interwikimap.url(realm, ':'.join(parts[1:]))
            raw_url = url
        elif filespec.startswith('//'):  # server-relative
            raw_url = url = filespec[1:]
            desc = url.rsplit('?')[0]
        elif filespec.startswith('/'):  # project-relative
            params = ''
            if '?' in filespec:
                filespec, params = filespec.rsplit('?', 1)
            url = formatter.href(filespec)
            if params:
                url += '?' + params
            raw_url, desc = url, filespec
        elif len(parts) == 3:  # realm:id:attachment-filename
            #                                 # or intertrac:realm:id
            realm, id, filename = parts
            intertrac_target = "%s:%s" % (id, filename)
            it = formatter.get_intertrac_url(realm, intertrac_target)
            if it:
                url, desc = it
                raw_url = url + unicode_quote('?format=raw')
            else:
                attachment = Resource(realm, id).child('attachment', filename)
        elif len(parts) == 2:
            realm, filename = parts
            if realm in browser_links:  # source:path
                # TODO: use context here as well
                rev = None
                if '@' in filename:
                    filename, rev = filename.rsplit('@', 1)
                url = formatter.href.browser(filename, rev=rev)
                raw_url = formatter.href.browser(filename,
                                                 rev=rev,
                                                 format='raw')
                desc = filespec
            else:  # #ticket:attachment or WikiPage:attachment
                # FIXME: do something generic about shorthand forms...
                realm = None
                id, filename = parts
                if id and id[0] == '#':
                    realm = 'ticket'
                    id = id[1:]
                elif id == 'htdocs':
                    raw_url = url = formatter.href.chrome('site', filename)
                    desc = os.path.basename(filename)
                elif id == 'shared':
                    raw_url = url = formatter.href.chrome('shared', filename)
                    desc = os.path.basename(filename)
                else:
                    realm = 'wiki'
                if realm:
                    attachment = Resource(realm,
                                          id).child('attachment', filename)
        elif len(parts) == 1:  # it's an attachment of the current resource
            attachment = formatter.resource.child('attachment', filespec)
        else:
            return system_message(_("No filespec given"))
        if attachment:
            try:
                desc = get_resource_summary(self.env, attachment)
            except ResourceNotFound:
                link = None
                raw_url = chrome_resource_path(formatter.context.req,
                                               'common/attachment.png')
                desc = _('No image "%(id)s" attached to %(parent)s',
                         id=attachment.id,
                         parent=get_resource_name(self.env, attachment.parent))
            else:
                if 'ATTACHMENT_VIEW' in formatter.perm(attachment):
                    url = get_resource_url(self.env, attachment,
                                           formatter.href)
                    raw_url = get_resource_url(self.env,
                                               attachment,
                                               formatter.href,
                                               format='raw')

        for key in ('title', 'alt'):
            if desc and key not in attr:
                attr[key] = desc
        if style:
            attr['style'] = '; '.join('%s:%s' % (k, escape(v))
                                      for k, v in style.iteritems())
        if not WikiSystem(self.env).is_safe_origin(raw_url,
                                                   formatter.context.req):
            attr['crossorigin'] = 'anonymous'  # avoid password prompt
        result = tag.img(src=raw_url, **attr)
        if link is not None:
            result = tag.a(result,
                           href=link or url,
                           style='padding:0; border:none')
        return result
Beispiel #5
0
 def _render_needslock(self, context):
     url = chrome_resource_path(context.req, 'common/lock-locked.png')
     return tag.img(src=url, alt=_("needs lock"), title=_("needs lock"))
Beispiel #6
0
    def expand_macro(self, formatter_or_context, name, content):
        """Return the HTML output of the macro.

        :param formatter_or_context: a Formatter when called as a macro,
               a RenderingContext when called by `GraphvizPlugin.render`

        :param name: Wiki macro command that resulted in this method being
               called. In this case, it should be 'graphviz', followed
               (or not) by the processor name, then by an output
               format, as following: graphviz.<processor>/<format>

               Valid processor names are: dot, neato, twopi, circo,
               and fdp.  The default is dot.

               Valid output formats are: jpg, png, gif, svg and svgz.
               The default is the value specified in the out_format
               configuration parameter. If out_format is not specified
               in the configuration, then the default is png.

               examples: graphviz.dot/png   -> dot    png
                         graphviz.neato/jpg -> neato  jpg
                         graphviz.circo     -> circo  png
                         graphviz/svg       -> dot    svg

        :param content: The text the user entered for the macro to process.
        """
        # check and load the configuration
        errmsg = self._load_config()
        if errmsg:
            return self._error_div(errmsg)

        ## Extract processor and format from name
        processor = out_format = None

        # first try with the RegExp engine
        try:
            m = re.match('graphviz\.?([a-z]*)\/?([a-z]*)', name)
            (processor, out_format) = m.group(1, 2)

        # or use the string.split method
        except:
            (d_sp, s_sp) = (name.split('.'), name.split('/'))
            if len(d_sp) > 1:
                s_sp = d_sp[1].split('/')
                if len(s_sp) > 1:
                    out_format = s_sp[1]
                processor = s_sp[0]
            elif len(s_sp) > 1:
                out_format = s_sp[1]

        # assign default values, if instance ones are empty
        if not out_format:
            out_format = self.out_format
        if not processor:
            processor = self.processor

        if processor in Graphviz.Processors:
            proc_cmd = self.cmds[processor]

        else:
            self.log.error('render_macro: requested processor (%s) not found.',
                           processor)
            return self._error_div('requested processor (%s) not found.' %
                                   processor)

        if out_format not in Graphviz.Formats:
            self.log.error('render_macro: requested format (%s) not found.',
                           out_format)
            return self._error_div(
                tag.p(
                    _(
                        "Graphviz macro processor error: "
                        "requested format (%(fmt)s) not valid.",
                        fmt=out_format)))

        encoded_cmd = (processor + str(self.processor_options)) \
            .encode(self.encoding)
        encoded_content = content.encode(self.encoding)
        sha_key = hashlib.sha256(encoded_cmd + encoded_content + (
            b'S' if self.sanitizer else b'')).hexdigest()
        img_name = '%s.%s.%s' % (sha_key, processor, out_format)
        # cache: hash.<dot>.<png>
        img_path = os.path.join(self.cache_dir, img_name)
        map_name = '%s.%s.map' % (sha_key, processor)
        # cache: hash.<dot>.map
        map_path = os.path.join(self.cache_dir, map_name)

        # Check for URL="" presence in graph code
        URL_in_graph = 'URL=' in content or 'href=' in content

        # Create image if not in cache
        if not os.path.exists(img_path):
            self._clean_cache()

            if self.sanitizer:
                content = self._sanitize_html_labels(content)

            if URL_in_graph:  # translate wiki TracLinks in URL
                if isinstance(formatter_or_context, RenderingContext):
                    context = formatter_or_context
                else:
                    context = formatter_or_context.context
                content = self._expand_wiki_links(context, out_format, content)
                encoded_content = content.encode(self.encoding)

            # Antialias PNGs with rsvg, if requested
            if out_format == 'png' and self.png_anti_alias == True:
                # 1. SVG output
                failure, errmsg = self._launch(encoded_content, proc_cmd,
                                               '-Tsvg', '-o%s.svg' % img_path,
                                               *self.processor_options)
                if failure:
                    return self._error_div(errmsg)

                # 2. SVG to PNG rasterization
                failure, errmsg = self._launch(None, self.rsvg_path,
                                               '--dpi-x=%d' % self.dpi,
                                               '--dpi-y=%d' % self.dpi,
                                               '%s.svg' % img_path, img_path)
                if failure:
                    return self._error_div(errmsg)

            else:  # Render other image formats
                failure, errmsg = self._launch(encoded_content, proc_cmd,
                                               '-T%s' % out_format,
                                               '-o%s' % img_path,
                                               *self.processor_options)
                if failure:
                    return self._error_div(errmsg)

            # Generate a map file for binary formats
            if URL_in_graph and out_format in Graphviz.Bitmap_Formats:

                # Create the map if not in cache
                if not os.path.exists(map_path):
                    failure, errmsg = self._launch(encoded_content, proc_cmd,
                                                   '-Tcmap', '-o%s' % map_path,
                                                   *self.processor_options)
                    if failure:
                        return self._error_div(errmsg)

        if errmsg:
            # there was a warning. Ideally we should be able to use
            # `add_warning` here, but that's not possible as the warnings
            # are already emitted at this point in the template processing
            return self._error_div(errmsg)

        # Generate HTML output
        img_url = formatter_or_context.href.graphviz(img_name)
        # for SVG(z)
        if out_format in Graphviz.Vector_Formats:
            try:  # try to get SVG dimensions
                f = open(img_path, 'r')
                svg = f.readlines(1024)  # don't read all
                f.close()
                svg = "".join(svg).replace('\n', '')
                w = re.search('width="([0-9]+)(.*?)" ', svg)
                h = re.search('height="([0-9]+)(.*?)"', svg)
                (w_val, w_unit) = w.group(1, 2)
                (h_val, h_unit) = h.group(1, 2)
                # Graphviz seems to underestimate height/width for SVG images,
                # so we have to adjust them.
                # The correction factor seems to be constant.
                w_val, h_val = [1.35 * float(x) for x in (w_val, h_val)]
                width = str(w_val) + w_unit
                height = str(h_val) + h_unit
            except ValueError:
                width = height = '100%'

            # insert SVG, IE compatibility
            return tag.object(tag.embed(src=img_url,
                                        type="image/svg+xml",
                                        width=width,
                                        height=height),
                              data=img_url,
                              type="image/svg+xml",
                              width=width,
                              height=height)

        # for binary formats, add map
        elif URL_in_graph and os.path.exists(map_path):
            f = open(map_path, 'r')
            map = f.readlines()
            f.close()
            map = "".join(map).replace('\n', '')
            return tag(
                tag.map(Markup(to_unicode(map)),
                        id='G' + sha_key,
                        name='G' + sha_key),
                tag.img(src=img_url,
                        usemap="#G" + sha_key,
                        alt=_("GraphViz image")))
        else:
            return tag.img(src=img_url, alt=_("GraphViz image"))