diff --git a/tailbone/templates/master/view.mako b/tailbone/templates/master/view.mako
index 22bdfb00..fcddff05 100644
--- a/tailbone/templates/master/view.mako
+++ b/tailbone/templates/master/view.mako
@@ -3,6 +3,23 @@
<%def name="title()">${model_title}: ${instance_title}%def>
+<%def name="head_tags()">
+ ${parent.head_tags()}
+ % if master.has_rows:
+ ${h.javascript_link(request.static_url('tailbone:static/js/jquery.ui.tailbone.js'))}
+
+
+ % endif
+%def>
+
<%def name="context_menu_items()">
${h.link_to("Back to {}".format(model_title_plural), index_url)}
${h.link_to("Permalink for this {}".format(model_title), action_url('view', instance))}
@@ -24,3 +41,7 @@
${form.render()|n}
+
+% if master.has_rows:
+ ${rows_grid|n}
+% endif
diff --git a/tailbone/views/master.py b/tailbone/views/master.py
index 562755ed..acf6e9bf 100644
--- a/tailbone/views/master.py
+++ b/tailbone/views/master.py
@@ -37,7 +37,7 @@ import formalchemy
from pyramid import httpexceptions
from pyramid.renderers import get_renderer, render_to_response, render
-from tailbone import forms
+from tailbone import forms, newgrids as grids
from tailbone.views import View
from tailbone.newgrids import filters, AlchemyGrid, GridAction
@@ -67,6 +67,11 @@ class MasterView(View):
grid_index = None
use_index_links = False
+ # ROW-RELATED ATTRS FOLLOW:
+
+ has_rows = False
+ model_row_class = None
+
@property
def Session(self):
"""
@@ -139,12 +144,105 @@ class MasterView(View):
if instance is None:
instance = self.get_instance()
form = self.make_form(instance)
- return self.render_to_response('view', {
+ if self.has_rows:
+
+ # If user just refreshed the page with a reset instruction, issue a
+ # redirect in order to clear out the query string.
+ if self.request.GET.get('reset-to-default-filters') == 'true':
+ return self.redirect(self.request.current_route_url(_query=None))
+
+ grid = self.make_row_grid(instance=instance)
+ if self.request.params.get('partial'):
+ self.request.response.content_type = b'text/html'
+ self.request.response.text = grid.render_grid()
+ return self.request.response
+
+ context = {
'instance': instance,
'instance_title': self.get_instance_title(instance),
'instance_editable': self.editable_instance(instance),
'instance_deletable': self.deletable_instance(instance),
- 'form': form})
+ 'form': form,
+ }
+ if self.has_rows:
+ context['rows_grid'] = grid.render_complete(allow_save_defaults=False,
+ tools=self.make_row_grid_tools())
+ return self.render_to_response('view', context)
+
+ def make_row_grid_tools(self):
+ pass
+
+ def make_row_grid(self, **kwargs):
+ """
+ Make and return a new (configured) rows grid instance.
+ """
+ instance = kwargs.pop('instance', self.get_instance())
+ data = self.get_row_data(instance)
+ kwargs = self.make_row_grid_kwargs(**kwargs)
+ key = '{}.{}'.format(self.get_grid_key(), self.request.matchdict[self.get_model_key()])
+ grid = grids.AlchemyGrid(key, self.request, data=data, model_class=self.model_row_class, **kwargs)
+ self._preconfigure_row_grid(grid)
+ self.configure_row_grid(grid)
+ grid.load_settings()
+ return grid
+
+ def _preconfigure_row_grid(self, g):
+ pass
+
+ def configure_row_grid(self, grid):
+ grid.configure()
+
+ def get_row_data(self, instance):
+ """
+ Generate the base data set for a rows grid.
+ """
+ raise NotImplementedError
+
+ @classmethod
+ def get_row_route_prefix(cls):
+ """
+ Route prefix specific to the row-level views for a batch, e.g.
+ ``'vendorcatalogs.rows'``.
+ """
+ return "{}.rows".format(cls.get_route_prefix())
+
+ @classmethod
+ def get_row_permission_prefix(cls):
+ """
+ Permission prefix specific to the row-level data for this batch type,
+ e.g. ``'vendorcatalogs.rows'``.
+ """
+ return "{}.rows".format(cls.get_permission_prefix())
+
+ def make_row_grid_kwargs(self, **kwargs):
+ """
+ Return a dict of kwargs to be used when constructing a new rows grid.
+ """
+ route_prefix = self.get_row_route_prefix()
+ permission_prefix = self.get_row_permission_prefix()
+
+ defaults = {
+ 'width': 'full',
+ 'filterable': True,
+ 'sortable': True,
+ 'pageable': True,
+ 'row_attrs': self.row_grid_row_attrs,
+ 'model_title': self.get_row_model_title(),
+ 'model_title_plural': self.get_row_model_title_plural(),
+ 'permission_prefix': permission_prefix,
+ 'route_prefix': route_prefix,
+ }
+ defaults.update(kwargs)
+ return defaults
+
+ def row_grid_row_attrs(self, row, i):
+ return {}
+
+ def get_row_model_title(self):
+ return "{} Row".format(self.get_model_title())
+
+ def get_row_model_title_plural(self):
+ return "{} Rows".format(self.get_model_title())
def view_index(self):
"""