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
RevLine 
[13690]1# -*- coding: utf-8 -*-
2#
[14003]3# Copyright (C) 2010-2014 Rob Guttman <guttman@alum.mit.edu>
[13690]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
[8168]9import re
[14356]10from pkg_resources import resource_filename
11
[16951]12from trac.core import Component, ExtensionPoint, implements
[13689]13from trac.prefs.api import IPreferencePanelProvider
[14718]14from trac.web.api import IRequestFilter
[16951]15from trac.web.chrome import (
[17548]16    Chrome, ITemplateProvider, add_script, add_script_data, add_stylesheet)
[13689]17
[14356]18from dynfields.options import Options
[17752]19from dynfields.rules import IRule, add_domain, _
[8168]20
[13689]21
[8168]22class DynamicFieldsModule(Component):
23    """A module that dynamically alters ticket fields based an extensible
[17752]24    set of rules.  Uses jQuery for full implementation.
25    """
[13991]26
[14718]27    implements(IPreferencePanelProvider, IRequestFilter, ITemplateProvider)
[13991]28
[8168]29    rules = ExtensionPoint(IRule)
[13991]30
[17521]31    target_re = re.compile(r"(?P<target>[^.]+).*")
32
[14356]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
[8168]38    # ITemplateProvider methods
[14718]39
[8168]40    def get_htdocs_dirs(self):
41        return [('dynfields', resource_filename(__name__, 'htdocs'))]
[13991]42
[8168]43    def get_templates_dirs(self):
44        return [resource_filename(__name__, 'templates')]
45
46    # IRequestFilter methods
[14718]47
[8168]48    def pre_process_request(self, req, handler):
49        return handler
[13991]50
[8168]51    def post_process_request(self, req, template, data, content_type):
[17502]52        if template in ('ticket.html', 'query.html'):
[14718]53            add_script_data(req, {'triggers': self._get_triggers(req)})
[15058]54            for script in ('dynfields.js', 'rules.js', 'layout.js'):
55                add_script(req, 'dynfields/%s' % script)
[9718]56            add_stylesheet(req, 'dynfields/layout.css')
[8168]57        return template, data, content_type
[13991]58
[14718]59    # IPreferencePanelProvider methods
[13991]60
[8168]61    def get_preference_panels(self, req):
[14356]62        if self._get_prefs_data(req):  # only show if there are preferences
63            # TRANSLATOR: the preferences tab label
64            yield 'dynfields', _("Dynamic Fields")
[8168]65
66    def render_preference_panel(self, req, panel):
67        opts = Options(self.env)
68        if req.method == 'POST':
69            opts.set_prefs(req)
[17548]70        prefs_data = self._get_prefs_data(req, opts)
71        data = {'data': prefs_data, 'saved': req.method == 'POST'}
[17855]72        if hasattr(Chrome, 'jenv'):
73            template = 'prefs_panel_jinja.html'
[17548]74        else:
[17855]75            template = 'prefs_panel.html'
76        return template, data
[13991]77
[14718]78    # Internal methods
79
[8168]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:
[13991]83
[8168]84          id (based on unique key)
85          label (of checkbox)
86          enabled ('1' or '0')
[13991]87          type ('none', 'select', or 'text')
[8168]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):
[13689]97                    continue
[17521]98                target = self.target_re.match(key).groupdict()['target']
[11518]99                trigger = rule.get_trigger(req, target, key, opts)
[8168]100                if not trigger:
101                    continue
[13991]102
[8168]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)
[13689]106                data.setdefault(rule.title, {'desc': rule.desc, 'prefs': []})
[8168]107                data[rule.title]['prefs'].append(pref)
108        return data
[14718]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
[17521]116            target = self.target_re.match(key).groupdict()['target']
[14718]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.