source: tagsplugin/tags/0.3rc1/tractags/macros.py

Last change on this file was 1788, checked in by muness, 17 years ago

Get it to work on Python 2.3 on Trac 0.9.4

File size: 8.2 KB
Line 
1from trac.core import *
2from trac.wiki.api import IWikiMacroProvider
3from trac.wiki import model
4from trac.util import Markup
5from trac.wiki import wiki_to_html, wiki_to_oneliner
6from StringIO import StringIO
7from tractags.api import TagEngine, ITagSpaceUser
8import inspect
9import re
10import string
11
12try:
13    sorted = sorted
14except NameError:
15    def sorted(iterable, cmp=None, key=str, reverse=False):
16        lst = [(key(i), i) for i in iterable]
17        lst.sort()
18        if reverse:
19            lst = reversed(lst)
20        return [i for __, i in lst]
21
22try:
23    set = set
24except:
25    from sets import Set as set
26
27class TagMacros(Component):
28    """ Versions of the old Wiki-only macros using the new tag API. """
29
30    implements(IWikiMacroProvider)
31
32    def _page_titles(self, pages):
33        """ Extract page titles, if possible. """
34        titles = {}
35        tagspace = TagEngine(self.env).tagspace.wiki
36        for pagename in pages:
37            href, link, title = tagspace.name_details(pagename)
38            titles[pagename] = title
39        return titles
40
41    def _tag_details(self, links, tags):
42        """ Extract dictionary of tag:(href, title) for all tags. """
43        for tag in tags:
44            if tag not in links:
45                links[tag] = TagEngine(self.env).get_tag_link(tag)
46        return links
47
48    def _current_page(self, req):
49        return req.hdf.getValue('wiki.page_name', '')
50
51    # IWikiMacroProvider methods
52    def get_macros(self):
53        yield 'TagCloud'
54        yield 'ListTagged'
55        yield 'TagIt'
56        yield 'ListTags'
57
58    def get_macro_description(self, name):
59        import pydoc
60        return pydoc.getdoc(getattr(self, 'render_' + name.lower()))
61
62    def render_macro(self, req, name, content):
63        from trac.web.chrome import add_stylesheet
64        add_stylesheet(req, 'tags/css/tractags.css')
65        # Translate macro args into python args
66        args = []
67        kwargs = {}
68        if content is not None:
69            try:
70                from parseargs import parseargs
71                args, kwargs = parseargs(content)
72            except Exception, e:
73                raise TracError("Invalid arguments '%s' (%s %s)" % (content, e.__class__.__name__, e))
74        return getattr(self, 'render_' + name.lower(), content)(req, *args, **kwargs)
75
76    # Macro implementations
77    def render_tagcloud(self, req, smallest=10, biggest=20, tagspace=None, tagspaces=[]):
78        """ Display a summary of all tags, with the font size reflecting the
79            number of pages the tag applies to. Font size ranges from 10 to 22
80            pixels, but this can be overridden by the smallest=n and biggest=n
81            macro parameters. By default, all tagspaces are displayed, but this
82            can be overridden with tagspaces=(wiki, ticket) or tagspace=wiki."""
83        smallest = int(smallest)
84        biggest = int(biggest)
85        engine = TagEngine(self.env)
86        # Get wiki tagspace
87        if tagspace:
88            tagspaces = [tagspace]
89        else:
90            tagspaces = tagspaces or engine.tagspaces
91        cloud = {}
92
93        for tag, names in engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems():
94            cloud[tag] = len(names)
95
96        tags = cloud.keys()
97
98        # No tags?
99        if not tags: return ''
100
101        # by_count maps tag counts to an index in the set of counts
102        by_count = list(set(cloud.values()))
103        by_count.sort()
104        by_count = dict([(c, float(i)) for i, c in enumerate(by_count)])
105
106        taginfo = self._tag_details({}, tags)
107        tags.sort()
108        rlen = float(biggest - smallest)
109        tlen = float(len(by_count))
110        scale = 1.0
111        if tlen:
112            scale = rlen / tlen
113        out = StringIO()
114        out.write('<ul class="tagcloud">\n')
115        last = tags[-1]
116        for tag in tags:
117            if tag == last:
118                cls = ' class="last"'
119            else:
120                cls = ''
121            out.write('<li%s><a rel="tag" title="%s" style="font-size: %ipx" href="%s">%s</a> <span class="tagcount">(%i)</span></li>\n' % (
122                       cls,
123                       taginfo[tag][1],
124                       smallest + int(by_count[cloud[tag]] * scale),
125                       taginfo[tag][0],
126                       tag,
127                       cloud[tag]))
128        out.write('</ul>\n')
129        return out.getvalue()
130
131    def render_listtagged(self, req, *tags, **kwargs):
132        """ List tagged objects. Takes a list of tags to match against.
133            The special tag '.' inserts the current Wiki page name.
134
135            Optional keyword arguments are tagspace=wiki,
136            tagspaces=(wiki, title, ...) and showheadings=true.
137
138            By default displays the intersection of objects matching each tag.
139            By passing operation=union this can be modified to display
140            the union of objects matching each tag.
141        """
142
143        if 'tagspace' in kwargs:
144            tagspaces = [kwargs.get('tagspace', None)]
145        else:
146            tagspaces = kwargs.get('tagspaces', '') or \
147                        list(TagEngine(self.env).tagspaces)
148        showheadings = kwargs.get('showheadings', 'false')
149        operation = kwargs.get('operation', 'intersection')
150        if operation not in ('union', 'intersection'):
151            raise TracError("Invalid tag set operation '%s'" % operation)
152
153        engine = TagEngine(self.env)
154        page_name = req.hdf.get('wiki.page_name')
155        if page_name:
156            tags = [tag == '.' and page_name or tag for tag in tags]
157
158        taginfo = {}
159        out = StringIO()
160        out.write('<ul class="listtagged">')
161        for tagspace, tagspace_names in sorted(engine.get_tagged_names(tags=tags, tagspaces=tagspaces, operation=operation, detailed=True).iteritems()):
162            if showheadings == 'true':
163                out.write('<lh>%s tags</lh>' % tagspace)
164            for name, tags in sorted(tagspace_names.iteritems()):
165                if tagspace == 'wiki' and unicode(name).startswith('tags/'): continue
166                tags = sorted(tags)
167                taginfo = self._tag_details(taginfo, tags)
168                href, link, title = engine.name_details(tagspace, name)
169                htitle = wiki_to_oneliner(title, self.env)
170                name_tags = ['<a href="%s" title="%s">%s</a>'
171                              % (taginfo[tag][0], taginfo[tag][1], tag)
172                              for tag in tags]
173                if not name_tags:
174                    name_tags = ''
175                else:
176                    name_tags = ' (' + ', '.join(sorted(name_tags)) + ')'
177                out.write('<li>%s %s%s</li>\n' %
178                          (link, htitle, name_tags))
179        out.write('</ul>')
180
181        return out.getvalue()
182
183    def render_tagit(self, req, *tags):
184        """ Tag the current page and display them (deprecated). """
185        return ''
186
187    def render_listtags(self, req, *tags, **kwargs):
188        """ List tags. For backwards compatibility, can accept a list of tags.
189            This will simply call ListTagged. Optional keyword arguments are
190            tagspace=wiki, tagspaces=(wiki, ticket, ...) and shownames=true. """
191        if tags:
192            # Backwards compatibility
193            return self.render_listtagged(req, *tags, **kwargs)
194
195        page = self._current_page(req)
196        engine = TagEngine(self.env)
197
198        showpages = kwargs.get('showpages', None) or kwargs.get('shownames', 'false')
199
200        if 'tagspace' in kwargs:
201            tagspaces = [kwargs['tagspace']]
202        else:
203            tagspaces = kwargs.get('tagspaces', []) or \
204                        list(TagEngine(self.env).tagspaces)
205
206        out = StringIO()
207        out.write('<ul class="listtags">\n')
208        tag_details = {}
209        for tag, names in sorted(engine.get_tags(tagspaces=tagspaces, detailed=True).iteritems()):
210            href, title = engine.get_tag_link(tag)
211            htitle = wiki_to_oneliner(title, self.env)
212            out.write('<li><a href="%s" title="%s">%s</a> %s <span class="tagcount">(%i)</span>' % (href, title, tag, htitle, len(names)))
213            if showpages == 'true':
214                out.write('\n')
215                out.write(self.render_listtagged(req, tag, tagspaces=tagspaces))
216                out.write('</li>\n')
217
218        out.write('</ul>\n')
219
220        return out.getvalue()
Note: See TracBrowser for help on using the repository browser.