def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': stream |= Transformer('.//input[@id="field-reporter"]').attr( 'disabled', 'disabled') stream |= Transformer('.//form[@id="addreply"]').attr( 'style', 'display: none') return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': # print "_____________ am in TextAreaDescription" fields = data['fields'] if self.description_descr: # print "having description_descr: %s" % self.description_descr # print "having description_template: %s" % self.descr_template html_d = self.descr_template % ('ticket-rndescr', self.description_descr) stream |= Transformer( './/th/label[@for="field-description"]').after( HTML(html_d)) for f in fields: if f['skip'] or not f[ 'type'] == 'textarea': # or not f.has_key('descr'): continue descr = self.config.get('ticket-custom', '%s.descr' % f['name']) if descr: # print "processing field %s" % f css_class = self.config.get('ticket-custom', '%s.css_class' % f['name']) # print css_class field_name = 'field-%s' % f['name'] tr_str = './/label[@for="%s"]' % field_name html = self.descr_template % (css_class, descr) stream |= Transformer(tr_str).after(HTML(html)) return stream
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ # get the GeoTicket component if not self.env.is_component_enabled(GeoTicket): return stream geoticket = self.env.components[GeoTicket] # filter for tickets if filename == 'ticket.html': stream |= Transformer( "//script[@src='%s']" % req.href.chrome('geoticket/js/reverse_geocode.js')).before( self.load_map(data['locations'])) # filter for queries - add the located tickets to a map if (filename == 'query.html' or filename == 'report_view.html') and data['locations']: stream |= Transformer('//head').append( self.load_map(data['locations'], req.environ.get('kml'))) if self.inject_map: stream |= Transformer("//div[@id='content']").after( self.content(None, None)) return stream
def generate(self, *args, **kwargs): "creates the RelatorioStream." serializer = OOSerializer(self._source, self._files) kwargs['__relatorio_make_href'] = ImageHref(serializer, kwargs) kwargs['__relatorio_make_dimension'] = ImageDimension(self.namespaces) kwargs['__relatorio_guess_type'] = self._guess_type kwargs['__relatorio_escape_invalid_chars'] = escape_xml_invalid_chars counter = ColumnCounter() kwargs['__relatorio_reset_col_count'] = counter.reset kwargs['__relatorio_inc_col_count'] = counter.inc kwargs['__relatorio_store_col_count'] = counter.store cache = ExpressionCache() kwargs['__relatorio_store_cache'] = cache.store kwargs['__relatorio_get_cache'] = cache.get stream = super(Template, self).generate(*args, **kwargs) if self.has_col_loop: # Note that we can't simply add a "number-columns-repeated" # attribute and then fill it with the correct number of columns # because that wouldn't work if more than one column is repeated. transformation = DuplicateColumnHeaders(counter) col_filter = Transformer('//repeat[namespace-uri()="%s"]' % RELATORIO_URI) col_filter = col_filter.apply(transformation) # Must consume the stream to fill counter stream = Stream(list(stream), self.serializer) | col_filter return RelatorioStream(stream, serializer)
def filter(self, stream): if self.active: routes = request.environ.get('pylons.routes_dict') if routes.get('controller') == 'package' \ and routes.get('action') == 'read': # add vocab tags to the bottom of the page tags = c.pkg_dict.get('vocab_tags_selected', []) for tag in tags: stream = stream | Transformer('body')\ .append(HTML('<p>%s</p>' % tag)) if routes.get('controller') == 'package' \ and routes.get('action') == 'edit': # add vocabs tag select box to edit page html = '<select id="vocab_tags" name="vocab_tags" size="60" multiple="multiple">' selected_tags = c.pkg_dict.get('vocab_tags_selected', []) for tag in c.vocab_tags: if tag in selected_tags: html += '<option selected="selected" value="%s">%s</option>' % ( tag, tag) else: html += '<option value="%s">%s</option>' % (tag, tag) html += '</select>' stream = stream | Transformer( 'fieldset[@id="basic-information"]').append(HTML(html)) return stream
def filter_stream(self, req, method, filename, stream, data): """ Wrap the banner and mainnav in a single banner_wrapper div """ add_stylesheet(req, "http://fonts.googleapis.com/css?family=Ubuntu") add_stylesheet(req, "lightertheme/theme.css") stream |= Transformer("//div[@id='banner']").wrap(tag.div(class_="banner_wrapper banner_wrapper_first")) stream |= Transformer("//div[@id='mainnav']").wrap(tag.div(class_="banner_wrapper banner_wrapper_second")) stream |= Transformer("//div[@class='banner_wrapper banner_wrapper_first']").append(tag.hr()) return stream filter = Transformer("//div[@id='banner']") stream |= ( filter.wrap(tag.div(id="banner_wrapper")) .end() .select("//div[@id='mainnav']") .cut(buffer, accumulate=True) .end() .buffer() .select("//div[@id='banner_wrapper']") .append(tag.hr()) .append(buffer) .end() ) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == "ticket.html": ticket = data.get("ticket") if ticket and ticket.exists and "TICKET_ADMIN" in req.perm(ticket.resource): filter = Transformer('//h3[@id="comment:description"]') stream |= filter.after(self._clone_form(req, ticket, data)) return stream
def filter_stream(self, req, method, filename, stream, data): # Add delete buttons to the ticket form ticket = data.get("ticket") if filename == "ticket.html" and "TICKET_ADMIN" in req.perm(ticket.resource): # Add Delete button to ticket description if data["ticket"].values["description"]: # Reply button and associated elements are present filter = Transformer("//div[@class='description']//div[@class='inlinebuttons']") stream |= filter.append( tag.input(type="submit", name="delete", title="Delete this ticket", value="Delete") ) else: # Reply button and associated elements not present filter = Transformer("//div[@class='description']/h3") stream |= filter.after( tag.form( tag.div( tag.input(type="submit", name="delete", title="Delete this ticket", value="Delete"), class_="inlinebuttons", ), name="addreply", method="get", action="#comment", ) ) # Add Delete buttons to ticket comments stream |= Transformer("//div[@id='changelog']//div[@class='inlinebuttons']").append( tag.input(type="submit", name="delete", title="Delete this comment", value="Delete") ) return stream
def filter_stream(self, req, method, filename, stream, data): """ Reformat the ``branch`` field of a ticket to show the history of the linked branch. """ if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists: branch = ticket['branch'] if branch: error = None if not self._is_valid_branch_name(branch): error = "not a valid branch name" elif not self._is_existing_branch(branch): error = "branch does not exist" else: try: master = self._dereference_head(MASTER_BRANCH) branch = self._dereference_head(branch) common_ancestor = self._common_ancestor(master,branch) if branch == common_ancestor: # the trac log page does not work if the revisions are equal error = "no commits on branch yet" else: filter = Transformer('//td[@headers="h_branch"]/text()') stream |= filter.wrap(tag.a(href=req.href.log(revs="%s-%s"%(common_ancestor,branch)))) except GitError: error = "failed to determine common ancestor with %s branch"%MASTER_BRANCH if error: filter = Transformer('//td[@headers="h_branch"]') stream |= filter.attr("title",error) return stream
def _generate_html(self, relation, relation_type, relation_role, stream, ticket): config = self.config['ticket-custom'] try: if relation_type == 'one': if ticket[relation.name + '_' + relation_role] is not None: target_ticket = Ticket(self.env, int(ticket[relation.name + '_' + relation_role])) stream |= Transformer('//div[@id="ticket"]//td[@headers="h_%s"]/text()' % (relation.name + '_' + relation_role)) \ .replace(tag.a('#%s %s' % (target_ticket.id, target_ticket['summary']), href='/ticket/' + str(target_ticket.id))) else: if ticket[relation.name + '_' + relation_role] is not None: target_tickets = [Ticket(self.env, int(i)) for i in ticket[relation.name + '_' + relation_role].split(',')] format = map(unicode.strip, config.get(relation.name + '_' + relation_role + '.format').split(',')) tbody = tag.tbody() for target_ticket in target_tickets: columns = [tag.td(tag.a('#' + str(target_ticket.id), href='/ticket/' + str(target_ticket.id)))] columns.extend([tag.td(target_ticket[field]) for field in format]) tbody.append(tag.tr(*columns)) stream |= Transformer('//div[@id="ticket"]//td[@headers="h_%s"]/text()' % (relation.name + '_' + relation_role)) \ .replace(tag.table(tbody, class_='relation_table')) except Exception as e: self.log.error(e.message) return stream
def generate(self, *args, **kwargs): "creates the RelatorioStream." serializer = OOSerializer(self._zip_source) kwargs['__relatorio_make_href'] = ImageHref(serializer.outzip, serializer.manifest, kwargs) kwargs['__relatorio_make_dimension'] = ImageDimension(self.namespaces) kwargs['__relatorio_guess_type'] = guess_type counter = ColumnCounter() kwargs['__relatorio_reset_col_count'] = counter.reset kwargs['__relatorio_inc_col_count'] = counter.inc kwargs['__relatorio_store_col_count'] = counter.store cache = ExpressionCache() kwargs['__relatorio_store_cache'] = cache.store kwargs['__relatorio_get_cache'] = cache.get stream = super(Template, self).generate(*args, **kwargs) if self.has_col_loop: # Note that we can't simply add a "number-columns-repeated" # attribute and then fill it with the correct number of columns # because that wouldn't work if more than one column is repeated. transformation = DuplicateColumnHeaders(counter) col_filter = Transformer('//repeat[namespace-uri()="%s"]' % RELATORIO_URI) col_filter = col_filter.apply(transformation) stream = Stream(list(stream), self.serializer) | col_filter return RelatorioStream(stream, serializer)
def filter_stream(self, req, method, filename, stream, data): match = re.match(r'^/browser/?$', req.path_info) if not match: return stream script_url = req.href('/chrome/common/js/expand_dir.js') filter = Transformer('//script[@src="' + script_url + '"]') return stream | filter.remove()
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ self.ticket_clone_permission in req.perm(ticket.resource): filter = Transformer('//h3[@id="comment:description"]') stream |= filter.after(self._clone_form(req, ticket, data)) return stream
def filter_stream(self, req, method, filename, stream, data): if re.match(r'^/(changeset|browser|attachment/ticket/\d+/.?).*', req.path_info): filter = Transformer('//h1') button = self._subscription_button(req.path_info, req.args.get('rev')) stream |= filter.before(button) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ 'TICKET_ADMIN' in req.perm(ticket.resource): filter = Transformer('//h3[@id="comment:description"]') stream |= filter.after(self._clone_form(req, ticket, data)) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ 'TICKET_CREATE' in req.perm(ticket.resource): # filter = Transformer('//h3[@id="comment:description"]') filter = Transformer( self.config.get('trac', 'clone_xpath') ) return stream | filter.after(self._clone_form(req, ticket, data)) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'query.html': filter_script = Transformer('//script[contains(@src, "jquery.js")]') filter_query = Transformer('table[@class="listing tickets"]/.') return stream | filter_script.after( tag.script( type="text/javascript", src=self.env.href('chrome', 'aq', 'js', 'query.js'))) \ | filter_query.prepend('<!-- Hello -->') return stream
def filter_stream(self, req, method, filename, stream, data): """ Wrap the banner and mainnav in a single banner_wrapper div """ buffer = StreamBuffer() filter = Transformer("//div[@id='banner']") stream |= filter.wrap(tag.div(id="banner_wrapper")).end( ).select("//div[@id='mainnav']").cut(buffer, accumulate=True).end().buffer( ).select("//div[@id='banner_wrapper']").append(tag.hr()).append(buffer).end() return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists: context = Context.from_request(req, ticket.resource) self.changesets = TicketChangesetsFormatter(self.env, context, ticket.id) exists = self.changesets.exists() if exists or not self.hide_when_none: filter = Transformer('//div[@id="attachments"]') return stream | filter.after(self._render(req, ticket, exists)) return stream
def filter_stream(self, req, method, filename, stream, data): """ Filter the ticket template and add the Cc Me! button next to the Cc list. """ if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ 'TICKET_APPEND' in req.perm(ticket.resource): transformer = Transformer('//th[@id="h_cc"]') stream |= transformer.append(self._ccme_form( req, ticket, data)) add_stylesheet(req, 'ccme/css/ccme.css') return stream
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ if filename in [ 'ticket.html', 'query.html', 'report_view.html', 'mapdashboard.html', 'regions_admin.html', 'wiki_view.html' ]: # XXX random E fix for minimum lattitude that somehow # works and I have no idea why min_lat = max(-89.999999999, self.min_lat) chrome = Chrome(self.env) _data = dict(req=req, wms_url=self.wms_url, min_lat=min_lat, max_lat=self.max_lat, min_lon=self.min_lon, max_lon=self.max_lon) template = chrome.load_template('layers.html') stream |= Transformer("//script[@src='%s']" % self.openlayers_url).after( template.generate(**_data)) return stream
def filter_stream(self, req, method, filename, stream, data): if not filename == 'report_list.html': return stream user = req.authname buffer = StreamBuffer() def check_report_permission(): delimiter = '</tr>' reportstream = str(buffer) reports_raw = reportstream.split(delimiter) reportstream = '' for report in reports_raw: if report != None and len(report) != 0: # determine the report id s = report.find('/report/') if s == -1: continue e = report.find('\"', s) if e == -1: continue report_id = report[s + len('/report/'):e] if self._has_permission(user, report_id): reportstream += report return HTML(reportstream) return stream | Transformer('//tbody/tr') \ .copy(buffer) \ .replace(check_report_permission)
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html' and req.authname != 'anonymous': ticket = data.get('ticket') if req.perm.has_permission('TICKET_ADMIN'): self.log.debug("TicketChangePlugin adding 'Change' links for ticket %s" % ticket.id) buffer = StreamBuffer() def insert_change_link(): cnum = list(buffer)[0][1][1][0][1] return tag(" ", tag.a("Change", href=("../ticketchangecomment/%s?cnum=%s" % (ticket.id, cnum)))) filter = Transformer("//div[@class='change']/div[@class='inlinebuttons']/input[@name='replyto']/@value") return stream | filter.copy(buffer).end() \ .select("//div[@class='change']/div[@class='inlinebuttons']/input[@value='Reply']") \ .after(insert_change_link) return stream
def filter_stream(self, req, method, filename, stream, data): if filename != 'query.html' and filename != 'report_list.html' and \ filename != 'report_view.html': return stream has_query_permission = self.query_permission in \ PermissionSystem(self.env).get_user_permissions(req.authname) buffer = StreamBuffer() def replace_query_link(): if has_query_permission: return buffer else: return HTML('<div id="ctxtnav" class="nav"></div>') def replace_filter_box(): if has_query_permission: return buffer else: return HTML('') return stream | Transformer('//div[@id="ctxtnav" and @class="nav"]') \ .copy(buffer) \ .replace(replace_query_link).end() \ .select('//form[@id="query" and @method="post" and @action]') \ .copy(buffer) \ .replace(replace_filter_box)
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ if filename == 'query.html' and self.inject_query: self.geoticket() # sanity check chrome = Chrome(self.env) variables = ('center_location', 'radius') _data = dict([(i, data.get(i)) for i in variables]) # georegions _data['geo_column_label'] = None _data['regions'] = None if self.env.is_component_enabled(GeoRegions): georegions = GeoRegions(self.env) if georegions.enabled(): regions = georegions.regions() if regions: column, regions = regions _data['geo_column_label'] = column _data['regions'] = regions _data['region'] = req.args.get('region') template = chrome.load_template('geoquery.html') stream |= Transformer("//fieldset[@id='columns']").after( template.generate(**_data)) return stream
def filter_stream(self, req, method, filename, stream, data): """ Adds project total count information in project summary block:: Downloads: 288 """ # TODO: Make interface for the project summary box and implement it here # Filter only the summary table wiki macro if filename != 'multiproject_summary.html': return stream # Load project and followers info project = Project.get(self.env) count = ProjectDownloadEntry.total_download_count(project.id) if count == 0: return stream # Add following information into project summary block trans = Transformer('//div[@class="summary"]/table').append( tag.tr( tag.th('Downloads:'), tag.td(count) ) ) return stream | trans
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ req.session.get(self.session_field, 'True') == 'True': filter_ = Transformer( '//script[contains(@src, "jquery.js")]') return stream | filter_.after( tag.script( type="text/javascript", src=self.env.href('chrome', 'ac', 'js', 'jquery.form.js'))) \ | filter_.after( tag.script( type="text/javascript", src=self.env.href('chrome', 'ac', 'js', 'comments.js'))) return stream
def filter_stream(self, req, method, filename, stream, data): """ filter hours and estimated hours fields to have them correctly display on the ticket.html """ if filename == 'ticket.html' and 'TICKET_VIEW_HOURS' in req.perm: field = [ field for field in data['fields'] if field['name'] == 'totalhours' ] if field: total_hours = field[0] ticket_id = data['ticket'].id if ticket_id is None: # new ticket field = '0' else: hours = '%.1f' \ % (self.get_total_hours(ticket_id) / 3600.0) field = tag.a(hours, href=req.href('hours', data['ticket'].id), title="hours for ticket %s" % data['ticket'].id) total_hours['rendered'] = field stream |= Transformer( "//input[@id='field-totalhours']").replace(field) return stream
def filter_stream(self, req, method, filename, stream, data): self.log.debug("ckintegration: template %s" % (filename)) # Act only when enabled, and editor_source defined, and current template has wiki-textareas if self.editor_source and self._check_editor_type(filename): # Some javascript global variable to add to the response to assist to tracwiki plugin add_script_data(req, { 'ck_editor_type': self.editor_type, 'ck_code_styles': self.get_styles_list(), 'trac_base_url': req.href.base, 'ck_tracwiki_path': req.href.chrome('ckintegration'), 'ck_resource_realm': 'wiki', 'ck_resource_id': '', 'form_token': req.form_token, }) # Load the needed scripts (CKEditor itself, and the tracwiki plugin add_script(req, self.editor_source) add_script(req, 'ckintegration/tracwiki.js') add_script(req, 'ckintegration/pastecode.js') # Inject a script that adds the tracwiki plugin as an external plugin to CKEditor # @todo: Perform init with a dedicated loader script # @todo: Use the init to modify the CKEditor toolbar ck_plugin_init = '<script type="text/javascript">CKEDITOR.plugins.addExternal("tracwiki", ck_tracwiki_path, "tracwiki.js");\n' ck_plugin_init += 'CKEDITOR.plugins.addExternal("pastecode", ck_tracwiki_path, "pastecode.js");</script>' stream |= Transformer('.//body').prepend(HTML(ck_plugin_init)) #add_script(req, 'ckintegration/ckloader.js') # Replace all relevant textarea fields in the template with CKEditor instances for field_name in self.template_fields[lower(filename)]: self.log.debug('Replacing textarea "%s" with CKEditor instance' % (field_name)) add_editor = '''<script type="text/javascript"> CKEDITOR.replace("%s", { extraPlugins : "tracwiki,pastecode" }); </script>''' % (field_name) #self.log.debug ("add_editor is %s" % add_editor) stream |= Transformer('.//textarea[@name="%s"]' % (field_name)).after(HTML(add_editor)) # Also replace custom textarea fields in the ticket template that have wiki format if 'ticket.html' == lower(filename) and 'fields' in data: for f in data['fields']: if f['skip'] or not lower(f['type']) == 'textarea' or \ not f.has_key('format') or not 'wiki' == lower(f['format']): continue field_name = 'field_%s' % f['name'] self.log.debug('Replacing textarea "%s" with CKEditor instance' % (field_name)) add_editor = '''<script type="text/javascript"> CKEDITOR.replace("%s", { extraPlugins : "tracwiki,pastecode" }); </script>''' % (field_name) stream |= Transformer('.//textarea[@name="%s"]' % (field_name)).after(HTML(add_editor)) return stream
def filter_stream(self, req, method, filename, stream, data): ''' add the flag that indicates the activation of the date picker javascript ''' if req.path_info.startswith('/ticket/') or req.path_info.startswith('/newticket'): stream |= Transformer('body/div[@id="main"]').prepend(tag.div( 'activate', id='ppShowDatePicker') ) return stream
def process_request(self, req): # Allow all POST requests (with a valid __FORM_TOKEN, ensuring that # the client has at least some permission). Additionally, allow GET # requests from TRAC_ADMIN for testing purposes. if req.method != 'POST': req.perm.require('TRAC_ADMIN') # @todo: Embed "tips" within the rendered output for the editor # (recognize TracLinks, table-stuff, macros, processors) # @todo: Save the content in server-side user-specific field for recovery realm = req.args.get('realm', 'wiki') id = req.args.get('id') version = req.args.get('version') if version is not None: try: version = int(version) except ValueError: version = None text = req.args.get('text', '') flavor = req.args.get('flavor') options = {} if 'escape_newlines' in req.args: options['escape_newlines'] = bool(int(req.args['escape_newlines'] or 0)) if 'shorten' in req.args: options['shorten'] = bool(int(req.args['shorten'] or 0)) resource = Resource(realm, id=id, version=version) context = Context.from_request(req, resource) rendered = format_to_cke_html(self.env, context, text, self.code_styles, **options) # since Trac renders underlined text as `<span class="underlined">text</span> # instead of u-tag, we need to adjust it for compatibility's sake # see also discussion at Google Groups: # https://groups.google.com/group/trac-dev/browse_thread/thread/833206a932d1f918 html = HTML(rendered) html |= Transformer('//span[@class="underline"]').rename('u').attr('class', None) # CKEditor renders indentation by using p style="margin-left: 40px" # instead of blockquote-tag html |= Transformer('//blockquote/p').attr('style', 'margin-left: 40px') html |= Transformer('//blockquote').unwrap() buffer = StringIO() html.render(out=buffer, encoding='utf-8') req.send( buffer.getvalue() )
def get_stream(self, req, method, filename, stream, original_data): if 'linkinfo' in req.args: link_info = tag.input(name="linkinfo", value=req.args['linkinfo'], type="hidden") else: link_info = tag.comment('no link') return Transformer('//form[@id="propertyform"]').prepend(link_info)
def filter_stream(self, req, method, filename, stream, data): """ filter the stream for the roadmap (/roadmap) and milestones /milestone/<milestone> """ if filename in ('roadmap.html', 'milestone_view.html'): trachours = TracHoursPlugin(self.env) hours = {} milestones = data.get('milestones') this_milestone = None if milestones is None: # /milestone view : only one milestone milestones = [ data['milestone'] ] this_milestone = milestones[0].name find_xpath = "//div[@class='milestone']//h1" xpath = "//div[@class='milestone']//div[@class='info']" else: # /roadmap view find_xpath = "//li[@class='milestone']//h2/a" xpath = "//li[@class='milestone']//div[@class='info']" for milestone in milestones: hours[milestone.name] = dict(totalhours=0., estimatedhours=0.,) db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("select id from ticket where milestone=%s", (milestone.name,)) tickets = [i[0] for i in cursor.fetchall()] if tickets: hours[milestone.name]['date'] = Ticket(self.env, tickets[0]).time_created for ticket in tickets: ticket = Ticket(self.env, ticket) # estimated hours for the ticket try: estimatedhours = float(ticket['estimatedhours']) except (ValueError, TypeError): estimatedhours = 0. hours[milestone.name]['estimatedhours'] += estimatedhours # total hours for the ticket (seconds -> hours) totalhours = trachours.get_total_hours(ticket.id) / 3600.0 hours[milestone.name]['totalhours'] += totalhours # update date for oldest ticket if ticket.time_created < hours[milestone.name]['date']: hours[milestone.name]['date'] = ticket.time_created b = StreamBuffer() stream |= Transformer(find_xpath).copy(b).end().select(xpath).append(self.MilestoneMarkup(b, hours, req.href, this_milestone)) return stream
def filter_stream(self, req, method, filename, stream, data): # Add delete buttons to the ticket form ticket = data.get('ticket') if filename == 'ticket.html' and 'TICKET_ADMIN' in req.perm(ticket.resource): # Add Delete button to ticket description if data['ticket'].values['description']: # Reply button and associated elements are present filter = Transformer("//div[@class='description']//div[@class='inlinebuttons']") stream |= filter.append(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete')) else: # Reply button and associated elements not present filter = Transformer("//div[@class='description']/h3") stream |= filter.after( \ tag.form(tag.div(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete'), class_='inlinebuttons' ), name='addreply', method='get', action='#comment') ) # Add Delete buttons to ticket comments stream |= Transformer("//div[@id='changelog']//div[@class='inlinebuttons']") \ .append(tag.input(type='submit', name='delete', title="Delete this comment", value='Delete')) return stream
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. """ if filename == "ticket.html" and \ ('TICKET_REMINDER_VIEW' in req.perm or 'TICKET_REMINDER_MODIFY' in req.perm or 'TICKET_ADMIN' in req.perm): tags = self._reminder_tags(req, data) if tags: ticket_resource = data['ticket'].resource context = Context.from_request(req, ticket_resource) attachments_data = AttachmentModule( self.env).attachment_data(context) add_stylesheet(req, 'ticketreminder/css/ticketreminder.css') # Will attachments section be displayed? attachments_or_ticket = Transformer( '//div[@id="attachments"]' ) if attachments_data['can_create'] or attachments_data[ 'attachments'] else Transformer('//div[@id="ticket"]') trac_nav = Transformer( '//form[@id="propertyform"]/div[@class="trac-nav"]') return stream | attachments_or_ticket.after( tags) | trac_nav.append(self._reminder_trac_nav(req, data)) return stream
def filter(self, stream): """ Modify dataset and resource view on the fly and add a link to the "pills" in the html templates, which are basically menuitems. """ from pylons import request, tmpl_context as c routes = request.environ.get('pylons.routes_dict') if routes.get('controller') == 'package' and routes.get('action') == \ 'resource_read': data = {'url': '/irods/%s' % json.loads(c.resource_json)['id']} stream = stream | Transformer('body//div[@id="minornavigation"]/ul')\ .append(HTML(html.IRODS_PILL%data)) elif routes.get('controller') == 'package' and routes.get('action') == \ 'read': data = {'url': '/irods_import/%s' % c.current_package_id} stream = stream | Transformer('body//div[@id="minornavigation"]/ul')\ .append(HTML(html.IRODS_PILL%data)) return stream
def filter(self, stream): from pylons import request, tmpl_context as c routes = request.environ.get('pylons.routes_dict') if routes.get('controller') == 'package' and \ routes.get('action') == 'search': data = { 'bbox': request.params.get('ext_bbox',''), 'default_extent': config.get('ckan.spatial.default_map_extent','') } stream = stream | Transformer('body//div[@id="dataset-search-ext"]')\ .append(HTML(html.SPATIAL_SEARCH_FORM % data)) stream = stream | Transformer('head')\ .append(HTML(html.SPATIAL_SEARCH_FORM_EXTRA_HEADER % data)) stream = stream | Transformer('body')\ .append(HTML(html.SPATIAL_SEARCH_FORM_EXTRA_FOOTER % data)) return stream
def filter_stream(self, req, method, filename, stream, data): if 'TICKET_ADMIN' in req.perm: if req.path_info == '/admin/ticket/components' or req.path_info == '/admin/ticket/components/': components = data.get('components') # 'components' will be None if component with specified name already exists. if not components: return stream default_ccs = DefaultCC.select(self.env) stream = stream | Transformer('//table[@id="complist"]/thead/tr') \ .append(tag.th('Default CC')) filter = Transformer('//table[@id="complist"]/tbody') default_comp = self.config.get('ticket', 'default_component') for comp in components: if default_comp == comp.name: default_tag = tag.input(type='radio', name='default', value=comp.name, checked='checked') else: default_tag = tag.input(type='radio', name='default', value=comp.name) if comp.name in default_ccs: default_cc = default_ccs[comp.name] else: default_cc = '' filter = filter.append(tag.tr(tag.td(tag.input(type='checkbox', name='sel', value=comp.name), class_='sel'), tag.td(tag.a(comp.name, href=req.href.admin('ticket', 'components') + '/' + comp.name), class_='name'), tag.td(comp.owner, class_='owner'), tag.td(default_tag, class_='default'), tag.td(default_cc, class_='defaultcc'))) return stream | filter elif req.path_info.startswith('/admin/ticket/components/') and data.get('component'): cc = DefaultCC(self.env, data.get('component').name) filter = Transformer('//form[@id="modcomp"]/fieldset/div[@class="buttons"]') filter = filter.before(tag.div("Default CC:", tag.br(), tag.input(type="text", name="defaultcc", value=cc.cc), class_="field")) \ .before(tag.input(type='hidden', name='old_name', value=cc.name)) return stream | filter return stream
def filter_stream(self, req, method, filename, stream, data): if filename not in ('ticket.html', 'ticket_preview.html'): return stream ticket = data.get('ticket') if not (ticket and ticket.exists and 'TICKET_ADMIN' in req.perm(ticket.resource)): return stream # Insert "Delete" buttons for ticket description and each comment def delete_ticket(): return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete'), tag.input( type='submit', value=captioned_button( req, u'–', # 'EN DASH' _("Delete")), title=_('Delete ticket'), class_="trac-delete"), class_="inlinebuttons"), action='#', method='get') def delete_comment(): for event in buffer: cnum, cdate = event[1][1].get('id')[12:].split('-', 1) return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete-comment'), tag.input(type='hidden', name='cnum', value=cnum), tag.input(type='hidden', name='cdate', value=cdate), tag.input( type='submit', value=captioned_button( req, u'–', # 'EN DASH' _("Delete")), title=_('Delete comment %(num)s', num=cnum), class_="trac-delete"), class_="inlinebuttons"), action='#', method='get') buffer = StreamBuffer() return stream | Transformer('//div[@class="description"]' '/h3[@id="comment:description"]') \ .after(delete_ticket).end() \ .select('//div[starts-with(@class, "change")]/@id') \ .copy(buffer).end() \ .select('//div[starts-with(@class, "change") and @id]' '/div[@class="trac-ticket-buttons"]') \ .prepend(delete_comment)
def filter_stream(self, req, method, filename, stream, data): if filename == "roadmap.html": sortcrit = self._get_settings(req, "sortcrit", self.criterias[0]) sortdirect = self._get_settings(req, "sortdirect", self.directions[0]) sel = ' selected = "selected"' html_str = "<div>" + _("Sort by: ") html_str += '<select name="sortcrit">' for crit in self.criterias: html_str += '<option value ="%s" %s>%s</option>' % (crit, sel if sortcrit == crit else "", _(crit)) html_str += "</select>" html_str += '<select name="sortdirect">' for dir in self.directions: html_str += '<option value ="%s" %s>%s</option>' % (dir, sel if sortdirect == dir else "", _(dir)) html_str += "</select></div>" html = HTML(html_str) filter = Transformer('//form[@id="prefs"]/div[@class="buttons"]') return stream | filter.before(html) return stream
def _show_branches_tags(self, req, info, changes): filters = [] for idx, item in enumerate(info): change = changes[item['rev']] branch_filter = Transformer('//table/tbody/tr[%d]/td[@class="summary"]' % (idx+1)) for name, head in change.get_branches(): #if branch not in ('default', 'master'): span = tag.span(name, class_="branch" + (" head" if head else ''), title="Branch head" if head else 'Branch') filters.append(branch_filter.append(span)) for tagname in change.get_tag_contains(): span = tag.span(tagname, class_="tag", title="Tag") filters.append(branch_filter.append(span)) return filters
def filter_stream(self, req, method, filename, stream, data): # If required component is disabled, skip this too if not self.env.is_component_enabled('multiproject.common.users.login.BasicAuthRequest'): return stream # Append auth=basic to href basic_auth = lambda stream: self._append_href(stream, {'auth': 'basic'}) trans = Transformer('//a[@class="rss"]').apply(basic_auth) return stream | trans
def filter_stream(self, req, method, filename, stream, data): if filename == 'ticket.html': ticket = data.get('ticket') if ticket and ticket.exists and \ 'TICKET_CREATE' in req.perm(ticket.resource): # Find the configured buttons (anything in # [ticket-create-buttons] that has a name like "*.tag") options=self.config.options('ticket-create-buttons') buttons=[] for n, v in options: p=n.split('.') if len(p)==2 and p[1] == 'tag': buttons.append(p[0]) # Create the configured buttons for b in buttons: tag=self.config.get('ticket-create-buttons','%s.tag' % b) filter = Transformer(tag) stream = stream | filter.prepend(self._create_button(b, req, ticket, data)) return stream
def filter_stream(self, req, method, template, stream, data): if not (template == 'browser.html' and data.get('dir')): # Only interested if browsing directories return stream repos = data.get('repos') or self.env.get_repository() rev = req.args.get('rev', None) for entry in data['dir']['entries']: try: if not entry.isdir and entry.name.lower().startswith('readme'): # Render any file starting with 'readme' node = repos.get_node(entry.path, rev) output = self._render_file(req, data['context'], repos, node, rev=rev) if output: if isinstance(output['rendered'], Stream): # strips the <div class="code" /> surrounding tag content = output['rendered'].select('*') else: content = output['rendered'] insert_where = Transformer( "//div[@id='content']/div[@id='help']") insert_what = tag.div( tag.h1(entry.name, tag.a(Markup(' ¶'), class_="anchor", href='#'+entry.name, title='Link to file'), id_=entry.name ), tag.div( content, class_="searchable", style="background:#FBFBFB;border:2px solid #EEE;padding:0 1em;", title=entry.name), class_="readme", style="padding-top:1em;" ) stream = stream | insert_where.before(insert_what) except Exception, e: # Just log and ignore any kind of error (permissions and more) self.log.debug(to_unicode(e))
def filter_stream(self, req, method, filename, stream, data): """Adds button to ticket page.""" if filename != 'ticket.html': return stream ticket = data.get('ticket') permission = self.config.get(CONFIG_SECTION, 'permission') if not ticket or not ticket.exists or permission not in req.perm(ticket.resource): return stream url = self.config.get(CONFIG_SECTION, 'kanban_base_url') service = LeanKitService(url, self.env) team_field = self.config.get(CONFIG_SECTION, 'trac_team_field') board = service.get_board(ticket[team_field]) if not board: return stream if ticket['status'] == 'closed': return stream html = Transformer('//div[@class="description"]') return stream | html.after(self._kanban_form(board, ticket))
def filter_stream(self, req, method, filename, stream, data): """ Wrap the banner and mainnav in a single banner_wrapper div """ for href in self.extra_stylesheets: add_stylesheet(req, href) add_stylesheet(req, '/lightertheme/theme.css') stream |= Transformer("//div[@id='banner']").wrap(tag.div(class_="banner_wrapper banner_wrapper_first")) stream |= Transformer("//div[@id='mainnav']").wrap(tag.div(class_="banner_wrapper banner_wrapper_second")) stream |= Transformer("//div[@class='banner_wrapper banner_wrapper_first']").append(tag.hr()) return stream filter = Transformer("//div[@id='banner']") stream |= filter.wrap(tag.div(id="banner_wrapper")).end( ).select("//div[@id='mainnav']").cut(buffer, accumulate=True).end().buffer( ).select("//div[@id='banner_wrapper']").append(tag.hr()).append(buffer).end() return stream
def filter_stream(self, req, method, filename, stream, data): if filename != 'ticket.html': return stream fields = data.get("fields") if not fields: return stream if not data.get('ticket'): return stream readd_fields = [] for field in data['fields']: if field['name'] in \ self.get_ticket_action_fields(req, data['ticket']): if field['name'] in ("reporter", "owner"): # these are hardcoded in trac's ticket_box.html template continue readd_fields.append(field) filter = Transformer('//table[@class="properties"]') trs = [] contents = [] for i, field in enumerate(readd_fields): field = [tag.th('%s:' % field.get("label", field['name']), id='h_%s' % field['name'], class_="missing" if not data['ticket'][field['name']] else ""), tag.td(field['rendered'] \ if 'rendered' in field \ else data['ticket'][field['name']], headers='h_%s' % field['name'], class_='searchable')] contents.append(field) if i % 2 == 1: trs.append(tag.tr(*contents)) contents = [] if len(contents): trs.append(tag.tr(*contents)) stream |= filter.append(tag(*trs)) return stream
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ if filename != 'ticket.html': return stream ticket = data['ticket'] for provider in self.providers: # TODO : sorting if provider.enabled(req, ticket): add_stylesheet(req, 'common/css/ticket-sidebar.css') filter = Transformer('//div[@id="content"]') stream |= filter.after(tag.div(provider.content(req, ticket), **{'class': "sidebar" })) return stream
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. """ if filename == "ticket.html" and \ ('TICKET_REMINDER_VIEW' in req.perm or 'TICKET_REMINDER_MODIFY' in req.perm or 'TICKET_ADMIN' in req.perm): tags = self._reminder_tags(req, data) if tags: ticket_resource = data['ticket'].resource context = Context.from_request(req, ticket_resource) attachments_data = AttachmentModule(self.env).attachment_data(context) add_stylesheet(req, 'ticketreminder/css/ticketreminder.css') # Will attachments section be displayed? attachments_or_ticket = Transformer('//div[@id="attachments"]') if attachments_data['can_create'] or attachments_data['attachments'] else Transformer('//div[@id="ticket"]') trac_nav = Transformer('//form[@id="propertyform"]/div[@class="trac-nav"]') return stream | attachments_or_ticket.after(tags) | trac_nav.append(self._reminder_trac_nav(req, data)) return stream
def filter_stream(self, req, method, filename, stream, data): if 'TICKET_ADMIN' in req.perm and \ req.path_info.startswith('/admin/ticket/components'): if data.get('component'): cc = DefaultCC(self.env, data.get('component').name) filter = Transformer('//form[@id="modcomp"]/fieldset' '/div[@class="field"][2]') filter = filter.after(tag.div("Default CC:", tag.br(), tag.input(type='text', name='defaultcc', value=cc.cc), class_='field')) \ .before(tag.input(type='hidden', name='old_name', value=cc.name)) return stream | filter else: filter = Transformer('//form[@id="addcomponent"]' '/fieldset/div[@class="buttons"]') stream |= filter.before(tag.div("Default CC:", tag.br(), tag.input(type='text', name='defaultcc'), class_='field')) default_ccs = DefaultCC.select(self.env) stream |= Transformer('//table[@id="complist"]/thead/tr') \ .append(tag.th('Default CC')) for i, comp in enumerate(data.get('components')): if comp.name in default_ccs: default_cc = default_ccs[comp.name] else: default_cc = '' filter = Transformer('//table[@id="complist"]' '/tbody/tr[%d]' % (i + 1)) stream |= filter.append(tag.td(default_cc, class_='defaultcc')) return stream return stream
def filter_stream(self, req, method, filename, stream, data): if filename == "roadmap.html": # Insert the new field for entering user names filter = Transformer('//form[@id="prefs"]/div[@class="buttons"]') return stream | filter.before(self._user_field_input(req)) return stream
def filter_stream(self, req, method, filename, stream, data): """ Quick and dirty solution - modify page on the fly to inject special field. It would be nicer if we can do it by creating custom field as this depends on page structure. """ #embed(header='Ticket Stream Filter') if filename == 'ticket.html': # Disable any direct bounty input filter = Transformer('.//input[@id="field-bounty"]') stream |= filter.attr("disabled", "disabled") ticket = data.get('ticket') if ticket and ticket.exists: identifier = ticket.id user = req.authname if req.authname != 'anonymous' else None request = self.call_api('GET', '/issue/%s' % identifier) fragment = tag() sponsorships = {} status = self.convert_status(ticket.values['status']) owner = ticket.values['owner'] tooltip = None if request != None and (request.status_code == 200 or request.status_code == 404): sponsorships = self.get_sponsorships(identifier) pledged_amount = sum_amounts(sponsorships.values()) user_sponsorship = sponsorships.get(user, Sponsorship()) # Bounty tooltip = u"Pledged: %d\u20ac" % pledged_amount if status == 'STARTED' or status == 'COMPLETED': confirmed_amount = sum_amounts(sponsorships.values(), ('CONFIRMED', 'VALIDATED', 'REJECTED', 'TRANSFERRED', 'REFUNDED')) tooltip += u" \nConfirmed: %d\u20ac" % confirmed_amount if status == 'COMPLETED': validated_amount = sum_amounts(sponsorships.values(), 'VALIDATED') tooltip += u" \nValidated: %d\u20ac" % validated_amount # Action action = None if (((status == 'STARTED' or status == 'COMPLETED') and user_sponsorship.status == 'PLEDGED') or (status == 'STARTED' and user != None and user != owner and user_sponsorship.status == None)): response = self.call_api('GET', '/config/payment_gateways') gateways = response.json().get('gateways') gateway_tags = [] if 'DUMMY' in gateways: gateway_tags.append(tag.input(type="submit", value="Payment Card", name='DUMMY')) if 'PAYPAL_STANDARD' in gateways: gateway_tags.append(tag.input(type="submit", value="PayPal", name='PAYPAL_STANDARD')) if 'PAYPAL_ADAPTIVE' in gateways: gateway_tags.append(tag.input(type="submit", value="PayPal", name='PAYPAL_ADAPTIVE')) if user_sponsorship.status == 'PLEDGED': action = tag.form( tag.input(type="button", name="confirm", value=u"Confirm %d\u20ac" % user_sponsorship.amount, id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "confirm")) else: #TODO: should be separate action action = tag.form( tag.input(name="amount", type="text", size="3", value="0", pattern="[0-9]*", title="money amount"), tag.input(type="button", value="Pledge & Confirm", id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), method="post", action=req.href.ticket(identifier, "confirm")) elif status == 'COMPLETED' and user_sponsorship.status in ('CONFIRMED', 'REJECTED', 'VALIDATED'): action = tag.form(method="post", action=req.href.ticket(identifier, "validate")) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'REJECTED': action.append(tag.input(type="submit", name='validate', value=u"Validate %d\u20ac" % user_sponsorship.amount)) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'VALIDATED': action.append(tag.input(type="submit", name='reject', value="Reject")) elif (status == 'READY' and user != None): if user_sponsorship.status == None: action = tag.form(tag.input(name="amount", type="text", size="3", value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", value="Pledge"), method="post", action=req.href.ticket(identifier, "sponsor")) elif user_sponsorship.status == 'PLEDGED': action = tag.form(tag.input(name="amount", type="text", size=3, value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", name="update", value="Update"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "update_sponsorship")) elif (user == None): action = tag.span(u"\u00A0", tag.a("Login", href=req.href.login()), " or ", tag.a("Register", href=req.href.register()), " to sponsor") if action != None: fragment.append(" ") fragment.append(action) else: error = "Connection error" if request: error = request.json().get("error", "Unknown error") fragment.append(tag.span("[BountyFunding Error]", title=error)) #chrome = Chrome(self.env) #chrome.add_jquery_ui(req) add_stylesheet(req, 'htdocs/styles/bountyfunding.css') add_script(req, 'htdocs/scripts/bountyfunding.js') if tooltip != None: filter = Transformer('.//td[@headers="h_bounty"]/text()') stream |= filter.wrap(tag.span(title=tooltip)) filter = Transformer('.//td[@headers="h_bounty"]') stream |= filter.attr("class", "bountyfunding") stream |= filter.append(fragment) return stream
def filter_stream(self, req, method, filename, stream, data): field_name = self._get_field_name(req.args) if 'TICKET_ADMIN' in req.perm and field_name and \ req.path_info.startswith('/admin/ticket'): if field_name in self._non_abstract_enums: field_objects = data.get(field_name + 's') else: field_objects = data.get('enums') default_ccs = DefaultCC.select(self.env, field_name) if field_objects: # list of field objects stream = stream | Transformer( '//table[@class="listing"]/thead/tr').append( tag.th('CC')) if field_name == 'component': transformer = Transformer('//table[@id="complist"]/tbody') default_comp = self.config.get( 'ticket', 'default_component') for idx, field_object in enumerate(field_objects): # Milestone object can be a tuple :/ try: field_object_name = field_object.name except AttributeError: field_object_name = field_object[0].name if field_object_name in default_ccs: default_cc = default_ccs[field_object_name] else: default_cc = '' # Annoyingly, we can't just append to the row if the # collection is components, it appears to blat it for # rendering later so you end up with no rows # This may be due to the collection being a generator, # but then again, who knows? if field_name == 'component': if default_comp == field_object_name: default_tag = tag.input( type='radio', name='default', value=field_object_name, checked='checked') else: default_tag = tag.input( type='radio', name='default', value=field_object_name) transformer = transformer.append( tag.tr( tag.td( tag.input(type='checkbox', name='sel', value=field_object_name), class_='sel'), tag.td( tag.a(field_object_name, href=req.href.admin( 'ticket', 'components') + '/' + \ field_object_name), class_='name'), tag.td(field_object.owner, class_='owner'), tag.td(default_tag, class_='default'), tag.td(default_cc, class_='defaultcc') ) ) else: stream = stream | Transformer( '//table[@class="listing"]/tbody/tr[%s]' % (idx+1,) ).append(tag.td(default_cc, class_='defaultcc')) if field_name == 'component': return stream | transformer else: # edit field object if field_name in self._non_abstract_enums: field_object = data.get(field_name) else: field_object = data.get('enum') if field_object: # Milestone object can be a tuple :/ try: field_object_name = field_object.name except AttributeError: field_object_name = field_object[0] if field_object_name in default_ccs: default_cc = default_ccs[field_object_name] else: default_cc = '' transformer = Transformer( '//form[@class="mod"]/fieldset/div[@class="buttons"]') transformer = transformer.before( tag.div(tag.label("Default CC:"), tag.br(), tag.input(type="text", name="defaultcc", value=default_cc), class_="field") ).before(tag.input(type='hidden', name='old_name', value=field_object_name)) return stream | transformer return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'timeline.html': # Insert the new field for entering user names filter = Transformer('//form[@id="prefs"]/fieldset') return stream | filter.before(tag.br()) | filter.before(tag.label("Filter Components (none for all): ")) | filter.before(tag.br()) | filter.before(self._components_field_input(req)) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == 'changeset.html': changeset = data.get('changeset') filter = Transformer('//dd[@class="message searchable"]') return stream | filter.after(self._review_attrs(req,changeset)) return stream
def filter_stream(self, req, method, filename, stream, data): if filename == "timeline.html": # Insert the new field for entering user names filter = Transformer('//form[@id="prefs"]/fieldset') return stream | filter.before(self._user_field_input(req)) return stream