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

Last change on this file was 1783, checked in by Alec Thomas, 18 years ago
  • Big API change, see api.py for details, but it makes life much easier for users.
  • ListTagged now performs an intersection rather than a union by default.
  • Version bump to 0.3 because of the API changes.
  • Added start of unit tests (still not 100% working).
File size: 7.2 KB
Line 
1from trac.core import *
2from trac.web.main import IRequestHandler
3from trac.web.chrome import ITemplateProvider, INavigationContributor
4from trac.util import Markup
5from StringIO import StringIO
6from trac.wiki.web_ui import WikiModule
7from trac.wiki.formatter import wiki_to_oneliner
8import re
9try:
10    set = set
11except:
12    from sets import Set as set
13
14_tag_split = re.compile('[,\s]+')
15
16class TagsWikiModule(WikiModule):
17    """ Replacement for the default Wiki module. Tag editing is much more
18        intuitive now, as it no longer requires the TagIt macro and JavaScript
19        magic. """
20
21    def _do_save(self, req, db, page):
22        # This method is overridden so the user doesn't get "Page not modified"
23        # exceptions when updating tags but not wiki content.
24        from tractags.api import TagEngine
25        if 'tags' in req.args:
26            newtags = set([t.strip() for t in
27                          _tag_split.split(req.args.get('tags')) if t.strip()])
28            wikitags = TagEngine(self.env).tagspace.wiki
29            oldtags = wikitags.get_tags([page.name])
30
31            if oldtags != newtags:
32                wikitags.replace_tags(req, page.name, newtags)
33                # No changes, just redirect
34                if req.args.get('text') == page.text:
35                    req.redirect(self.env.href.wiki(page.name))
36                    return
37        return WikiModule._do_save(self, req, db, page)
38
39    def process_request(self, req):
40        from tractags.api import TagEngine
41        from trac.web.chrome import add_stylesheet
42
43        add_stylesheet(req, 'tags/css/tractags.css')
44
45        pagename = req.args.get('page', 'WikiStart')
46        action = req.args.get('action', 'view')
47
48        engine = TagEngine(self.env)
49        wikitags = engine.tagspace.wiki
50        tags = list(wikitags.get_tags([pagename]))
51        tags.sort()
52
53        if action == 'edit':
54            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
55        elif action == 'view':
56            hdf_tags = []
57            for tag in tags:
58                href, title = engine.get_tag_link(tag)
59                hdf_tags.append({'name': tag,
60                                 'href': href,
61                                 'title': title})
62            req.hdf['tags'] = hdf_tags
63        result = WikiModule.process_request(self, req)
64        if result is None:
65            return None
66        if result[0] == 'wiki.cs':
67            return 'tagswiki.cs', None
68        return result
69
70class TagsModule(Component):
71    """ Serve a /tags namespace. Top-level displays tag cloud, sub-levels
72        display output of ListTagged(tag).
73
74        The following configuration options are supported:
75
76        [tags]
77        # Use a tag list or cloud for the main index
78        index = cloud|list
79        # Show tagspace headings in the index
80        index.showheadings = false|true
81        # Minium font size for tag cloud index
82        index.cloud.smallest = 10
83        # Maximum font size for tag cloud index
84        index.cloud.biggest = 30
85    """
86    implements(IRequestHandler, INavigationContributor, ITemplateProvider)
87
88    def _prepare_wiki(self, req):
89        from tractags.api import TagEngine
90        page = req.path_info[6:] or 'WikiStart'
91        engine = TagEngine(self.env)
92        wikitags = engine.tagspace.wiki
93        tags = list(wikitags.get_tags(page))
94        tags.sort()
95
96        action = req.args.get('action', 'view')
97        if action == 'edit':
98            req.hdf['tags'] = req.args.get('tags', ', '.join(tags))
99        elif action == 'view':
100            hdf_tags = []
101            for tag in tags:
102                href, title = engine.get_tag_link(tag)
103                hdf_tags.append({'name': tag,
104                                 'href': href,
105                                 'title': title})
106            req.hdf['tags'] = hdf_tags
107
108    # ITemplateProvider methods
109    def get_templates_dirs(self):
110        """
111        Return the absolute path of the directory containing the provided
112        ClearSilver templates.
113        """
114        from pkg_resources import resource_filename
115        return [resource_filename(__name__, 'templates')]
116
117    def get_htdocs_dirs(self):
118        """Return the absolute path of a directory containing additional
119        static resources (such as images, style sheets, etc).
120        """
121        from pkg_resources import resource_filename
122        return [('tags', resource_filename(__name__, 'htdocs'))]
123   
124    # INavigationContributor methods
125    def get_active_navigation_item(self, req):
126        return 'tags'
127
128    def get_navigation_items(self, req):
129        from trac.web.chrome import Chrome
130        yield ('metanav', 'tags',
131               Markup('<a href="%s" accesskey="T">Tag Index</a>',
132                      self.env.href.tags()))
133
134    # IRequestHandler methods
135    def match_request(self, req):
136        return req.path_info.startswith('/tags')
137
138    def process_request(self, req):
139        from tractags.macros import TagMacros
140        from trac.web.chrome import add_stylesheet
141
142        add_stylesheet(req, 'tags/css/tractags.css')
143        req.hdf['trac.href.tags'] = self.env.href.tags()
144        showheadings = self.config.getbool('tags', 'index.showheadings',
145                                           'false') and 'true' or 'false'
146        smallest = int(self.config.get('tags', 'index.cloud.smallest', 10))
147        biggest = int(self.config.get('tags', 'index.cloud.biggest', 30))
148
149        if req.path_info == '/tags':
150            index = self.env.config.get('tags', 'index', 'cloud')
151            if index == 'cloud':
152                req.hdf['tag.body'] = Markup(
153                    TagMacros(self.env).render_tagcloud(req, smallest=smallest, biggest=biggest))
154            elif index == 'list':
155                req.hdf['tag.body'] = Markup(
156                    TagMacros(self.env).render_listtagged(req,
157                        showheadings=showheadings))
158            else:
159                raise TracError("Invalid index style '%s'" % index)
160        else:
161            tag = req.path_info[6:]
162            req.hdf['tag.name'] = tag
163            req.hdf['tag.body'] = Markup(
164                TagMacros(self.env).render_listtagged(
165                    req, tag, showheadings=showheadings))
166        return 'tags.cs', None
167
168# XXX I think this is planned for some AJAX goodness, commenting out for now. (Alec) XXX
169#class TagsLi(Component):
170#    implements(IRequestHandler)
171#   
172#    # IRequestHandler methods
173#    def match_request(self, req):
174#        return req.path_info == '/tagli'
175#               
176#    def process_request(self, req):
177#        db = self.env.get_db_cnx()
178#        cursor = db.cursor()
179#        cs = db.cursor()
180#        tag = req.args.get('tag')
181#        req.send_response(200)
182#        req.send_header('Content-Type', 'text/plain')
183#        req.end_headers()
184#        buf = StringIO()
185#        if tag:
186#            buf.write('WHERE tag LIKE \'%s%s\'' % (tag,'%'))
187#           
188#        cursor.execute('SELECT DISTINCT tag FROM tags %s ORDER BY tag' % (buf.getvalue()))
189#
190#        msg = StringIO()
191#
192#        msg.write('<ul>')
193#        while 1:
194#            row = cursor.fetchone()
195#            if row == None:
196#                 break
197#
198#            t = row[0]
199#            msg.write('<li>')
200#            msg.write(t)
201#            msg.write('</li>')
202#
203#        msg.write('</ul>')
204#        req.write(msg.getvalue())
Note: See TracBrowser for help on using the repository browser.