root/tagsplugin/trunk/tractags/wiki.py

Revision 3882, 6.5 kB (checked in by athomas, 4 years ago)
  • Remove redundant js files.
  • Add link to existing Wiki page, or new page "template" if tag query was a
    single term. Fixes #2509.
  • Added TagSystem.get_all_tags().
  • Added req argument to describe_tagged_resources().
  • Added docstrings to macros.
  • Widened Wiki tag input field slightly.
Line 
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright (C) 2006 Alec Thomas <alec@swapoff.org>
4 #
5 # This software is licensed as described in the file COPYING, which
6 # you should have received as part of this distribution.
7 #
8
9 import re
10 from trac.core import *
11 from tractags.api import DefaultTagProvider, TagSystem
12 from trac.web.chrome import add_stylesheet, add_script
13 from trac.wiki.api import IWikiSyntaxProvider
14 from trac.resource import Resource, render_resource_link, get_resource_url
15 from trac.mimeview.api import Context
16 from trac.web.api import ITemplateStreamFilter
17 from trac.wiki.api import IWikiPageManipulator, IWikiChangeListener
18 from trac.wiki.model import WikiPage
19 from trac.util.compat import sorted
20 from genshi.builder import tag
21 from genshi.filters.transform import Transformer
22
23
24 class WikiTagProvider(DefaultTagProvider):
25     """Tag provider for the Wiki."""
26     realm = 'wiki'
27
28     first_head = re.compile('=\s+([^=]*)=')
29
30     def check_permission(self, perm, operation):
31         map = {'view': 'WIKI_VIEW', 'modify': 'WIKI_MODIFY'}
32         return super(WikiTagProvider, self).check_permission(perm, operation) \
33             and map[operation] in perm
34
35     def describe_tagged_resource(self, req, resource):
36         if not self.check_permission(req.perm(resource), 'view'):
37             return ''
38         page = WikiPage(self.env, resource.id)
39         if page.exists:
40             ret = self.first_head.search(page.text)
41             return ret and ret.group(1) or ''
42         return ''
43
44
45 class WikiTagInterface(Component):
46     """Implement the user interface for tagging Wiki pages."""
47     implements(ITemplateStreamFilter, IWikiPageManipulator,
48                IWikiChangeListener)
49
50     # ITemplateStreamFilter methods
51     def filter_stream(self, req, method, filename, stream, data):
52         page_name = req.args.get('page', 'WikiStart')
53         resource = Resource('wiki', page_name)
54         if filename == 'wiki_view.html' and 'TAGS_VIEW' in req.perm(resource):
55             return self._wiki_view(req, stream)
56         elif filename == 'wiki_edit.html' and 'TAGS_MODIFY' in req.perm(resource):
57             return self._wiki_edit(req, stream)
58         return stream
59
60     # IWikiPageManipulator methods
61     def prepare_wiki_page(self, req, page, fields):
62         pass
63
64     def validate_wiki_page(self, req, page):
65         # If we're saving the wiki page, and can modify tags, do so
66         if req and 'TAGS_MODIFY' in req.perm(page.resource) \
67                 and req.path_info.startswith('/wiki') and 'save' in req.args:
68             page_modified = req.args.get('text') != page.old_text or \
69                     page.readonly != int('readonly' in req.args)
70             # Always save tags if the page has been otherwise modified
71             if page_modified:
72                 self._update_tags(req, page)
73             elif page.version > 0:
74                 # If the page hasn't been otherwise modified, save the tags
75                 # and redirect so we don't get the "page has not been modified"
76                 # warning
77                 if self._update_tags(req, page):
78                     req.redirect(get_resource_url(self.env, page.resource, req.href, version=None))
79         return []
80
81     # IWikiChangeListener methods
82     def wiki_page_added(self, page):
83         pass
84
85     def wiki_page_changed(self, page, version, t, comment, author, ipnr):
86         pass
87
88     def wiki_page_deleted(self, page):
89         tag_system = TagSystem(self.env)
90         # XXX Ugh. Hopefully this will be sufficient to full any endpoints.
91         from trac.test import Mock, MockPerm
92         req = Mock(authname='anonymous', perm=MockPerm())
93         tag_system.delete_tags(req, page.resource)
94
95     def wiki_page_version_deleted(self, page):
96         pass
97
98     # Internal methods
99     def _page_tags(self, req):
100         pagename = req.args.get('page', 'WikiStart')
101
102         tag_system = TagSystem(self.env)
103         resource = Resource('wiki', pagename)
104         tags = sorted(tag_system.get_tags(req, resource))
105         return tags
106
107     def _wiki_view(self, req, stream):
108         tags = self._page_tags(req)
109         if not tags:
110             return stream
111         tag_system = TagSystem(self.env)
112         add_stylesheet(req, 'tags/css/tractags.css')
113         li = []
114         for tag_ in tags:
115             resource = Resource('tag', tag_)
116             anchor = render_resource_link(self.env,
117                 Context.from_request(req, resource), resource)
118             anchor = anchor(rel='tag')
119             li.append(tag.li(anchor, ' '))
120
121         insert = tag.ul(class_='tags')(tag.li('Tags', class_='header'), li)
122         return stream | Transformer('//div[@class="buttons"]').before(insert)
123
124     def _update_tags(self, req, page):
125         tag_system = TagSystem(self.env)
126         newtags = tag_system.split_into_tags(req.args.get('tags', ''))
127         oldtags = tag_system.get_tags(req, page.resource)
128
129         if oldtags != newtags:
130             tag_system.set_tags(req, page.resource, newtags)
131             return True
132         return False
133
134     def _wiki_edit(self, req, stream):
135
136         insert = tag.div(class_='field')(
137             tag.label(
138                 'Tag under: (', tag.a('view all tags', href=req.href.tags()), ')',
139                 tag.br(),
140                 tag.input(id='tags', type='text', name='tags', size='50',
141                           value=req.args.get('tags', ' '.join(self._page_tags(req)))),
142                 )
143             )
144         return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
145
146
147 class TagWikiSyntaxProvider(Component):
148     """Provide tag:<expr> links."""
149
150     implements(IWikiSyntaxProvider)
151
152     # IWikiSyntaxProvider methods
153     def get_wiki_syntax(self):
154         yield (r'''\[tag(?:ged)?:(?P<tlpexpr>(?:'.*?'|".*?"|\S)+)\s+(?P<tlptitle>.*?]*)\]''',
155                lambda f, n, m: self._format_tagged(f,
156                                     m.group('tlpexpr'),
157                                     m.group('tlptitle')))
158         yield (r'''(?P<tagsyn>tag(?:ged)?):(?P<texpr>(?:'.*?'|".*?"|\S)+)''',
159                lambda f, n, m: self._format_tagged(f,
160                                     m.group('texpr'),
161                                     '%s:%s' % (m.group('tagsyn'), m.group('texpr'))))
162
163     def get_link_resolvers(self):
164         return []
165
166     def _format_tagged(self, formatter, target, label):
167         if label:
168             href = formatter.context.href
169             url = get_resource_url(self.env, Resource('tag', target), href)
170             return tag.a(label, href=url)
171         return render_resource_link(self.env, formatter.context,
172                                     Resource('tag', target))
Note: See TracBrowser for help on using the browser.