diff --git a/tailbone/forms/core.py b/tailbone/forms/core.py index a5ab3355..9624f6fb 100644 --- a/tailbone/forms/core.py +++ b/tailbone/forms/core.py @@ -338,7 +338,7 @@ class Form(object): assume_local_times=False, renderers=None, renderer_kwargs={}, hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None, action_url=None, cancel_url=None, component='tailbone-form', - vuejs_component_kwargs=None, vuejs_field_converters={}, + vuejs_component_kwargs=None, vuejs_field_converters={}, json_data={}, included_templates={}, # TODO: ugh this is getting out hand! can_edit_help=False, edit_help_url=None, route_prefix=None, ): @@ -381,6 +381,8 @@ class Form(object): self.component = component self.vuejs_component_kwargs = vuejs_component_kwargs or {} self.vuejs_field_converters = vuejs_field_converters or {} + self.json_data = json_data or {} + self.included_templates = included_templates or {} self.can_edit_help = can_edit_help self.edit_help_url = edit_help_url self.route_prefix = route_prefix @@ -966,6 +968,30 @@ class Form(object): kwargs.setdefault(':configure-fields-help', 'configureFieldsHelp') return HTML.tag(self.component, **kwargs) + def set_json_data(self, key, value): + """ + Establish a data value for use in client-side JS. This value + will be JSON-encoded and made available to the + `` component within the client page. + """ + self.json_data[key] = value + + def include_template(self, template, context): + """ + Declare a JS template as required by the current form. This + template will then be included in the final page, so all + widgets behave correctly. + """ + self.included_templates[template] = context + + def render_included_templates(self): + templates = [] + for template, context in self.included_templates.items(): + context = dict(context) + context['form'] = self + templates.append(HTML.literal(render(template, context))) + return HTML.literal('\n').join(templates) + def render_field_complete(self, fieldname, bfield_attrs={}): """ Render the given field completely, i.e. with ```` diff --git a/tailbone/templates/master/form.mako b/tailbone/templates/master/form.mako index c142d8ef..1339bd91 100644 --- a/tailbone/templates/master/form.mako +++ b/tailbone/templates/master/form.mako @@ -3,8 +3,14 @@ <%def name="modify_this_page_vars()"> ${parent.modify_this_page_vars()} - % if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple': - - % endif + % endif + + + ${form.render_included_templates()} + diff --git a/tailbone/views/master.py b/tailbone/views/master.py index c6ce44e0..20dc0dcf 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -2695,8 +2695,15 @@ class MasterView(View): context.update(data) context.update(self.template_kwargs(**context)) - if hasattr(self, 'template_kwargs_{}'.format(template)): - context.update(getattr(self, 'template_kwargs_{}'.format(template))(**context)) + + method_name = f'template_kwargs_{template}' + if hasattr(self, method_name): + context.update(getattr(self, method_name)(**context)) + for supp in self.iter_view_supplements(): + if hasattr(supp, 'template_kwargs'): + context.update(getattr(supp, 'template_kwargs')(**context)) + if hasattr(supp, method_name): + context.update(getattr(supp, method_name)(**context)) # First try the template path most specific to the view. mako_path = '{}/{}.mako'.format(self.get_template_prefix(), template) @@ -4441,6 +4448,9 @@ class MasterView(View): if not self.has_perm('view_global'): obj.local_only = True + for supp in self.iter_view_supplements(): + obj = supp.objectify(obj, form, data) + return obj def objectify_contact(self, contact, data): @@ -5892,6 +5902,9 @@ class ViewSupplement(object): renderers, default values etc. for them. """ + def objectify(self, obj, form, data): + return obj + def get_xref_buttons(self, obj): return []