From 7b1947914e50d40c357e0343fffc2625e41bc030 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Thu, 23 May 2019 12:10:11 -0500 Subject: [PATCH] Make Buefy grids use proper Vue.js component structure at least, better than before...this lets each page have the final say about the app logic etc. --- tailbone/static/js/tailbone.buefy.grid.js | 168 +++++++ .../static/js/tailbone.buefy.gridfilters.js | 24 - tailbone/templates/grids/buefy.mako | 443 ++++++------------ tailbone/templates/master/index.mako | 22 +- 4 files changed, 340 insertions(+), 317 deletions(-) create mode 100644 tailbone/static/js/tailbone.buefy.grid.js delete mode 100644 tailbone/static/js/tailbone.buefy.gridfilters.js diff --git a/tailbone/static/js/tailbone.buefy.grid.js b/tailbone/static/js/tailbone.buefy.grid.js new file mode 100644 index 00000000..c2720340 --- /dev/null +++ b/tailbone/static/js/tailbone.buefy.grid.js @@ -0,0 +1,168 @@ + +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() + }) + }, + + focusValue: function() { + this.$refs.valueInput.focus() + // this.$refs.valueInput.select() + } + } +} + +Vue.component('grid-filter', GridFilter) + + +let TailboneGrid = { + template: '#tailbone-grid-template', + + methods: { + + getRowClass(row, index) { + return this.rowStatusMap[index] + }, + + loadAsyncData(params) { + + if (params === undefined) { + params = [ + 'partial=true', + `sortkey=${this.sortField}`, + `sortdir=${this.sortOrder}`, + `pagesize=${this.perPage}`, + `page=${this.page}` + ].join('&') + } + + this.loading = true + this.$http.get(`?${params}`).then(({ data }) => { + this.data = data.data + this.rowStatusMap = data.row_status_map + this.total = data.total_items + this.firstItem = data.first_item + this.lastItem = data.last_item + this.loading = false + }) + .catch((error) => { + this.data = [] + this.total = 0 + this.loading = false + throw error + }) + }, + + onPageChange(page) { + this.page = page + this.loadAsyncData() + }, + + onSort(field, order) { + this.sortField = field + this.sortOrder = order + // always reset to first page when changing sort options + // TODO: i mean..right? would we ever not want that? + this.page = 1 + this.loadAsyncData() + }, + + resetView() { + this.loading = true + location.href = '?reset-to-default-filters=true' + }, + + addFilter(filter_key) { + + // reset dropdown so user again sees "Add Filter" placeholder + this.$nextTick(function() { + this.selectedFilter = null + }) + + // show corresponding grid filter + this.filters[filter_key].visible = true + this.filters[filter_key].active = true + + // track down the component + var gridFilter = null + for (var gf of this.$refs.gridFilters) { + if (gf.filter.key == filter_key) { + gridFilter = gf + break + } + } + + // tell component to focus the value field, ASAP + this.$nextTick(function() { + gridFilter.focusValue() + }) + + }, + + applyFilters(params) { + if (params === undefined) { + params = [] + } + + params.push('partial=true') + params.push('filter=true') + + for (var key in this.filters) { + var filter = this.filters[key] + if (filter.active) { + params.push(key + '=' + encodeURIComponent(filter.value)) + params.push(key + '.verb=' + encodeURIComponent(filter.verb)) + } else { + filter.visible = false + } + } + + this.loadAsyncData(params.join('&')) + }, + + clearFilters() { + + // explicitly deactivate all filters + for (var key in this.filters) { + this.filters[key].active = false + } + + // then just "apply" as normal + this.applyFilters() + }, + + saveDefaults() { + + // apply current filters as normal, but add special directive + const params = ['save-current-filters-as-defaults=true'] + this.applyFilters(params) + }, + + deleteResults(event) { + + // submit form if user confirms + // TODO: how/where to get/show "plural model title" here? + // if (confirm("You are about to delete " + this.total + " ${grid.model_title_plural}.\n\nAre you sure?")) { + if (confirm("You are about to delete " + this.total + " objects.\n\nAre you sure?")) { + event.target.form.submit() + } + }, + + checkedRowUUIDs() { + var uuids = []; + for (var row of this.$data.checkedRows) { + uuids.push(row.uuid) + } + return uuids + } + } +} diff --git a/tailbone/static/js/tailbone.buefy.gridfilters.js b/tailbone/static/js/tailbone.buefy.gridfilters.js deleted file mode 100644 index 3a000f23..00000000 --- a/tailbone/static/js/tailbone.buefy.gridfilters.js +++ /dev/null @@ -1,24 +0,0 @@ - -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() - }) - }, - - focusValue: function() { - this.$refs.valueInput.focus() - // this.$refs.valueInput.select() - } - } -} - -Vue.component('grid-filter', GridFilter) diff --git a/tailbone/templates/grids/buefy.mako b/tailbone/templates/grids/buefy.mako index 70d7ea12..82c3d5b7 100644 --- a/tailbone/templates/grids/buefy.mako +++ b/tailbone/templates/grids/buefy.mako @@ -60,311 +60,170 @@ + + +
+ +
diff --git a/tailbone/templates/master/index.mako b/tailbone/templates/master/index.mako index 28ac7da7..4fd3b50a 100644 --- a/tailbone/templates/master/index.mako +++ b/tailbone/templates/master/index.mako @@ -15,7 +15,7 @@ <%def name="extra_javascript()"> ${parent.extra_javascript()} % if use_buefy: - ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.gridfilters.js') + '?ver={}'.format(tailbone.__version__))} + ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.grid.js') + '?ver={}'.format(tailbone.__version__))} % endif + + % if use_buefy: ## TODO: stop using |n filter ${grid.render_buefy(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n} + ${self.make_tailbone_grid_app()} % else: ## no buefy, so do the traditional thing