diff --git a/browser/common.py b/browser/common.py index f019673..f216f5e 100644 --- a/browser/common.py +++ b/browser/common.py @@ -132,7 +132,55 @@ class EditForm(form.EditForm): return parentUrl + '/contents.html' -class BaseView(GenericView, I18NView): +class SortableMixin(object): + + @Lazy + def sortInfo(self): + result = {} + for k, v in self.request.form.items(): + if k.startswith('sortinfo_'): + tableName = k[len('sortinfo_'):] + if ',' in v: + fn, dir = v.split(',') + else: + fn = v + dir = 'asc' + result[tableName] = dict(colName=fn, ascending=(dir=='asc')) + return result + + def isSortableColumn(self, tableName, colName): + return False # overwrite in subclass + + def getSortUrl(self, tableName, colName): + url = str(self.request.URL) + paramChar = '?' in url and '&' or '?' + si = self.sortInfo.get(tableName) + if si is not None and si.get('colName') == colName: + dir = si['ascending'] and 'desc' or 'asc' + else: + dir = 'asc' + return '%s%ssortinfo_%s=%s,%s' % (url, paramChar, tableName, colName, dir) + + def getSortParams(self, tableName): + url = str(self.request.URL) + paramChar = '?' in url and '&' or '?' + si = self.sortInfo.get(tableName) + if si is not None: + colName = si['colName'] + dir = si['ascending'] and 'asc' or 'desc' + return '%ssortinfo_%s=%s,%s' % (paramChar, tableName, colName, dir) + return '' + + def getSortImage(self, tableName, colName): + si = self.sortInfo.get(tableName) + if si is not None and si.get('colName') == colName: + if si['ascending']: + return '/@@/cybertools.icons/arrowdown.gif' + else: + return '/@@/cybertools.icons/arrowup.gif' + + +class BaseView(GenericView, I18NView, SortableMixin): actions = {} portlet_actions = [] diff --git a/expert/browser/report.py b/expert/browser/report.py index c3e1456..ed8c892 100644 --- a/expert/browser/report.py +++ b/expert/browser/report.py @@ -192,6 +192,13 @@ class ResultsConceptView(ConceptView): ri = component.getAdapter(self.report, IReportInstance, name=reportType) ri.view = self + if not ri.sortCriteria: + si = self.sortInfo.get('results') + if si is not None: + fnames = (si['colName'],) + ri.sortCriteria = [f for f in ri.getSortFields() + if f.name in fnames] + ri.sortDescending = not si['ascending'] return ri def results(self): @@ -212,6 +219,12 @@ class ResultsConceptView(ConceptView): if opt: return opt[0] + def isSortableColumn(self, tableName, colName): + if tableName == 'results': + if colName in [f.name for f in self.reportInstance.getSortFields()]: + return True + return False + class EmbeddedResultsConceptView(ResultsConceptView): diff --git a/expert/browser/results.pt b/expert/browser/results.pt index 62a9085..e7252de 100644 --- a/expert/browser/results.pt +++ b/expert/browser/results.pt @@ -35,38 +35,50 @@ -
+

Download Data + tal:define="params python:item.getSortParams(tableName)" + tal:attributes="href string:${item/downloadLink}$params">Download Data

- - + - +
+ + + + + +
- - + +
- - + +
diff --git a/expert/report.py b/expert/report.py index bbab6ac..2b75172 100644 --- a/expert/report.py +++ b/expert/report.py @@ -120,7 +120,9 @@ class ReportInstance(BaseReport): result = list(self.selectObjects(parts)) # may modify parts qc = CompoundQueryCriteria(parts) return ResultSet(self, result, rowFactory=self.rowFactory, - sortCriteria=self.getSortCriteria(), queryCriteria=qc, + sortCriteria=self.getSortCriteria(), + sortDescending=self.sortDescending, + queryCriteria=qc, limits=limits) def selectObjects(self, parts):