| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | |
|---|
| 3 | from fnmatch import fnmatch |
|---|
| 4 | import re |
|---|
| 5 | |
|---|
| 6 | from trac.core import Component, implements |
|---|
| 7 | from trac.config import ListOption |
|---|
| 8 | from trac.web.api import IRequestFilter |
|---|
| 9 | from trac.web.chrome import ITemplateProvider, add_link, add_stylesheet, add_script |
|---|
| 10 | from trac.web.href import Href |
|---|
| 11 | from trac.util.html import Markup |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | __all__ = ['WysiwygModule'] |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | class WysiwygModule(Component): |
|---|
| 18 | implements(ITemplateProvider, IRequestFilter) |
|---|
| 19 | |
|---|
| 20 | wysiwyg_stylesheets = ListOption('tracwysiwyg', 'wysiwyg_stylesheets', |
|---|
| 21 | doc="""Add stylesheets to the WYSIWYG editor""") |
|---|
| 22 | |
|---|
| 23 | templates = ListOption('tracwysiwyg', 'templates', doc="""\ |
|---|
| 24 | List of template names that the plugin will show a WYSIWYG editor |
|---|
| 25 | on each TracWiki textarea. The plugin shows on all pages by |
|---|
| 26 | default.""") |
|---|
| 27 | |
|---|
| 28 | # ITemplateProvider#get_htdocs_dirs |
|---|
| 29 | def get_htdocs_dirs(self): |
|---|
| 30 | from pkg_resources import resource_filename |
|---|
| 31 | return [('tracwysiwyg', resource_filename(__name__, 'htdocs'))] |
|---|
| 32 | |
|---|
| 33 | # ITemplateProvider#get_templates_dirs |
|---|
| 34 | def get_templates_dirs(self): |
|---|
| 35 | return [] |
|---|
| 36 | |
|---|
| 37 | # IRequestFilter#pre_process_request |
|---|
| 38 | def pre_process_request(self, req, handler): |
|---|
| 39 | return handler |
|---|
| 40 | |
|---|
| 41 | # IRequestFilter#post_process_request |
|---|
| 42 | def post_process_request(self, req, template, content_type): |
|---|
| 43 | if not _is_wysiwyg_enabled(template, self.templates): |
|---|
| 44 | return template, content_type |
|---|
| 45 | |
|---|
| 46 | add_link(req, 'tracwysiwyg-base', req.href() or '/') |
|---|
| 47 | stylesheets = ['chrome/common/css/trac.css', 'chrome/tracwysiwyg/editor.css'] |
|---|
| 48 | stylesheets += self.wysiwyg_stylesheets |
|---|
| 49 | for stylesheet in stylesheets: |
|---|
| 50 | add_link(req, 'tracwysiwyg-stylesheet', _expand_filename(req, stylesheet)) |
|---|
| 51 | add_stylesheet(req, 'tracwysiwyg/wysiwyg.css') |
|---|
| 52 | add_script(req, 'tracwysiwyg/wysiwyg.js') |
|---|
| 53 | footer = req.hdf['project.footer'] + '<script type="text/javascript">TracWysiwyg.initialize();</script>' |
|---|
| 54 | req.hdf['project.footer'] = Markup(footer) |
|---|
| 55 | return template, content_type |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | def _expand_filename(req, filename): |
|---|
| 59 | if filename.startswith('chrome/common/') and 'htdocs_location' in req.hdf: |
|---|
| 60 | href = Href(req.hdf['htdocs_location']) |
|---|
| 61 | return href(filename[14:]) |
|---|
| 62 | if filename.startswith('/') or re.match(r'https?://', filename): |
|---|
| 63 | href = Href(filename) |
|---|
| 64 | return href() |
|---|
| 65 | return req.href(filename) |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | def _is_wysiwyg_enabled(template, patterns): |
|---|
| 69 | if not patterns: |
|---|
| 70 | return True |
|---|
| 71 | for pattern in patterns: |
|---|
| 72 | positive = not pattern.startswith('!') |
|---|
| 73 | if not positive: |
|---|
| 74 | pattern = pattern[1:] |
|---|
| 75 | if fnmatch(template, pattern): |
|---|
| 76 | return positive |
|---|
| 77 | return False |
|---|