| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | |
|---|
| 3 | import re |
|---|
| 4 | from trac.core import * |
|---|
| 5 | from trac.util import escape, Markup, reversed, sorted |
|---|
| 6 | from trac.wiki.api import IWikiChangeListener, IWikiSyntaxProvider |
|---|
| 7 | from trac.wiki.model import WikiPage |
|---|
| 8 | from urlparse import urlparse |
|---|
| 9 | from trac.wiki.formatter import format_to_oneliner |
|---|
| 10 | from trac.mimeview import Context |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | class KeywordReplace(Component): |
|---|
| 14 | """ Replce wiki keywords from a table in a Wiki page. |
|---|
| 15 | (KeywordReplace by default). |
|---|
| 16 | """ |
|---|
| 17 | |
|---|
| 18 | implements(IWikiSyntaxProvider, IWikiChangeListener) |
|---|
| 19 | |
|---|
| 20 | replace = {} |
|---|
| 21 | compiled_replace = None |
|---|
| 22 | valid_replace = re.compile(r'^\S+$', re.UNICODE) |
|---|
| 23 | replace_page = property(lambda self: self.env.config.get('replace', 'page', |
|---|
| 24 | 'KeywordReplace')) |
|---|
| 25 | def __init__(self): |
|---|
| 26 | self._update_replace() |
|---|
| 27 | |
|---|
| 28 | def _update_replace(self): |
|---|
| 29 | self.env.log.debug('Updating replace database') |
|---|
| 30 | page = WikiPage(self.env, self.replace_page) |
|---|
| 31 | self.replace = {} |
|---|
| 32 | if not page.exists: |
|---|
| 33 | return |
|---|
| 34 | for line in page.text.splitlines(): |
|---|
| 35 | self.env.log.warning(line) |
|---|
| 36 | line = line.rstrip() |
|---|
| 37 | |
|---|
| 38 | if line.startswith('||') and line.endswith('||') and line[3] != "'": |
|---|
| 39 | try: |
|---|
| 40 | a, d = ([i.strip() for i in line.strip('||').split('||')] + ['', ''])[0:2] |
|---|
| 41 | assert self.valid_replace.match(a), "Invalid replaces %s" % a |
|---|
| 42 | self.replace[a] = (escape(d)) |
|---|
| 43 | except Exception, d: |
|---|
| 44 | self.env.log.warning("Invalid replaces line: %s", line) |
|---|
| 45 | keys = reversed(sorted(self.replace.keys(), key=lambda a: len(a))) |
|---|
| 46 | self.compiled_replace = \ |
|---|
| 47 | r'''\b(?P<replaces>%s)\b''' % '|'.join(keys) |
|---|
| 48 | |
|---|
| 49 | # XXX Very ugly, but only "reliable" way? |
|---|
| 50 | from trac.wiki.parser import WikiParser |
|---|
| 51 | WikiParser(self.env)._compiled_rules = None |
|---|
| 52 | |
|---|
| 53 | def _replaces_formatter(self, formatter, ns, match): |
|---|
| 54 | replaces = match.group('replaces') |
|---|
| 55 | |
|---|
| 56 | if replaces not in self.replace: |
|---|
| 57 | return match.group(0) |
|---|
| 58 | title = self.replace[replaces] |
|---|
| 59 | |
|---|
| 60 | context = Context.from_request(formatter.req, formatter.resource) |
|---|
| 61 | |
|---|
| 62 | return Markup('<span>%s</span>' % (format_to_oneliner(self.env,context,title))) |
|---|
| 63 | |
|---|
| 64 | # IWikiSyntaxProvider methods |
|---|
| 65 | |
|---|
| 66 | def get_wiki_syntax(self): |
|---|
| 67 | if self.compiled_replace: |
|---|
| 68 | yield (self.compiled_replace, self._replaces_formatter) |
|---|
| 69 | |
|---|
| 70 | def get_link_resolvers(self): |
|---|
| 71 | return [] |
|---|
| 72 | |
|---|
| 73 | # IWikiChangeListener methods |
|---|
| 74 | |
|---|
| 75 | def wiki_page_added(self, page): |
|---|
| 76 | if page.name == self.replace_page: |
|---|
| 77 | self._update_replace() |
|---|
| 78 | |
|---|
| 79 | def wiki_page_changed(self, page, version, t, comment, author, ipnr=None): |
|---|
| 80 | if page.name == self.replace_page: |
|---|
| 81 | self._update_replace() |
|---|
| 82 | |
|---|
| 83 | def wiki_page_deleted(self, page): |
|---|
| 84 | if page.name == self.replace_page: |
|---|
| 85 | self._update_replace() |
|---|
| 86 | |
|---|
| 87 | def wiki_page_version_deleted(self, page): |
|---|
| 88 | if page.name == self.replace_page: |
|---|
| 89 | self._update_replace() |
|---|