def __init__(self, view, account_management_interface, register_help_bookmark, verify_bookmark): super().__init__(view) self.add_child(P(view, text=_('You have successfully registered.'))) self.add_child( P(view, text= _('Before we can allow you to log in, however, you need to prove to us that you are indeed the owner of %s.' ) % account_management_interface.email)) p = P(view, text=_('In order to do this, an email was sent to {email} containing a secret code. '\ 'Please check your email, retrieve the code and then enter it on {verify}.')) self.add_child( p.format(verify=A.from_bookmark( view, verify_bookmark.with_description(_('the verification page'))), email=TextNode(view, account_management_interface.email))) self.add_child( P(view, text= _('Sometimes these emails arrive immediately, but they may also be delayed.' ))) last_p = P( view, text= _('If you do not receive the email within an hour or so, please follow {trouble}.' )) self.add_child( last_p.format(trouble=A.from_bookmark( view, register_help_bookmark.with_description( _('our troubleshooting procedure')))))
def test_dropdown_menus_with_divider(web_fixture): """You can add a divider to a DropdownMenu.""" sub_menu = DropdownMenu(web_fixture.view) sub_menu.add_a(A(web_fixture.view, Url('/an/url'), description='sub menu item')) sub_menu.add_divider() sub_menu.add_a(A(web_fixture.view, Url('/another/url'), description='another sub menu item')) [item1, divider, item2] = sub_menu.html_representation.children assert 'dropdown-divider' in divider.get_attribute('class').split()
def test_button_layouts_on_anchors(web_fixture): """A ButtonLayout can also be used to make an A (anchor) look like a button.""" anchor = A(web_fixture.view, href=Url('/an/href'), description='link text').use_layout(ButtonLayout()) tester = WidgetTester(anchor) [rendered_anchor] = tester.xpath(XPath.link().with_text('link text')) assert rendered_anchor.attrib['class'] == 'btn btn-secondary' assert 'aria-disabled' not in rendered_anchor.attrib assert 'tabindex' not in rendered_anchor.attrib anchor = A(web_fixture.view, href=Url('/an/href'), description='link text', write_check=lambda: False).use_layout(ButtonLayout()) tester = WidgetTester(anchor) [rendered_anchor] = tester.xpath(XPath.link().with_text('link text')) assert rendered_anchor.attrib['class'] == 'btn btn-secondary disabled' assert rendered_anchor.attrib['aria-disabled'] == 'true' assert rendered_anchor.attrib['tabindex'] == '-1'
def __init__(self, view, account_management_interface): super().__init__(view) self.add_child( P(view, text=_('You are trying to register using the email address "%s"') % account_management_interface.email)) self.add_child( P(view, text= _('That address is already registered and active on the system.' 'This means that you (or someone else) must have registered using that email address' ' previously.'))) forgot_password_bookmark = self.user_interface.get_bookmark( relative_path='/resetPassword') last_p = P( view, text= _('You can gain access to this account by following our {procedure}.' )) self.add_child( last_p.format(procedure=A.from_bookmark( view, forgot_password_bookmark.with_description( _(' password reset procedure')))))
def add_dropdown(self, title, dropdown_menu, drop_position='down', query_arguments={}): """Adds the dropdown_menu :class:`DropdownMenu` to this Nav. It appears as the top-level item with text `title`. :keyword drop_position: Position relative to the item where the dropdown should appear ('up', 'down', 'left' or 'right'). :keyword query_arguments: (For internal use) """ if self.open_item == title: extra_query_arguments = {'open_item': ''} else: extra_query_arguments = {'open_item': title} extra_query_arguments.update(query_arguments) bookmark = Bookmark.for_widget( title, query_arguments=extra_query_arguments).on_view(self.view) submenu = MenuItem(self.view, A.from_bookmark(self.view, bookmark)) self.menu_items.append(submenu) li = self.add_html_for_item(submenu) li.add_child(dropdown_menu) if self.open_item == title: li.append_class('show') submenu.a.append_class('dropdown-toggle') submenu.a.set_attribute('data-toggle', 'dropdown') submenu.a.set_attribute('role', 'button') submenu.a.set_attribute('aria-haspopup', 'true') # submenu.a.set_attribute('aria-expanded', 'true') #FYI no need to set this this as it is handled by bootstrap js li.append_class(DropdownMenuPosition(drop_position).as_html_snippet()) return submenu
def add_dropdown(self, title, dropdown_menu, drop_up=False, query_arguments={}): """Adds the dropdown_menu :class:`DropdownMenu` to this Nav. It appears as the top-level item with text `title`. :keyword drop_up: If True, the dropdown will drop upwards from its item, instead of down. :keyword query_arguments: (For internal use) """ if self.open_item == title: extra_query_arguments = {'open_item': ''} else: extra_query_arguments = {'open_item': title} extra_query_arguments.update(query_arguments) bookmark = Bookmark.for_widget( title, query_arguments=extra_query_arguments).on_view(self.view) submenu = MenuItem(self.view, A.from_bookmark(self.view, bookmark)) self.menu_items.append(submenu) li = self.add_html_for_item(submenu) li.add_child(dropdown_menu) if self.open_item == title: li.append_class('open') submenu.a.append_class('dropdown-toggle') submenu.a.set_attribute('data-toggle', 'dropdown') submenu.a.set_attribute('data-target', '-') submenu.a.add_child(Span(self.view)).append_class('caret') li.append_class('drop%s' % ('up' if drop_up else 'down')) return submenu
def __init__(self, view, account_management_interface): super().__init__(view) self.add_child( P(view, text= _('There is no record of someone trying to register the email address "%s".' ) % account_management_interface.email)) self.add_child( P(view, text= _('Perhaps you mistyped your email address when registering? The system also removes ' 'such a registration request if you take a long time to get around to verifying it.' ))) register_bookmark = self.user_interface.get_bookmark( relative_path='/register') last_p = P( view, text=_( 'Whatever the case, please {register} to rectify the problem.') ) self.add_child( last_p.format(register=A.from_bookmark( view, register_bookmark.with_description(_( 'register again')))))
def __init__(self, view): super().__init__(view, 'simple_form') self.use_layout(FormLayout()) if self.exception: self.layout.add_alert_for_domain_exception(self.exception) domain_object = self.get_or_create_domain_object() link = self.add_child( A(view, Url('/'), description='Open another tab...')) link.set_attribute('target', '_blank') self.add_child( P(view, text= '...and increment the value there. Come back here and submit the value. A Concurrency error will be shown' )) #Your own widget that tracks changes self.add_child(MyConcurrencyWidget(view, domain_object)) self.layout.add_input( TextInput(self, domain_object.fields.some_field_value)) self.define_event_handler(domain_object.events.submit) self.add_child(Button(self, domain_object.events.submit)) self.define_event_handler(domain_object.events.increment) self.add_child(Button(self, domain_object.events.increment))
def dropdown_menus(fixture): """You can add a DropdownMenu as a dropdown inside a Nav.""" menu = Nav(fixture.view) sub_menu = DropdownMenu(fixture.view) sub_menu.add_a(A(fixture.view, Url('/an/url'), description='sub menu item')) menu.add_dropdown('Dropdown title', sub_menu) [item] = menu.html_representation.children vassert(item.tag_name == 'li') vassert('dropdown' in item.get_attribute('class')) [toggle, added_sub_menu] = item.children vassert('dropdown-toggle' in toggle.get_attribute('class')) vassert('dropdown' in toggle.get_attribute('data-toggle')) vassert('-' in toggle.get_attribute('data-target')) vassert('caret' in toggle.children[1].get_attribute('class')) title_text = toggle.children[0].value vassert(title_text == 'Dropdown title') vassert(added_sub_menu is sub_menu) vassert('dropdown-menu' in added_sub_menu.html_representation.get_attribute('class').split()) vassert(isinstance(added_sub_menu.html_representation, Div)) [dropdown_item] = added_sub_menu.html_representation.children vassert(isinstance(dropdown_item, A)) vassert('dropdown-item' in dropdown_item.get_attribute('class').split())
def set_brand_text(self, brand_text): """Sets the brand to be a link to the home page that contains the given text. :param brand_text: Text to use for branding. """ brand_a = A(self.view, Url('/'), description=brand_text) self.set_brand(brand_a)
def test_dropdown_menus(web_fixture): """You can add a DropdownMenu as a dropdown inside a Nav.""" menu = Nav(web_fixture.view) sub_menu = DropdownMenu(web_fixture.view) sub_menu.add_a(A(web_fixture.view, Url('/an/url'), description='sub menu item')) menu.add_dropdown('Dropdown title', sub_menu) [item] = menu.html_representation.children assert item.tag_name == 'li' assert 'dropdown' in item.get_attribute('class') [toggle, added_sub_menu] = item.children assert 'dropdown-toggle' in toggle.get_attribute('class') assert 'button' in toggle.get_attribute('role') assert 'true' in toggle.get_attribute('aria-haspopup') assert 'dropdown' in toggle.get_attribute('data-toggle') title_text = toggle.children[0].value assert title_text == 'Dropdown title' assert added_sub_menu is sub_menu assert 'dropdown-menu' in added_sub_menu.html_representation.get_attribute('class').split() assert isinstance(added_sub_menu.html_representation, Div) [dropdown_item] = added_sub_menu.html_representation.children assert isinstance(dropdown_item, A) assert 'dropdown-item' in dropdown_item.get_attribute('class').split()
def create_items(self, menu): self.add_bordering_link_for(menu, '←', 'First', 1, not self.page_index.has_previous_page) self.add_bordering_link_for(menu, '«', 'Prev', self.page_index.previous_page.number, not self.page_index.has_previous_page) for page in self.page_index.pages_in_range: bookmark = self.paged_panel.get_bookmark( page_number=page.number, description=page.description) bookmark.query_arguments[ 'start_page_number'] = self.page_index.start_page_number link = A.from_bookmark(self.view, bookmark) item = menu.add_a(link) item.html_representation.add_attribute_source( ActiveStateAttributes(item)) self.add_styling_to_menu_item(item) if self.page_index.current_page_number == page.number: item.set_active() self.add_bordering_link_for(menu, '»', 'Next', self.page_index.next_page.number, not self.page_index.has_next_page) self.add_bordering_link_for(menu, '→', 'Last', self.page_index.last_page.number, not self.page_index.has_next_page)
def button_layouts_on_anchors(fixture): """A ButtonLayout can also be used to make an A (anchor) look like a button.""" anchor = A(fixture.view, href=Url('/an/href'), description='link text').use_layout(ButtonLayout()) tester = WidgetTester(anchor) [rendered_anchor] = tester.xpath(XPath.link_with_text('link text')) vassert(rendered_anchor.attrib['class'] == 'btn')
def __init__(self, view, account_management_interface, register_help_bookmark): super(CongratsWidget, self).__init__(view) self.add_child(P(view, text=_('You have successfully registered.'))) self.add_child(P(view, text=_('Before we can allow you to log in, however, you need to prove to us that you are indeed the owner of %s.') % account_management_interface.email)) self.add_child(P(view, text=_('You can do that by following instructions just emailed to that address.'))) self.add_child(P(view, text=_('Sometimes these emails arrive immediately, but they may also be delayed.'))) last_p = P(view, text=_('If you do not receive the email within an hour or so, please follow {trouble}.')) self.add_child(last_p.format(trouble=A.from_bookmark(view, register_help_bookmark.with_description(_('our troubleshooting procedure')))))
def new_menu_item_a(self): description = 'The link' href = Url('/link') menu_item_a = A(self.web_fixture.view, self.href, description=description) return menu_item_a
def __init__(self, view): super().__init__(view) error_widget = self.body.insert_child(0, ErrorWidget(view)) error_widget.add_child(H(view, 1, text='Oops, something broke')) error_widget.add_child(P(view, text=error_widget.error_message)) error_widget.add_child( A(view, Url(error_widget.error_source_href), description='Click here to try again'))
def __init__(self, view, account_management_interface): super(ChoosePasswordWidget, self).__init__(view) explanation = P(view, text=_('Do you have your secret key? You can only choose a new password if you {reset_password}.')) link_text = _('previously requested a secret key to be sent to your registered email address') step1_bookmark = self.user_interface.get_bookmark(relative_path='/resetPassword', description=link_text) self.add_child(explanation.format(reset_password=A.from_bookmark(view, step1_bookmark))) self.add_child(ChoosePasswordForm(view, account_management_interface))
def disabled(self): """The mouse cursor is shown as no-access on disabled items.""" def not_allowed(): return False self.menu_item_with_state = A(self.view, Url('/another_url'), write_check=not_allowed) self.state_indicator_class = 'disabled'
def add_bookmark(self, bookmark, active_regex=None): """Adds a MenuItem for the given :class:`Bookmark` to this Menu'. Answers the added MenuItem. .. versionadded:: 3.2 """ return self.add_a(A.from_bookmark(self.view, bookmark), active_regex=active_regex, exact_match=bookmark.exact)
def __init__(self, view, account_management_interface): super(ResetPasswordWidget, self).__init__(view) explanation = P(view, text=_('To ensure you are not an impostor, resetting your password is a two step '\ 'process: First, we send a "secret key" to your registered email address. '\ 'Then, {choose_password}. But you need that secret key for the last step in order to prove '\ 'that you are indeed the owner of the registered email address.')) link_text = _('you can choose a new password') step2_bookmark = self.user_interface.get_bookmark(relative_path='/choosePassword', description=link_text) self.add_child(explanation.format(choose_password=A.from_bookmark(view, step2_bookmark))) self.add_child(ResetPasswordForm(view, account_management_interface))
def add_bordering_link_for(self, menu, short_description, long_description, start_page_number, disabled): link = A.from_bookmark(self.view, self.get_bookmark(start_page_number=start_page_number, disabled=disabled)) link.add_child(Span(self.view, text=short_description)).set_attribute('aria-hidden', 'true'); link.add_child(Span(self.view, text=long_description)).append_class('sr-only'); link.set_attribute('aria-label', long_description); link.set_active(not disabled) item = menu.add_a(link) item.html_representation.add_attribute_source(AccessRightAttributes(link)) self.add_styling_to_menu_item(item)
def __init__(self, view, address_book_ui): super(AddressBookList, self).__init__(view) current_account = LoginSession.for_current_session().account address_books = [book for book in AddressBook.address_books_visible_to(current_account)] bookmarks = [address_book_ui.get_address_book_bookmark(address_book, description=address_book.display_name) for address_book in address_books] for bookmark in bookmarks: p = self.add_child(P(view)) p.add_child(A.from_bookmark(view, bookmark))
def test_button_layouts_on_disabled_anchors(web_fixture): """Disabled A's are marked with a class so Bootstrap can style them appropriately.""" def can_write(): return False anchor = A(web_fixture.view, href=Url('/an/href'), description='link text', write_check=can_write) anchor.use_layout(ButtonLayout()) tester = WidgetTester(anchor) [rendered_anchor] = tester.xpath(XPath.link().with_text('link text')) assert rendered_anchor.attrib['class'] == 'btn btn-secondary disabled'
def __init__(self, view): super().__init__(view) self.add_child( Alert(view, 'This is an alert in danger color', severity='danger')) self.add_child( Alert(view, 'This is an alert in primary color', severity='primary')) self.add_child(A(view, Url('#'), description='Link styled as button')).use_layout( ButtonLayout(style='primary'))
def add_control(self, previous=False): control_a = self.carousel_panel.add_child(A(self.view, self.url)) control_a.append_class('carousel-control-prev' if previous else 'carousel-control-next') control_a.set_attribute('role', 'button') control_a.set_attribute('data-slide', 'prev' if previous else 'next') span_icon = control_a.add_child(Span(self.view)) span_icon.append_class('carousel-control-%s-icon' % ('prev' if previous else 'next')) span_icon.set_attribute('aria-hidden', 'true') span_text = control_a.add_child(Span(self.view, text=_('Previous') if previous else _('Next'))) span_text.append_class('sr-only') return control_a
def test_visual_feedback_on_items(web_fixture, visual_feedback_scenarios): """The state of a MenuItem is visually indicated to a user.""" menu = Nav(web_fixture.view) menu.add_a(A(web_fixture.view, Url('/an_url'))) menu.add_a(visual_feedback_scenarios.menu_item_with_state) [defaulted_item, item_with_state] = menu.html_representation.children [defaulted_a] = defaulted_item.children [a_with_state] = item_with_state.children assert visual_feedback_scenarios.state_indicator_class not in defaulted_a.get_attribute('class') assert visual_feedback_scenarios.state_indicator_class in a_with_state.get_attribute('class')
def test_rendering_active_menu_items(web_fixture, menu_item_scenarios): """A MenuItem is marked as active based on its active_regex or the A it represents.""" description = 'The link' href = Url('/link') menu = Nav(web_fixture.view) menu_item_a = A(web_fixture.view, href, description=description) menu.add_a(menu_item_a, active_regex=menu_item_scenarios.active_regex) tester = WidgetTester(menu) actual = tester.get_html_for('//li') active_str = '' if not menu_item_scenarios.active else 'active ' expected_menu_item_html = '<li class="nav-item"><a href="/link" class="%snav-link">The link</a></li>' % (active_str) assert actual == expected_menu_item_html
def __init__(self, view, account_management_interface, verify_bookmark): super().__init__(view) config = ExecutionContext.get_context().config self.add_child( P(view, text=_('There is a registration pending for email address "%s".') % account_management_interface.email)) self.add_child( P(view, text=_( 'Before you can log in, you need to verify your email address using the secret key ' 'sent to that address. It looks like you did not do that.'))) self.add_child( P(view, text= _('You should receive the automated email anything between a minute to an hour after ' 'registration. Sometimes though, your email software may mistakenly identify our ' 'email as junk email. If this happens it will be hidden away in a "junk email" ' 'folder or just not shown to you.'))) self.add_child( P(view, text= _('You can have the email re-sent to you by clicking on the button below.' ))) self.add_child( P(view, text= _('Before you do that, however, please make sure that your email system will allow ' 'emails from "%s" through to you.') % config.accounts.admin_email)) self.add_child( P(view, text= _('Sometimes these emails arrive immediately, but they may also be delayed.' ))) p = P( view, text= _('Once you located the email, retrieve the code and then enter it on {verify}.' )) self.add_child( p.format(verify=A.from_bookmark( view, verify_bookmark.with_description(_('the verification page'))))) self.add_child(RegistrationPendingForm(view))
def create_sorter_link(self, column_number, heading_widget): show_control = (column_number == self.page_index.sort_column_number) if show_control: sort_descending = 'off' if self.page_index.sort_descending else 'on' link_class = 'sorted-descending' if sort_descending=='off' else 'sorted-ascending' else: sort_descending = 'off' link_class = None bookmark = Bookmark.for_widget(None, query_arguments={'sort_column_number': column_number, 'sort_descending': sort_descending}) link = A.from_bookmark(self.view, bookmark.on_view(self.view)) link.add_child(heading_widget) if link_class: link.append_class(link_class) return link
def __init__(self, view, event_channel_name, account_management_interface): super().__init__(view, event_channel_name) self.account_management_interface = account_management_interface if self.exception: self.add_child( Alert(view, self.exception.as_user_message(), 'warning')) login_inputs = self.add_child( FieldSet(view, legend_text=_('Please specify'))).use_layout(FormLayout()) email_cue = P(view, _('The email address you used to register here.')) login_inputs.layout.add_input( CueInput( TextInput(self, self.account_management_interface.fields.email), email_cue)) password_cue = P( view, _('The secret password you supplied upon registration.')) password_cue_input = CueInput( PasswordInput(self, self.account_management_interface.fields.password), password_cue) forgot_password_bookmark = self.user_interface.get_bookmark( relative_path='/resetPassword', description=_('Forgot your password?')) password_cue_input.add_child( A.from_bookmark(view, forgot_password_bookmark)) login_inputs.layout.add_input(password_cue_input) stay_cue = P(view, _('If selected, you will stay logged in for longer.')) login_inputs.layout.add_input( CueInput( CheckboxInput( self, self.account_management_interface.fields.stay_logged_in), stay_cue)) login_buttons = self.add_child(ActionButtonGroup(view)) btn = login_buttons.add_child( Button(self, account_management_interface.events.login_event, style='primary'))