diff --git a/tailbone/forms/core.py b/tailbone/forms/core.py index a6795c24..e8bc369f 100644 --- a/tailbone/forms/core.py +++ b/tailbone/forms/core.py @@ -714,8 +714,8 @@ class Form(object): def render_field_readonly(self, field_name, **kwargs): label = HTML.tag('label', self.get_label(field_name), for_=field_name) field = self.render_field_value(field_name) or '' - field_div = HTML.tag('div', class_='field', c=field) - return HTML.tag('div', class_='field-wrapper {}'.format(field_name), c=label + field_div) + field_div = HTML.tag('div', class_='field', c=[field]) + return HTML.tag('div', class_='field-wrapper {}'.format(field_name), c=[label, field_div]) def render_field_value(self, field_name): record = self.model_instance diff --git a/tailbone/forms/widgets.py b/tailbone/forms/widgets.py index 666d9f41..d0b13f22 100644 --- a/tailbone/forms/widgets.py +++ b/tailbone/forms/widgets.py @@ -83,6 +83,7 @@ class JQueryDateWidget(dfwidget.DateInputWidget): ) options.update(kw.get('extra_options', {})) kw.setdefault('options_json', json.dumps(options)) + kw.setdefault('selected_callback', None) values = self.get_template_values(field, cstruct, kw) return field.renderer(template, **values) diff --git a/tailbone/grids/core.py b/tailbone/grids/core.py index 41b13a71..60374577 100644 --- a/tailbone/grids/core.py +++ b/tailbone/grids/core.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2017 Lance Edgar +# Copyright © 2010-2018 Lance Edgar # # This file is part of Rattail. # @@ -27,7 +27,7 @@ Core Grid Classes from __future__ import unicode_literals, absolute_import import datetime -import urllib +from six.moves import urllib import six import sqlalchemy as sa @@ -911,8 +911,12 @@ class Grid(object): """ Returns the rendered contents of the 'actions' column for a given row. """ - main_actions = filter(None, [self.render_action(a, row, i) for a in self.main_actions]) - more_actions = filter(None, [self.render_action(a, row, i) for a in self.more_actions]) + main_actions = [self.render_action(a, row, i) + for a in self.main_actions] + main_actions = [a for a in main_actions if a] + more_actions = [self.render_action(a, row, i) + for a in self.more_actions] + more_actions = [a for a in more_actions if a] if more_actions: icon = HTML.tag('span', class_='ui-icon ui-icon-carat-1-e') link = tags.link_to("More" + icon, '#', class_='more') @@ -1072,5 +1076,5 @@ class URLMaker(object): params = self.request.GET.copy() params["page"] = page params["partial"] = "1" - qs = urllib.urlencode(params, True) + qs = urllib.parse.urlencode(params, True) return '{}?{}'.format(self.request.path, qs) diff --git a/tailbone/grids/filters.py b/tailbone/grids/filters.py index 8ae73456..37719275 100644 --- a/tailbone/grids/filters.py +++ b/tailbone/grids/filters.py @@ -773,4 +773,4 @@ class GridFiltersForm(forms.Form): """ style = 'display: none;' if filtr.verb in filtr.valueless_verbs else None return HTML.tag('div', class_='value', style=style, - c=filtr.render_value(**kwargs)) + c=[filtr.render_value(**kwargs)]) diff --git a/tailbone/views/master.py b/tailbone/views/master.py index bce46bdb..8048e3ea 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -216,7 +216,10 @@ class MasterView(View): # Return grid only, if partial page was requested. if self.request.params.get('partial'): - self.request.response.content_type = b'text/html' + if six.PY3: + self.request.response.content_type = 'text/html' + else: + self.request.response.content_type = b'text/html' self.request.response.text = grid.render_grid() return self.request.response @@ -1227,9 +1230,16 @@ class MasterView(View): response.content_length = os.path.getsize(path) content_type = self.download_content_type(path, filename) if content_type: - response.content_type = six.binary_type(content_type) - filename = os.path.basename(path).encode('ascii', 'replace') - response.content_disposition = b'attachment; filename={}'.format(filename) + if six.PY3: + response.content_type = content_type + else: + response.content_type = six.binary_type(content_type) + if six.PY3: + filename = os.path.basename(path) + response.content_disposition = 'attachment; filename={}'.format(filename) + else: + filename = os.path.basename(path).encode('ascii', 'replace') + response.content_disposition = b'attachment; filename={}'.format(filename) return response def download_content_type(self, path, filename): diff --git a/tailbone/views/people.py b/tailbone/views/people.py index 051d19af..0fbacbc9 100644 --- a/tailbone/views/people.py +++ b/tailbone/views/people.py @@ -178,7 +178,7 @@ class PeopleView(MasterView): for user in users: text = user.username url = self.request.route_url('users.view', uuid=user.uuid) - items.append(HTML.tag('li', c=tags.link_to(text, url))) + items.append(HTML.tag('li', c=[tags.link_to(text, url)])) if items: return HTML.tag('ul', c=items) elif self.request.has_perm('users.create'): diff --git a/tailbone/views/principal.py b/tailbone/views/principal.py index 23ad27cb..d879c696 100644 --- a/tailbone/views/principal.py +++ b/tailbone/views/principal.py @@ -129,8 +129,8 @@ class PermissionsRenderer(Object): if checked: label = perms[key]['label'] span = HTML.tag('span', c="[X]" if checked else "[ ]") - inner += HTML.tag('p', class_='perm', c=span + ' ' + label) + inner += HTML.tag('p', class_='perm', c=[span, HTML(' '), label]) rendered = True if rendered: - html += HTML.tag('div', class_='group', c=inner) + html += HTML.tag('div', class_='group', c=[inner]) return html or "(none granted)" diff --git a/tailbone/views/users.py b/tailbone/views/users.py index 9be9a2f8..86167de5 100644 --- a/tailbone/views/users.py +++ b/tailbone/views/users.py @@ -169,8 +169,11 @@ class UsersView(PrincipalMasterView): roles = self.get_possible_roles().all() role_values = [(s.uuid, six.text_type(s)) for s in roles] f.set_node('roles', colander.Set()) + size = len(roles) + if size < 3: + size = 3 f.set_widget('roles', dfwidget.SelectWidget(multiple=True, - size=len(roles), + size=size, values=role_values)) if self.editing: f.set_default('roles', [r.uuid for r in user.roles]) @@ -234,7 +237,7 @@ class UsersView(PrincipalMasterView): for role in roles: text = role.name url = self.request.route_url('roles.view', uuid=role.uuid) - items.append(HTML.tag('li', c=tags.link_to(text, url))) + items.append(HTML.tag('li', c=[tags.link_to(text, url)])) return HTML.tag('ul', c=items) def editable_instance(self, user):