def render(self, request): """render page""" logger = logging.getLogger(__name__) logger.debug('rendering page') self.content = render(self.header(), self.content, *self.args) app_theme = request.app.theme if hasattr(request, 'app') else None site_theme = request.site.theme self.theme = self.kwargs.get('theme', app_theme or site_theme or 'default') self.theme_uri = '/themes/' + self.theme zoom.render.add_helpers( zoom.forms.helpers(request), self.helpers(request), ) template = zoom.tools.get_template(self.template, self.theme) if zoom.system.site.settings.site.cookie_consent: zoom.requires('cookieconsent') return HTMLResponse(template, status=self.status)
def spinner(): """A progress spinner >>> isinstance(spinner(), str) True """ zoom.requires('spin') return div(id='spinner')
def app(request): """Return a page containing a list of available apps""" zoom.requires('fontawesome4') css = """ .app-icons ul { list-style-type: none; margin-top: 50px; } .app-icons li { display: inline; } .zoom-app-as-icon { width: 110px; height: 120px; text-align: center; float: left; } .zoom-app-as-icon:hover { background: #eee; } .zoom-app-icon { height: 50px; width: 50px; border-radius: 5px; margin-top: 16px; padding-top: 5px; line-height: 50px; text-align: center; box-shadow: inset 0px 49px 0px -24px #67828b; background-color: #5a7179; border: 1px solid #ffffff; display: inline-block; color: #ffffff; font-size: 15px; text-decoration: none; } .zoom-app-icon .fa { font-size: 2em; } """ if len(request.route) > 1 or request.data: return zoom.home() skip = 'home', 'logout', 'login', 'settings' content = h.div( h.ul( a.as_icon for a in sorted(request.site.apps, key=lambda a: a.title.lower()) if a.name not in skip and a.visible and request.user.can_run(a) ), classed='app-icons' ) + '<div style="clear:both"></div>' return zoom.page(content, css=css)
def app(request): zoom.requires('Morphext') content = ul(link_to(text, url) for text, url in [ ('Info', '/info'), ]) js = """ $("#js-rotating").Morphext({ animation: "bounceIn", separator: ",", speed: 2000, }); """ return page( '<span id="js-rotating">Hello, Howdy, Hola, Hi</span> World!<br>{}'. format(content), title='Hello', js=js, )
def render_in_state(self, state): zoom.requires('fontawesome') selector = '[data-flag-id="%s"]'%self.id # Maybe render styles. add_page_dependencies() doesn't work here in the # case that this is the result of a helper being used, since the head # of the document will already have been rendered. flag_style = ''' <style> %s .icon-flag { cursor: pointer; color: %s; } %s .icon-flag[data-active="true"] { color: %s; } </style> '''%( selector, self.data.get('off_color') or 'gray', selector, self.data.get('on_color') or 'black' ) fa_import = ''' <link rel="stylesheet" href="//use.fontawesome.com/releases/v5.0.6/css/all.css"/> ''' if getattr(context, '_flag_inc_fa', False): fa_import = str() context._flag_inc_fa = True return '''%s%s <i class="fa fa-%s icon-flag" title="%s" data-active="%s"></i> '''%( fa_import, flag_style, self.data.get('icon') or 'star', self.get_label_in_state(state), str(state).lower() )
def dropzone(url, **kwargs): """Dropzone component A basic dropzone component that supports drag and drop uploading of files which are posted to the URL provided. >>> zoom.system.site = zoom.sites.Site() >>> zoom.system.site.packages = {} >>> zoom.system.request = zoom.utils.Bunch(app=zoom.utils.Bunch(name='hello', packages={}, common_packages={})) >>> c = dropzone('/app/files') >>> isinstance(c, zoom.Component) True """ zoom.requires('dropzone') id = 'dropzone_' + uuid.uuid4().hex js = """ var %(id)s = new Dropzone("#%(id)s", {url: "%(url)s"}); """ % dict(id=id, url=url) html = div(classed='dropzone', id=id, **kwargs) return zoom.Component(html)#, js=js)
def index(self): """Show all images""" actions = 'Edit', tpl = """ <a href="{image.access_url}" class="image-item-container"> <img class="images-thumbnail" title="{image.image_name}" src="/content/images/{image.image_id}"> <div class="images-linker-container"> {image.markdown_linker} </div> </a> """ content = ''.join( tpl.format(image=image) for image in zoom.store_of(Image)) zoom.requires('fontawesome4') return zoom.page(content, title='Images', actions=actions, css=css, libs=('/content/static/markdown-linker.js', ))
def format(self, chart): """Format a Chart""" zoom.requires('chartjs') return zoom.DynamicComponent.format(self, chart=chart)
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) zoom.requires('fontawesome4')
def browse(data, **kwargs): """browse data""" def getcol(item, index): if isinstance(item, dict): return item.get(index, None) elif isinstance(item, (tuple, list)): return item[index] else: return getattr(item, index) labels = kwargs.get('labels') fields = kwargs.get('fields') columns = kwargs.get('columns') title = kwargs.get('title') actions = kwargs.get('actions', []) header = kwargs.get('header') footer = kwargs.get('footer', '') sortable = kwargs.get('sortable', False) table_id = kwargs.get('table_id', uuid.uuid4().hex) items = list(data) if labels: if not columns: if len(items) and hasattr(items[0], 'get'): columns = [name_for(label).lower() for label in labels] elif len(items) and hasattr(items[0], '__len__') and len(items[0]): columns = range(len(labels)) else: columns = [name_for(label).lower() for label in labels] else: if columns: labels = columns else: if len(items) and isinstance(items[0], Record): labels = columns = sorted_column_names(set([ a for item in items for a in item.attributes() if not a.startswith('__') ])) elif (len(items) and hasattr(items[0], 'keys') and callable(getattr(items[0], 'keys'))): # list of dicts labels = columns = [ a for a in sorted_column_names(items[0].keys()) if not a.startswith('__') ] elif len(items) and hasattr(items[0], '__dict__'): # list of objects labels = columns = [items[0].__dict__.keys()] elif hasattr(data, 'cursor'): # Result object labels = [c[0] for c in data.cursor.description] columns = range(len(labels)) elif len(items) and hasattr(items[0], '__len__') and len(items[0]): # list of lists? labels = items[0] columns = range(len(items[0])) items = items[1:] else: if len(items): raise Exception('%s' % hasattr(items[0],'__len__')) return '<div class="baselist"><table><tbody><tr><td>None</td></th></tbody></table></div>' columns = list(columns) labels = list(labels) invisible = [] formatters = [] alignments = [] if fields: invisible_labels = [] lookup = fields.as_dict() for n, col in enumerate(columns): if col in lookup: field = lookup[col] better_label = field.label visible = field.visible and field.browse if visible: alignments.append(field.alignment) formatters.append(str) else: better_label = None visible = True values = [getcol(row, col) for row in items] formatter, alignment = get_format(col, values) alignments.append(alignment) formatters.append(formatter) if better_label: if n > len(labels): labels.append(better_label) else: labels[n] = better_label if not visible: invisible.append(col) invisible_labels.append(n) for n in reversed(invisible_labels): del labels[n] alist = [] for item in items: fields.initialize(item) flookup = fields.display_value() row = [ flookup.get(col, getcol(item, col)) for col in columns if col not in invisible ] alist.append(row) else: alist = [[getcol(item, col) for col in columns] for item in items] styling = calculate_styling(columns, labels, alist) formatters = [s[0] for s in styling] alignments = [s[1] for s in styling] column_alignments = """ #%s tbody>tr>td:nth-child(%s) { text-align: right; padding-right: 20px; } #%s thead>tr>th:nth-child(%s) { text-align: right; padding-right: 20px; } """ alignment_css = ''.join( column_alignments % (table_id, n+1, table_id, n+1) for n, alignment in enumerate(alignments) if alignment == 'right' ) css = alignment_css t = [] if labels: t.append('<thead><tr>') colnum = 0 for label in labels: colnum += 1 t.append('<th>%s</th>' % label) t.append('</tr></thead>') t.append('<tbody>') count = 0 for row in alist: count += 1 t.append('<tr id="row-%s">' % (count)) for n, item in enumerate(row): try: value = formatters[n].format(item) except BaseException: value = repr(item) wrapping = len(value) < 80 and ' nowrap' or '' cell_tpl = '<td{}>%s</td>'.format(wrapping) t.append(cell_tpl % value) t.append('</tr>') t.append('</tbody>') if not count: t.append('<tr><td colspan=%s>None</td></tr>' % len(labels)) if not header: if title: header = '<div class="title">%s</div>' % title if actions: header += as_actions(actions) header_body = header and ('<div class="header">%s</div>' % header) or '' footer_body = footer and ('<div class="footer">%s</div>' % footer) or '' if sortable: zoom.requires('datatables') js = """ $('#{}').DataTable( {{ "lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]], "dom": '<if>rt<lp><"clear">', paging: false, "oLanguage": {{ "sSearch": "Filter" }} }} ); """.format(table_id) css += """ .dataTables_filter label { font-weight: normal; } """ zoom.Component(css=css, js=js).render() else: zoom.Component(css=css).render() table_tag = '<table id="{}">'.format(table_id) result = '\n'.join( ['<div class="baselist">'] + [header_body] + [table_tag] + t + ['</table>'] + [footer_body] + ['</div>'] ) return result
def standard_zoom_head_tags(): zoom.requires('standard-zoom-assets') tags = 'styles', 'css', 'head', 'tracker' return ''.join('{{%s}}' % tag for tag in tags)
def requires(*packages): zoom.requires(*packages) return ''
def index(self): """Index page""" zoom.requires('fontawesome4') content = zoom.tools.load('icons.html') subtitle = 'Icons available as part of FontAwesome 4<br><br>' return zoom.page(content, title='Icons', subtitle=subtitle)
def use_common_package(message): zoom.requires('common_package_test') return zoom.Component(h.tag('div', message, id='common_package_test'))
def format(self, chart): """Format a Chart""" zoom.requires('pivot-table') return (zoom.Component( "<div class='pivot-table' id='%s'></div>" % chart.selector) + zoom.DynamicComponent.format(self, chart=chart))