예제 #1
0
 def render_registration_fields(self, req, data):
     """Add an email address text input field to the registration form."""
     # Preserve last input for editing on failure instead of typing
     # everything again.
     old_value = req.args.get('email', '').strip()
     insert = tag.label(_("Email:"),
                        tag.input(type='text', name='email', size=20,
                                  class_='textwidget', value=old_value)
              )
     # Deferred import required to aviod circular import dependencies.
     from acct_mgr.web_ui import AccountModule
     reset_password = AccountModule(self.env).reset_password_enabled
     verify_account = is_enabled(self.env, EmailVerificationModule) and \
                      EmailVerificationModule(self.env).verify_email
     if verify_account:
         # TRANSLATOR: Registration form hints for a mandatory input field.
         hint = tag.p(_("""The email address is required for Trac to send
                        you a verification token."""), class_='hint')
         if reset_password:
             hint = tag(hint, tag.p(_(
                        """Entering your email address will also enable you
                        to reset your password if you ever forget it."""),
                        class_='hint')
                    )
         return tag(insert, hint), data
     elif reset_password:
         # TRANSLATOR: Registration form hint, if email input is optional.
         hint = tag.p(_("""Entering your email address will enable you to
                        reset your password if you ever forget it."""),
                      class_='hint')
         return dict(optional=tag(insert, hint)), data
     else:
         # Always return the email text input itself as optional field.
         return dict(optional=insert), data
예제 #2
0
    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.
        """

        #self.env.log.info(filename)
        add_captcha = False
        if data['authname'] == 'anonymous':
            if self.is_banned(req):
                self.env.log.debug("%s %s %s%s: IP banned as spammer" % (req.remote_addr, req.remote_user, req.base_path, req.path_info))
                stream = tag.label("System offline.")
                return stream
                
            href = req.path_info
            self.env.log.debug(href)
            self.env.log.debug(filename)
            if filename == "ticket.html":
                if "newticket" in href:
                    add_captcha = 'TICKET_CREATE' in req.perm
                elif "ticket" in href:
                    add_captcha = 'TICKET_MODIFY' in req.perm or 'TICKET_APPEND' in req.perm
            elif filename == "wiki_edit.html":
                add_captcha = 'WIKI_MODIFY' in req.perm
        
        if add_captcha:
            # Insert the math question right before the submit buttons
            stream = stream | Transformer('//div[@class="buttons"]').before(self.get_content(req))
        return stream
예제 #3
0
 def _process_edit(self, req, stream, method, tags):
     stage = 1                     
     elm = tag.div([tag.label('Tag under: (', 
                              tag.a('view all tags', href=req.href.tags()),
                              ')', 
                              for_='tags'), 
                    tag.br(), 
                    tag.input(title='Comma separated list of tags',
                              type='text',
                              id='tags',
                              size='30',
                              name='tags',
                              value=', '.join(tags)
                             ),
                   ], class_='field')
     for kind, data, pos in stream:            
         yield kind, data, pos
         if stage == 1 and \
            kind is START and \
            data[0].localname == 'input' and \
            data[1].get('id') == 'comment':
             stage = 2
         elif stage == 2 and \
              kind is END and \
              data.localname == 'div':
             for e in elm.generate():
                 yield e
             stage = None
예제 #4
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename.startswith("roadmap"):
            filter_projects = smp_filter_settings(req, 'roadmap', 'projects')
            filter = Transformer('//form[@id="prefs"]/fieldset/div[1]')
            stream = stream | filter.before(tag.label("Filter Projects:")) | filter.before(tag.br()) | filter.before(self._projects_field_input(req, filter_projects)) | filter.before(tag.br())

        return stream
예제 #5
0
    def render_registration_fields(self, req, data):
        """Add a hidden text input field to the registration form, and
        a visible one with mandatory input as well, if token is configured.
        """
        if self.reg_basic_token:
            # Preserve last input for editing on failure instead of typing
            # everything again.
            old_value = req.args.get('basic_token', '')

            # TRANSLATOR: Hint for visible bot trap registration input field.
            hint = tag.p(Markup(_(
                """Please type [%(token)s] as verification token,
                exactly replicating everything within the braces.""",
                token=tag.b(self.reg_basic_token))), class_='hint')
            insert = tag(
                tag.label(_("Parole:"),
                          tag.input(type='text', name='basic_token', size=20,
                                    class_='textwidget', value=old_value)),
                          hint
                )
        else:
            insert = None
        # TRANSLATOR: Registration form hint for hidden bot trap input field.
        insert = tag(insert,
                     tag.input(type='hidden', name='sentinel',
                               title=_("Better do not fill this field."))
                 )
        return insert, data
예제 #6
0
    def render_registration_fields(self, req, data):
        """Add a hidden text input field to the registration form, and
        a visible one with mandatory input as well, if token is configured.
        """
        if self.reg_basic_token:
            # Preserve last input for editing on failure instead of typing
            # everything again.
            old_value = req.args.get('basic_token', '')

            # TRANSLATOR: Hint for visible bot trap registration input field.
            hint = tag.p(Markup(_(
                """Apologies for the inconvenience, but please use the Sugarlabs Wiki,
                find the page referring to find the gold in the pot, and insert here
                the four words on the second line, or send mail to systems mailing list.""",
                token=tag.b(self.reg_basic_token))), class_='hint')
            insert = tag(
                tag.label(_("Parole:"),
                          tag.input(type='text', name='basic_token', size=20,
                                    class_='textwidget', value=old_value)),
                          hint
                )
        else:
            insert = None
        # TRANSLATOR: Registration form hint for hidden bot trap input field.
        insert = tag(insert,
                     tag.input(type='hidden', name='sentinel',
                               title=_("Better do not fill this field."))
                 )
        return insert, data
예제 #7
0
    def filter_stream(self, req, method, filename, stream, data):
        """
        Returns changed stream for `prefs_general.html` template with notification
        opt-out preference option.

        `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.
        """

        if filename == 'prefs_general.html' and req.authname != 'anonymous':
            stream |= Transformer('.//table').append(
                tag.tr(
                    tag.th(
                        tag.label('Ticket notifications opt-out:', **{'for': 'ticket-notification-optout'}),
                    ),
                    tag.td(
                        tag.input(type="hidden", name="ticket-notification-optout_cb", value=""),
                        tag.input(type="checkbox", id="ticket-notification-optout", name="ticket-notification-optout", checked=req.session.get('ticket-notification-optout') or None),
                    ),
                    **{'class': 'field'}
                ),
            )
        return stream
예제 #8
0
    def filter_stream(self, req, method, filename, stream, data):
        # check preconditions
        if filename != 'ticket.html':
            return stream
        transformer = Transformer()
        # build 'Hide these fields' Area
        hide_names = req.session.get('hidefieldchanges', [])
        hide_fields = []
        for field in data['fields']:
            name = field['name']
            checkbox = name in hide_names \
                and tag.input(type='checkbox', checked=True, name=name) \
                or tag.input(type='checkbox', name=name)
            hide_fields.append(tag.label(checkbox, field['label']))
            hide_fields.append(tag.br)
        hide_fields.append(tag.input(name='submit', type='submit', value='Hide these fields'))
        transformer = transformer \
            .select('//div[@id="changelog"]') \
            .before(tag.form(tag.input(value='hide changes', id='hidechangesbutton', type='button', style_='float: right;'),
                             tag.div(hide_fields, style='display: none', id='hidefields'),
                             action='#', class_='inlinebuttons hidechanges')).end()
        # build 'show all changes' button
#        showallbutton = tag.input(value='show all', name='showall', class_='showallbutton', type='submit', style_='float: right;')
#        showallbutton = tag.form(showallbutton, action='#', method='get', class_='inlinebuttons hidechanges')
#        transformer = transformer.select('//div[@id="changelog"]').before(showallbutton).end()
        # build 'hide customfield' buttons
        hidebutton = tag.input(value='hide', name="hide", class_='hidebutton', style_='display: none', type='submit')
        hidebutton = tag.form(hidebutton, action='#', method='get', class_='inlinebuttons hidefieldchanges')
        transformer = transformer \
            .select('//div[@id="changelog"]/div[@class="change"]/ul[@class="changes"]/li') \
            .prepend(hidebutton).end()
        # return filtered stream
        return stream | transformer
    def render_ticket_action_control(self, req, ticket, action):
        config = self.parse_config()
        assert action in config

        control = []
        hints = []

        data = config[action]
        
        action_name = action # @@TODO: config'able label/name

        chrome = Chrome(self.env)

        from trac.ticket.web_ui import TicketModule
        prepared_fields = TicketModule(self.env)._prepare_fields(req, ticket)

        for field in data.get('fields', []):
            id = "action_%s_%s" % (action, field)

            operation = data.get('operations', {}).get(field, "change")
            assert operation in ["change", "unset"]
            if operation == "unset":
                hints.append("%s will be unset" % field) # @@TODO: i18n
                continue
            assert operation == "change"
            current_value = ticket._old.get(field, ticket[field]) or ""

            rendered_control = ''
            prepared_field = [pfield for pfield in prepared_fields 
                              if pfield['name'] == field]
            if len(prepared_field):
                prepared_field = prepared_field[0]

                # we can't use chrome.render_template here, or it will blow away
                # key scripts like jquery.js and trac.js in the eventual 'primary' template
                # that's rendered by process_request
                template = chrome.load_template("ticket_fields.html", method="xhtml")
                rendered_control = template.generate(ticket=ticket, field=prepared_field)
                if rendered_control:
                    rendered_control = Markup(rendered_control)
            control.append(tag.label(field,
                                     rendered_control or tag.input(
                        name=id, id=id,
                        type='text', value=current_value)))

        current_status = ticket._old.get('status', ticket['status'])
        new_status = data['status'].get(current_status) or \
            data['status']['*']

        if new_status != '*':
            hints.append("Next status will be %s" % new_status) # @@TODO: i18n

        add_script(req, "workflow_ticketfields/workflow_ticketfields.js")
        return (action_name, tag.div(*[tag.div(element, style=("display: inline-block; "
                                                               "margin-right: 1em"))
                                       for element in control],
                                      class_="workflow_ticket_fields",
                                      style="margin-left: 2em; display: none"), 
                '. '.join(hints) + '.' if hints else '')
예제 #10
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename == 'timeline.html':
            filter_projects = self._filtered_projects(req) 

            filter = Transformer('//form[@id="prefs"]/div[1]')
            stream = stream | filter.before(tag.label("Filter Projects:")) | filter.before(tag.br()) | filter.before(self._projects_field_input(req, filter_projects)) | filter.before(tag.br()) | filter.before(tag.br())

        return stream
예제 #11
0
def prepend_ctxtnav(req, elm_or_label, href):
    """Prepend an entry to the current page's ctxtnav bar.
    
    add_ctxtnav(), sadly, always appends to the right side of the (right-aligned by default) context nav, changing the onscreen locations of the links people are already used to.
    """
    elm = tag(tag.label(elm_or_label, for_='rev'), ' ',
              tag.input(type='text', id='rev', readonly='readonly',
                        value=href, size=len(href)))
    req.chrome.setdefault('ctxtnav', []).insert(0, elm)
예제 #12
0
 def _build_renamechildren_field(self):
     return tag.div(tag.label(
         tag.input(_("Also rename children"), \
                     type='checkbox',
                     id='rename_children', \
                     name='rename_children',
                     checked='checked') \
                     ), \
                    class_='field')
예제 #13
0
 def _wiki_edit(self, req, stream):
     insert = tag.div(class_='field')(
         tag.label(
             'Tag under: (', tag.a('view all tags', href=req.href.tags()), ')',
             tag.br(),
             tag.input(id='tags', type='text', name='tags', size='30',
                       value=req.args.get('tags', ' '.join(self._page_tags(req)))),
             )
         )
     return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
예제 #14
0
 def _filterBox(self, req, label, name):
     return tag.label(
         label,
         tag.input(
             type="text",
             name=name,
             value=self._session(req, name, ""),
             style_="width:60%",
             title=_("available prefixes: contains: ~, starts with: ^, ends with: $"),
         ),
     )
예제 #15
0
 def _toggleBox(self, req, label, name, default):
     if self._session(req, name, default) == 'true':
         checkbox= tag.input(type= 'checkbox',
                             name= name,
                             value='true',
                             checked='checked')
     else:
         checkbox= tag.input(type= 'checkbox',
                             name= name,
                             value= 'true')
     return checkbox + ' ' + tag.label(label, for_= name)
예제 #16
0
 def _wiki_edit(self, req, stream):
     # TRANSLATOR: Label text for link to '/tags'.
     link = tag.a(_("view all tags"), href=req.href.tags())
     # TRANSLATOR: ... (view all tags)
     insert = tag(Markup(_("Tag under: (%(tags_link)s)", tags_link=link)))
     insert(
         tag.br(),
         tag.input(id='tags', type='text', name='tags', size='50',
             value=req.args.get('tags', ' '.join(self._page_tags(req))))
     )
     insert = tag.div(tag.label(insert), class_='field')
     return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
예제 #17
0
    def filter_stream(self, req, method, filename, stream, data):
        if req.path_info.startswith('/register') and (
            req.method == 'GET' or
            'registration_error' in data):
            question = None
            if self.question is not None and len(self.question)>0:
                question = tag.label(
                    tag(self.question + " "),
                    tag.input(id='question', type='text', name='question')
                    )
            # First Fieldset of the registration form XPath match
            xpath_match = '//form[@id="acctmgr_registerform"]/fieldset[1]'
            if question is None:
                return stream
            else:
                return stream | Transformer(xpath_match). \
                    append(tag(Markup(question)))
        # Admin Configuration
        elif req.path_info.startswith('/admin/accounts/config'):
            api_html = tag.div(
                tag.label("Question:", for_="registerquestion_question") +
                tag.input(class_="textwidget", name="question",
                          value=self.question, size=60)
            ) + tag.div(
                tag.label("Answer:", for_="registerquestion_answer") +
                tag.input(class_="textwidget", name="answer",
                          value=self.answer, size=60)
            ) + tag.div(
                tag.label("Hint:", for_="registerquestion_hint") +
                tag.input(class_="textwidget", name="hint",
                          value=self.hint, size=60)
            ) + tag.br()


            # First fieldset of the Account Manager config form
            xpath_match = '//form[@id="accountsconfig"]/fieldset[1]'

            return stream | Transformer(xpath_match). \
                before(tag.fieldset(tag.legend("Anti-Robot Question For Registration") + api_html))
        return stream
예제 #18
0
 def _user_field_input(self, req):
     return tag.div(
         tag.label(
             "Include users: ",
             tag.input(
                 type="text",
                 name="inc_users",
                 value=req.session.get("timeline.filter.inc_users", ""),
                 style_="width:60%",
             ),
         )
         + tag.br()
         + tag.label(
             "Exclude users: ",
             tag.input(
                 type="text",
                 name="exc_users",
                 value=req.session.get("timeline.filter.exc_users", ""),
                 style_="width:60%",
             ),
         )
     )
예제 #19
0
    def __new_project(self):
        all_projects = self.__SmpModel.get_all_projects()

        return tag.div(
                       tag.label(
                       'Project:',
                       tag.br(),
                       tag.select(
                       tag.option(),
                       [tag.option(row[1], value=row[0]) for row in sorted(all_projects, key=itemgetter(1))],
                       name="project")
                       ),
                       class_="field")
예제 #20
0
def _create_select(label_text, id, name, options, selected_name=None, default_selection=None):
    select = tag.select(id=id, name=name)
    if selected_name is None and default_selection is not None:
        selected_name = default_selection
    for option_name in options:
        if option_name == selected_name:
            select.append(tag.option(option_name, value=option_name, selected='selected'))
        else:
            select.append(tag.option(option_name, value=option_name))
    insert = tag(label_text)
    insert(
        tag.br(), select
    )
    insert = tag.div(tag.label(insert), class_='field')
    return insert
예제 #21
0
 def filter_stream(self, req, method, filename, stream, data):
     if 'ticket' in data and 'remote_sites' in data:
         add_script(req, 'tracremoteticket/js/remoteticket.js')
         
         transf = Transformer('//select[@id="linked-end"]')
         label = tag.label(' in ', for_='remote-site')
         local = tag.option('this project', value=req.href.newticket(),
                            selected='selected')
         remotes = [tag.option(rs['title'], 
                               value=Href(rs['url']).newticket())
                    for rs in data['remote_sites']]
         select = tag.select([local] + remotes, id='remote-site')
         content = label + select
         stream |= transf.after(content)
         
     return stream
예제 #22
0
 def filter_stream(self, req, method, filename, stream, data):
     if filename == "customfieldadmin.html":
         add_script(req, "datefield/js/customfield-admin.js")
         add_stylesheet(req, "datefield/css/customfield-admin.css")
         stream = stream | Transformer('.//select[@id="type"]').append(
             tag.option("Date", value="date", id="date_type_option")
         )
         stream = stream | Transformer('.//form[@id="addcf"]/fieldset/div[@class="buttons"]').before(
             tag.div(
                 tag.input(id="date_empty", type="checkbox", name="date_empty"),
                 tag.label("Allow empty date"),
                 for_="date_empty",
                 class_="field",
                 id="date_empty_option",
             )
         )
     return stream
예제 #23
0
    def __edit_project(self, data):
        component = data.get('component').name
        all_projects = self.__SmpModel.get_all_projects()
        id_project_component = self.__SmpModel.get_id_projects_component(component)
        id_projects_selected = []

        for id_project in id_project_component:
            id_projects_selected.append(id_project[0])

        return tag.div(
                       tag.label(
                       'Available in Project(s):',
                       tag.br(),
                       tag.select(
                       tag.option("All", value="0"),
                       [tag.option(row[1], selected=(row[0] in id_projects_selected or None), value=row[0]) for row in sorted(all_projects, key=itemgetter(1))],
                       name="project", multiple="multiple", size="10")
                       ),
                       class_="field")
예제 #24
0
    def __edit_project(self, data):
        milestone = data.get('milestone').name
        all_projects = self.__SmpModel.get_all_projects()
        id_project_milestone = self.__SmpModel.get_id_project_milestone(milestone)

        if id_project_milestone != None:
            id_project_selected = id_project_milestone[0]
        else:
            id_project_selected = None

        return tag.div(
                       tag.label(
                       'Project:',
                       tag.br(),
                       tag.select(
                       tag.option(),
                       [tag.option(row[1], selected=(id_project_selected == row[0] or None), value=row[0]) for row in sorted(all_projects, key=itemgetter(1))],
                       name="project")
                       ),
                       class_="field")
예제 #25
0
    def _version_edit(self, data):
        milestone = data.get('milestone').name
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT version FROM milestone_version WHERE milestone=%s", (milestone,))
        row = cursor.fetchone()
        value = row and row[0]

        cursor.execute("SELECT name FROM version WHERE time IS NULL OR time = 0 OR time>%s "
                       "OR name = %s ORDER BY name",
                       (to_timestamp(None), value))

        return tag.div(
            tag.label(
                'Version:',
                tag.br(),
                tag.select(
                    tag.option(),
                    [tag.option(row[0], selected=(value == row[0] or None)) for row in cursor],
                    name="version")),
            class_="field")
예제 #26
0
    def _version_edit(self, data):
        milestone = data.get('milestone').name
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "SELECT version FROM milestone_version WHERE milestone=%s",
            (milestone, ))
        row = cursor.fetchone()
        value = row and row[0]

        cursor.execute(
            "SELECT name FROM version WHERE time IS NULL OR time = 0 OR time>%s "
            "OR name = %s ORDER BY name", (to_timestamp(None), value))

        return tag.div(tag.label(
            'Version:', tag.br(),
            tag.select(tag.option(), [
                tag.option(row[0], selected=(value == row[0] or None))
                for row in cursor
            ],
                       name="version")),
                       class_="field")
예제 #27
0
 def get_content(self, req):
     """Returns the Genshi tags for the new HTML elements representing the
     Captcha.
     """
     values = {}
     values['ip'] = req.remote_addr
     values['submitted'] = int(time.time())
     math_problem_text = self.create_math_problem(values)
     values['author'] = req.args.get('author')
     values['summary'] = req.args.get('field_summary')
     values['text'] = self.get_failed_attempt_text(req)
     values['href'] = req.path_info
     
     # Save the problem so that the post request of the web server knows
     # which request to process.  This is required on FCGI and mod_python
     # web servers, because there may be many different processes handling
     # the request and there's no guarantee that the same web server will
     # handle both the form display and the form submit.
     db = self.env.get_db_cnx()
     cursor = db.cursor()
     fields = values.keys()
     cursor.execute("INSERT INTO mathcaptcha_history (%s) VALUES (%s)"
                    % (','.join(fields),
                       ','.join(['%s'] * len(fields))),
                    [values[name] for name in fields])
     id = db.get_last_id(cursor, 'mathcaptcha_history')
     db.commit()
     self.env.log.debug("%s %s %s%s: generating math solution: id=%d, %d %s %d = %d" % (req.remote_addr, req.remote_user, req.base_path, req.path_info, id, values['left_operand'], values['operator'], values['right_operand'], values['solution']))
     
     # Obfuscating the names of the input variables to trick spam harvesters
     # to put other data in the solutions field.  The math solution is
     # named "email" in the hopes that it will attract email addresses
     # instead of numbers.  The database key is named "url" to try to
     # attract non-numbers
     content = tag.div()(
         tag.label('Anonymous users are allowed to post by %s ' % math_problem_text) + tag.input(type='text', name='email', class_='textwidget', size='5') + tag.input(type='hidden', name='url', value=str(id + self.id_offset))
         )
     return content
예제 #28
0
    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.
        """

        #self.env.log.info(filename)
        add_captcha = False
        if data['authname'] == 'anonymous':
            if self.is_banned(req):
                self.env.log.debug("%s %s %s%s: IP banned as spammer" %
                                   (req.remote_addr, req.remote_user,
                                    req.base_path, req.path_info))
                stream = tag.label("System offline.")
                return stream

            href = req.path_info
            self.env.log.debug(href)
            self.env.log.debug(filename)
            if filename == "ticket.html":
                if "newticket" in href:
                    add_captcha = 'TICKET_CREATE' in req.perm
                elif "ticket" in href:
                    add_captcha = 'TICKET_MODIFY' in req.perm or 'TICKET_APPEND' in req.perm
            elif filename == "wiki_edit.html":
                add_captcha = 'WIKI_MODIFY' in req.perm

        if add_captcha:
            # Insert the math question right before the submit buttons
            stream = stream | Transformer('//div[@class="buttons"]').before(
                self.get_content(req))
        return stream
예제 #29
0
 def render_registration_fields(self, req, data):
     """Add an email address text input field to the registration form."""
     # Preserve last input for editing on failure instead of typing
     # everything again.
     old_value = req.args.get('email', '').strip()
     insert = tag.label(
         _("Email:"),
         tag.input(type='text',
                   name='email',
                   size=20,
                   class_='textwidget',
                   value=old_value))
     # Deferred import required to aviod circular import dependencies.
     from acct_mgr.web_ui import AccountModule
     reset_password = AccountModule(self.env).reset_password_enabled
     verify_account = is_enabled(self.env, EmailVerificationModule) and \
                      AccountManager(self.env).verify_email
     if verify_account:
         # TRANSLATOR: Registration form hints for a mandatory input field.
         hint = tag.p(_("""The email address is required for Trac to send
                        you a verification token."""),
                      class_='hint')
         if reset_password:
             hint = tag(
                 hint,
                 tag.p(_("""Entering your email address will also enable you
                        to reset your password if you ever forget it."""),
                       class_='hint'))
         return tag(insert, hint), data
     elif reset_password:
         # TRANSLATOR: Registration form hint, if email input is optional.
         hint = tag.p(_("""Entering your email address will enable you to
                        reset your password if you ever forget it."""),
                      class_='hint')
         return dict(optional=tag(insert, hint)), data
     else:
         # Always return the email text input itself as optional field.
         return dict(optional=insert), data
예제 #30
0
 def filter_stream(self, req, method, filename, stream, data):
     if filename == "customfieldadmin.html":
         add_script(req, 'datefield/js/customfield-admin.js')
         add_stylesheet(req, 'datefield/css/customfield-admin.css')
         stream = stream | Transformer('.//select[@id="type"]').append(
             tag.option('Date', value='date', id="date_type_option")
         )
         stream = stream | Transformer(
             './/form[@id="addcf"]/fieldset/div[@class="buttons"]'
         ).before(
             tag.div(
                 tag.input(
                     id="date_empty", 
                     type="checkbox", 
                     name="date_empty"
                 ), 
                 tag.label('Allow empty date'), 
                 for_="date_empty", 
                 class_="field",
                 id="date_empty_option"
             )
         )
     return stream
예제 #31
0
    def _contruct_tickets_table(self, req, ticket, childtickets, priorities):
        # trac.ini : Which columns to display in child ticket listing?
        columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner'])

        tablediv = tag.div()
        tablediv.append(tag.label(tag.input(type="checkbox", id="cb_show_closed"),
                                  "show closed tickets"))

        for tkt_types, type_tickets in groupby(childtickets, lambda t: t['type']):
            tablediv.append(tag.h2("Type: %s" % tkt_types, class_="report-result"))
            tablediv.append(
                    tag.table(
                        tag.thead(
                            tag.tr(
                                tag.th("Ticket",class_="id"),
                                [ tag.th(s.title(),class_=s) for s in columns ])
                            ),
                        tag.tbody([ self._table_row(req,tkt,columns,priorities) for tkt in type_tickets]),
                        class_="listing tickets",
                        )
                    )

        return tablediv
예제 #32
0
 def _toggleBox(self, req, label, name, default):
     if self._session(req, name, default) == "true":
         checkbox = tag.input(type="checkbox", name=name, value="true", checked="checked")
     else:
         checkbox = tag.input(type="checkbox", name=name, value="true")
     return checkbox + " " + tag.label(label, for_=name)
예제 #33
0
 def _filterBox(self, req, label, name):
     return tag.label(label,
                      tag.input(type= "text",
                                name= name,
                                value= self._session(req, name, ''),
                                style_= "width:60%"))
예제 #34
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename not in ('ticket.html', 'ticket.rss'):
            return stream

        ticket_id = req.args.get('id')
        if not ticket_id:
            return stream

        # determine the username of the current user
        user = req.authname

        # determine if the user has the permission to see private comments
        perms = PermissionSystem(self.env)
        has_private_permission = \
            self.private_comment_permission in perms.get_user_permissions(user)

        # Remove private comments from Ticket Page
        if filename == 'ticket.html':
            buf = StreamBuffer()

            def check_comments():
                delimiter = '<div xmlns="http://www.w3.org/1999/xhtml" ' + \
                            'class="change" id="trac-change-'

                comment_stream = str(buf)
                # split the comment_stream to get single comments
                comments_raw = comment_stream.split(delimiter)
                comment_stream = ''

                for comment in comments_raw:
                    if comment is None or len(comment) < 1:
                        continue

                    # determine comment id
                    find = comment.find('">')
                    if find == -1:
                        continue
                    comment_id = comment[:find]

                    # concat the delimiter and the comment again
                    comment_code = delimiter + comment

                    # if the user has the permission to see the comment
                    # the comment_code will be appended to the comment_stream
                    comment_private = self._is_comment_private(
                        ticket_id, comment_id)

                    if comment_private:
                        comment_code = comment_code.replace(
                            '<span class="threading">',
                            '<span class="threading"> <span class="%s">'
                            'this comment is private</span>' %
                            str(self.css_class_private_comment_marker))

                    if has_private_permission or not comment_private:
                        comment_stream += comment_code

                return HTML(comment_stream)

            # filter all comments
            stream |= Transformer('//div[@class="change" and @id]') \
                .copy(buf).replace(check_comments)

            # if the user has the private comment permission the checkboxes
            # to change the private value will be added
            if has_private_permission:
                comment_box = tag.label(
                    _("Private Comment:"),
                    tag.input(type='checkbox', name='private_comment'))
                stream |= Transformer('//h2[@id="trac-add-comment"]') \
                    .after(comment_box)
                # Trac 1.0 and later:
                # stream |= Transformer(
                #   '//div[@id="trac-add-comment"]//fieldset').prepend(input)

        # Remove private comments from ticket RSS feed
        if filename == 'ticket.rss':
            comments = self._get_all_private_comments(ticket_id)

            self.log.debug("Private Comments for Ticket %d: %s" %
                           (ticket_id, comments))

            for comment_id in comments:
                stream |= Transformer('//item[%d]' % comment_id).remove()

        return stream
예제 #35
0
    def filter_stream(self, req, method, filename, stream, data):
        if filename == "ticket.html":
            ##Check Permissions
            enchants = self.config.get('blackmagic', 'tweaks', '')
            for field in (x.strip() for x in enchants.split(',')):
                self.env.log.debug("Checking %s:" % field)
                disabled = False
                hidden = False
                #Get a list of the permissions from the config, split them on commas and remove spaces
                perms = self.config.get('blackmagic', '%s.permission' % field, '').upper()
                #Default to not having permissions
                hasPerm = True
                if perms:
                    hasPerm = False
                    #If there are permissions
                    self.env.log.debug("perm: %s" % len(perms))
                    perms = perms.split(',')
                    #walk the list we got back and check the request for the permission
                    for perm in perms:
                        perm = perm.strip()
                        self.env.log.debug("Checking perm: %s" % perm)
                        if perm in req.perm:
                            self.env.log.debug("User has perm: %s" % perm)
                            hasPerm = True
                    if hasPerm == False:
                        denial = self.config.get('blackmagic', '%s.ondenial' % field, None)
                        if denial:
                            if denial == "disable":
                                disabled = True
                            elif denial == "hide":
                                hidden = True
                            else:
                                disabled = True
                        else:
                            disabled = True

                self.env.log.debug('hasPerm: %s' % hasPerm)
                if hidden == False:
                    if self.config.get('blackmagic', '%s.label' % field, None):
                        labelTXT = self.config.get('blackmagic', '%s.label' % field)
                        label = tag.label("%s:" %labelTXT, for_="field-%s" % field)
                        stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(label)

                if hasPerm == False:   
                    if istrue(self.config.get('blackmagic', '%s.hide' % field, None)):
                        hidden = True
                        
                    if disabled or istrue(self.config.get('blackmagic', '%s.disable' % field, False)):
                        stream = stream | Transformer('//*[@id="field-%s"]' % field).attr("disabled", "disabled")
                        label = self.config.get('blackmagic', '%s.label' % field)
                        if not label:
                            label = field.capitalize()
                        if not self.gray_disabled:
                            stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(
                                tag.strike()('%s:' % label)
                            )
                        else:
                            stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(
                                tag.span(style="color:%s" % self.gray_disabled)('%s:' % label)
                            )
                    
                    if hidden or istrue(self.config.get('blackmagic', '%s.hide' % field, None)):
                        stream = stream | Transformer('//th[@id="h_%s"]' % field).replace(" ") 
                        stream = stream | Transformer('//td[@headers="h_%s"]' % field).replace(" ")
                        stream = stream | Transformer('//label[@for="field-%s"]' % field).replace(" ")
                        stream = stream | Transformer('//*[@id="field-%s"]' % field).replace(" ")

                    
                if hidden == False:
                    if self.config.get('blackmagic', '%s.notice' % field, None):
                        stream = stream | Transformer('//*[@id="field-%s"]' % field).after(
                            tag.br() + tag.small(class_="notice-%s" %field)(
                                tag.em()(
                                    Markup(self.config.get('blackmagic', '%s.notice' % field))
                                )
                            )
                        )
                    
                tip = self.config.get('blackmagic', '%s.tip' % field, None)
                if tip:
                    stream = stream | Transformer('//div[@id="banner"]').before(
                        tag.script(type="text/javascript", 
                        src=req.href.chrome("blackmagic", "js", "wz_tooltip.js"))()
                    )
                    
                    stream = stream | Transformer('//*[@id="field-%s"]' % field).attr(
                        "onmouseover", "Tip('%s')" % tip.replace(r"'", r"\'")
                    )
                        
                    
        return stream
예제 #36
0
    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
예제 #37
0
class AddCommentMacro(WikiMacroBase):
    """A macro to add comments to a page. Usage:
    {{{
    [[AddComment]]
    }}}
    The macro accepts one optional argument that allows appending
    to the wiki page even though user may not have modify permission:
    {{{
    [[AddComment(appendonly)]]
    }}}
    """
    implements(IWikiMacroProvider, IRequestFilter, IMacroPoster)

    def expand_macro(self, formatter, name, content):

        args, kw = parse_args(content)
        req = formatter.req
        context = formatter.context

        # Prevent multiple inclusions - store a temp in req
        if hasattr(req, 'addcommentmacro'):
            raise TracError('\'AddComment\' macro cannot be included twice.')
        req.addcommentmacro = True

        # Prevent it being used outside of wiki page context
        resource = context.resource
        if not resource.realm == 'wiki':
            raise TracError(
                '\'AddComment\' macro can only be used in Wiki pages.')

        # Setup info and defaults
        authname = req.authname
        page = WikiPage(self.env, resource)
        page_url = req.href.wiki(resource.id)
        wikipreview = req.args.get("preview", "")

        # Can this user add a comment to this page?
        appendonly = ('appendonly' in args)
        cancomment = False
        if page.readonly:
            if 'WIKI_ADMIN' in req.perm(resource):
                cancomment = True
        elif 'WIKI_MODIFY' in req.perm(resource):
            cancomment = True
        elif appendonly and 'WIKI_VIEW' in req.perm(resource):
            cancomment = True
        else:
            self.log.debug(
                'Insufficient privileges for %s to AddComment to %s',
                req.authname, resource.id)

        # Get the data from the POST
        comment = req.args.get("addcomment", "")
        preview = req.args.get("previewaddcomment", "")
        cancel = req.args.get("canceladdcomment", "")
        submit = req.args.get("submitaddcomment", "")
        if not cancel and req.authname == 'anonymous':
            authname = req.args.get("authoraddcomment", authname)

        # Ensure [[AddComment]] is not present in comment, so that infinite
        # recursion does not occur.
        comment = to_unicode(
            re.sub('(^|[^!])(\[\[AddComment)', '\\1!\\2', comment))

        the_preview = the_message = the_form = tag()

        # If we are submitting or previewing, inject comment as it should look
        if cancomment and comment and (preview or submit):
            heading = tag.h4("Comment by ",
                             authname,
                             " on ",
                             to_unicode(time.strftime('%c', time.localtime())),
                             id="commentpreview")
            if preview:
                the_preview = tag.div(heading,
                                      format_to_html(self.env, context,
                                                     comment),
                                      class_="wikipage",
                                      id="preview")

        # Check the form_token
        form_ok = True
        if submit and req.args.get('__FORM_TOKEN', '') != req.form_token:
            form_ok = False
            the_message = tag.div(tag.strong("ERROR: "),
                                  "AddComment received incorrect form token. "
                                  "Do you have cookies enabled?",
                                  class_="system-message")

        # When submitting, inject comment before macro
        if comment and submit and cancomment and form_ok:
            submitted = False
            newtext = ""
            for line in page.text.splitlines():
                if line.find('[[AddComment') == 0:
                    newtext += "==== Comment by %s on %s ====\n%s\n\n" % (
                        authname,
                        to_unicode(time.strftime('%c',
                                                 time.localtime())), comment)
                    submitted = True
                newtext += line + "\n"
            if submitted:
                page.text = newtext

                # Let the wiki page manipulators have a look at the
                # submission.
                valid = True
                req.args.setdefault('comment', 'Comment added.')
                try:
                    for manipulator in WikiModule(self.env).page_manipulators:
                        for field, message in manipulator.validate_wiki_page(
                                req, page):
                            valid = False
                            if field:
                                the_message += tag.div(tag.strong(
                                    "invalid field '%s': " % field),
                                                       message,
                                                       class_="system-message")
                            else:
                                the_message += tag.div(tag.strong("invalid: "),
                                                       message,
                                                       class_="system-message")

                # The TracSpamfilterPlugin does not generate messages,
                # but throws RejectContent.
                except TracError, s:
                    valid = False
                    the_message += tag.div(tag.strong("ERROR: "),
                                           s,
                                           class_="system-message")

                if valid:
                    page.save(authname, req.args['comment'],
                              req.environ['REMOTE_ADDR'])
                    # We can't redirect from macro as it will raise RequestDone
                    # which like other macro errors gets swallowed in the Formatter.
                    # We need to re-raise it in a post_process_request instead.
                    try:
                        self.env.log.debug(
                            "AddComment saved - redirecting to: %s" % page_url)
                        req._outheaders = []
                        req.redirect(page_url)
                    except RequestDone:
                        req.addcomment_raise = True
            else:
                the_message = tag.div(
                    tag.strong("ERROR: "), "[[AddComment]] "
                    "macro call must be the only content on its line. "
                    "Could not add comment.",
                    class_="system-message")

        the_form = tag.form(
            tag.fieldset(
                tag.legend("Add comment"),
                tag.div((wikipreview and "Page preview..." or None),
                        tag.textarea((not cancel and comment or ""),
                                     class_="wikitext",
                                     id="addcomment",
                                     name="addcomment",
                                     cols=80,
                                     rows=5,
                                     disabled=(not cancomment and "disabled"
                                               or None)),
                        class_="field"),
                (req.authname == 'anonymous' and tag.div(
                    tag.label("Your email or username:"******"authoraddcomment"),
                    tag.input(id="authoraddcomment",
                              type="text",
                              size=30,
                              value=authname,
                              name="authoraddcomment",
                              disabled=(not cancomment and "disabled"
                                        or None))) or None),
                tag.input(type="hidden",
                          name="__FORM_TOKEN",
                          value=req.form_token),
                tag.div(tag.input(value="Add comment",
                                  type="submit",
                                  name="submitaddcomment",
                                  size=30,
                                  disabled=(not cancomment and "disabled"
                                            or None)),
                        tag.input(value="Preview comment",
                                  type="submit",
                                  name="previewaddcomment",
                                  disabled=(not cancomment and "disabled"
                                            or None)),
                        tag.input(value="Cancel",
                                  type="submit",
                                  name="canceladdcomment",
                                  disabled=(not cancomment and "disabled"
                                            or None)),
                        class_="buttons"),
            ),
            method="post",
            action=page_url + "#commenting",
        )

        if not wikipreview:
            # Wiki edit preview already adds this javascript file
            add_script(req, 'common/js/wikitoolbar.js')

        return tag.div(the_preview, the_message, the_form, id="commenting")
예제 #38
0
파일: wiki.py 프로젝트: prologic/sahriswiki
def AddComment(macro, environ, data, *args, **kwargs):
    """Display an add comment form allowing users to post comments.

    This macro allows you to display an add comment form on the current
    page allowing users to post comments. The comments are added to the
    page's content itself.
    
    **Arguments:** //No Arguments//

    **Example(s):**
    {{{
    <<AddComment>>
    }}}

    <<AddComment>>
    """

    # Setup info and defaults
    parser = environ.parser
    request = environ.request

    page = data["page"]
    page_name = page["name"]
    page_text = page["text"]

    # Get the data from the POST
    comment = request.kwargs.get("comment", "")
    action = request.kwargs.get("action", "")
    author = request.kwargs.get("author", environ._user())

    # Ensure <<AddComment>> is not present in comment, so that infinite
    # recursion does not occur.
    comment = re.sub("(^|[^!])(\<\<AddComment)", "\\1!\\2", comment)

    the_preview = None
    the_comment = None

    # If we are submitting or previewing, inject comment as it should look
    if action == "preview":
        the_preview = tag.div(tag.h1("Preview"), id="preview")
        the_preview += tag.div(parser.generate(comment,
                                               environ=(environ, data)),
                               class_="article")

    # When submitting, inject comment before macro
    if comment and action == "save":
        new_text = ""
        comment_text = "\n==== Comment by %s on %s ====\n\n%s\n\n" % (
            author, time.strftime('%c', time.localtime()), comment)
        for line in page_text.split("\n"):
            if line.find("<<AddComment") == 0:
                new_text += comment_text
            new_text += line + "\n"

        search = environ.search
        storage = environ.storage

        storage.reopen()
        search.update(environ)

        storage.save_text(page_name, new_text, author,
                          "Comment added by %s" % author)

        search.update_page(environ.get_page(page_name),
                           page_name,
                           text=new_text)

        the_comment = tag.div(parser.generate(comment_text,
                                              environ=(environ, data)),
                              class_="article")

    the_form = tag.form(
        tag.input(type="hidden", name="parent", value=page["node"]),
        tag.fieldset(
            tag.legend("Add Comment"),
            tag.p(tag.textarea(
                (not action in ("cancel", "save") and comment or ""),
                id="comment",
                name="comment",
                cols=80,
                rows=5),
                  class_="text"),
            tag.h4(tag.label("Your email or username:"******"author")),
            tag.p(tag.input(id="author",
                            name="author",
                            type="text",
                            value=(not action in ("cancel", "save")) and author
                            or ""),
                  class_="input"),
            tag.p(tag.button("Preview",
                             type="submit",
                             name="action",
                             value="preview"),
                  tag.button("Save",
                             type="submit",
                             name="action",
                             value="save"),
                  tag.button("Cancel",
                             type="submit",
                             name="action",
                             value="cancel"),
                  class_="button"),
        ),
        method="post",
        action="")

    return tag(the_preview, the_comment, the_form)
예제 #39
0
    def filter_stream(self, req, method, filename, stream, data):
        if req.path_info.startswith('/register') and (
                req.method == 'GET' or 'registration_error' in data
                or 'captcha_error' in req.session):
            if not (self.private_key or self.private_key):
                return stream
            captcha_opts = tag.script("""\
var RecaptchaOptions = {
  theme: "%s",
  lang: "%s"
}""" % (self.theme, self.lang),
                                      type='text/javascript')
            captcha_js = captcha.displayhtml(
                self.public_key,
                use_ssl=req.scheme == 'https',
                error='reCAPTCHA incorrect. Please try again.')
            # First Fieldset of the registration form XPath match
            xpath_match = '//form[@id="acctmgr_registerform"]/fieldset[1]'
            return stream | Transformer(xpath_match). \
                append(captcha_opts + tag(Markup(captcha_js)))
        # Admin Configuration
        elif req.path_info.startswith('/admin/accounts/config'):
            api_html = tag.div(
                tag.label("Public Key:", for_="recaptcha_public_key") +
                tag.input(class_="textwidget",
                          name="recaptcha_public_key",
                          value=self.public_key,
                          size=40)
            ) + tag.div(
                tag.label("Private Key:", for_="recaptcha_private_key") +
                tag.input(class_="textwidget",
                          name="recaptcha_private_key",
                          value=self.private_key,
                          size=40))
            if not (self.private_key or self.public_key):
                api_html = tag.div(
                    tag.a(
                        "Generate a reCAPTCHA API key for this Trac "
                        "instance domain.",
                        target="_blank",
                        href="http://recaptcha.net/api/getkey?domain=%s&"
                        "app=TracRecaptchaRegister" %
                        req.environ.get('SERVER_NAME'))) + tag.br() + api_html

            theme_html = tag.div(
                tag.label("reCPATCHA theme:", for_='recaptcha_theme') +
                tag.select(
                    tag.option("Black Glass",
                               value="blackglass",
                               selected=self.theme == 'blackglass' or None) +
                    tag.option("Clean",
                               value="clean",
                               selected=self.theme == 'clean' or None) +
                    tag.option("Red",
                               value="red",
                               selected=self.theme == 'red' or None) +
                    tag.option("White",
                               value="white",
                               selected=self.theme == 'white' or None),
                    name='recaptcha_theme'))

            language_html = tag.div(
                tag.label("reCAPTCHA language:", for_='recaptcha_lang') +
                tag.select(tag.option(
                    "Dutch", value="nl", selected=self.lang == 'nl' or None
                ) + tag.option(
                    "English", value="en", selected=self.lang == 'en' or None
                ) + tag.option("French", selected=self.lang == 'fr' or None) +
                           tag.option("German",
                                      value="de",
                                      selected=self.lang == 'de' or None) +
                           tag.option("Portuguese",
                                      value="pt",
                                      selected=self.lang == 'pt' or None) +
                           tag.option("Russian",
                                      value="ru",
                                      selected=self.lang == 'ru' or None) +
                           tag.option("Spanish",
                                      value="es",
                                      selected=self.lang == 'es' or None) +
                           tag.option("Turkish",
                                      value="tr",
                                      selected=self.lang == 'tr' or None),
                           name='recaptcha_lang'))

            # First fieldset of the Account Manager config form
            xpath_match = '//form[@id="accountsconfig"]/fieldset[1]'

            return stream | Transformer(xpath_match). \
                before(tag.fieldset(tag.legend("reCAPTCHA") + api_html +
                                    tag.br() + theme_html + language_html))
        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