Add basic checkbox support to new grids.
Also: * Add 'creatable', 'editable' etc. to master view class. * Add styles for warning/notice grid rows. * Misc. other tweaks.
This commit is contained in:
parent
e79531fda8
commit
d2b065a8fc
|
@ -159,5 +159,10 @@ class AlchemyGrid(Grid):
|
||||||
self._fa_grid._set_active(row, orm.object_session(row))
|
self._fa_grid._set_active(row, orm.object_session(row))
|
||||||
yield row
|
yield row
|
||||||
|
|
||||||
|
def get_row_key(self, row):
|
||||||
|
mapper = orm.object_mapper(row)
|
||||||
|
assert len(mapper.primary_key) == 1
|
||||||
|
return getattr(row, mapper.primary_key[0].key)
|
||||||
|
|
||||||
def render_cell(self, row, column):
|
def render_cell(self, row, column):
|
||||||
return column.field.render_readonly()
|
return column.field.render_readonly()
|
||||||
|
|
|
@ -42,7 +42,8 @@ class Grid(object):
|
||||||
joiners={}, filterable=False, filters={},
|
joiners={}, filterable=False, filters={},
|
||||||
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,
|
||||||
width='auto', checkboxes=False, **kwargs):
|
width='auto', checkboxes=False, row_attrs={}, cell_attrs={},
|
||||||
|
**kwargs):
|
||||||
self.key = key
|
self.key = key
|
||||||
self.request = request
|
self.request = request
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
|
@ -73,6 +74,8 @@ class Grid(object):
|
||||||
|
|
||||||
self.width = width
|
self.width = width
|
||||||
self.checkboxes = checkboxes
|
self.checkboxes = checkboxes
|
||||||
|
self.row_attrs = row_attrs
|
||||||
|
self.cell_attrs = cell_attrs
|
||||||
|
|
||||||
def get_default_filters(self):
|
def get_default_filters(self):
|
||||||
"""
|
"""
|
||||||
|
@ -473,6 +476,8 @@ class Grid(object):
|
||||||
classes = ['newgrid']
|
classes = ['newgrid']
|
||||||
if self.width == 'full':
|
if self.width == 'full':
|
||||||
classes.append('full')
|
classes.append('full')
|
||||||
|
if self.checkboxes:
|
||||||
|
classes.append('selectable')
|
||||||
return {'class_': ' '.join(classes),
|
return {'class_': ' '.join(classes),
|
||||||
'data-url': self.request.current_route_url(_query=None),
|
'data-url': self.request.current_route_url(_query=None),
|
||||||
'data-permalink': self.request.current_route_url()}
|
'data-permalink': self.request.current_route_url()}
|
||||||
|
@ -533,16 +538,14 @@ class Grid(object):
|
||||||
|
|
||||||
def get_row_attrs(self, row, i):
|
def get_row_attrs(self, row, i):
|
||||||
"""
|
"""
|
||||||
Returns a properly-formatted set of attributes which will be applied to
|
Returns a dict of HTML attributes which is to be applied to the row's
|
||||||
the ``<tr>`` element for the given row. Note that ``i`` will be a
|
``<tr>`` element. Note that ``i`` will be a 1-based index value for
|
||||||
1-based index value for the row within its table. The meaning of
|
the row within its table. The meaning of ``row`` is basically not
|
||||||
``row`` is basically not defined; it depends on the type of data the
|
defined; it depends on the type of data the grid deals with.
|
||||||
grid deals with.
|
|
||||||
"""
|
"""
|
||||||
# attrs = {'class_': self.get_row_class(row, i)}
|
if callable(self.row_attrs):
|
||||||
# attrs = {}
|
return self.row_attrs(row, i)
|
||||||
# return format_attrs(**attrs)
|
return self.row_attrs
|
||||||
return {}
|
|
||||||
|
|
||||||
# def get_row_class(self, row, i):
|
# def get_row_class(self, row, i):
|
||||||
# class_ = self.default_row_class(row, i)
|
# class_ = self.default_row_class(row, i)
|
||||||
|
@ -552,18 +555,34 @@ class Grid(object):
|
||||||
# class_ = '{0} {1}'.format(class_, extra)
|
# class_ = '{0} {1}'.format(class_, extra)
|
||||||
# return class_
|
# return class_
|
||||||
|
|
||||||
# def checkbox(self, key):
|
def get_row_key(self, row):
|
||||||
# """
|
raise NotImplementedError
|
||||||
# Render a checkbox using the given key.
|
|
||||||
# """
|
def checkbox(self, row):
|
||||||
# return tags.checkbox('checkbox-{0}-{1}'.format(self.key, key))
|
return True
|
||||||
|
|
||||||
|
def checked(self, row):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def render_checkbox(self, row):
|
||||||
|
"""
|
||||||
|
Returns a boolean indicating whether ot not a checkbox should be
|
||||||
|
rendererd for the given row. Default implementation returns ``True``
|
||||||
|
in all cases.
|
||||||
|
"""
|
||||||
|
if not self.checkbox(row):
|
||||||
|
return ''
|
||||||
|
return tags.checkbox('checkbox-{0}-{1}'.format(self.key, self.get_row_key(row)),
|
||||||
|
checked=self.checked(row))
|
||||||
|
|
||||||
def get_cell_attrs(self, row, column):
|
def get_cell_attrs(self, row, column):
|
||||||
"""
|
"""
|
||||||
Returns a dictionary of HTML attributes which should be applied to the
|
Returns a dictionary of HTML attributes which should be applied to the
|
||||||
``<td>`` element in which the given row and column "intersect".
|
``<td>`` element in which the given row and column "intersect".
|
||||||
"""
|
"""
|
||||||
return {}
|
if callable(self.cell_attrs):
|
||||||
|
return self.cell_attrs(row, column)
|
||||||
|
return self.cell_attrs
|
||||||
|
|
||||||
def render_cell(self, row, column):
|
def render_cell(self, row, column):
|
||||||
return ''
|
return ''
|
||||||
|
|
|
@ -44,7 +44,6 @@ p {
|
||||||
}
|
}
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
float: right;
|
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,18 +133,46 @@
|
||||||
* tbody
|
* tbody
|
||||||
******************************/
|
******************************/
|
||||||
|
|
||||||
.newgrid table tbody td {
|
.newgrid tbody td {
|
||||||
padding: 5px 6px;
|
padding: 5px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newgrid table tbody tr:nth-child(odd) {
|
.newgrid.selectable tbody td {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr:nth-child(odd) {
|
||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newgrid table tbody tr.hovering {
|
.newgrid tbody tr.hovering {
|
||||||
background-color: #bbbbbb;
|
background-color: #bbbbbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.notice {
|
||||||
|
background-color: #fd6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.notice:nth-child(odd) {
|
||||||
|
background-color: #fe8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.notice.hovering {
|
||||||
|
background-color: #ec7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.warning {
|
||||||
|
background-color: #fcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.warning:nth-child(odd) {
|
||||||
|
background-color: #ebb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newgrid tbody tr.warning.hovering {
|
||||||
|
background-color: #daa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
* main actions
|
* main actions
|
||||||
|
|
23
tailbone/static/js/jquery.ui.tailbone.js
vendored
23
tailbone/static/js/jquery.ui.tailbone.js
vendored
|
@ -115,6 +115,29 @@
|
||||||
$(this).removeClass('hovering');
|
$(this).removeClass('hovering');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Do some extra stuff for grids with checkboxes.
|
||||||
|
if (this.grid.hasClass('selectable')) {
|
||||||
|
|
||||||
|
// (Un-)Check all rows when clicking check-all box in header.
|
||||||
|
this.element.on('click', 'thead th.checkbox input', function() {
|
||||||
|
var checked = $(this).prop('checked');
|
||||||
|
that.grid.find('tbody td.checkbox input').prop('checked', checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Select current row when clicked, unless clicking checkbox
|
||||||
|
// (since that already does select the row) or a link (since
|
||||||
|
// that does something completely different).
|
||||||
|
this.element.on('click', 'tbody td.checkbox input', function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
this.element.on('click', 'tbody a', function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
this.element.on('click', 'tbody tr', function() {
|
||||||
|
$(this).find('td.checkbox input').click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Show 'more' actions when user hovers over 'more' link.
|
// Show 'more' actions when user hovers over 'more' link.
|
||||||
this.element.on('mouseenter', '.actions a.more', function() {
|
this.element.on('mouseenter', '.actions a.more', function() {
|
||||||
that.grid.find('.actions div.more').hide();
|
that.grid.find('.actions div.more').hide();
|
||||||
|
|
|
@ -112,11 +112,6 @@ $(function() {
|
||||||
$('input[type=submit]').button();
|
$('input[type=submit]').button();
|
||||||
$('input[type=reset]').button();
|
$('input[type=reset]').button();
|
||||||
|
|
||||||
/*
|
|
||||||
* Enhance new-style grids.
|
|
||||||
*/
|
|
||||||
$('.newgrid-wrapper').gridwrapper();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When filter labels are clicked, (un)check the associated checkbox.
|
* When filter labels are clicked, (un)check the associated checkbox.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -131,7 +131,6 @@
|
||||||
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')}
|
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.menubar.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.menubar.js'))}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.loadmask.min.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.loadmask.min.js'))}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js'))}
|
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
<%def name="context_menu_items()">
|
<%def name="context_menu_items()">
|
||||||
<li>${h.link_to("Back to {0}".format(model_title_plural), url(route_prefix))}</li>
|
<li>${h.link_to("Back to {0}".format(model_title_plural), url(route_prefix))}</li>
|
||||||
% if request.has_perm('{0}.view'.format(permission_prefix)):
|
% if master.viewable and request.has_perm('{0}.view'.format(permission_prefix)):
|
||||||
<li>${h.link_to("View this {0}".format(model_title), action_url('view', instance))}</li>
|
<li>${h.link_to("View this {0}".format(model_title), action_url('view', instance))}</li>
|
||||||
% endif
|
% endif
|
||||||
% if request.has_perm('{0}.delete'.format(permission_prefix)):
|
% if master.deletable and request.has_perm('{0}.delete'.format(permission_prefix)):
|
||||||
<li>${h.link_to("Delete this {0}".format(model_title), action_url('delete', instance))}</li>
|
<li>${h.link_to("Delete this {0}".format(model_title), action_url('delete', instance))}</li>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -9,8 +9,18 @@
|
||||||
|
|
||||||
<%def name="title()">${grid.model_title_plural}</%def>
|
<%def name="title()">${grid.model_title_plural}</%def>
|
||||||
|
|
||||||
|
<%def name="head_tags()">
|
||||||
|
${parent.head_tags()}
|
||||||
|
${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js'))}
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
$('.newgrid-wrapper').gridwrapper();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="context_menu_items()">
|
<%def name="context_menu_items()">
|
||||||
% if request.has_perm('{0}.create'.format(grid.permission_prefix)):
|
% if master.creatable and request.has_perm('{0}.create'.format(grid.permission_prefix)):
|
||||||
<li>${h.link_to("Create a new {0}".format(grid.model_title), url('{0}.create'.format(grid.route_prefix)))}</li>
|
<li>${h.link_to("Create a new {0}".format(grid.model_title), url('{0}.create'.format(grid.route_prefix)))}</li>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
<%def name="context_menu_items()">
|
<%def name="context_menu_items()">
|
||||||
<li>${h.link_to("Back to {0}".format(model_title_plural), url(route_prefix))}</li>
|
<li>${h.link_to("Back to {0}".format(model_title_plural), url(route_prefix))}</li>
|
||||||
% if request.has_perm('{0}.edit'.format(permission_prefix)):
|
% if master.editable and request.has_perm('{0}.edit'.format(permission_prefix)):
|
||||||
<li>${h.link_to("Edit this {0}".format(model_title), action_url('edit', instance))}</li>
|
<li>${h.link_to("Edit this {0}".format(model_title), action_url('edit', instance))}</li>
|
||||||
% endif
|
% endif
|
||||||
% if request.has_perm('{0}.delete'.format(permission_prefix)):
|
% if master.deletable and master.deletable_instance(instance) and request.has_perm('{0}.delete'.format(permission_prefix)):
|
||||||
<li>${h.link_to("Delete this {0}".format(model_title), action_url('delete', instance))}</li>
|
<li>${h.link_to("Delete this {0}".format(model_title), action_url('delete', instance))}</li>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
## % if grid.checkboxes:
|
% if grid.checkboxes:
|
||||||
## <th class="checkbox">${h.checkbox('check-all')}</th>
|
<th class="checkbox">${h.checkbox('check-all')}</th>
|
||||||
## % endif
|
% endif
|
||||||
% for column in grid.iter_visible_columns():
|
% for column in grid.iter_visible_columns():
|
||||||
${grid.column_header(column)}
|
${grid.column_header(column)}
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -17,9 +17,9 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
% for i, row in enumerate(grid.iter_rows(), 1):
|
% for i, row in enumerate(grid.iter_rows(), 1):
|
||||||
<tr ${format_attrs(**grid.get_row_attrs(row, i))}>
|
<tr ${format_attrs(**grid.get_row_attrs(row, i))}>
|
||||||
## % if grid.checkboxes:
|
% if grid.checkboxes:
|
||||||
## <td class="checkbox">${grid.checkbox(row)}</td>
|
<td class="checkbox">${grid.render_checkbox(row)}</td>
|
||||||
## % endif
|
% endif
|
||||||
% for column in grid.iter_visible_columns():
|
% for column in grid.iter_visible_columns():
|
||||||
<td ${format_attrs(**grid.get_cell_attrs(row, column))}>${grid.render_cell(row, column)}</td>
|
<td ${format_attrs(**grid.get_cell_attrs(row, column))}>${grid.render_cell(row, column)}</td>
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
% endfor
|
% endfor
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
% if grid.pageable:
|
% if grid.pageable and grid.pager:
|
||||||
<div class="pager">
|
<div class="pager">
|
||||||
<p class="showing">
|
<p class="showing">
|
||||||
showing ${grid.pager.first_item} thru ${grid.pager.last_item} of ${grid.pager.item_count}
|
showing ${grid.pager.first_item} thru ${grid.pager.last_item} of ${grid.pager.item_count}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
${h.javascript_link('https://code.jquery.com/jquery-1.11.3.min.js')}
|
${h.javascript_link('https://code.jquery.com/jquery-1.11.3.min.js')}
|
||||||
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')}
|
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.menubar.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.menubar.js'))}
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js'))}
|
|
||||||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
|
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
|
||||||
${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))}
|
${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))}
|
||||||
${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))}
|
${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))}
|
||||||
|
|
|
@ -45,11 +45,19 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
Base "master" view class. All model master views should derive from this.
|
Base "master" view class. All model master views should derive from this.
|
||||||
"""
|
"""
|
||||||
|
creatable = True
|
||||||
|
viewable = True
|
||||||
|
editable = True
|
||||||
|
deletable = True
|
||||||
|
|
||||||
creating = False
|
creating = False
|
||||||
viewing = False
|
viewing = False
|
||||||
editing = False
|
editing = False
|
||||||
deleting = False
|
deleting = False
|
||||||
|
|
||||||
|
row_attrs = {}
|
||||||
|
cell_attrs = {}
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Available Views
|
# Available Views
|
||||||
##############################
|
##############################
|
||||||
|
@ -123,13 +131,10 @@ class MasterView(View):
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Flush immediately to force any pending integrity errors etc.; that
|
self.delete_instance(instance)
|
||||||
# way we don't set flash message until we know we have success.
|
|
||||||
Session.delete(instance)
|
|
||||||
Session.flush()
|
|
||||||
self.request.session.flash("{0} {1} has been deleted.".format(
|
self.request.session.flash("{0} {1} has been deleted.".format(
|
||||||
self.get_model_title(), instance))
|
self.get_model_title(), instance))
|
||||||
return HTTPFound(location=self.get_index_url())
|
return self.redirect(self.get_after_delete_url(instance))
|
||||||
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
|
@ -237,6 +242,7 @@ class MasterView(View):
|
||||||
the template prefix.
|
the template prefix.
|
||||||
"""
|
"""
|
||||||
data.update({
|
data.update({
|
||||||
|
'master': self,
|
||||||
'model_title': self.get_model_title(),
|
'model_title': self.get_model_title(),
|
||||||
'model_title_plural': self.get_model_title_plural(),
|
'model_title_plural': self.get_model_title_plural(),
|
||||||
'route_prefix': self.get_route_prefix(),
|
'route_prefix': self.get_route_prefix(),
|
||||||
|
@ -300,28 +306,55 @@ class MasterView(View):
|
||||||
'pageable': True,
|
'pageable': True,
|
||||||
'main_actions': self.get_main_actions(),
|
'main_actions': self.get_main_actions(),
|
||||||
'more_actions': self.get_more_actions(),
|
'more_actions': self.get_more_actions(),
|
||||||
|
'checkbox': self.checkbox,
|
||||||
|
'checked': self.checked,
|
||||||
|
'row_attrs': self.get_row_attrs,
|
||||||
|
'cell_attrs': self.get_cell_attrs,
|
||||||
'model_title': self.get_model_title(),
|
'model_title': self.get_model_title(),
|
||||||
'model_title_plural': self.get_model_title_plural(),
|
'model_title_plural': self.get_model_title_plural(),
|
||||||
'permission_prefix': self.get_permission_prefix(),
|
'permission_prefix': self.get_permission_prefix(),
|
||||||
'route_prefix': self.get_route_prefix(),
|
'route_prefix': self.get_route_prefix(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def get_row_attrs(self, row, i):
|
||||||
|
"""
|
||||||
|
Returns a dict of HTML attributes which is to be applied to the row's
|
||||||
|
``<tr>`` element. Note that ``i`` will be a 1-based index value for
|
||||||
|
the row within its table. The meaning of ``row`` is basically not
|
||||||
|
defined; it depends on the type of data the grid deals with.
|
||||||
|
"""
|
||||||
|
if callable(self.row_attrs):
|
||||||
|
return self.row_attrs(row, i)
|
||||||
|
return self.row_attrs
|
||||||
|
|
||||||
|
def get_cell_attrs(self, row, column):
|
||||||
|
"""
|
||||||
|
Returns a dictionary of HTML attributes which should be applied to the
|
||||||
|
``<td>`` element in which the given row and column "intersect".
|
||||||
|
"""
|
||||||
|
if callable(self.cell_attrs):
|
||||||
|
return self.cell_attrs(row, column)
|
||||||
|
return self.cell_attrs
|
||||||
|
|
||||||
def get_main_actions(self):
|
def get_main_actions(self):
|
||||||
"""
|
"""
|
||||||
Return a list of 'main' actions for the grid.
|
Return a list of 'main' actions for the grid.
|
||||||
"""
|
"""
|
||||||
return [
|
actions = []
|
||||||
self.make_action('view', icon='zoomin'),
|
if self.viewable:
|
||||||
]
|
actions.append(self.make_action('view', icon='zoomin'))
|
||||||
|
return actions
|
||||||
|
|
||||||
def get_more_actions(self):
|
def get_more_actions(self):
|
||||||
"""
|
"""
|
||||||
Return a list of 'more' actions for the grid.
|
Return a list of 'more' actions for the grid.
|
||||||
"""
|
"""
|
||||||
return [
|
actions = []
|
||||||
self.make_action('edit', icon='pencil'),
|
if self.editable:
|
||||||
self.make_action('delete', icon='trash'),
|
actions.append(self.make_action('edit', icon='pencil'))
|
||||||
]
|
if self.deletable:
|
||||||
|
actions.append(self.make_action('delete', icon='trash'))
|
||||||
|
return actions
|
||||||
|
|
||||||
def make_action(self, key, **kwargs):
|
def make_action(self, key, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -350,6 +383,7 @@ class MasterView(View):
|
||||||
data = self.make_query()
|
data = self.make_query()
|
||||||
kwargs = self.make_grid_kwargs()
|
kwargs = self.make_grid_kwargs()
|
||||||
grid = factory(key, self.request, data=data, model_class=self.model_class, **kwargs)
|
grid = factory(key, self.request, data=data, model_class=self.model_class, **kwargs)
|
||||||
|
grid._fa_grid.prettify = prettify
|
||||||
self.configure_grid(grid)
|
self.configure_grid(grid)
|
||||||
grid.load_settings()
|
grid.load_settings()
|
||||||
return grid
|
return grid
|
||||||
|
@ -387,6 +421,21 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
return session.query(self.model_class)
|
return session.query(self.model_class)
|
||||||
|
|
||||||
|
def checkbox(self, instance):
|
||||||
|
"""
|
||||||
|
Returns a boolean indicating whether ot not a checkbox should be
|
||||||
|
rendererd for the given row. Default implementation returns ``True``
|
||||||
|
in all cases.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
def checked(self, instance):
|
||||||
|
"""
|
||||||
|
Returns a boolean indicating whether ot not a checkbox should be
|
||||||
|
checked by default, for the given row. Default implementation returns
|
||||||
|
``False`` in all cases.
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# CRUD Stuff
|
# CRUD Stuff
|
||||||
|
@ -445,11 +494,39 @@ class MasterView(View):
|
||||||
Event hook, called just after an existing instance is saved.
|
Event hook, called just after an existing instance is saved.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def deletable_instance(self, instance):
|
||||||
|
"""
|
||||||
|
Returns boolean indicating whether or not the given instance can be
|
||||||
|
considered "deletable". Returns ``True`` by default; override as
|
||||||
|
necessary.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
def before_delete(self, instance):
|
def before_delete(self, instance):
|
||||||
"""
|
"""
|
||||||
Event hook, called just before deletion is attempted.
|
Event hook, called just before deletion is attempted.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def delete_instance(self, instance):
|
||||||
|
"""
|
||||||
|
Delete the instance, or mark it as deleted, or whatever you need to do.
|
||||||
|
"""
|
||||||
|
# Flush immediately to force any pending integrity errors etc.; that
|
||||||
|
# way we don't set flash message until we know we have success.
|
||||||
|
Session.delete(instance)
|
||||||
|
Session.flush()
|
||||||
|
|
||||||
|
def get_after_delete_url(self, instance):
|
||||||
|
"""
|
||||||
|
Returns the URL to which the user should be redirected after
|
||||||
|
successfully "deleting" the given instance.
|
||||||
|
"""
|
||||||
|
if hasattr(self, 'after_delete_url'):
|
||||||
|
if callable(self.after_delete_url):
|
||||||
|
return self.after_delete_url(instance)
|
||||||
|
return self.after_delete_url
|
||||||
|
return self.get_index_url()
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Config Stuff
|
# Config Stuff
|
||||||
##############################
|
##############################
|
||||||
|
@ -476,13 +553,15 @@ class MasterView(View):
|
||||||
"List/Search {0}".format(model_title_plural))
|
"List/Search {0}".format(model_title_plural))
|
||||||
|
|
||||||
# create
|
# create
|
||||||
|
if cls.creatable:
|
||||||
config.add_route('{0}.create'.format(route_prefix), '{0}/new'.format(url_prefix))
|
config.add_route('{0}.create'.format(route_prefix), '{0}/new'.format(url_prefix))
|
||||||
config.add_view(cls, attr='create', route_name='{0}.create'.format(route_prefix),
|
config.add_view(cls, attr='create', route_name='{0}.create'.format(route_prefix),
|
||||||
permission='{0}.create'.format(permission_prefix))
|
permission='{0}.create'.format(permission_prefix))
|
||||||
config.add_tailbone_permission(permission_prefix, '{0}.create'.format(permission_prefix),
|
config.add_tailbone_permission(permission_prefix, '{0}.create'.format(permission_prefix),
|
||||||
"Create new {0}".format(model_title_plural))
|
"Create new {0}".format(model_title))
|
||||||
|
|
||||||
# view
|
# view
|
||||||
|
if cls.viewable:
|
||||||
config.add_route('{0}.view'.format(route_prefix), '{0}/{{{1}}}'.format(url_prefix, model_key))
|
config.add_route('{0}.view'.format(route_prefix), '{0}/{{{1}}}'.format(url_prefix, model_key))
|
||||||
config.add_view(cls, attr='view', route_name='{0}.view'.format(route_prefix),
|
config.add_view(cls, attr='view', route_name='{0}.view'.format(route_prefix),
|
||||||
permission='{0}.view'.format(permission_prefix))
|
permission='{0}.view'.format(permission_prefix))
|
||||||
|
@ -490,15 +569,17 @@ class MasterView(View):
|
||||||
"View {0} Details".format(model_title))
|
"View {0} Details".format(model_title))
|
||||||
|
|
||||||
# edit
|
# edit
|
||||||
|
if cls.editable:
|
||||||
config.add_route('{0}.edit'.format(route_prefix), '{0}/{{{1}}}/edit'.format(url_prefix, model_key))
|
config.add_route('{0}.edit'.format(route_prefix), '{0}/{{{1}}}/edit'.format(url_prefix, model_key))
|
||||||
config.add_view(cls, attr='edit', route_name='{0}.edit'.format(route_prefix),
|
config.add_view(cls, attr='edit', route_name='{0}.edit'.format(route_prefix),
|
||||||
permission='{0}.edit'.format(permission_prefix))
|
permission='{0}.edit'.format(permission_prefix))
|
||||||
config.add_tailbone_permission(permission_prefix, '{0}.edit'.format(permission_prefix),
|
config.add_tailbone_permission(permission_prefix, '{0}.edit'.format(permission_prefix),
|
||||||
"Edit {0}".format(model_title_plural))
|
"Edit {0}".format(model_title))
|
||||||
|
|
||||||
# delete
|
# delete
|
||||||
|
if cls.deletable:
|
||||||
config.add_route('{0}.delete'.format(route_prefix), '{0}/{{{1}}}/delete'.format(url_prefix, model_key))
|
config.add_route('{0}.delete'.format(route_prefix), '{0}/{{{1}}}/delete'.format(url_prefix, model_key))
|
||||||
config.add_view(cls, attr='delete', route_name='{0}.delete'.format(route_prefix),
|
config.add_view(cls, attr='delete', route_name='{0}.delete'.format(route_prefix),
|
||||||
permission='{0}.delete'.format(permission_prefix))
|
permission='{0}.delete'.format(permission_prefix))
|
||||||
config.add_tailbone_permission(permission_prefix, '{0}.delete'.format(permission_prefix),
|
config.add_tailbone_permission(permission_prefix, '{0}.delete'.format(permission_prefix),
|
||||||
"Delete {0}".format(model_title_plural))
|
"Delete {0}".format(model_title))
|
||||||
|
|
Loading…
Reference in a new issue