From abbc66b13dfd6455c6850863382be9bfde1e9fe6 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Wed, 23 Sep 2020 07:50:35 -0400 Subject: [PATCH 01/17] 2202 add deselect to next_sort helper text --- seeker/views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 8b87425..79e91ac 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -102,13 +102,13 @@ def header(self): q['s'] = '%s%s' % (d, self.field) else: q['s'] = self.field - next_sort = 'descending' if sort == 'Ascending' else 'ascending' + next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' sr_label = (' (%s)' % sort) if sort else '' if self.field_definition: span = ''.format(self.field_definition) else: span = '' - html = '%s%s %s' % (cls, q.urlencode(), next_sort, q['s'], self.header_html, sr_label, span) + html = '%s%s %s' % (cls, q.urlencode(), next_sort, q['s'], self.header_html, sr_label, span) return mark_safe(html) def context(self, result, **kwargs): @@ -1077,7 +1077,7 @@ def header(self, results=None): else: data_sort = self.field - next_sort = 'descending' if sort == 'Ascending' else 'ascending' + next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' sr_label = (' (%s)' % sort) if sort else '' # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped @@ -1089,7 +1089,7 @@ def header(self, results=None): span = ''.format(self.field_definition) else: span = '' - html = '{}{} {}'.format(cls, next_sort, data_sort, self.header_html, sr_label, span) + html = '{}{} {}'.format(cls, next_sort, data_sort, self.header_html, sr_label, span) return mark_safe(html) def get_data_max_length(self, results): From 24c9c79270e8471b2813d1f402a4df98785363f9 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Thu, 24 Sep 2020 09:12:17 -0400 Subject: [PATCH 02/17] 2202 Allow the sorting column to be deselected when it is currently Descending and it is clicked --- seeker/views.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 79e91ac..9971faf 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -98,8 +98,7 @@ def header(self): # If the current sort field is this field, give it a class a change direction. sort = 'Descending' if field.startswith('-') else 'Ascending' cls += ' desc' if field.startswith('-') else ' asc' - d = '' if field.startswith('-') else '-' - q['s'] = '%s%s' % (d, self.field) + q['s'] = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) else: q['s'] = self.field next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' @@ -1065,6 +1064,7 @@ def header(self, results=None): cls += ' {}_{}'.format(self.model_lower, self.field.replace('.', '_')) if not self.sort: return mark_safe('%s' % (cls, self.header_html)) + print("** Current search_object:", self.view.search_object) current_sort = self.view.search_object['sort'] sort = None cls += ' sort' @@ -1072,8 +1072,7 @@ def header(self, results=None): # If the current sort field is this field, give it a class a change direction. sort = 'Descending' if current_sort.startswith('-') else 'Ascending' cls += ' desc' if current_sort.startswith('-') else ' asc' - d = '' if current_sort.startswith('-') else '-' - data_sort = '{}{}'.format(d, self.field) + data_sort = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) else: data_sort = self.field @@ -1208,7 +1207,7 @@ def search_url(self): Generally, this will be a 'reverse' call to the URL associated with this view. """ - sort = '' + sort = [] """ Default field to sort by. Prepend '-' to reverse sort. """ @@ -1396,7 +1395,7 @@ def post(self, request, *args, **kwargs): except ValueError: return HttpResponseBadRequest("Improperly formatted 'search_object', json.loads failed.") - # Sanity check that the search object has all of it's required components + # Sanity check that the search object has all of its required components if not all(k in self.search_object for k in ('query', 'keywords', 'page', 'sort', 'display')): return HttpResponseBadRequest("The 'search_object' is not in the proper format.") From 76a453697a664b1d83f9b213b27994279e54fe0c Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Wed, 7 Oct 2020 15:17:49 -0400 Subject: [PATCH 03/17] 2202 Enable AdvancedColumn header to pass sort value as a list, and enable case for sort dictionary creation to be true. --- seeker/views.py | 65 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 9971faf..b925bd5 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -751,22 +751,23 @@ def apply_sort_descriptor(self, sort): desc = sort.startswith('-') field = sort.lstrip('-') missing = self.missing_sort + sort_querydict = {'order': 'desc' if desc else 'asc'} if missing == '_low': - missing = '_last' if desc else '_first' + sort_querydict.update({'missing':'_last' if desc else '_first'}) elif missing == '_high': - missing = '_first' if desc else '_last' + sort_querydict.update({'missing':'_first' if desc else '_last'}) return { - field: { - 'order': 'desc' if desc else 'asc', - 'missing': missing, - } + sort: sort_querydict } def sort_descriptor(self, sort): - if self.missing_sort is None or isinstance(sort, dict): + if isinstance(sort, dict): return sort if not isinstance(sort, list): - return self.apply_sort_descriptor(sort) + applied = self.apply_sort_descriptor(sort) + print("instance after sort was applied:", applied) + return applied + #return self.apply_sort_descriptor(sort) else: sort_dict = {} for s in sort: @@ -1067,15 +1068,37 @@ def header(self, results=None): print("** Current search_object:", self.view.search_object) current_sort = self.view.search_object['sort'] sort = None + sort_fields = [] cls += ' sort' - if current_sort.lstrip('-') == self.field: - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if current_sort.startswith('-') else 'Ascending' - cls += ' desc' if current_sort.startswith('-') else ' asc' - data_sort = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) + # if isinstance(current_sort, str): + # print("current_sort before string to list conversion", current_sort) + # # This conditional prevents setting current_sort to [''] + # current_sort = [] if not current_sort else [current_sort] + # print("current_sort value before looping", current_sort) + #if current_sort != '': + #for sort_field in current_sort: + #if sort_field.lstrip('-') == self.field: + if isinstance(current_sort, list): + for sort_field in current_sort: + if sort_field.lstrip('-') == self.field: + # If the current sort field is this field, give it a class a change direction. + sort = 'Descending' if sort_field.startswith('-') else 'Ascending' + cls += ' desc' if sort_field.startswith('-') else ' asc' + data_sort = '' if sort_field.startswith('-') else '{}{}'.format('-', self.field) + sort_fields.append(data_sort) + else: + data_sort = self.field + sort_fields.append(data_sort) else: - data_sort = self.field - + if current_sort.lstrip('-') == self.field: + # If the current sort field is this field, give it a class a change direction. + sort = 'Descending' if current_sort.startswith('-') else 'Ascending' + cls += ' desc' if current_sort.startswith('-') else ' asc' + data_sort = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) + sort_fields.append(data_sort) + else: + data_sort = self.field + sort_fields.append(data_sort) next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' sr_label = (' (%s)' % sort) if sort else '' @@ -1088,7 +1111,8 @@ def header(self, results=None): span = ''.format(self.field_definition) else: span = '' - html = '{}{} {}'.format(cls, next_sort, data_sort, self.header_html, sr_label, span) + sort_fields = "''" if not sort_fields else sort_fields + html = '{}{} {}'.format(cls, next_sort, sort_fields, self.header_html, sr_label, span) return mark_safe(html) def get_data_max_length(self, results): @@ -1526,7 +1550,13 @@ def render_results(self, export): search = self.apply_highlight(search, columns) # Finally, grab the results. + search_object_sort = self.search_object['sort'] + print("here is the search object sort that i will attempt to split", search_object_sort) + if search_object_sort.startswith('['): + self.search_object['sort'] = self.search_object['sort'].strip("[]\'\"").split(',') + print("here it is after splitting:", self.search_object['sort']) sort = self.get_sort_field(columns, self.search_object['sort'], display) + print("Results of sort descriptor:", self.sort_descriptor(sort)) if sort: if (self.missing_sort is None or isinstance(sort, dict)) and isinstance(sort, list): results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() @@ -1572,6 +1602,9 @@ def render_results(self, export): } self.modify_json_response(json_response, context) + #print("Right before sending advanced serarch and json response:") + #print("context sort", context['sort']) + #print("json_response", json_response) advanced_search_performed.send(sender=self.__class__, request=self.request, context=context, json_response=json_response) return JsonResponse(json_response) From a4197ed51e09086f1c2a6a5e46b8cc6f13038b41 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Wed, 7 Oct 2020 16:03:25 -0400 Subject: [PATCH 04/17] 2202 reorganized AdvancedColumn header to remove repeated & commented code --- seeker/views.py | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index b925bd5..af76111 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -764,10 +764,7 @@ def sort_descriptor(self, sort): if isinstance(sort, dict): return sort if not isinstance(sort, list): - applied = self.apply_sort_descriptor(sort) - print("instance after sort was applied:", applied) - return applied - #return self.apply_sort_descriptor(sort) + return self.apply_sort_descriptor(sort) else: sort_dict = {} for s in sort: @@ -1070,35 +1067,19 @@ def header(self, results=None): sort = None sort_fields = [] cls += ' sort' - # if isinstance(current_sort, str): - # print("current_sort before string to list conversion", current_sort) - # # This conditional prevents setting current_sort to [''] - # current_sort = [] if not current_sort else [current_sort] - # print("current_sort value before looping", current_sort) - #if current_sort != '': - #for sort_field in current_sort: - #if sort_field.lstrip('-') == self.field: - if isinstance(current_sort, list): - for sort_field in current_sort: - if sort_field.lstrip('-') == self.field: - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if sort_field.startswith('-') else 'Ascending' - cls += ' desc' if sort_field.startswith('-') else ' asc' - data_sort = '' if sort_field.startswith('-') else '{}{}'.format('-', self.field) - sort_fields.append(data_sort) - else: - data_sort = self.field - sort_fields.append(data_sort) - else: - if current_sort.lstrip('-') == self.field: + if not isinstance(current_sort, list): + current_sort = [current_sort] + for sort_field in current_sort: + if sort_field.lstrip('-') == self.field: # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if current_sort.startswith('-') else 'Ascending' - cls += ' desc' if current_sort.startswith('-') else ' asc' - data_sort = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) + sort = 'Descending' if sort_field.startswith('-') else 'Ascending' + cls += ' desc' if sort_field.startswith('-') else ' asc' + data_sort = '' if sort_field.startswith('-') else '{}{}'.format('-', self.field) sort_fields.append(data_sort) else: data_sort = self.field sort_fields.append(data_sort) + next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' sr_label = (' (%s)' % sort) if sort else '' @@ -1111,7 +1092,8 @@ def header(self, results=None): span = ''.format(self.field_definition) else: span = '' - sort_fields = "''" if not sort_fields else sort_fields + if not sort_fields or sort_fields == ['']: + sort_fields = "''" html = '{}{} {}'.format(cls, next_sort, sort_fields, self.header_html, sr_label, span) return mark_safe(html) From cca016439b1587be4a51861ac5f1b1190ca39183 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Tue, 23 Mar 2021 09:25:39 -0400 Subject: [PATCH 05/17] 2202 loop through search_object['sort'] when it is a list to create sort descriptor. Advanced column header processes search_object['sort'] as a list --- seeker/views.py | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index af76111..94d3a12 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1062,10 +1062,8 @@ def header(self, results=None): cls += ' {}_{}'.format(self.model_lower, self.field.replace('.', '_')) if not self.sort: return mark_safe('%s' % (cls, self.header_html)) - print("** Current search_object:", self.view.search_object) current_sort = self.view.search_object['sort'] sort = None - sort_fields = [] cls += ' sort' if not isinstance(current_sort, list): current_sort = [current_sort] @@ -1074,11 +1072,10 @@ def header(self, results=None): # If the current sort field is this field, give it a class a change direction. sort = 'Descending' if sort_field.startswith('-') else 'Ascending' cls += ' desc' if sort_field.startswith('-') else ' asc' - data_sort = '' if sort_field.startswith('-') else '{}{}'.format('-', self.field) - sort_fields.append(data_sort) - else: - data_sort = self.field - sort_fields.append(data_sort) + d = '' if sort_field.startswith('-') else '-' + data_sort = '{}{}'.format(d, self.field) + else: + data_sort = self.field next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' sr_label = (' (%s)' % sort) if sort else '' @@ -1092,9 +1089,7 @@ def header(self, results=None): span = ''.format(self.field_definition) else: span = '' - if not sort_fields or sort_fields == ['']: - sort_fields = "''" - html = '{}{} {}'.format(cls, next_sort, sort_fields, self.header_html, sr_label, span) + html = '{}{} {}'.format(cls, next_sort, data_sort, self.header_html, sr_label, span) return mark_safe(html) def get_data_max_length(self, results): @@ -1532,16 +1527,14 @@ def render_results(self, export): search = self.apply_highlight(search, columns) # Finally, grab the results. - search_object_sort = self.search_object['sort'] - print("here is the search object sort that i will attempt to split", search_object_sort) - if search_object_sort.startswith('['): - self.search_object['sort'] = self.search_object['sort'].strip("[]\'\"").split(',') - print("here it is after splitting:", self.search_object['sort']) - sort = self.get_sort_field(columns, self.search_object['sort'], display) - print("Results of sort descriptor:", self.sort_descriptor(sort)) + if isinstance(self.search_object['sort'], list): + sort = [self.get_sort_field(columns, s, display) for s in self.search_object['sort']] + else: + sort = self.get_sort_field(columns, self.search_object['sort'], display) + if sort: if (self.missing_sort is None or isinstance(sort, dict)) and isinstance(sort, list): - results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() + results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() else: results = search.sort(self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() else: @@ -1584,9 +1577,6 @@ def render_results(self, export): } self.modify_json_response(json_response, context) - #print("Right before sending advanced serarch and json response:") - #print("context sort", context['sort']) - #print("json_response", json_response) advanced_search_performed.send(sender=self.__class__, request=self.request, context=context, json_response=json_response) return JsonResponse(json_response) From 1edd4d06730401b95300324d07f23fad8683f735 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Tue, 23 Mar 2021 09:40:55 -0400 Subject: [PATCH 06/17] 2202 remove unnecessary changes --- seeker/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index dcf27b2..394a79a 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -95,7 +95,8 @@ def header(self): # If the current sort field is this field, give it a class a change direction. sort = 'Descending' if field.startswith('-') else 'Ascending' cls += ' desc' if field.startswith('-') else ' asc' - q['s'] = '' if current_sort.startswith('-') else '{}{}'.format('-', self.field) + d = '' if field.startswith('-') else '-' + q['s'] = '%s%s' % (d, self.field) else: q['s'] = self.field next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' @@ -1206,7 +1207,7 @@ def search_url(self): Generally, this will be a 'reverse' call to the URL associated with this view. """ - sort = [] + sort = '' """ Default field to sort by. Prepend '-' to reverse sort. """ @@ -1531,7 +1532,7 @@ def render_results(self, export): if sort: if (self.missing_sort is None or isinstance(sort, dict)) and isinstance(sort, list): - results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() + results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() else: results = search.sort(self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() else: From 43f4bc7534973b3fa470257cb29f5426658ba363 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Wed, 24 Mar 2021 11:47:45 -0400 Subject: [PATCH 07/17] 2202 Add numbers to column headers to show their precedence in the sort list if their field is being sorted upon --- seeker/templates/advanced_seeker/seeker.html | 1 + seeker/views.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/seeker/templates/advanced_seeker/seeker.html b/seeker/templates/advanced_seeker/seeker.html index ea33699..61dcde3 100644 --- a/seeker/templates/advanced_seeker/seeker.html +++ b/seeker/templates/advanced_seeker/seeker.html @@ -10,6 +10,7 @@ th.sort.asc, th.sort.desc { background-color: #ffe; } th.sort.asc:before { padding-right: 5px; content: '\25B3'; } th.sort.desc:before { padding-right: 5px; content: '\25BD'; } + .sort_rank { color: #6a6a6a; font-size: 12px; padding-right: 5px; } .table-seeker em { background-color: #ffd; padding: 1px 3px; border-radius: 4px; border: 1px solid #eee; } #criteria { padding-top: 10px; } diff --git a/seeker/views.py b/seeker/views.py index 394a79a..5571211 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1061,6 +1061,7 @@ def header(self, results=None): return mark_safe('%s' % (cls, self.header_html)) current_sort = self.view.search_object['sort'] sort = None + sort_order = 0 cls += ' sort' if not isinstance(current_sort, list): current_sort = [current_sort] @@ -1071,6 +1072,7 @@ def header(self, results=None): cls += ' desc' if sort_field.startswith('-') else ' asc' d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) + sort_order = current_sort.index(sort_field) + 1 else: data_sort = self.field @@ -1086,7 +1088,11 @@ def header(self, results=None): span = ''.format(self.field_definition) else: span = '' - html = '{}{} {}'.format(cls, next_sort, data_sort, self.header_html, sr_label, span) + if sort_order: + sort_rank = '{}'.format(sort_order) + else: + sort_rank = '' + html = '{}{}{} {}'.format(cls, sort_rank, next_sort, data_sort, self.header_html, sr_label, span) return mark_safe(html) def get_data_max_length(self, results): From 0675fed01c730fbd6707ffff73ebacc4412350b7 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Mon, 29 Mar 2021 16:12:57 -0400 Subject: [PATCH 08/17] 2202 indicate default sorted column, simplify changes and allow normal seeker functionality without any upgrading --- seeker/templates/advanced_seeker/results.html | 4 +- seeker/templates/seeker/seeker.html | 1 + seeker/templatetags/seeker.py | 8 ++- seeker/views.py | 49 +++++++++++-------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/seeker/templates/advanced_seeker/results.html b/seeker/templates/advanced_seeker/results.html index ef8168b..6671c79 100644 --- a/seeker/templates/advanced_seeker/results.html +++ b/seeker/templates/advanced_seeker/results.html @@ -23,9 +23,9 @@ {% endif %} {% for col in display_columns %} {% if use_wordwrap_header %} - {% seeker_column_header col results %} + {% seeker_column_header col results default_sort %} {% else %} - {{ col.header }} + {% column_header col default_sort %} {% endif %} {% endfor %} {% endblock table-headers %} diff --git a/seeker/templates/seeker/seeker.html b/seeker/templates/seeker/seeker.html index a4d4b1e..91de5fb 100644 --- a/seeker/templates/seeker/seeker.html +++ b/seeker/templates/seeker/seeker.html @@ -10,6 +10,7 @@ th.sort.asc, th.sort.desc { background-color: #ffe; } th.sort.asc:before { padding-right: 5px; content: '\25B3'; } th.sort.desc:before { padding-right: 5px; content: '\25BD'; } + .sort_rank { color: #6a6a6a; font-size: 12px; padding-right: 5px; } .table-seeker em { background-color: #ffd; padding: 1px 3px; border-radius: 4px; border: 1px solid #eee; } #criteria { padding-top: 10px; } diff --git a/seeker/templatetags/seeker.py b/seeker/templatetags/seeker.py index 4a86de8..f6f1543 100644 --- a/seeker/templatetags/seeker.py +++ b/seeker/templatetags/seeker.py @@ -65,8 +65,12 @@ def seeker_column(column, result, **kwargs): @register.simple_tag -def seeker_column_header(column, results=None): - return column.header(results) +def seeker_column_header(column, results=None, default_sort=None): + return column.header(results, default_sort) + +@register.simple_tag +def column_header(column, default_sort=None): + return column.header(default_sort=default_sort) @register.simple_tag diff --git a/seeker/views.py b/seeker/views.py index 5571211..e6a7ef6 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1052,7 +1052,8 @@ def dispatch(self, request, *args, **kwargs): class AdvancedColumn(Column): - def header(self, results=None): + def header(self, results=None, default_sort=None): + cls = '{}_{}'.format(self.view.document._doc_type.name, self.field.replace('.', '_')) cls += ' {}_{}'.format(self.view.document.__name__.lower(), self.field.replace('.', '_')) if self.model_lower: @@ -1065,19 +1066,25 @@ def header(self, results=None): cls += ' sort' if not isinstance(current_sort, list): current_sort = [current_sort] - for sort_field in current_sort: - if sort_field.lstrip('-') == self.field: - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if sort_field.startswith('-') else 'Ascending' - cls += ' desc' if sort_field.startswith('-') else ' asc' - d = '' if sort_field.startswith('-') else '-' - data_sort = '{}{}'.format(d, self.field) - sort_order = current_sort.index(sort_field) + 1 + sr_label = '' + data_sort = self.field + if not current_sort or current_sort == ['']: + if default_sort.lstrip('-') == self.field: + cls += ' desc' if default_sort.startswith('-') else ' asc' + sort_default = sort = 'Descending' if default_sort.startswith('-') else 'Ascending' + sr_label = '({})'.format(sort_default) else: - data_sort = self.field + for sort_field in current_sort: + if sort_field.lstrip('-') == self.field: + # If the current sort field is this field, give it a class a change direction. + sort = 'Descending' if sort_field.startswith('-') else 'Ascending' + cls += ' desc' if sort_field.startswith('-') else ' asc' + d = '' if sort_field.startswith('-') else '-' + data_sort = '{}{}'.format(d, self.field) + sort_order = current_sort.index(sort_field) + 1 + sr_label = ('Number {} in sort order ({})'.format(sort_order, sort)) next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' - sr_label = (' (%s)' % sort) if sort else '' # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped # (i.e. has
in header) we skip it. @@ -1531,16 +1538,17 @@ def render_results(self, export): search = self.apply_highlight(search, columns) # Finally, grab the results. - if isinstance(self.search_object['sort'], list): - sort = [self.get_sort_field(columns, s, display) for s in self.search_object['sort']] - else: - sort = self.get_sort_field(columns, self.search_object['sort'], display) - + sort = self.get_sort_field(columns, self.search_object['sort'], display) + + default_sort_field = '' + sort_descrip_dict = self.sort_descriptor(sort) + if sort_descrip_dict: + default_sort_field = list(sort_descrip_dict.keys())[0].replace('.raw', '') + if list(sort_descrip_dict.values())[0]['order'] == 'desc': + default_sort_field = '{}{}'.format('-', default_sort_field) + if sort: - if (self.missing_sort is None or isinstance(sort, dict)) and isinstance(sort, list): - results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() - else: - results = search.sort(self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() + results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() else: results = search[offset:offset + page_size].params(request_timeout=self.search_timeout).execute() @@ -1569,6 +1577,7 @@ def render_results(self, export): 'results': results, 'show_rank': self.show_rank, 'sort': sort, + 'default_sort': default_sort_field, 'export_name': self.export_name, 'use_wordwrap_header': self.use_wordwrap_header, 'search': search From 0c4ede762bd94b8b156d531aa8bf297b99c71e4d Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Tue, 18 Jan 2022 09:51:14 -0500 Subject: [PATCH 09/17] 2202 Revert changes to apply_sort_descriptor, split one-line if/else/if onto multiple lines --- seeker/views.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 234b0fc..fe5e07b 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -99,7 +99,12 @@ def header(self): q['s'] = '%s%s' % (d, self.field) else: q['s'] = self.field - next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' + next_sorting = { + 'Acending': 'sort descending', + 'Descending': 'remove from sort' + } + #If this field isn't already being sorted upon, label it as being sorted ascending + next_sort = next_sorting.get(sort, 'sort ascending') sr_label = format_html(' ({})', sort) if sort else '' if self.field_definition: span = format_html('', self.field_definition) @@ -791,13 +796,15 @@ def apply_sort_descriptor(self, sort): desc = sort.startswith('-') field = sort.lstrip('-') missing = self.missing_sort - sort_querydict = {'order': 'desc' if desc else 'asc'} if missing == '_low': - sort_querydict.update({'missing':'_last' if desc else '_first'}) + missing = '_last' if desc else '_first' elif missing == '_high': - sort_querydict.update({'missing':'_first' if desc else '_last'}) + missing = '_first' if desc else '_last' return { - sort: sort_querydict + field: { + 'order': 'desc' if desc else 'asc', + 'missing': missing, + } } def sort_descriptor(self, sort): @@ -1136,7 +1143,7 @@ def header(self, results=None, default_sort=None): if default_sort.lstrip('-') == self.field: cls += ' desc' if default_sort.startswith('-') else ' asc' sort_default = sort = 'Descending' if default_sort.startswith('-') else 'Ascending' - sr_label = '({})'.format(sort_default) + sr_label = format_html('({})', sort_default) else: for sort_field in current_sort: if sort_field.lstrip('-') == self.field: @@ -1146,9 +1153,14 @@ def header(self, results=None, default_sort=None): d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) sort_order = current_sort.index(sort_field) + 1 - sr_label = format_html(' Number {} in sort order ({})', sort_order, sort) + sr_label = format_html('Number {} in sort order ({})', sort_order, sort) - next_sort = 'sort descending' if sort == 'Ascending' else 'remove from sort' if sort == 'Descending' else 'sort ascending' + next_sorting = { + 'Acending': 'sort descending', + 'Descending': 'remove from sort' + } + #If this field isn't already being sorted upon, label it as being sorted ascending + next_sort = next_sorting.get(sort, 'sort ascending') # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped # (i.e. has
in header) we skip it. @@ -1160,7 +1172,7 @@ def header(self, results=None, default_sort=None): else: span = '' if sort_order: - sort_rank = '{}'.format(sort_order) + sort_rank = format_html('{} ', sort_order) else: sort_rank = '' html = format_html( From f9f8b6c9aa2c603fd1ccb07250ed288c3ffc1986 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Fri, 21 Jan 2022 16:19:31 -0500 Subject: [PATCH 10/17] 2202 Correct sort order toggling for default sort field, remove indication of sort rank/sort order when only one field is being sorted upon] --- seeker/views.py | 50 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index fe5e07b..d4361ed 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -100,7 +100,7 @@ def header(self): else: q['s'] = self.field next_sorting = { - 'Acending': 'sort descending', + 'Ascending': 'sort descending', 'Descending': 'remove from sort' } #If this field isn't already being sorted upon, label it as being sorted ascending @@ -794,14 +794,14 @@ def get_search(self, keywords=None, facets=None, aggregate=True, include_extra=T def apply_sort_descriptor(self, sort): desc = sort.startswith('-') - field = sort.lstrip('-') + # field = sort.lstrip('-') missing = self.missing_sort if missing == '_low': missing = '_last' if desc else '_first' elif missing == '_high': missing = '_first' if desc else '_last' return { - field: { + sort: { 'order': 'desc' if desc else 'asc', 'missing': missing, } @@ -1138,12 +1138,21 @@ def header(self, results=None, default_sort=None): if not isinstance(current_sort, list): current_sort = [current_sort] sr_label = '' + next_sort = '' + next_sorting = { + 'Ascending': 'sort descending', + 'Descending': 'remove from sort' + } data_sort = self.field if not current_sort or current_sort == ['']: + print("default_sort:", default_sort) if default_sort.lstrip('-') == self.field: cls += ' desc' if default_sort.startswith('-') else ' asc' sort_default = sort = 'Descending' if default_sort.startswith('-') else 'Ascending' + d = '' if default_sort.startswith('-') else '-' + data_sort = '{}{}'.format(d, self.field) sr_label = format_html('({})', sort_default) + next_sort = next_sorting.get(sort_default, 'sort ascending') else: for sort_field in current_sort: if sort_field.lstrip('-') == self.field: @@ -1153,15 +1162,13 @@ def header(self, results=None, default_sort=None): d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) sort_order = current_sort.index(sort_field) + 1 - sr_label = format_html('Number {} in sort order ({})', sort_order, sort) - - next_sorting = { - 'Acending': 'sort descending', - 'Descending': 'remove from sort' - } - #If this field isn't already being sorted upon, label it as being sorted ascending - next_sort = next_sorting.get(sort, 'sort ascending') - + if len(current_sort) == 1: + sr_label = format_html('({})', sort) + else: + sr_label = format_html('Number {} in sort order ({})', sort_order, sort) + #If this field isn't already being sorted upon, label it as being sorted ascending + next_sort = next_sorting.get(sort, 'sort ascending') + # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped # (i.e. has
in header) we skip it. if results and ' ' in self.header_html and not '{} ', sort_order) else: sort_rank = '' - html = format_html( - '{}{}{} {}', - cls, sort_rank, next_sort, data_sort, self.header_html, sr_label, span) + + if sort_order: + sort_rank = format_html('{} ', sort_order) + else: + sort_rank = '' + + # Don't indicate sort rank when only one field is being sorted upon + if len(current_sort) == 1: + html = format_html( + '{}{} {}', + cls, next_sort, data_sort, self.header_html, sr_label, span) + else: + html = format_html( + '{}{}{} {}', + cls, sort_rank, next_sort, data_sort, self.header_html, sr_label, span) return html def get_data_max_length(self, results): @@ -1628,6 +1647,7 @@ def render_results(self, export): default_sort_field = '' sort_descrip_dict = self.sort_descriptor(sort) if sort_descrip_dict: + print("default sort field", default_sort_field) default_sort_field = list(sort_descrip_dict.keys())[0].replace('.raw', '') if list(sort_descrip_dict.values())[0]['order'] == 'desc': default_sort_field = '{}{}'.format('-', default_sort_field) From 639c26c61b1c61f1bcd1bd010bf35f770daea9c1 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Thu, 3 Feb 2022 10:12:54 -0500 Subject: [PATCH 11/17] WIP: 2202 blank sort field indicator in searchObject['sort'] --- seeker/templates/advanced_seeker/results.html | 4 +- seeker/templatetags/seeker.py | 8 +- seeker/views.py | 107 +++++++++--------- 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/seeker/templates/advanced_seeker/results.html b/seeker/templates/advanced_seeker/results.html index 6671c79..ff7e4e5 100644 --- a/seeker/templates/advanced_seeker/results.html +++ b/seeker/templates/advanced_seeker/results.html @@ -23,9 +23,9 @@ {% endif %} {% for col in display_columns %} {% if use_wordwrap_header %} - {% seeker_column_header col results default_sort %} + {% seeker_column_header col results sort_descriptor_list %} {% else %} - {% column_header col default_sort %} + {% column_header col sort_descriptor_list %} {% endif %} {% endfor %} {% endblock table-headers %} diff --git a/seeker/templatetags/seeker.py b/seeker/templatetags/seeker.py index f6f1543..0d52a30 100644 --- a/seeker/templatetags/seeker.py +++ b/seeker/templatetags/seeker.py @@ -65,12 +65,12 @@ def seeker_column(column, result, **kwargs): @register.simple_tag -def seeker_column_header(column, results=None, default_sort=None): - return column.header(results, default_sort) +def seeker_column_header(column, results=None, sort_descriptor_list=None): + return column.header(results, sort_descriptor_list) @register.simple_tag -def column_header(column, default_sort=None): - return column.header(default_sort=default_sort) +def column_header(column, sort_descriptor_list=None): + return column.header(sort_descriptor_list=sort_descriptor_list) @register.simple_tag diff --git a/seeker/views.py b/seeker/views.py index d4361ed..70add44 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -794,29 +794,30 @@ def get_search(self, keywords=None, facets=None, aggregate=True, include_extra=T def apply_sort_descriptor(self, sort): desc = sort.startswith('-') - # field = sort.lstrip('-') + field = sort.lstrip('-') missing = self.missing_sort if missing == '_low': missing = '_last' if desc else '_first' elif missing == '_high': missing = '_first' if desc else '_last' - return { - sort: { - 'order': 'desc' if desc else 'asc', - 'missing': missing, + sort_descriptor = { + field: {'order': 'desc' if desc else 'asc',} } - } + if missing: + sort_descriptor[field]['missing'] = missing + return sort_descriptor def sort_descriptor(self, sort): if isinstance(sort, dict): return sort - if not isinstance(sort, list): - return self.apply_sort_descriptor(sort) else: - sort_dict = {} + sort = [sort] if isinstance(sort, str) else sort + if '' in sort: + sort.remove('') + sort_list = [] for s in sort: - sort_dict.update(self.apply_sort_descriptor(s)) - return sort_dict + sort_list.append(self.apply_sort_descriptor(s)) + return sort_list def is_initial(self): """ @@ -1123,8 +1124,9 @@ def dispatch(self, request, *args, **kwargs): class AdvancedColumn(Column): - def header(self, results=None, default_sort=None): + def header(self, results=None, sort_descriptor_list=None): + print("sort descriptor list is", sort_descriptor_list) cls = '{}_{}'.format(self.view.document._doc_type.name, self.field.replace('.', '_')) cls += ' {}_{}'.format(self.view.document.__name__.lower(), self.field.replace('.', '_')) if self.model_lower: @@ -1132,11 +1134,14 @@ def header(self, results=None, default_sort=None): if not self.sort: return format_html('{}', cls, self.header_html) current_sort = self.view.search_object['sort'] + if not isinstance(current_sort, list): + current_sort = [current_sort] + # if '' in current_sort: + # current_sort.remove('') sort = None sort_order = 0 cls += ' sort' - if not isinstance(current_sort, list): - current_sort = [current_sort] + sr_label = '' next_sort = '' next_sorting = { @@ -1144,30 +1149,28 @@ def header(self, results=None, default_sort=None): 'Descending': 'remove from sort' } data_sort = self.field - if not current_sort or current_sort == ['']: - print("default_sort:", default_sort) - if default_sort.lstrip('-') == self.field: - cls += ' desc' if default_sort.startswith('-') else ' asc' - sort_default = sort = 'Descending' if default_sort.startswith('-') else 'Ascending' - d = '' if default_sort.startswith('-') else '-' + if sort_descriptor_list: + potential_default = list(sort_descriptor_list[0].keys())[0] + if sort_descriptor_list[0][potential_default].get('order', None) == 'desc': + potential_default = '{}{}'.format('-', potential_default) + potential_default = potential_default.replace('.raw', '') + if potential_default not in current_sort: + current_sort.append(potential_default) + for sort_field in current_sort: + print("comparing sort_field", sort_field.lstrip('-'), "with field", self.field) + if sort_field.lstrip('-') == self.field: + # If the current sort field is this field, give it a class a change direction. + sort = 'Descending' if sort_field.startswith('-') else 'Ascending' + cls += ' desc' if sort_field.startswith('-') else ' asc' + d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) - sr_label = format_html('({})', sort_default) - next_sort = next_sorting.get(sort_default, 'sort ascending') - else: - for sort_field in current_sort: - if sort_field.lstrip('-') == self.field: - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if sort_field.startswith('-') else 'Ascending' - cls += ' desc' if sort_field.startswith('-') else ' asc' - d = '' if sort_field.startswith('-') else '-' - data_sort = '{}{}'.format(d, self.field) - sort_order = current_sort.index(sort_field) + 1 - if len(current_sort) == 1: - sr_label = format_html('({})', sort) - else: - sr_label = format_html('Number {} in sort order ({})', sort_order, sort) - #If this field isn't already being sorted upon, label it as being sorted ascending - next_sort = next_sorting.get(sort, 'sort ascending') + sort_order = current_sort.index(sort_field) + 1 + if len(current_sort) == 1: + sr_label = format_html('({})', sort) + else: + sr_label = format_html('Number {} in sort order ({})', sort_order, sort) + # If this field isn't already being sorted upon, label it as being sorted ascending + next_sort = next_sorting.get(sort, 'sort ascending') # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped # (i.e. has
in header) we skip it. @@ -1178,10 +1181,6 @@ def header(self, results=None, default_sort=None): span = format_html('', self.field_definition) else: span = '' - if sort_order: - sort_rank = format_html('{} ', sort_order) - else: - sort_rank = '' if sort_order: sort_rank = format_html('{} ', sort_order) @@ -1456,8 +1455,14 @@ def get_sort_field(self, columns, sort, display): # Make sure we sanitize the sort fields. sort_fields = [] column_lookup = { c.field: c for c in columns } - # Order of precedence for sort is: parameter, the default from the view, and then the first displayed column (if any are displayed) - sort = sort or self.sort or display[0] if len(display) else '' + + # If all columns have been intentionally deselected from the sort, do not default to any column + if sort == ['']: + sort = '' + else: + # Order of precedence for sort is: parameter, the default from the view, and then the first displayed column (if any are displayed) + sort = sort or self.sort or display[0] if len(display) else '' + # Get the column based on the field name, and use it's "sort" field, if applicable. if not isinstance(sort, list): return self.apply_sort_field(column_lookup, sort) @@ -1643,20 +1648,10 @@ def render_results(self, export): # Finally, grab the results. sort = self.get_sort_field(columns, self.search_object['sort'], display) + sort_descriptor_list = self.sort_descriptor(sort) - default_sort_field = '' - sort_descrip_dict = self.sort_descriptor(sort) - if sort_descrip_dict: - print("default sort field", default_sort_field) - default_sort_field = list(sort_descrip_dict.keys())[0].replace('.raw', '') - if list(sort_descrip_dict.values())[0]['order'] == 'desc': - default_sort_field = '{}{}'.format('-', default_sort_field) - if sort: - if (self.missing_sort is None or isinstance(sort, dict)) and isinstance(sort, list): - results = search.sort(*self.sort_descriptor(sort))[offset:offset + page_size].execute() - else: - results = search.sort(self.sort_descriptor(sort))[offset:offset + page_size].execute() + results = search.sort(*sort_descriptor_list)[offset:offset + page_size].execute() else: results = search[offset:offset + page_size].execute() @@ -1686,7 +1681,7 @@ def render_results(self, export): 'total_hits': results.hits.total.value, 'show_rank': self.show_rank, 'sort': sort, - 'default_sort': default_sort_field, + 'sort_descriptor_list': sort_descriptor_list, 'export_name': self.export_name, 'use_wordwrap_header': self.use_wordwrap_header, 'search': search From 61ee48782d75afa51261a9f4fcbc80533c97fe61 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Thu, 3 Feb 2022 14:41:04 -0500 Subject: [PATCH 12/17] #2202 - use sort object flag isInitialSort/is_initial_sort to determine whether or not to use the default sort field, account for .label as part of column field name --- seeker/views.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 70add44..9153862 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -812,8 +812,6 @@ def sort_descriptor(self, sort): return sort else: sort = [sort] if isinstance(sort, str) else sort - if '' in sort: - sort.remove('') sort_list = [] for s in sort: sort_list.append(self.apply_sort_descriptor(s)) @@ -1125,8 +1123,6 @@ def dispatch(self, request, *args, **kwargs): class AdvancedColumn(Column): def header(self, results=None, sort_descriptor_list=None): - - print("sort descriptor list is", sort_descriptor_list) cls = '{}_{}'.format(self.view.document._doc_type.name, self.field.replace('.', '_')) cls += ' {}_{}'.format(self.view.document.__name__.lower(), self.field.replace('.', '_')) if self.model_lower: @@ -1136,12 +1132,9 @@ def header(self, results=None, sort_descriptor_list=None): current_sort = self.view.search_object['sort'] if not isinstance(current_sort, list): current_sort = [current_sort] - # if '' in current_sort: - # current_sort.remove('') sort = None sort_order = 0 cls += ' sort' - sr_label = '' next_sort = '' next_sorting = { @@ -1153,11 +1146,10 @@ def header(self, results=None, sort_descriptor_list=None): potential_default = list(sort_descriptor_list[0].keys())[0] if sort_descriptor_list[0][potential_default].get('order', None) == 'desc': potential_default = '{}{}'.format('-', potential_default) - potential_default = potential_default.replace('.raw', '') + potential_default = potential_default.replace('.raw', '').replace('.label','') if potential_default not in current_sort: current_sort.append(potential_default) for sort_field in current_sort: - print("comparing sort_field", sort_field.lstrip('-'), "with field", self.field) if sort_field.lstrip('-') == self.field: # If the current sort field is this field, give it a class a change direction. sort = 'Descending' if sort_field.startswith('-') else 'Ascending' @@ -1165,6 +1157,7 @@ def header(self, results=None, sort_descriptor_list=None): d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) sort_order = current_sort.index(sort_field) + 1 + print("index of", sort_field, "in current sort", current_sort) if len(current_sort) == 1: sr_label = format_html('({})', sort) else: @@ -1447,7 +1440,7 @@ def apply_sort_field(self, column_lookup, sort): return('-{}'.format(c.sort) if sort.startswith('-') else c.sort) return sort - def get_sort_field(self, columns, sort, display): + def get_sort_field(self, columns, sort, is_initial_sort, display): """ Returns the appropriate sort field for a given sort value. """ @@ -1456,12 +1449,12 @@ def get_sort_field(self, columns, sort, display): sort_fields = [] column_lookup = { c.field: c for c in columns } - # If all columns have been intentionally deselected from the sort, do not default to any column - if sort == ['']: - sort = '' - else: - # Order of precedence for sort is: parameter, the default from the view, and then the first displayed column (if any are displayed) + # Order of precedence for sort is: parameter, the default from the view, and then the first displayed column (if any are displayed) + if is_initial_sort: sort = sort or self.sort or display[0] if len(display) else '' + else: + # If all columns have been intentionally deselected from the sort, do not default to any column + sort = sort if sort else [] # Get the column based on the field name, and use it's "sort" field, if applicable. if not isinstance(sort, list): @@ -1647,7 +1640,7 @@ def render_results(self, export): search = self.apply_highlight(search, columns) # Finally, grab the results. - sort = self.get_sort_field(columns, self.search_object['sort'], display) + sort = self.get_sort_field(columns, self.search_object['sort'], self.search_object.get('isInitialSort', True), display) sort_descriptor_list = self.sort_descriptor(sort) if sort: From 885103b8fb27003815f4a9e71962537744bf17ef Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Thu, 3 Feb 2022 15:29:25 -0500 Subject: [PATCH 13/17] #2202 - prevent situation where initial load would store an empty string as the first sort-upon field, causing a sort rank to display --- seeker/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/seeker/views.py b/seeker/views.py index 9153862..30e6e28 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1132,6 +1132,8 @@ def header(self, results=None, sort_descriptor_list=None): current_sort = self.view.search_object['sort'] if not isinstance(current_sort, list): current_sort = [current_sort] + if '' in current_sort: + current_sort.remove('') sort = None sort_order = 0 cls += ' sort' @@ -1147,8 +1149,10 @@ def header(self, results=None, sort_descriptor_list=None): if sort_descriptor_list[0][potential_default].get('order', None) == 'desc': potential_default = '{}{}'.format('-', potential_default) potential_default = potential_default.replace('.raw', '').replace('.label','') - if potential_default not in current_sort: + print("potential default is", potential_default) + if potential_default and potential_default not in current_sort: current_sort.append(potential_default) + print("current sort before for loop", current_sort) for sort_field in current_sort: if sort_field.lstrip('-') == self.field: # If the current sort field is this field, give it a class a change direction. From 4e01f24c09424d2c481f89253dac75d9919210c9 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Tue, 8 Feb 2022 19:05:53 -0500 Subject: [PATCH 14/17] 2202 Use presence of isInitialSort in the search object to correctly label the next sorting direction if client is not set up to use multisort for AdvancedSeeker --- seeker/views.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 30e6e28..1762de7 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1129,6 +1129,7 @@ def header(self, results=None, sort_descriptor_list=None): cls += ' {}_{}'.format(self.model_lower, self.field.replace('.', '_')) if not self.sort: return format_html('{}', cls, self.header_html) + is_multicolumn = 'isInitialSort' in self.view.search_object current_sort = self.view.search_object['sort'] if not isinstance(current_sort, list): current_sort = [current_sort] @@ -1139,20 +1140,14 @@ def header(self, results=None, sort_descriptor_list=None): cls += ' sort' sr_label = '' next_sort = '' - next_sorting = { - 'Ascending': 'sort descending', - 'Descending': 'remove from sort' - } data_sort = self.field if sort_descriptor_list: potential_default = list(sort_descriptor_list[0].keys())[0] if sort_descriptor_list[0][potential_default].get('order', None) == 'desc': potential_default = '{}{}'.format('-', potential_default) potential_default = potential_default.replace('.raw', '').replace('.label','') - print("potential default is", potential_default) if potential_default and potential_default not in current_sort: current_sort.append(potential_default) - print("current sort before for loop", current_sort) for sort_field in current_sort: if sort_field.lstrip('-') == self.field: # If the current sort field is this field, give it a class a change direction. @@ -1161,12 +1156,15 @@ def header(self, results=None, sort_descriptor_list=None): d = '' if sort_field.startswith('-') else '-' data_sort = '{}{}'.format(d, self.field) sort_order = current_sort.index(sort_field) + 1 - print("index of", sort_field, "in current sort", current_sort) if len(current_sort) == 1: sr_label = format_html('({})', sort) else: sr_label = format_html('Number {} in sort order ({})', sort_order, sort) - # If this field isn't already being sorted upon, label it as being sorted ascending + next_sorting = { + 'Ascending': 'sort descending', + 'Descending': 'remove from sort' if is_multicolumn else 'sort ascending' + } + # If this field isn't already being sorted upon, label its next sort direction as ascending next_sort = next_sorting.get(sort, 'sort ascending') # If results provided, we check to see if header has space to allow for wordwrapping. If it already wordwrapped From 58c3159ec516854ebd7c5261f0f9d44805842652 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Thu, 10 Feb 2022 16:13:32 -0500 Subject: [PATCH 15/17] WIP: 2202 - Revert sort_descriptor to its original return type (dictionary rather than list of dictionaries) to be non-breaking, initial commit for SeekerView --- seeker/views.py | 74 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 1762de7..699ce7f 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -82,23 +82,47 @@ def bind(self, view, visible): return self - def header(self): + def header(self, sort_list=None): cls = '%s_%s' % (self.view.document._doc_type.name, self.field.replace('.', '_')) cls += ' %s_%s' % (self.model_lower, self.field.replace('.', '_')) if not self.sort: return format_html('{}', cls, self.header_html) q = self.view.request.GET.copy() - field = q.get('s', '') + sort_fields = q.getlist('s', []) sort = None + sort_order = 0 + sort_rank = '' cls += ' sort' - if field.lstrip('-') == self.field: - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if field.startswith('-') else 'Ascending' - cls += ' desc' if field.startswith('-') else ' asc' - d = '' if field.startswith('-') else '-' - q['s'] = '%s%s' % (d, self.field) + data_sort = '' + if sort_fields: + for field in sort_fields: + if self.field.lstrip('-') == field.lstrip('-'): + # If the current sort field is this field, give it a class a change direction. + sort = 'Descending' if field.startswith('-') else 'Ascending' + cls += ' desc' if field.startswith('-') else ' asc' + d = '' if field.startswith('-') else '-' + data_sort = '%s%s' % (d, self.field) + if d: + # if this column is selected, its sort rank will be maintained when its direction is changed + current_sort = q.getlist('s', []) + field_index = current_sort.index(field) + current_sort[field_index] = data_sort + q.setlist('s', current_sort) + else: + # remove from the sort + current_sort = q.getlist('s', []) + current_sort.remove(field) + q.setlist('s', current_sort) + else: + data_sort = self.field + q.appendlist('s', data_sort) else: q['s'] = self.field + # sort_order = sort_list.index(sort_field) + 1 + # if len(sort_list) == 1: + # sr_label = format_html('({})', sort) + # else: + # sr_label = format_html('Number {} in sort order ({})', sort_order, sort) next_sorting = { 'Ascending': 'sort descending', 'Descending': 'remove from sort' @@ -110,16 +134,17 @@ def header(self): span = format_html('', self.field_definition) else: span = '' + + if sort_order and len(sort_list) != 1: + sort_rank = format_html('{} ', sort_order) + else: + # Don't indicate sort rank when only one field is being sorted upon + sort_rank = '' + + html = format_html( - '{}{} {}', - cls, - q.urlencode(), - next_sort, - q['s'], - self.header_html, - sr_label, - span - ) + '{}{}{} {}', + cls, sort_rank, q.urlencode(), next_sort, data_sort, self.header_html, sr_label, span) return html def context(self, result, **kwargs): @@ -260,6 +285,11 @@ class SeekerView(View): The second value is the index/position of the field (used as the index in list.insert(index, 'field name')). """ + sort_list = [] + """ + Used for storing sorts from the query string, not used by AdvancedSeekerView + """ + @property def required_display_fields(self): return [t[0] for t in self.required_display] @@ -811,11 +841,7 @@ def sort_descriptor(self, sort): if isinstance(sort, dict): return sort else: - sort = [sort] if isinstance(sort, str) else sort - sort_list = [] - for s in sort: - sort_list.append(self.apply_sort_descriptor(s)) - return sort_list + return self.apply_sort_descriptor(sort) def is_initial(self): """ @@ -920,6 +946,7 @@ def render(self): 'available_page_sizes': self.available_page_sizes, 'page_spread': self.page_spread, 'sort': sort, + 'sort_list': self.sort_list, 'querystring': context_querystring, 'reset_querystring': self.normalized_querystring(ignore=['p', 's', 'saved_search']), 'show_rank': self.show_rank, @@ -1643,7 +1670,8 @@ def render_results(self, export): # Finally, grab the results. sort = self.get_sort_field(columns, self.search_object['sort'], self.search_object.get('isInitialSort', True), display) - sort_descriptor_list = self.sort_descriptor(sort) + sort = [sort] if isinstance(sort, str) else sort + sort_descriptor_list = [self.sort_descriptor(s) for s in sort] if sort: results = search.sort(*sort_descriptor_list)[offset:offset + page_size].execute() From c1adfbefc18d17c1a16018f3513e35a0842669bf Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Fri, 11 Feb 2022 09:12:42 -0500 Subject: [PATCH 16/17] 2202 Add multisort as the default functionality to SeekerView Column.header(). Builds a querystring/href for each column that handles adding sort fields, changing sort field direction, and removing sort fields. --- seeker/views.py | 66 ++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 699ce7f..94c5fac 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -82,7 +82,7 @@ def bind(self, view, visible): return self - def header(self, sort_list=None): + def header(self): cls = '%s_%s' % (self.view.document._doc_type.name, self.field.replace('.', '_')) cls += ' %s_%s' % (self.model_lower, self.field.replace('.', '_')) if not self.sort: @@ -93,49 +93,55 @@ def header(self, sort_list=None): sort_order = 0 sort_rank = '' cls += ' sort' + sr_label = '' data_sort = '' if sort_fields: - for field in sort_fields: - if self.field.lstrip('-') == field.lstrip('-'): - # If the current sort field is this field, give it a class a change direction. - sort = 'Descending' if field.startswith('-') else 'Ascending' - cls += ' desc' if field.startswith('-') else ' asc' - d = '' if field.startswith('-') else '-' - data_sort = '%s%s' % (d, self.field) - if d: - # if this column is selected, its sort rank will be maintained when its direction is changed - current_sort = q.getlist('s', []) - field_index = current_sort.index(field) - current_sort[field_index] = data_sort - q.setlist('s', current_sort) - else: - # remove from the sort - current_sort = q.getlist('s', []) - current_sort.remove(field) - q.setlist('s', current_sort) + if (self.field in sort_fields or '-{}'.format(self.field) in sort_fields): + field = self.field + d = '-' + # If the current sort field is this field, give it a class a change direction. + if not self.field in sort_fields: + field = '-{}'.format(self.field) + d = '' + sort_order = q.getlist('s', []).index(field) + 1 + sort = 'Ascending' if d else 'Descending' + cls += ' asc' if d else ' desc' + data_sort = '%s%s' % (d, self.field) + if d: + # if this column is selected, its sort rank will be maintained when its direction is changed + current_sort = q.getlist('s', []) + field_index = current_sort.index(field) + current_sort[field_index] = data_sort + q.setlist('s', current_sort) else: - data_sort = self.field + # remove from the sort + current_sort = q.getlist('s', []) + current_sort.remove(field) + q.setlist('s', current_sort) + else: + data_sort = self.field + if self.field not in q.getlist('s', []): q.appendlist('s', data_sort) else: q['s'] = self.field - # sort_order = sort_list.index(sort_field) + 1 - # if len(sort_list) == 1: - # sr_label = format_html('({})', sort) - # else: - # sr_label = format_html('Number {} in sort order ({})', sort_order, sort) + + if sort: + if len(sort_fields) == 1: + sr_label = format_html('({})', sort) + else: + sr_label = format_html('Number {} in sort order ({})', sort_order, sort) next_sorting = { 'Ascending': 'sort descending', 'Descending': 'remove from sort' } #If this field isn't already being sorted upon, label it as being sorted ascending next_sort = next_sorting.get(sort, 'sort ascending') - sr_label = format_html(' ({})', sort) if sort else '' if self.field_definition: span = format_html('', self.field_definition) else: span = '' - if sort_order and len(sort_list) != 1: + if sort_order and len(sort_fields) > 1: sort_rank = format_html('{} ', sort_order) else: # Don't indicate sort rank when only one field is being sorted upon @@ -285,11 +291,6 @@ class SeekerView(View): The second value is the index/position of the field (used as the index in list.insert(index, 'field name')). """ - sort_list = [] - """ - Used for storing sorts from the query string, not used by AdvancedSeekerView - """ - @property def required_display_fields(self): return [t[0] for t in self.required_display] @@ -946,7 +947,6 @@ def render(self): 'available_page_sizes': self.available_page_sizes, 'page_spread': self.page_spread, 'sort': sort, - 'sort_list': self.sort_list, 'querystring': context_querystring, 'reset_querystring': self.normalized_querystring(ignore=['p', 's', 'saved_search']), 'show_rank': self.show_rank, From 529f858d6f79a3910c73aa31fb84aadc33aee565 Mon Sep 17 00:00:00 2001 From: Zoee Leckron Date: Fri, 11 Feb 2022 09:56:08 -0500 Subject: [PATCH 17/17] 2202 consolidate code related to sort_rank class --- seeker/views.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/seeker/views.py b/seeker/views.py index 94c5fac..0b32569 100644 --- a/seeker/views.py +++ b/seeker/views.py @@ -1204,20 +1204,15 @@ def header(self, results=None, sort_descriptor_list=None): else: span = '' - if sort_order: + # Don't indicate sort rank when only one field is being sorted upon + if sort_order and len(current_sort) > 1: sort_rank = format_html('{} ', sort_order) else: sort_rank = '' - # Don't indicate sort rank when only one field is being sorted upon - if len(current_sort) == 1: - html = format_html( - '{}{} {}', - cls, next_sort, data_sort, self.header_html, sr_label, span) - else: - html = format_html( - '{}{}{} {}', - cls, sort_rank, next_sort, data_sort, self.header_html, sr_label, span) + html = format_html( + '{}{}{} {}', + cls, sort_rank, next_sort, data_sort, self.header_html, sr_label, span) return html def get_data_max_length(self, results):