source: timingandestimationplugin/branches/trac0.12-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
RevLine 
[4260]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
[10266]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
[4260]20#@staticmethod
21def disable_field(stream, field):
[7919]22    def select_helper(stream):
23        s = Stream(stream)
[10266]24        name = s.select('@name').textOf()
[7919]25        opt = s.select('//option[@selected]')
26        if not opt: s.select('//option[position()=1]')
[10266]27        text = opt.select("text()").textOf()
28        value = s.select('@value').textOf()
[7919]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
[4260]37    def helper(field_stream):
[4270]38        s = Stream(field_stream)
[10266]39        value = s.select('@value').textOf()
40        name = s.select('@name').textOf()
[4260]41        for kind,data,pos in tag.span(value, id=("field-%s"%field)).generate():
42            yield kind,data,pos
[4270]43        for kind,data,pos in tag.input(value=value, name=name, type="hidden").generate():
44            yield kind,data,pos
[4260]45
[7919]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
[4260]49
50
51def remove_header(stream, field):
52    """ Removes the display from the ticket properties """
[4261]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))
[4260]57    return stream
58
[9630]59def remove_changelog(self, stream, field):
[4261]60    """ Removes entries from the visible changelog"""
[9630]61    #self.log.debug('Begin ChangeLog Filter')
62    check = self.env.config.get('ticket-custom',field+'.label', field).lower().strip()
[4261]63    def helper(field_stream):
[10266]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
[4261]74            #identity stream filter
[10266]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
[4261]80    stream = stream | Transformer('//ul[@class="changes"]/li').filter(helper)
81    return stream
82   
83
[9630]84def hide_field(self, stream , field):
[4261]85    """ Replaces a field from the form area with an input type=hidden"""
86    def helper (field_stream):
[10266]87        type = Stream(field_stream).select('@type').textOf()
[5348]88        if type == 'checkbox':
[10266]89            if Stream(field_stream).select('@checked').textOf() == "checked":
[5348]90                value = 1
91            else:
92                value = 0
93        else:
[10266]94            value = Stream(field_stream).select('@value').textOf()
95        name = Stream(field_stream).select('@name').textOf()
[4270]96        for kind,data,pos in tag.input( value=value,
[4261]97                                        type="hidden", name=name).generate():
98            yield kind,data,pos
[7919]99
100    def select_helper(stream):
101        s = Stream(stream)
[10266]102        name = s.select('@name').textOf()
[7919]103        opt = s.select('//option[@selected]')
104        if not opt: s.select('//option[position()=1]')
[10266]105        text = opt.select("text()").textOf()
106        value = s.select('@value').textOf()
[7919]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
[4261]111    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(" ")
[7919]112    stream = stream | Transformer('//input[@id="field-%s"]' % field).filter(helper)
113    stream = stream | Transformer('//select[@id="field-%s"]' % field).filter(select_helper)
[4261]114
[9630]115    return remove_changelog(self, remove_header(stream , field), field)
[4261]116
[9630]117def remove_field(self, stream , field):
[4260]118    """ Removes a field from the form area"""
119    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(" ")
[7869]120    stream = stream | Transformer('//*[@id="field-%s"]' % field).replace(" ")
[9630]121    return remove_changelog(self,remove_header(stream , field), field)
[4260]122
123def istrue(v, otherwise=None):
[7235]124    if isinstance(v, bool):
125        return v
126    if str(v).lower() in ('yes', 'true', '1', 'on'):
[4260]127        return True
[7235]128    if not otherwise:
129        return False
130    return otherwise
[4260]131
[4261]132csection = 'field settings'
133
[4260]134class TicketTweaks(Component):
[4270]135    implements(ITemplateStreamFilter, ITemplateProvider)   
[4260]136    ## ITemplateStreamFilter
137   
138    def filter_stream(self, req, method, filename, stream, data):
[4261]139        self.log.debug('IN BlackMagic')
[4260]140        if not filename == "ticket.html":
[4261]141            self.log.debug('Not a ticket returning')
[4260]142            return stream
[4264]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)
[4260]147            disabled = False
148            hidden = False
149            hide_summary = False
[4261]150            remove = False
151            perms = self.config.getlist(csection, '%s.permission' % field, [])
[4264]152            self.log.debug('read permission config: %s has %s' % (field, perms))
[4260]153            for (perm, denial) in [s.split(":") for s in perms] :
154                perm = perm.upper()
[4264]155                self.log.debug('testing permission: %s:%s should act= %s' %
[4261]156                               (field, perm, (not req.perm.has_permission(perm) or perm == "ALWAYS")))
157                if (not req.perm.has_permission(perm) or perm == "ALWAYS"): 
[4260]158                    if denial:
159                        denial = denial.lower()
160                        if denial == "disable":
161                            disabled = True
162                        elif denial == "hide":
163                            hidden = True
[4261]164                        elif denial == "remove":
165                            remove = True
[4260]166                        else:
167                            disabled = True
168                    else:
169                        disabled = True
170                   
[4261]171                if disabled or istrue(self.config.get(csection, '%s.disable' % field, False)):
[4264]172                    self.log.debug('disabling: %s' % field)
[4261]173                    stream = disable_field(stream, field)
[4260]174
[4261]175                if self.config.get(csection, '%s.label' % field, None):
[4264]176                    self.log.debug('labeling: %s' % field)
[4260]177                    stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(
[4261]178                        self.config.get(csection, '%s.label' % field)
[4260]179                    )
180                   
[4261]181                if self.config.get(csection, '%s.notice' % field, None):
[4264]182                    self.log.debug('noticing: %s' % field)
[4260]183                    stream = stream | Transformer('//*[@id="field-%s"]' % field).after(
184                        tag.br() + tag.small()(
185                            tag.em()(
[4261]186                                Markup(self.config.get(csection, '%s.notice' % field))
[4260]187                            )
188                        )
189                    )
190                   
[4261]191                tip = self.config.get(csection, '%s.tip' % field, None)
[4260]192                if tip:
[4264]193                    self.log.debug('tipping: %s' % field)
[4260]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                   
[4261]203                if remove or istrue(self.config.get(csection, '%s.remove' % field, None)):
[4264]204                    self.log.debug('removing: %s' % field)
[9630]205                    stream = remove_field(self, stream, field)
[4261]206
207                if hidden or istrue(self.config.get(csection, '%s.hide' % field, None)):
[4264]208                    self.log.debug('hiding: %s' % field)
[9630]209                    stream = hide_field(self, stream, field)
[4260]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.