def _get_element(self, **kwargs) -> htmler.Element: cont = htmler.TagLessElement() cont.append_child(htmler.H2(lang.t('theming@installed_themes'))) table = cont.append_child( htmler.Table(css='table table-striped table-bordered table-hover')) t_head = table.append_child(htmler.Tr()) t_head.append_child(htmler.Th(lang.t('theming@name'))) t_head.append_child(htmler.Th(lang.t('theming@version'))) t_head.append_child(htmler.Th(lang.t('theming@author'))) t_head.append_child(htmler.Th(lang.t('theming@url'))) t_head.append_child(htmler.Th(lang.t('theming@actions'))) t_body = table.append_child(htmler.Tbody()) for theme in _api.get_all().values(): tr = t_body.append_child(htmler.Tr()) tr.append_child(htmler.Td(theme.name)) tr.append_child(htmler.Td(theme.version)) tr.append_child( htmler.Td( htmler.A(theme.author['name'], href=theme.author['url'], target='_blank'))) tr.append_child( htmler.Td(htmler.A(theme.url, href=theme.url, target='_blank'))) actions = htmler.TagLessElement(child_sep=' ') if _api.get().name != theme.name: # 'Switch' button btn_switch = htmler.A( title=lang.t('theming@switch_to_this_theme'), href='#', role='button', css='btn btn-default btn-light btn-sm button-switch', data_package_name=theme.package_name) btn_switch.append_child(htmler.I(css='fa fas fa-power-off')) actions.append_child(btn_switch) # 'Uninstall' button btn_delete = htmler.A( title=lang.t('theming@uninstall_theme'), href='#', role='button', css='btn btn-danger btn-sm button-uninstall', data_package_name=theme.package_name) btn_delete.append_child(htmler.I(css='fa fas fa-trash')) actions.append_child(btn_delete) tr.append_child(htmler.Td(actions)) return cont
def render(self) -> str: # 'Create' toolbar button if self._model_class.odm_ui_creation_allowed( ) and odm_auth.check_model_permissions(self._model, PERM_CREATE): create_form_url = router.rule_url( self._m_form_rule, { 'model': self._model, 'eid': 0, '__redirect': router.current_url(), }) title = lang.t('odm_ui@create') btn = htmler.A(href=create_form_url, css='btn btn-default btn-light add-button', title=title) btn.append_child(htmler.I(css='fa fas fa-fw fa-plus')) self._widget.toolbar.append_child(btn) self._widget.toolbar.append_child(htmler.Span(' ')) # 'Delete' toolbar button if self._model_class.odm_ui_deletion_allowed(): delete_form_url = router.rule_url(self._d_form_rule, {'model': self._model}) title = lang.t('odm_ui@delete_selected') btn = htmler.A( href=delete_form_url, css='hidden btn btn-danger mass-action-button sr-only', title=title) btn.append_child(htmler.I(css='fa fas fa-fw fa-remove fa-times')) self._widget.toolbar.append_child(btn) self._widget.toolbar.append_child(htmler.Span(' ')) # Additional toolbar buttons for btn_data in self._model_class.odm_ui_browser_mass_action_buttons(): ep = btn_data.get('ep') url = router.rule_url(ep) if ep else '#' css = 'btn btn-{} mass-action-button'.format( btn_data.get('color', 'default btn-light')) icon = 'fa fas fa-fw fa-' + btn_data.get('icon', 'question') button = htmler.A(href=url, css=css, title=btn_data.get('title')) if icon: button.append_child(htmler.I(css=icon)) self._widget.toolbar.append_child(button) self._widget.toolbar.append_child(htmler.Span(' ')) frm = htmler.Form(self._widget.render(), action='#', method='post', css='table-responsive odm-ui-browser') return frm.render()
def __init__(self, uid: str, **kwargs): rows_url = http_api.url('auth_admin@browser_rows', {'e_type': 'user'}) data_fields = [ ('login', 'auth_admin@login', True), ('first_last_name', 'auth_admin@full_name', True), ('roles', 'auth_admin@roles', False), ('status', 'auth_admin@status', True), ('is_public', 'auth_admin@is_public', True), ('is_online', 'auth_admin@is_online', True), ('created', 'auth_admin@created', True), ('last_activity', 'auth_admin@last_activity', True), ('_actions', 'auth_admin@actions', False), ] super().__init__(uid, rows_url=rows_url, data_fields=data_fields, checkbox=False, **kwargs) add_btn_url = router.rule_url( 'auth_admin@form_user_modify', { 'uid': '0', '__redirect': router.rule_url('auth_admin@browse_users') }) add_btn = htmler.A(href=add_btn_url, css='btn btn-default btn-light') add_btn.append_child(htmler.I(css='fa fa-plus')) self.toolbar.append_child(add_btn) self._css += ' widget-auth-admin-browser'
def __init__(self, uid: str, **kwargs): rows_url = http_api.url('auth_admin@browser_rows', {'e_type': 'role'}) data_fields = [ ('name', 'auth_admin@name', True), ('description', 'auth_admin@description', False), ('permissions', 'auth_admin@permissions', False), ('_actions', 'auth_admin@actions', False), ] super().__init__(uid, rows_url=rows_url, data_fields=data_fields, checkbox=False, **kwargs) add_btn_url = router.rule_url( 'auth_admin@form_role_modify', { 'uid': '0', '__redirect': router.rule_url('auth_admin@browse_roles') }) add_btn = htmler.A(href=add_btn_url, css='btn btn-default btn-light') add_btn.append_child(htmler.I(css='fa fa-plus')) self.toolbar.append_child(add_btn) self._css += ' widget-auth-admin-browser'
def _get_row(self, widgets: List[Abstract], row_num: int = 0, add_css: str = '') -> htmler.Tr: """Build single row """ slot_tr = htmler.Tr(css='slot ' + add_css) slot_tr.append_child( htmler.Td('[{}]'.format(row_num + 1), css='order-col')) # Widgets for w in widgets: w.name = self._get_row_widget_name(w) w.form_group = False w_td = htmler.Td(css='widget-col widget-col-' + w.uid) w_td.append_child(w.renderable()) slot_tr.append_child(w_td) # Actions actions_td = htmler.Td(css='actions-col') slot_tr.append_child(actions_td) # 'Remove' button if self._enabled: remove_btn = htmler.A( href='#', css='button-remove-slot btn btn-sm btn-danger') remove_btn.append_child( htmler.I(css='fa fas fa-icon fa-remove fa-times')) actions_td.append_child(remove_btn) return slot_tr
def __init__(self, uid: str, **kwargs): """Init. """ super().__init__(uid, **kwargs) self._html_em = htmler.A(href=kwargs.get('href', '#')) if self._dismiss: self._html_em.set_attr('data_dismiss', self._dismiss)
def _render_item(self, entity: _model.Menu) -> Optional[htmler.Li]: if not entity.enabled: return root = htmler.Li(css='nav-item {}'.format('active' if self._is_item_active(entity) else '')) a = root.append_child(htmler.A(entity.title, href=self._item_url(entity), css='nav-link')) if entity.new_window: a.set_attr('target', '_blank') return root
def _get_element(self, **kwargs) -> htmler.Element: """Hook """ self._data['header-hidden'] = self._is_header_hidden if self._max_rows: self._data['max-rows'] = self._max_rows base_row = self._get_widgets() table = htmler.Table(css='content-table') # Header thead = htmler.Thead(css='hidden sr-only slots-header') table.append_child(thead) row = htmler.Tr() thead.append_child(row) row.append_child(htmler.Th(' ', css='order-col')) for w in self._get_widgets(): row.append_child(htmler.Th(w.label, css='widget-col')) row.append_child(htmler.Th(css='actions-col')) # Table body tbody = htmler.Tbody(css='slots') table.append_child(tbody) # Base slot tbody.append_child( self._get_row(base_row, add_css='base hidden sr-only')) # Rows for em in self._get_rows(): tbody.append_child(em) # Footer tfoot = htmler.Tfoot() tfoot_tr = htmler.Tr() tfoot_td = htmler.Td(colspan=len(self._get_widgets()) + 2) tfoot_tr.append_child(tfoot_td) tfoot.append_child(tfoot_tr) table.append_child(tfoot) if self._enabled: add_btn = htmler.A( href='#', css='button-add-slot btn btn-default btn-light btn-sm') if self._add_btn_icon: add_btn.append_child(htmler.I(css=self._add_btn_icon)) if self._add_btn_label: add_btn.append_child(self._add_btn_label) tfoot_td.append_child(add_btn) return table
def _render_dropdown(self, entity: _model.Menu) -> Optional[htmler.Li]: if not entity.enabled: return # Dropdown's root root = htmler.Li(css='nav-item dropdown') # Toggler root.append_child(htmler.A(entity.title, id=entity.ref, href='#', css='nav-link dropdown-toggle', role='button', data_toggle='dropdown', aria_haspopup='true', aria_expanded='false')) # Dropdown dropdown = root.append_child(htmler.Div(css='dropdown-menu', aria_labelledby=entity.ref)) for e in entity.children: # type: _model.Menu if e.enabled: a_css = 'dropdown-item {}'.format('active' if self._is_item_active(e) else '') a = dropdown.append_child(htmler.A(e.title, href=self._item_url(e), css=a_css)) if e.new_window: a.set_attr('target', '_blank') return root
def _render_sidebar(sidebar: admin.SideBar) -> htmler.Aside: """Render admin's sidebar """ aside = htmler.Aside(css='main-sidebar') sidebar_section_em = htmler.Section(css='sidebar') aside.append_child(sidebar_section_em) root_menu_ul = htmler.Ul(css='sidebar-menu') sidebar_section_em.append_child(root_menu_ul) sections, menus = sidebar.items # Do actual rendering for section in sections: li = htmler.Li(lang.t(section['title']), css='header', data_section_weight=section['weight']) root_menu_ul.append_child(li) # Building top level menu item for menu in menus[section['sid']]: # Link a = htmler.A( href=router.url(menu['path'], lang=lang.get_current())) # Icon if menu['icon']: a.append_child(htmler.I(css=menu['icon'])) # Title a.append_child(htmler.Span(lang.t(menu['title']))) # Label if menu['label']: label_class = 'label pull-right label-' + menu[ 'label_class'] a.append_child( htmler.Span(lang.t(menu['label']), css=label_class)) # List element li = htmler.Li(data_menu_weight=menu['weight']) # Active state if menu['active']: li.set_attr('css', 'active') li.append_child(a) root_menu_ul.append_child(li) return aside
def odm_ui_browser_row(self) -> dict: """Hook """ r = {} # Title if self.has_field('title'): r['title'] = (str(htmler.A(self.title, href=self.url)) if self.url else self.title) # Status if self.has_field('status'): status = self.status status_str = self.t('content_status_{}_{}'.format(self.model, status)) label_css = badge_css = 'primary' if status == CONTENT_STATUS_WAITING: label_css = badge_css = 'warning' elif status == CONTENT_STATUS_UNPUBLISHED: label_css = 'default' badge_css = 'secondary' status = str(htmler.Span(status_str, css='label label-{} badge badge-{}'.format(label_css, badge_css))) r['status'] = status # Images if self.has_field('images'): label_css = 'default' if not len(self.images) else 'primary' badge_css = 'secondary' if not len(self.images) else 'primary' images_count = '<span class="label label-{} badge badge-{}">{}</span>'. \ format(label_css, badge_css, len(self.images)) r['images'] = images_count # Author if self.has_field('author') and self.odm_auth_check_model_permissions(self.model, PERM_MODIFY): r['author'] = self.author.first_last_name if self.author else ' ' # Publish time if self.has_field('publish_time'): r['publish_time'] = self.f_get('publish_time', fmt='%d.%m.%Y %H:%M') return r
def get_rows(self, args: routing.ControllerArgs) -> dict: """Get browser rows. """ # Instantiate finder finder = odm.find(self._model) # Check if the user can modify/delete any entity if not odm_auth.check_model_permissions(self._model, [PERM_MODIFY, PERM_DELETE]) and \ odm_auth.check_model_permissions(self._model, [PERM_MODIFY_OWN, PERM_DELETE_OWN]): # Show only entities owned by user finder.mock.has_field('author') and finder.eq( 'author', self._current_user) # Let model to finish finder setup _api.dispense_entity(self._model).odm_ui_browser_setup_finder( finder, args) # Sort sort_order = odm.I_DESC if args.get( 'order', self.default_sort_order) in (-1, 'desc') else odm.I_ASC sort_field = args.get('sort') if sort_field and finder.mock.has_field(sort_field): finder.sort([(sort_field, sort_order)]) elif self.default_sort_field: finder.sort([(self.default_sort_field, sort_order)]) # Get root elements first finder.add_sort('_parent', pos=0) # Prepare result r = {'total': finder.count(), 'rows': []} # Build table rows cursor = finder.skip(args.get('offset', 0)).get(args.get('limit', 0)) for entity in cursor: row = entity.odm_ui_browser_row() events.fire('odm_ui@browser_row.{}'.format(self._model), entity=entity, row=row) if not row: continue # Build row's cells fields_data = { '__id': str(entity.id), '__parent': str(entity.parent.id) if entity.parent else None, } if not isinstance(row, dict): raise TypeError( '{}.odm_ui_browser_row() must return dict, got {}'.format( entity.__class__.__name__, type(row))) for df in self.data_fields: fields_data[df[0]] = row.get(df[0], ' ') # Action buttons if self._model_class.odm_ui_entity_actions_enabled() and \ (self._model_class.odm_ui_modification_allowed() or self._model_class.odm_ui_deletion_allowed()): actions = htmler.TagLessElement(child_sep=' ') for btn_data in entity.odm_ui_browser_entity_actions(self): color = 'btn btn-sm btn-' + btn_data.get( 'color', 'default btn-light') title = btn_data.get('title', '') url = btn_data.get('url') if not url: rule = btn_data.get('rule') url = router.rule_url( rule, {'ids': str(entity.id)}) if rule else '#' btn = htmler.A(href=url, css=color + ' ' + btn_data.get('css', ''), title=title, role='button') if btn_data.get('disabled'): btn.set_attr('aria_disabled', 'true') btn.add_css('disabled') btn.append_child( htmler.I(css=btn_data.get('icon', 'fa fas fa-fw fa-question'))) actions.append_child(btn) fields_data['entity-actions'] = actions.render() r['rows'].append(fields_data) return r
def process_img_tag(match): """Converts single body [img] tag into HTML <img> tag """ nonlocal responsive_images, images_width # Image index img_index = int(match.group(1)) # Does image exist? if entity_images_count < img_index: return '' img = entity_images[img_index - 1] # Additional parameters defaults link_orig = False link_target = '_blank' link_class = '' img_css = '' enlarge = enlarge_images_setting alt = entity.title if entity.has_field('title') else '' width = 0 height = 0 responsive = responsive_images for arg in match.group(2).split(':'): # type: str arg = arg.strip() if arg in ('link_orig', 'link'): link_orig = True elif arg.startswith('link_target='): link_target = arg.split('=')[1] elif arg.startswith('link_class='): link_class = arg.split('=')[1] elif arg in ('skip_enlarge', 'no_enlarge'): enlarge = False elif arg.startswith('class='): img_css = arg.split('=')[1] elif arg.startswith('alt='): alt = arg.split('=')[1] elif arg.startswith('width='): responsive = False try: width = int(arg.split('=')[1]) except ValueError: width = 0 elif arg.startswith('height='): responsive = False try: height = int(arg.split('=')[1]) except ValueError: height = 0 if images_width: responsive = False width = images_width # HTML code if responsive: r = img.get_responsive_html(alt, enlarge=enlarge, css=util.escape_html(img_css)) else: r = img.get_html(alt, width=width, height=height, enlarge=enlarge, css=util.escape_html(img_css)) # Link to original file if link_orig: link = htmler.A(r, href=img.url, target=link_target, title=util.escape_html(alt)) if link_class: link.set_attr('css', util.escape_html(link_class)) r = str(link) return r