Cleanup grid/filters logic a bit
get rid of grids.js file, remove filter templates from complete.mako move all that instead to filter-components.mako for now, base template does import + setup for the latter, "just in case" a given view has any grids. each grid should (still) be isolated but no code should be duplicated now. whereas before the grid filter templates were in comlete.mako and hence could be declared more than once if multiple grids are on a page
This commit is contained in:
parent
d6fa83cd87
commit
9f984241c4
|
@ -1,167 +0,0 @@
|
|||
|
||||
const GridFilterNumericValue = {
|
||||
template: '#grid-filter-numeric-value-template',
|
||||
props: {
|
||||
value: String,
|
||||
wantsRange: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
startValue: null,
|
||||
endValue: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.wantsRange) {
|
||||
if (this.value.includes('|')) {
|
||||
let values = this.value.split('|')
|
||||
if (values.length == 2) {
|
||||
this.startValue = values[0]
|
||||
this.endValue = values[1]
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// when changing from e.g. 'equal' to 'between' filter verbs,
|
||||
// must proclaim new filter value, to reflect (lack of) range
|
||||
wantsRange(val) {
|
||||
if (val) {
|
||||
this.$emit('input', this.startValue + '|' + this.endValue)
|
||||
} else {
|
||||
this.$emit('input', this.startValue)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.startValue.focus()
|
||||
},
|
||||
startValueChanged(value) {
|
||||
if (this.wantsRange) {
|
||||
value += '|' + this.endValue
|
||||
}
|
||||
this.$emit('input', value)
|
||||
},
|
||||
endValueChanged(value) {
|
||||
value = this.startValue + '|' + value
|
||||
this.$emit('input', value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Vue.component('grid-filter-numeric-value', GridFilterNumericValue)
|
||||
|
||||
|
||||
const GridFilterDateValue = {
|
||||
template: '#grid-filter-date-value-template',
|
||||
props: {
|
||||
value: String,
|
||||
dateRange: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.dateRange) {
|
||||
if (this.value.includes('|')) {
|
||||
let values = this.value.split('|')
|
||||
if (values.length == 2) {
|
||||
this.startDate = values[0]
|
||||
this.endDate = values[1]
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.startDate.focus()
|
||||
},
|
||||
startDateChanged(value) {
|
||||
if (this.dateRange) {
|
||||
value += '|' + this.endDate
|
||||
}
|
||||
this.$emit('input', value)
|
||||
},
|
||||
endDateChanged(value) {
|
||||
value = this.startDate + '|' + value
|
||||
this.$emit('input', value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Vue.component('grid-filter-date-value', GridFilterDateValue)
|
||||
|
||||
|
||||
const GridFilter = {
|
||||
template: '#grid-filter-template',
|
||||
props: {
|
||||
filter: Object
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
changeVerb() {
|
||||
// set focus to value input, "as quickly as we can"
|
||||
this.$nextTick(function() {
|
||||
this.focusValue()
|
||||
})
|
||||
},
|
||||
|
||||
valuedVerb() {
|
||||
/* this returns true if the filter's current verb should expose value input(s) */
|
||||
|
||||
// if filter has no "valueless" verbs, then all verbs should expose value inputs
|
||||
if (!this.filter.valueless_verbs) {
|
||||
return true
|
||||
}
|
||||
|
||||
// if filter *does* have valueless verbs, check if "current" verb is valueless
|
||||
if (this.filter.valueless_verbs.includes(this.filter.verb)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// current verb is *not* valueless
|
||||
return true
|
||||
},
|
||||
|
||||
multiValuedVerb() {
|
||||
/* this returns true if the filter's current verb should expose a multi-value input */
|
||||
|
||||
// if filter has no "multi-value" verbs then we safely assume false
|
||||
if (!this.filter.multiple_value_verbs) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if filter *does* have multi-value verbs, see if "current" is one
|
||||
if (this.filter.multiple_value_verbs.includes(this.filter.verb)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// current verb is not multi-value
|
||||
return false
|
||||
},
|
||||
|
||||
focusValue: function() {
|
||||
this.$refs.valueInput.focus()
|
||||
// this.$refs.valueInput.select()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.component('grid-filter', GridFilter)
|
|
@ -3,6 +3,7 @@
|
|||
<%namespace file="/autocomplete.mako" import="tailbone_autocomplete_template" />
|
||||
<%namespace name="base_meta" file="/base_meta.mako" />
|
||||
<%namespace file="/formposter.mako" import="declare_formposter_mixin" />
|
||||
<%namespace file="/grids/filter-components.mako" import="make_grid_filter_components" />
|
||||
<%namespace name="page_help" file="/page_help.mako" />
|
||||
<%namespace name="multi_file_upload" file="/multi_file_upload.mako" />
|
||||
<!DOCTYPE html>
|
||||
|
@ -90,7 +91,6 @@
|
|||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.numericinput.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__))}
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.grid.js') + '?ver={}'.format(tailbone.__version__))}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
@ -896,6 +896,9 @@
|
|||
</%def>
|
||||
|
||||
<%def name="make_whole_page_component()">
|
||||
|
||||
${make_grid_filter_components()}
|
||||
|
||||
${self.declare_whole_page_vars()}
|
||||
${self.modify_whole_page_vars()}
|
||||
${self.finalize_whole_page_vars()}
|
||||
|
|
|
@ -1,131 +1,5 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
|
||||
<script type="text/x-template" id="grid-filter-numeric-value-template">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<b-input v-model="startValue"
|
||||
ref="startValue"
|
||||
@input="startValueChanged">
|
||||
</b-input>
|
||||
</div>
|
||||
<div v-show="wantsRange"
|
||||
class="level-item">
|
||||
and
|
||||
</div>
|
||||
<div v-show="wantsRange"
|
||||
class="level-item">
|
||||
<b-input v-model="endValue"
|
||||
ref="endValue"
|
||||
@input="endValueChanged">
|
||||
</b-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="grid-filter-date-value-template">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<tailbone-datepicker v-model="startDate"
|
||||
ref="startDate"
|
||||
@input="startDateChanged">
|
||||
</tailbone-datepicker>
|
||||
</div>
|
||||
<div v-show="dateRange"
|
||||
class="level-item">
|
||||
and
|
||||
</div>
|
||||
<div v-show="dateRange"
|
||||
class="level-item">
|
||||
<tailbone-datepicker v-model="endDate"
|
||||
ref="endDate"
|
||||
@input="endDateChanged">
|
||||
</tailbone-datepicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="grid-filter-template">
|
||||
|
||||
<div class="level filter" v-show="filter.visible">
|
||||
<div class="level-left"
|
||||
style="align-items: start;">
|
||||
|
||||
<div class="level-item filter-fieldname">
|
||||
|
||||
<b-field>
|
||||
<b-checkbox-button v-model="filter.active" native-value="IGNORED">
|
||||
<b-icon pack="fas" icon="check" v-show="filter.active"></b-icon>
|
||||
<span>{{ filter.label }}</span>
|
||||
</b-checkbox-button>
|
||||
</b-field>
|
||||
|
||||
</div>
|
||||
|
||||
<b-field grouped v-show="filter.active"
|
||||
class="level-item"
|
||||
style="align-items: start;">
|
||||
|
||||
<b-select v-model="filter.verb"
|
||||
@input="focusValue()"
|
||||
class="filter-verb">
|
||||
<option v-for="verb in filter.verbs"
|
||||
:key="verb"
|
||||
:value="verb">
|
||||
{{ filter.verb_labels[verb] }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
## only one of the following "value input" elements will be rendered
|
||||
|
||||
<grid-filter-date-value v-if="filter.data_type == 'date'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
:date-range="filter.verb == 'between'"
|
||||
ref="valueInput">
|
||||
</grid-filter-date-value>
|
||||
|
||||
<b-select v-if="filter.data_type == 'choice'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
<option v-for="choice in filter.choices"
|
||||
:key="choice"
|
||||
:value="choice">
|
||||
{{ filter.choice_labels[choice] || choice }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
<grid-filter-numeric-value v-if="filter.data_type == 'number'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
:wants-range="filter.verb == 'between'"
|
||||
ref="valueInput">
|
||||
</grid-filter-numeric-value>
|
||||
|
||||
<b-input v-if="filter.data_type == 'string' && !multiValuedVerb()"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
</b-input>
|
||||
|
||||
<b-input v-if="filter.data_type == 'string' && multiValuedVerb()"
|
||||
type="textarea"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
</b-input>
|
||||
|
||||
</b-field>
|
||||
|
||||
</div><!-- level-left -->
|
||||
</div><!-- level -->
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="${grid.component}-template">
|
||||
<div>
|
||||
|
||||
|
|
313
tailbone/templates/grids/filter-components.mako
Normal file
313
tailbone/templates/grids/filter-components.mako
Normal file
|
@ -0,0 +1,313 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
|
||||
<%def name="make_grid_filter_components()">
|
||||
${self.make_grid_filter_numeric_value_component()}
|
||||
${self.make_grid_filter_date_value_component()}
|
||||
${self.make_grid_filter_component()}
|
||||
</%def>
|
||||
|
||||
<%def name="make_grid_filter_numeric_value_component()">
|
||||
<script type="text/x-template" id="grid-filter-numeric-value-template">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<b-input v-model="startValue"
|
||||
ref="startValue"
|
||||
@input="startValueChanged">
|
||||
</b-input>
|
||||
</div>
|
||||
<div v-show="wantsRange"
|
||||
class="level-item">
|
||||
and
|
||||
</div>
|
||||
<div v-show="wantsRange"
|
||||
class="level-item">
|
||||
<b-input v-model="endValue"
|
||||
ref="endValue"
|
||||
@input="endValueChanged">
|
||||
</b-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
|
||||
const GridFilterNumericValue = {
|
||||
template: '#grid-filter-numeric-value-template',
|
||||
props: {
|
||||
value: String,
|
||||
wantsRange: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
startValue: null,
|
||||
endValue: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.wantsRange) {
|
||||
if (this.value.includes('|')) {
|
||||
let values = this.value.split('|')
|
||||
if (values.length == 2) {
|
||||
this.startValue = values[0]
|
||||
this.endValue = values[1]
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
} else {
|
||||
this.startValue = this.value
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// when changing from e.g. 'equal' to 'between' filter verbs,
|
||||
// must proclaim new filter value, to reflect (lack of) range
|
||||
wantsRange(val) {
|
||||
if (val) {
|
||||
this.$emit('input', this.startValue + '|' + this.endValue)
|
||||
} else {
|
||||
this.$emit('input', this.startValue)
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.startValue.focus()
|
||||
},
|
||||
startValueChanged(value) {
|
||||
if (this.wantsRange) {
|
||||
value += '|' + this.endValue
|
||||
}
|
||||
this.$emit('input', value)
|
||||
},
|
||||
endValueChanged(value) {
|
||||
value = this.startValue + '|' + value
|
||||
this.$emit('input', value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Vue.component('grid-filter-numeric-value', GridFilterNumericValue)
|
||||
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="make_grid_filter_date_value_component()">
|
||||
<script type="text/x-template" id="grid-filter-date-value-template">
|
||||
<div class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<tailbone-datepicker v-model="startDate"
|
||||
ref="startDate"
|
||||
@input="startDateChanged">
|
||||
</tailbone-datepicker>
|
||||
</div>
|
||||
<div v-show="dateRange"
|
||||
class="level-item">
|
||||
and
|
||||
</div>
|
||||
<div v-show="dateRange"
|
||||
class="level-item">
|
||||
<tailbone-datepicker v-model="endDate"
|
||||
ref="endDate"
|
||||
@input="endDateChanged">
|
||||
</tailbone-datepicker>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script>
|
||||
|
||||
const GridFilterDateValue = {
|
||||
template: '#grid-filter-date-value-template',
|
||||
props: {
|
||||
value: String,
|
||||
dateRange: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.dateRange) {
|
||||
if (this.value.includes('|')) {
|
||||
let values = this.value.split('|')
|
||||
if (values.length == 2) {
|
||||
this.startDate = values[0]
|
||||
this.endDate = values[1]
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
} else {
|
||||
this.startDate = this.value
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.startDate.focus()
|
||||
},
|
||||
startDateChanged(value) {
|
||||
if (this.dateRange) {
|
||||
value += '|' + this.endDate
|
||||
}
|
||||
this.$emit('input', value)
|
||||
},
|
||||
endDateChanged(value) {
|
||||
value = this.startDate + '|' + value
|
||||
this.$emit('input', value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Vue.component('grid-filter-date-value', GridFilterDateValue)
|
||||
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="make_grid_filter_component()">
|
||||
<script type="text/x-template" id="grid-filter-template">
|
||||
|
||||
<div class="level filter" v-show="filter.visible">
|
||||
<div class="level-left"
|
||||
style="align-items: start;">
|
||||
|
||||
<div class="level-item filter-fieldname">
|
||||
|
||||
<b-field>
|
||||
<b-checkbox-button v-model="filter.active" native-value="IGNORED">
|
||||
<b-icon pack="fas" icon="check" v-show="filter.active"></b-icon>
|
||||
<span>{{ filter.label }}</span>
|
||||
</b-checkbox-button>
|
||||
</b-field>
|
||||
|
||||
</div>
|
||||
|
||||
<b-field grouped v-show="filter.active"
|
||||
class="level-item"
|
||||
style="align-items: start;">
|
||||
|
||||
<b-select v-model="filter.verb"
|
||||
@input="focusValue()"
|
||||
class="filter-verb">
|
||||
<option v-for="verb in filter.verbs"
|
||||
:key="verb"
|
||||
:value="verb">
|
||||
{{ filter.verb_labels[verb] }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
## only one of the following "value input" elements will be rendered
|
||||
|
||||
<grid-filter-date-value v-if="filter.data_type == 'date'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
:date-range="filter.verb == 'between'"
|
||||
ref="valueInput">
|
||||
</grid-filter-date-value>
|
||||
|
||||
<b-select v-if="filter.data_type == 'choice'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
<option v-for="choice in filter.choices"
|
||||
:key="choice"
|
||||
:value="choice">
|
||||
{{ filter.choice_labels[choice] || choice }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
<grid-filter-numeric-value v-if="filter.data_type == 'number'"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
:wants-range="filter.verb == 'between'"
|
||||
ref="valueInput">
|
||||
</grid-filter-numeric-value>
|
||||
|
||||
<b-input v-if="filter.data_type == 'string' && !multiValuedVerb()"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
</b-input>
|
||||
|
||||
<b-input v-if="filter.data_type == 'string' && multiValuedVerb()"
|
||||
type="textarea"
|
||||
v-model="filter.value"
|
||||
v-show="valuedVerb()"
|
||||
ref="valueInput">
|
||||
</b-input>
|
||||
|
||||
</b-field>
|
||||
|
||||
</div><!-- level-left -->
|
||||
</div><!-- level -->
|
||||
|
||||
</script>
|
||||
<script>
|
||||
|
||||
const GridFilter = {
|
||||
template: '#grid-filter-template',
|
||||
props: {
|
||||
filter: Object
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
changeVerb() {
|
||||
// set focus to value input, "as quickly as we can"
|
||||
this.$nextTick(function() {
|
||||
this.focusValue()
|
||||
})
|
||||
},
|
||||
|
||||
valuedVerb() {
|
||||
/* this returns true if the filter's current verb should expose value input(s) */
|
||||
|
||||
// if filter has no "valueless" verbs, then all verbs should expose value inputs
|
||||
if (!this.filter.valueless_verbs) {
|
||||
return true
|
||||
}
|
||||
|
||||
// if filter *does* have valueless verbs, check if "current" verb is valueless
|
||||
if (this.filter.valueless_verbs.includes(this.filter.verb)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// current verb is *not* valueless
|
||||
return true
|
||||
},
|
||||
|
||||
multiValuedVerb() {
|
||||
/* this returns true if the filter's current verb should expose a multi-value input */
|
||||
|
||||
// if filter has no "multi-value" verbs then we safely assume false
|
||||
if (!this.filter.multiple_value_verbs) {
|
||||
return false
|
||||
}
|
||||
|
||||
// if filter *does* have multi-value verbs, see if "current" is one
|
||||
if (this.filter.multiple_value_verbs.includes(this.filter.verb)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// current verb is not multi-value
|
||||
return false
|
||||
},
|
||||
|
||||
focusValue: function() {
|
||||
this.$refs.valueInput.focus()
|
||||
// this.$refs.valueInput.select()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vue.component('grid-filter', GridFilter)
|
||||
|
||||
</script>
|
||||
</%def>
|
|
@ -299,6 +299,11 @@
|
|||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="make_grid_component()">
|
||||
## TODO: stop using |n filter?
|
||||
${grid.render_complete(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
|
||||
</%def>
|
||||
|
||||
<%def name="render_grid_component()">
|
||||
<${grid.component} ref="grid" :csrftoken="csrftoken"
|
||||
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
|
||||
|
@ -309,11 +314,16 @@
|
|||
</%def>
|
||||
|
||||
<%def name="make_this_page_component()">
|
||||
|
||||
## define grid
|
||||
${self.make_grid_component()}
|
||||
|
||||
${parent.make_this_page_component()}
|
||||
<script type="text/javascript">
|
||||
|
||||
${grid.component_studly}.data = function() { return ${grid.component_studly}Data }
|
||||
## finalize grid
|
||||
<script>
|
||||
|
||||
${grid.component_studly}.data = () => { return ${grid.component_studly}Data }
|
||||
Vue.component('${grid.component}', ${grid.component_studly})
|
||||
|
||||
</script>
|
||||
|
@ -323,13 +333,6 @@
|
|||
${self.page_content()}
|
||||
</%def>
|
||||
|
||||
<%def name="render_this_page_template()">
|
||||
${parent.render_this_page_template()}
|
||||
|
||||
## TODO: stop using |n filter
|
||||
${grid.render_complete(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
|
||||
</%def>
|
||||
|
||||
<%def name="modify_this_page_vars()">
|
||||
${parent.modify_this_page_vars()}
|
||||
<script type="text/javascript">
|
||||
|
|
Loading…
Reference in a new issue