source: timingandestimationplugin/branches/trac1.0-Permissions/timingandestimationplugin/blackmagic.py

Last change on this file was 10266, checked in by Russ Tyndall, 12 years ago

fixed UTF-8 field label bugs related to genshi Stream.render calls re #8866

File size: 9.3 KB
Line 
1from trac.core import Component, implements, TracError
2from trac.config import Option, IntOption, ListOption, BoolOption
3from trac.web.chrome import ITemplateProvider, add_stylesheet, add_script
4from pkg_resources import resource_filename
5from trac.web.api import ITemplateStreamFilter
6from genshi.builder import tag
7from genshi.core import Markup, Stream
8from genshi.filters.transform import Transformer
9import re, cPickle
10from trac.perm import IPermissionRequestor
11
12from genshi.filters import HTMLSanitizer
13from genshi.output import TextSerializer
14
15def textOf(self, **keys):
16    return self.render('text', None, **keys)
17
18Stream.textOf = textOf
19
20#@staticmethod
21def disable_field(stream, field):
22    def select_helper(stream):
23        s = Stream(stream)
24        name = s.select('@name').textOf()
25        opt = s.select('//option[@selected]')
26        if not opt: s.select('//option[position()=1]')
27        text = opt.select("text()").textOf()
28        value = s.select('@value').textOf()
29        if not value: value = text
30
31        for kind,data,pos in tag.span(text, id=("field-%s"%field)).generate():
32            yield kind,data,pos
33        for kind,data,pos in tag.input(value=value, name=name, type="hidden").generate():
34            yield kind,data,pos
35
36
37    def helper(field_stream):
38        s = Stream(field_stream)
39        value = s.select('@value').textOf()
40        name = s.select('@name').textOf()
41        for kind,data,pos in tag.span(value, id=("field-%s"%field)).generate():
42            yield kind,data,pos
43        for kind,data,pos in tag.input(value=value, name=name, type="hidden").generate():
44            yield kind,data,pos
45
46    stream = stream | Transformer( '//select[@id="field-%s"]' % field ).filter(select_helper)
47    stream = stream | Transformer( '//input[@id="field-%s"]' % field ).filter(helper)
48    return stream
49
50
51def remove_header(stream, field):
52    """ Removes the display from the ticket properties """
53    stream = stream | \
54        Transformer('//th[@id="h_%s"]' % field).replace(tag.th(id="h_%s" % field))
55    stream = stream | \
56        Transformer('//td[@headers="h_%s"]' % field).replace(tag.th(id="h_%s" % field))
57    return stream
58
59def remove_changelog(self, stream, field):
60    """ Removes entries from the visible changelog"""
61    #self.log.debug('Begin ChangeLog Filter')
62    check = self.env.config.get('ticket-custom',field+'.label', field).lower().strip()
63    def helper(field_stream):
64        try:
65            s = Stream(field_stream)
66            self.log.debug('ChangeLog Pre')
67            # without None as the second value we get str instead of unicode
68            # and that causes things to break sometimes
69            f = s.select('//strong/text()').textOf(strip_markup=True).lower()
70            # self.log.debug(u'ChangeLog Pre 2 : %s: %r', type(f), f)
71            self.log.debug('ChangeLog Filter: field:%s, label:%s, we are looking at:%r, skip?%s',
72                           field, check, f, check == f )
73            if check != f: #if we are the field just skip it
74            #identity stream filter
75                for kind, data, pos in s:
76                    yield kind, data, pos
77        except Exception, e:
78            self.log.exception('ChangeLog: Stream Filter Exception');
79            raise e
80    stream = stream | Transformer('//ul[@class="changes"]/li').filter(helper)
81    return stream
82   
83
84def hide_field(self, stream , field):
85    """ Replaces a field from the form area with an input type=hidden"""
86    def helper (field_stream):
87        type = Stream(field_stream).select('@type').textOf()
88        if type == 'checkbox':
89            if Stream(field_stream).select('@checked').textOf() == "checked":
90                value = 1
91            else:
92                value = 0
93        else:
94            value = Stream(field_stream).select('@value').textOf()
95        name = Stream(field_stream).select('@name').textOf()
96        for kind,data,pos in tag.input( value=value,
97                                        type="hidden", name=name).generate():
98            yield kind,data,pos
99
100    def select_helper(stream):
101        s = Stream(stream)
102        name = s.select('@name').textOf()
103        opt = s.select('//option[@selected]')
104        if not opt: s.select('//option[position()=1]')
105        text = opt.select("text()").textOf()
106        value = s.select('@value').textOf()
107        if not value: value = text
108        for kind,data,pos in tag.input(value=value, name=name, type="hidden").generate():
109            yield kind,data,pos
110
111    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(" ")
112    stream = stream | Transformer('//input[@id="field-%s"]' % field).filter(helper)
113    stream = stream | Transformer('//select[@id="field-%s"]' % field).filter(select_helper)
114
115    return remove_changelog(self, remove_header(stream , field), field)
116
117def remove_field(self, stream , field):
118    """ Removes a field from the form area"""
119    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(" ")
120    stream = stream | Transformer('//*[@id="field-%s"]' % field).replace(" ")
121    return remove_changelog(self,remove_header(stream , field), field)
122
123def istrue(v, otherwise=None):
124    if isinstance(v, bool):
125        return v
126    if str(v).lower() in ('yes', 'true', '1', 'on'):
127        return True
128    if not otherwise:
129        return False
130    return otherwise
131
132csection = 'field settings'
133
134class TicketTweaks(Component):
135    implements(ITemplateStreamFilter, ITemplateProvider)   
136    ## ITemplateStreamFilter
137   
138    def filter_stream(self, req, method, filename, stream, data):
139        self.log.debug('IN BlackMagic')
140        if not filename == "ticket.html":
141            self.log.debug('Not a ticket returning')
142            return stream
143        fields = self.config.getlist(csection, 'fields', [])
144        self.log.debug('read enchants = %r' % fields)
145        for field in fields:
146            self.log.debug('starting : %s' % field)
147            disabled = False
148            hidden = False
149            hide_summary = False
150            remove = False
151            perms = self.config.getlist(csection, '%s.permission' % field, [])
152            self.log.debug('read permission config: %s has %s' % (field, perms))
153            for (perm, denial) in [s.split(":") for s in perms] :
154                perm = perm.upper()
155                self.log.debug('testing permission: %s:%s should act= %s' %
156                               (field, perm, (not req.perm.has_permission(perm) or perm == "ALWAYS")))
157                if (not req.perm.has_permission(perm) or perm == "ALWAYS"): 
158                    if denial:
159                        denial = denial.lower()
160                        if denial == "disable":
161                            disabled = True
162                        elif denial == "hide":
163                            hidden = True
164                        elif denial == "remove":
165                            remove = True
166                        else:
167                            disabled = True
168                    else:
169                        disabled = True
170                   
171                if disabled or istrue(self.config.get(csection, '%s.disable' % field, False)):
172                    self.log.debug('disabling: %s' % field)
173                    stream = disable_field(stream, field)
174
175                if self.config.get(csection, '%s.label' % field, None):
176                    self.log.debug('labeling: %s' % field)
177                    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(
178                        self.config.get(csection, '%s.label' % field)
179                    )
180                   
181                if self.config.get(csection, '%s.notice' % field, None):
182                    self.log.debug('noticing: %s' % field)
183                    stream = stream | Transformer('//*[@id="field-%s"]' % field).after(
184                        tag.br() + tag.small()(
185                            tag.em()(
186                                Markup(self.config.get(csection, '%s.notice' % field))
187                            )
188                        )
189                    )
190                   
191                tip = self.config.get(csection, '%s.tip' % field, None)
192                if tip:
193                    self.log.debug('tipping: %s' % field)
194                    stream = stream | Transformer('//div[@id="banner"]').before(
195                        tag.script(type="text/javascript", 
196                        src=req.href.chrome("blackmagic", "js", "wz_tooltip.js"))()
197                    )
198                   
199                    stream = stream | Transformer('//*[@id="field-%s"]' % field).attr(
200                        "onmouseover", "Tip('%s')" % tip.replace(r"'", r"\'")
201                    )
202                   
203                if remove or istrue(self.config.get(csection, '%s.remove' % field, None)):
204                    self.log.debug('removing: %s' % field)
205                    stream = remove_field(self, stream, field)
206
207                if hidden or istrue(self.config.get(csection, '%s.hide' % field, None)):
208                    self.log.debug('hiding: %s' % field)
209                    stream = hide_field(self, stream, field)
210                   
211        return stream
212
213    ## ITemplateProvider
214
215    def get_htdocs_dirs(self):
216        from pkg_resources import resource_filename
217        return [('blackmagic', resource_filename(__name__, 'htdocs'))]
218         
219    def get_templates_dirs(self):
220        return []   
Note: See TracBrowser for help on using the repository browser.