source: dynamicfieldsplugin/trunk/dynfields/web_ui.py

Last change on this file was 17855, checked in by Ryan J Ollos, 3 years ago

2.6.0dev: Add prefs template for Trac 1.4+

Refs #13875.

  • Property svn:executable set to *
File size: 4.7 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2010-2014 Rob Guttman <guttman@alum.mit.edu>
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
9import re
10from pkg_resources import resource_filename
11
12from trac.core import Component, ExtensionPoint, implements
13from trac.prefs.api import IPreferencePanelProvider
14from trac.web.api import IRequestFilter
15from trac.web.chrome import (
16    Chrome, ITemplateProvider, add_script, add_script_data, add_stylesheet)
17
18from dynfields.options import Options
19from dynfields.rules import IRule, add_domain, _
20
21
22class DynamicFieldsModule(Component):
23    """A module that dynamically alters ticket fields based an extensible
24    set of rules.  Uses jQuery for full implementation.
25    """
26
27    implements(IPreferencePanelProvider, IRequestFilter, ITemplateProvider)
28
29    rules = ExtensionPoint(IRule)
30
31    target_re = re.compile(r"(?P<target>[^.]+).*")
32
33    def __init__(self):
34        # bind the 'dynfields' catalog to the specified locale directory
35        locale_dir = resource_filename(__name__, 'locale')
36        add_domain(self.env.path, locale_dir)
37
38    # ITemplateProvider methods
39
40    def get_htdocs_dirs(self):
41        return [('dynfields', resource_filename(__name__, 'htdocs'))]
42
43    def get_templates_dirs(self):
44        return [resource_filename(__name__, 'templates')]
45
46    # IRequestFilter methods
47
48    def pre_process_request(self, req, handler):
49        return handler
50
51    def post_process_request(self, req, template, data, content_type):
52        if template in ('ticket.html', 'query.html'):
53            add_script_data(req, {'triggers': self._get_triggers(req)})
54            for script in ('dynfields.js', 'rules.js', 'layout.js'):
55                add_script(req, 'dynfields/%s' % script)
56            add_stylesheet(req, 'dynfields/layout.css')
57        return template, data, content_type
58
59    # IPreferencePanelProvider methods
60
61    def get_preference_panels(self, req):
62        if self._get_prefs_data(req):  # only show if there are preferences
63            # TRANSLATOR: the preferences tab label
64            yield 'dynfields', _("Dynamic Fields")
65
66    def render_preference_panel(self, req, panel):
67        opts = Options(self.env)
68        if req.method == 'POST':
69            opts.set_prefs(req)
70        prefs_data = self._get_prefs_data(req, opts)
71        data = {'data': prefs_data, 'saved': req.method == 'POST'}
72        if hasattr(Chrome, 'jenv'):
73            template = 'prefs_panel_jinja.html'
74        else:
75            template = 'prefs_panel.html'
76        return template, data
77
78    # Internal methods
79
80    def _get_prefs_data(self, req, opts=None):
81        """Returns the pref data, a dict of rule class titles whose values
82        include lists of rule spec preference dicts each with these keys:
83
84          id (based on unique key)
85          label (of checkbox)
86          enabled ('1' or '0')
87          type ('none', 'select', or 'text')
88          options (list of options if type is 'select')
89          value (saved preference or default value)
90        """
91        if opts is None:
92            opts = Options(self.env)
93        data = {}
94        for rule in self.rules:
95            for key in opts:
96                if not opts.has_pref(key):
97                    continue
98                target = self.target_re.match(key).groupdict()['target']
99                trigger = rule.get_trigger(req, target, key, opts)
100                if not trigger:
101                    continue
102
103                # this rule spec has a pref - so get it!
104                pref = opts.get_pref(req, target, key)
105                rule.update_pref(req, trigger, target, key, opts, pref)
106                data.setdefault(rule.title, {'desc': rule.desc, 'prefs': []})
107                data[rule.title]['prefs'].append(pref)
108        return data
109
110    def _get_triggers(self, req):
111        """Converts trac.ini config to dict of triggers with rule specs."""
112        triggers = {}
113        opts = Options(self.env)
114        for key in opts:
115            # extract the target field
116            target = self.target_re.match(key).groupdict()['target']
117
118            # extract rule specifications from configs
119            for rule in self.rules:
120                trigger = rule.get_trigger(req, target, key, opts)
121                if not trigger:
122                    continue
123                if not opts.is_enabled(req, key):
124                    continue
125                value, _ = opts.get_value_and_options(req, target, key)
126                spec = {'rule_name': rule.name, 'trigger': trigger,
127                        'target': target, 'value': value}
128                rule.update_spec(req, key, opts, spec)
129                triggers.setdefault(trigger, []).append(spec)
130
131        return triggers
Note: See TracBrowser for help on using the repository browser.