Add support for Buefy autocomplete; several other form tweaks

at least the Edit User form should work now, for instance
This commit is contained in:
Lance Edgar 2019-06-08 13:46:00 -05:00
parent d7e19865de
commit 2b6d88105c
16 changed files with 390 additions and 42 deletions

View file

@ -1,4 +1,5 @@
## -*- coding: utf-8 -*-
## -*- coding: utf-8; -*-
## TODO: This function signature is getting out of hand...
<%def name="autocomplete(field_name, service_url, field_value=None, field_display=None, width='300px', select=None, selected=None, cleared=None, change_clicked=None, options={})">
<div id="${field_name}-container" class="autocomplete-container">
@ -56,3 +57,31 @@
});
</script>
</%def>
<%def name="tailbone_autocomplete_template()">
<script type="text/x-template" id="tailbone-autocomplete-template">
<div>
<b-autocomplete ref="autocomplete"
:name="name"
v-show="!selected"
v-model="autocompleteValue"
:data="data"
@typing="getAsyncData"
@select="selectionMade"
@input="itemSelected"
keep-first>
<template slot-scope="props">
{{ props.option.label }}
</template>
</b-autocomplete>
<b-button v-if="selected"
style="width: 100%; justify-content: left;"
@click="clearSelection()">
{{ selected.label }} (click to change)
</b-button>
</div>
</script>
</%def>

View file

@ -2,10 +2,14 @@
css_class css_class|field.widget.css_class;
oid oid|field.oid;
field_display field_display;
style style|field.widget.style"
id="${oid}-container"
class="autocomplete-container">
style style|field.widget.style;
url url|field.widget.service_url;
use_buefy use_buefy|0;"
tal:omit-tag="">
<div tal:condition="not use_buefy"
id="${oid}-container"
class="autocomplete-container">
<input type="hidden"
name="${name}"
id="${oid}"
@ -98,5 +102,16 @@
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
<tailbone-autocomplete name="${name}"
service-url="${url}"
v-model="${vmodel}"
initial-label="${field_display}">
</tailbone-autocomplete>
</div>
</div>

View file

@ -1,13 +1,26 @@
<div class="checkbox">
<input tal:define="name name|field.name;
true_val true_val|field.widget.true_val;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
oid oid|field.oid"
type="checkbox"
<div tal:define="name name|field.name;
true_val true_val|field.widget.true_val;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
oid oid|field.oid;
use_buefy use_buefy|0;"
tal:omit-tag="">
<div tal:condition="not use_buefy" class="checkbox">
<input type="checkbox"
name="${name}" value="${true_val}"
id="${oid}"
tal:attributes="checked cstruct == true_val;
class css_class;
style style;" />
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<b-checkbox name="${name}"
v-model="${vmodel}"
native-value="${true_val}">
{{ ${vmodel} }}
</b-checkbox>
</div>
</div>

View file

@ -0,0 +1,60 @@
<div i18n:domain="deform" tal:omit-tag=""
tal:define="oid oid|field.oid;
name name|field.name;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
use_buefy use_buefy|0;">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<div>
<input type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
i18n:attributes="placeholder"
placeholder="Password"/>
</div>
<div>
<input type="password"
name="${name}-confirm"
value="${field.widget.redisplay and confirm or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
confirm_attributes|field.widget.confirm_attributes|{};"
id="${oid}-confirm"
i18n:attributes="placeholder"
placeholder="Confirm Password"/>
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy">
${field.start_mapping()}
<b-input type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
i18n:attributes="placeholder"
placeholder="Password">
</b-input>
<b-input type="password"
name="${name}-confirm"
value="${field.widget.redisplay and confirm or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
confirm_attributes|field.widget.confirm_attributes|{};"
id="${oid}-confirm"
i18n:attributes="placeholder"
placeholder="Confirm Password">
</b-input>
${field.end_mapping()}
</div>
</div>

View file

@ -58,12 +58,14 @@
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
>
<input type="hidden" name="__start__" value="${name}:sequence"
tal:condition="multiple" />
<b-select tal:attributes="name name;
id oid;
placeholder '(please choose)';
class string: form-control ${css_class or ''};
multiple multiple;
:multiple str(multiple).lower();
size size;
style style;
v-model vmodel;
@ -88,6 +90,8 @@
</tal:loop>
</b-select>
<input type="hidden" name="__end__" value="${name}:sequence"
tal:condition="multiple" />
</div>
</div>

View file

@ -0,0 +1,27 @@
<div tal:define="rows rows|field.widget.rows;
cols cols|field.widget.cols;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
name name|field.name;
style style|field.widget.style;
use_buefy use_buefy|0;"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<textarea tal:attributes="rows rows;
cols cols;
class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
name="${name}">${cstruct}</textarea>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<b-input type="textarea"
name="${name}"
v-model="${vmodel}">
</b-input>
</div>
</div>

View file

@ -0,0 +1,32 @@
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
use_buefy use_buefy|0;"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
<b-input name="${name}"
v-model="${vmodel}">
</b-input>
</div>
</span>

View file

@ -11,7 +11,38 @@
${form.render(buttons=capture(self.render_form_buttons))|n}
</%def>
<%def name="render_buefy_form()">
<div class="form">
<tailbone-form></tailbone-form>
</div>
</%def>
<%def name="render_form_complete()">
% if use_buefy:
${self.render_form()}
<script type="text/x-template" id="form-page-template">
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
${self.render_buefy_form()}
</div>
<div style="display: flex; align-items: flex-start;">
<div class="object-helpers">
${self.object_helpers()}
</div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>
</div>
</script>
<div id="form-page-app">
<form-page></form-page>
</div>
% else:
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
@ -29,6 +60,7 @@
</div>
</div>
% endif
</%def>
<%def name="modify_tailbone_form()">
@ -43,8 +75,14 @@
Vue.component('tailbone-form', TailboneForm)
const FormPage = {
template: '#form-page-template'
}
Vue.component('form-page', FormPage)
new Vue({
el: '#tailbone-form-app'
el: '#form-page-app'
})
</script>
@ -53,6 +91,6 @@
${self.render_form_complete()}
% if form.use_buefy:
% if use_buefy:
${self.make_tailbone_form_app()}
% endif

View file

@ -91,21 +91,10 @@
% for field in form.fields:
% if field in dform:
<% field = dform[field] %>
% if isinstance(field.schema.typ, colander.Date):
field_model_${field.name}: null,
% elif isinstance(field.schema.typ, deform.FileData):
field_model_${field.name}: null,
% else:
field_model_${field.name}: ${'null' if field.cstruct is colander.null else json.dumps(field.cstruct)|n},
% endif
field_model_${field.name}: ${form.get_vuejs_model_value(field)|n},
% endif
% endfor
% endif
}
</script>
<div id="tailbone-form-app">
<tailbone-form></tailbone-form>
</div>

View file

@ -20,16 +20,28 @@
% endif
</%def>
<%def name="render_form()">
<%def name="render_buefy_form()">
<br />
% if use_buefy:
<b-notification type="is-danger" :closable="false">
You are about to delete the following ${model_title} and all associated data:
</b-notification>
% else:
<p>You are about to delete the following ${model_title} and all associated data:</p>
% endif
${parent.render_form()}
${parent.render_buefy_form()}
</%def>
<%def name="render_form_buttons()">
<br />
% if use_buefy:
<b-notification type="is-danger" :closable="false">
Are you sure about this?
</b-notification>
% else:
<p>Are you sure about this?</p>
% endif
<br />
${h.form(request.current_route_url(), class_=None if form.use_buefy else 'autodisable')}
@ -39,15 +51,13 @@
<once-button tag="a" href="${form.cancel_url}"
text="Whoops, nevermind...">
</once-button>
% else:
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
% endif
% if form.use_buefy:
<once-button type="is-primary" native-type="submit"
<once-button type="is-primary is-danger"
native-type="submit"
text="Yes, please DELETE this data forever!">
</once-button>
% else:
${h.submit('submit', "Yes, please DELETE this data forever!", class_='button is-primary')}
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
${h.submit('submit', "Yes, please DELETE this data forever!", class_='button is-primary')}
% endif
</div>
${h.end_form()}

View file

@ -141,13 +141,12 @@
<input type="hidden"
name="uuids"
:value="checkedRowUUIDs()" />
<b-button type="is-primary"
native-type="submit"
icon-pack="fas"
icon-left="object-ungroup"
:disabled="checkedRows.length != 2">
Merge 2 ${model_title_plural}
</b-button>
<once-button type="is-primary"
native-type="submit"
icon-left="object-ungroup"
:disabled="checkedRows.length != 2"
text="Merge 2 ${model_title_plural}">
</once-button>
% else:
${h.hidden('uuids')}
<button type="submit" class="button">Merge 2 ${model_title_plural}</button>

View file

@ -1,6 +1,7 @@
## -*- coding: utf-8; -*-
<%namespace file="/grids/nav.mako" import="grid_index_nav" />
<%namespace file="/feedback_dialog_buefy.mako" import="feedback_dialog" />
<%namespace file="/autocomplete.mako" import="tailbone_autocomplete_template" />
<%namespace name="base_meta" file="/base_meta.mako" />
<!DOCTYPE html>
<html lang="en">
@ -30,6 +31,11 @@
</head>
<body>
## TODO: should move template to JS, then can postpone the JS
${tailbone_autocomplete_template()}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.autocomplete.js') + '?ver={}'.format(tailbone.__version__))}
<header>
<nav class="navbar" role="navigation" aria-label="main navigation">