OMG so many Buefy things...and much to be done yet it seems

these changes are all with Buefy "forms" support in mind.  hopefully didn't
break any legacy/jquery stuff... and yeah, lots more left to do still for the
sake of Buefy forms
This commit is contained in:
Lance Edgar 2019-05-22 15:31:23 -05:00
parent eea3f671af
commit 6c3722737d
13 changed files with 192 additions and 73 deletions

View file

@ -130,10 +130,51 @@ class CasesUnitsWidget(dfwidget.Widget):
return validated return validated
class DynamicCheckboxWidget(dfwidget.CheckboxWidget):
"""
This checkbox widget can be "dynamic" in the sense that form logic can
control its value and state.
"""
template = 'checkbox_dynamic'
class PlainSelectWidget(dfwidget.SelectWidget): class PlainSelectWidget(dfwidget.SelectWidget):
template = 'select_plain' template = 'select_plain'
class CustomSelectWidget(dfwidget.SelectWidget):
"""
This widget is mostly for convenience. You can set extra kwargs for the
:meth:`serialize()` method, e.g.::
widget.set_template_values(foo='bar')
"""
def set_template_values(self, **kw):
if not hasattr(self, 'extra_template_values'):
self.extra_template_values = {}
self.extra_template_values.update(kw)
def get_template_values(self, field, cstruct, kw):
values = super(CustomSelectWidget, self).get_template_values(field, cstruct, kw)
if hasattr(self, 'extra_template_values'):
values.update(self.extra_template_values)
return values
class DynamicSelectWidget(CustomSelectWidget):
"""
This is a "normal" select widget, but instead of (or in addition to) its
values being set when constructed, they must be assigned dynamically in
real-time, e.g. based on other user selections.
Really all this widget "does" is render some Vue.js-compatible HTML, but
the page which contains the widget is ultimately responsible for wiring up
the logic for things to work right.
"""
template = 'select_dynamic'
class JQuerySelectWidget(dfwidget.SelectWidget): class JQuerySelectWidget(dfwidget.SelectWidget):
template = 'select_jquery' template = 'select_jquery'

View file

@ -11,7 +11,6 @@ const TailboneDatepicker = {
'icon="calendar-alt"', 'icon="calendar-alt"',
':date-formatter="formatDate"', ':date-formatter="formatDate"',
':date-parser="parseDate"', ':date-parser="parseDate"',
':value="value ? parseDate(value) : null"',
'@input="dateChanged"', '@input="dateChanged"',
'>', '>',
'</b-datepicker>' '</b-datepicker>'
@ -20,7 +19,6 @@ const TailboneDatepicker = {
props: { props: {
name: String, name: String,
id: String, id: String,
value: String
}, },
methods: { methods: {
@ -43,8 +41,7 @@ const TailboneDatepicker = {
}, },
dateChanged(date) { dateChanged(date) {
this.value = this.formatDate(date) this.$emit('input', this.formatDate(date))
this.$emit('input', this.value)
} }
} }

View file

@ -0,0 +1,23 @@
const TailboneTimepicker = {
template: [
'<b-timepicker',
':name="name"',
':id="id"',
'editable',
'placeholder="Click to select ..."',
'icon-pack="fas"',
'icon="clock"',
'hour-format="12"',
'>',
'</b-timepicker>'
].join(' '),
props: {
name: String,
id: String
}
}
Vue.component('tailbone-timepicker', TailboneTimepicker)

View file

@ -0,0 +1,13 @@
<!-- -*- mode: html; -*- -->
<b-checkbox tal:define="name name|field.name;
oid oid|field.oid;
true_val true_val|field.widget.true_val;
vmodel vmodel|'field_model_' + field.name;
disabled_attr disabled_attr|'field_disabled_' + field.name;"
name="${name}"
id="${oid}"
native-value="${true_val}"
v-model="${vmodel}"
tal:attributes=":disabled disabled_attr;">
{{ ${vmodel} }}
</b-checkbox>

View file

@ -35,11 +35,12 @@
</script> </script>
</div> </div>
<div tal:condition="use_buefy"> <div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()} ${field.start_mapping()}
<tailbone-datepicker name="date" <tailbone-datepicker name="date"
id="${oid}" id="${oid}"
value="${cstruct}"> v-model="${vmodel}">
</tailbone-datepicker> </tailbone-datepicker>
${field.end_mapping()} ${field.end_mapping()}
</div> </div>

View file

@ -7,7 +7,8 @@
unicode unicode|str; unicode unicode|str;
optgroup_class optgroup_class|field.widget.optgroup_class; optgroup_class optgroup_class|field.widget.optgroup_class;
multiple multiple|field.widget.multiple; multiple multiple|field.widget.multiple;
use_buefy use_buefy|0;" use_buefy use_buefy|0;
input_handler input_handler|'';"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag=""> <div tal:condition="not use_buefy" tal:omit-tag="">
@ -62,7 +63,8 @@
class string: form-control ${css_class or ''}; class string: form-control ${css_class or ''};
multiple multiple; multiple multiple;
size size; size size;
style style;"> style style;
@input input_handler;">
<tal:loop tal:repeat="item values"> <tal:loop tal:repeat="item values">
<optgroup tal:condition="isinstance(item, optgroup_class)" <optgroup tal:condition="isinstance(item, optgroup_class)"

View file

@ -0,0 +1,31 @@
<!-- -*- mode: html; -*- -->
<div tal:define="
name name|field.name;
oid oid|field.oid;
style style|field.widget.style;
size size|field.widget.size;
css_class css_class|field.widget.css_class;
unicode unicode|str;
optgroup_class optgroup_class|field.widget.optgroup_class;
multiple multiple|field.widget.multiple;
input_handler input_handler|'';"
tal:omit-tag="">
<b-select tal:attributes="name name;
id oid;
placeholder '(please choose)';
class string: form-control ${css_class or ''};
multiple multiple;
size size;
style style;
@input input_handler;">
<option v-for="item in ${name}_options"
tal:attributes=":key 'item.value';
:value 'item.value';">
{{ item.label }}
</option>
</b-select>
</div>

View file

@ -1,9 +1,14 @@
<!-- -*- mode: html; -*- -->
<span tal:define="size size|field.widget.size; <span tal:define="size size|field.widget.size;
css_class css_class|field.widget.css_class; css_class css_class|field.widget.css_class;
oid oid|field.oid; oid oid|field.oid;
style style|field.widget.style|None; style style|field.widget.style|None;
type_name type_name|field.widget.type_name;" type_name type_name|field.widget.type_name;
field_name field_name|field.name;
use_buefy use_buefy|0;"
tal:omit-tag=""> tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()} ${field.start_mapping()}
<input type="${type_name}" <input type="${type_name}"
name="time" name="time"
@ -21,4 +26,16 @@
} }
); );
</script> </script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<tailbone-timepicker name="time"
id="${oid}"
v-model="${vmodel}">
</tailbone-timepicker>
${field.end_mapping()}
</div>
</span> </span>

View file

@ -1,14 +1,41 @@
## -*- coding: utf-8 -*- ## -*- coding: utf-8; -*-
<%inherit file="/base.mako" /> <%inherit file="/base.mako" />
<%def name="context_menu_items()"></%def> <%def name="context_menu_items()"></%def>
<div class="form-wrapper"> <%def name="render_form()">
${form.render()|n}
</%def>
<ul class="context-menu"> <%def name="make_buefy_form_app()">
<script type="text/javascript">
const BuefyForm = {
template: '#buefy-form-template'
}
Vue.component('buefy-form', BuefyForm)
new Vue({
el: '#buefy-form-app'
})
</script>
</%def>
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
${self.render_form()}
</div>
<ul id="context-menu">
${self.context_menu_items()} ${self.context_menu_items()}
</ul> </ul>
${form.render()|n}
</div> </div>
% if form.use_buefy:
${self.make_buefy_form_app()}
% endif

View file

@ -60,18 +60,3 @@
<div id="buefy-form-app"> <div id="buefy-form-app">
<buefy-form></buefy-form> <buefy-form></buefy-form>
</div> </div>
<script type="text/javascript">
const BuefyForm = {
template: '#buefy-form-template',
}
Vue.component('buefy-form', BuefyForm)
new Vue({
el: '#buefy-form-app'
})
</script>

View file

@ -1,18 +1,6 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/base.mako" /> <%inherit file="/form.mako" />
<%def name="title()">New ${model_title_plural if master.creates_multiple else model_title}</%def> <%def name="title()">New ${model_title_plural if master.creates_multiple else model_title}</%def>
<%def name="context_menu_items()"></%def> ${parent.body()}
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
${form.render()|n}
</div><!-- form-wrapper -->
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>

View file

@ -1,5 +1,5 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<%inherit file="/base.mako" /> <%inherit file="/form.mako" />
<%def name="title()">${index_title} &raquo; ${report.name}</%def> <%def name="title()">${index_title} &raquo; ${report.name}</%def>
@ -11,16 +11,9 @@
% endif % endif
</%def> </%def>
<%def name="render_form()">
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
<p style="padding: 1em;">${report.__doc__}</p> <p style="padding: 1em;">${report.__doc__}</p>
${form.render()|n} ${parent.render_form()}
</div><!-- form-wrapper --> </%def>
<ul id="context-menu"> ${parent.body()}
${self.context_menu_items()}
</ul>
</div>

View file

@ -290,6 +290,7 @@
## Tailbone / Buefy stuff ## Tailbone / Buefy stuff
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.datepicker.js') + '?ver={}'.format(tailbone.__version__))} ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.datepicker.js') + '?ver={}'.format(tailbone.__version__))}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.oncebutton.js') + '?ver={}'.format(tailbone.__version__))} ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.oncebutton.js') + '?ver={}'.format(tailbone.__version__))}
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.timepicker.js') + '?ver={}'.format(tailbone.__version__))}
<script type="text/javascript"> <script type="text/javascript">
var session_timeout = ${request.get_session_timeout() or 'null'}; var session_timeout = ${request.get_session_timeout() or 'null'};