Improve checkbox click handling support for grids

i.e. let custom use define click handlers
This commit is contained in:
Lance Edgar 2019-10-31 17:55:44 -05:00
parent a857d31776
commit bcfb4f257d
5 changed files with 96 additions and 10 deletions

View file

@ -73,7 +73,8 @@ class Grid(object):
joiners={}, filterable=False, filters={}, use_byte_string_filters=False, joiners={}, filterable=False, filters={}, use_byte_string_filters=False,
sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc', sortable=False, sorters={}, default_sortkey=None, default_sortdir='asc',
pageable=False, default_pagesize=20, default_page=1, pageable=False, default_pagesize=20, default_page=1,
checkboxes=False, checked=None, main_actions=[], more_actions=[], delete_speedbump=False, checkboxes=False, checked=None, check_handler=None, check_all_handler=None,
main_actions=[], more_actions=[], delete_speedbump=False,
ajax_data_url=None, ajax_data_url=None,
**kwargs): **kwargs):
@ -124,6 +125,9 @@ class Grid(object):
self.checked = checked self.checked = checked
if self.checked is None: if self.checked is None:
self.checked = lambda item: False self.checked = lambda item: False
self.check_handler = check_handler
self.check_all_handler = check_all_handler
self.main_actions = main_actions or [] self.main_actions = main_actions or []
self.more_actions = more_actions or [] self.more_actions = more_actions or []
self.delete_speedbump = delete_speedbump self.delete_speedbump = delete_speedbump
@ -1155,6 +1159,7 @@ class Grid(object):
raw_data = self.make_visible_data() raw_data = self.make_visible_data()
data = [] data = []
status_map = {} status_map = {}
checked = []
# iterate over data rows # iterate over data rows
for i in range(len(raw_data)): for i in range(len(raw_data)):
@ -1197,6 +1202,11 @@ class Grid(object):
if status: if status:
status_map[i] = status status_map[i] = status
# set checked flag if applicable
if self.checkboxes:
if self.checked(rowobj):
checked.append(i)
data.append(row) data.append(row)
results = { results = {
@ -1204,6 +1214,13 @@ class Grid(object):
'row_status_map': status_map, 'row_status_map': status_map,
} }
if self.checkboxes:
results['checked_rows'] = checked
# TODO: this seems a bit hacky, but is required for now to
# initialize things on the client side...
results['checked_rows_code'] = '[{}]'.format(
', '.join(['TailboneGridCurrentData[{}]'.format(i) for i in checked]))
if self.pageable and self.pager is not None: if self.pageable and self.pager is not None:
results['total_items'] = self.pager.item_count results['total_items'] = self.pager.item_count
results['per_page'] = self.pager.items_per_page results['per_page'] = self.pager.items_per_page

View file

@ -93,6 +93,10 @@ Vue.component('grid-filter', GridFilter)
let TailboneGrid = { let TailboneGrid = {
template: '#tailbone-grid-template', template: '#tailbone-grid-template',
props: {
csrftoken: String,
},
computed: { computed: {
// note, can use this with v-model for hidden 'uuids' fields // note, can use this with v-model for hidden 'uuids' fields
selected_uuids: function() { selected_uuids: function() {
@ -120,14 +124,14 @@ let TailboneGrid = {
this.loading = true this.loading = true
this.$http.get(`${this.ajaxDataUrl}?${params}`).then(({ data }) => { this.$http.get(`${this.ajaxDataUrl}?${params}`).then(({ data }) => {
this.data = data.data TailboneGridCurrentData = data.data
this.data = TailboneGridCurrentData
this.rowStatusMap = data.row_status_map this.rowStatusMap = data.row_status_map
this.total = data.total_items this.total = data.total_items
this.firstItem = data.first_item this.firstItem = data.first_item
this.lastItem = data.last_item this.lastItem = data.last_item
this.loading = false this.loading = false
// TODO: should "merge" checked results from server? this.checkedRows = this.locateCheckedRows(data.checked_rows)
this.checkedRows = []
}) })
.catch((error) => { .catch((error) => {
this.data = [] this.data = []
@ -137,6 +141,18 @@ let TailboneGrid = {
}) })
}, },
locateCheckedRows(checked) {
let rows = []
if (checked) {
for (let i = 0; i < this.data.length; i++) {
if (checked.includes(i)) {
rows.push(this.data[i])
}
}
}
return rows
},
onPageChange(page) { onPageChange(page) {
this.page = page this.page = page
this.loadAsyncData() this.loadAsyncData()
@ -244,6 +260,14 @@ let TailboneGrid = {
uuids.push(row.uuid) uuids.push(row.uuid)
} }
return uuids return uuids
} },
allRowUUIDs() {
let uuids = []
for (let row of this.data) {
uuids.push(row.uuid)
}
return uuids
},
} }
} }

View file

@ -5,10 +5,45 @@
* Add "row status" styles for Buefy grid tables. * Add "row status" styles for Buefy grid tables.
********************************************************************************/ ********************************************************************************/
/**************************************************
* grid rows with "warning" status
**************************************************/
tr.warning { tr.warning {
background-color: #fcc; background-color: #fcc;
} }
/**************************************************
* grid rows with "notice" status
**************************************************/
tr.notice { tr.notice {
background-color: #fe8; background-color: #fe8;
} }
/**************************************************
* grid rows which are "checked" (selected)
**************************************************/
/* TODO: this references some color values, whereas it would be preferable
* to refer to some sort of "state" instead, color of which was
* configurable. b/c these are just the default Buefy theme colors. */
tr.is-checked {
background-color: #7957d5;
color: white;
}
tr.is-checked:hover {
color: #363636;
}
tr.is-checked a {
color: white;
}
tr.is-checked:hover a {
color: #7957d5;
}

View file

@ -131,7 +131,15 @@
:row-class="getRowClass" :row-class="getRowClass"
:checkable="checkable" :checkable="checkable"
% if grid.checkboxes:
:checked-rows.sync="checkedRows" :checked-rows.sync="checkedRows"
% endif
% if grid.check_handler:
@check="${grid.check_handler}"
% endif
% if grid.check_all_handler:
@check-all="${grid.check_all_handler}"
% endif
## TODO: definitely will be wanting this... ## TODO: definitely will be wanting this...
## :is-row-checkable="" ## :is-row-checkable=""
@ -228,18 +236,20 @@
<script type="text/javascript"> <script type="text/javascript">
let TailboneGridCurrentData = ${json.dumps(grid_data['data'])|n}
let TailboneGridData = { let TailboneGridData = {
loading: false, loading: false,
checkedRows: [],
selectedFilter: null, selectedFilter: null,
ajaxDataUrl: ${json.dumps(grid.ajax_data_url)|n}, ajaxDataUrl: ${json.dumps(grid.ajax_data_url)|n},
data: ${json.dumps(grid_data['data'])|n}, data: TailboneGridCurrentData,
rowStatusMap: ${json.dumps(grid_data['row_status_map'])|n}, rowStatusMap: ${json.dumps(grid_data['row_status_map'])|n},
checkable: ${json.dumps(grid.checkboxes)|n}, checkable: ${json.dumps(grid.checkboxes)|n},
## TODO: should be dumping json from server here? % if grid.checkboxes:
## checkedRows: [], checkedRows: ${grid_data['checked_rows_code']|n},
% endif
paginated: ${json.dumps(grid.pageable)|n}, paginated: ${json.dumps(grid.pageable)|n},
total: ${len(grid_data['data']) if static_data else grid_data['total_items']}, total: ${len(grid_data['data']) if static_data else grid_data['total_items']},

View file

@ -253,7 +253,7 @@
</%def> </%def>
<%def name="page_content()"> <%def name="page_content()">
<tailbone-grid <tailbone-grid :csrftoken="csrftoken"
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple': % if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
@deleteActionClicked="deleteObject" @deleteActionClicked="deleteObject"
% endif % endif