Skip to content

Commit

Permalink
Merge pull request #1906 from laws-africa/sort
Browse files Browse the repository at this point in the history
Sorting
  • Loading branch information
longhotsummer authored Jul 16, 2024
2 parents 77c1872 + 10e9e4e commit 749fbba
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 84 deletions.
5 changes: 0 additions & 5 deletions liiweb/views/legislation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ class LegislationListView(FilteredDocumentListView):
latest_expression_only = True
extra_context = {"doc_table_citations": True, "legislation_list_sort": "title"}

def get_template_names(self):
if self.request.htmx:
return ["peachjam/faceted_doc_table.html"]
return ["liiweb/legislation_list.html"]

def filter_queryset(self, qs):
if self.variant == "all":
pass
Expand Down
16 changes: 12 additions & 4 deletions peachjam/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ class BaseDocumentFilterForm(forms.Form):
attorneys = forms.CharField(required=False)
outcomes = forms.CharField(required=False)

sort = forms.ChoiceField(
required=False,
choices=[
("title", _("Title") + " (A - Z)"),
("-title", _("Title") + " (Z - A)"),
("-date", _("Date") + " " + _("(Newest first)")),
("date", _("Date") + " " + _("(Oldest first)")),
],
)

def __init__(self, data, *args, **kwargs):
self.params = QueryDict(mutable=True)
self.params.update(data)
Expand Down Expand Up @@ -147,10 +157,8 @@ def filter_queryset(self, queryset, exclude=None):
return queryset

def order_queryset(self, queryset, exclude=None):
if self.cleaned_data.get("alphabet") and exclude != "alphabet":
queryset = queryset.order_by("title")
else:
queryset = queryset.order_by("-date", "title")
sort = self.cleaned_data.get("sort") or "-date"
queryset = queryset.order_by(sort, "title")
return queryset


Expand Down
27 changes: 27 additions & 0 deletions peachjam/js/components/document-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class DocumentTable {
public root: HTMLElement;

constructor (root: HTMLElement) {
this.root = root;
this.setupSorting();
}

setupSorting () {
this.root.querySelectorAll('[data-sort]').forEach((el) => {
el.addEventListener('click', (e: Event) => {
this.setSort(el.getAttribute('data-sort') || '');
});
});
}

setSort (value: string) {
// find the enclosing form element and set the value of the name=sort input
const form = this.root.closest('form');
if (form && form.sort) {
form.sort.value = value;
form.sort.dispatchEvent(new Event('change'));
}
}
}

export default DocumentTable;
2 changes: 2 additions & 0 deletions peachjam/js/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CopyToClipboard } from './clipboard';
import { RelationshipEnrichments } from './RelationshipEnrichment';
import DocumentList from './document-list';
import DocumentTable from './document-table';
import DocumentContent from './DocumentContent/index';
import NavigationSelect from './navigation-select';
import { ToggleTab } from './tabs';
Expand All @@ -15,6 +16,7 @@ const components: Record<string, any> = {
// Data components
CopyToClipboard,
DocumentContent,
DocumentTable,
DocumentList,
NavigationSelect,
RelationshipEnrichments,
Expand Down
83 changes: 59 additions & 24 deletions peachjam/js/peachjam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import '@lawsafrica/law-widgets/dist/components/la-table-of-contents-controller'
import '@lawsafrica/law-widgets/dist/components/la-decorate-external-refs';
import '@lawsafrica/law-widgets/dist/components/la-decorate-internal-refs';
import '@lawsafrica/law-widgets/dist/components/la-decorate-terms';
import 'htmx.org';
// @ts-ignore
import htmx from 'htmx.org';

export interface PeachJamConfig {
appName: string;
Expand Down Expand Up @@ -43,8 +44,10 @@ class PeachJam {
this.setupConfig();
// add the current user agent to the root HTML element for use with pocketlaw
document.documentElement.setAttribute('data-user-agent', navigator.userAgent.toLowerCase());
this.setupHtmx();
this.setupSentry();
this.createComponents();
this.createComponents(document.body);
this.createVueComponents(document.body);
this.setupTooltips();
this.setupPopovers();
this.scrollNavTabs();
Expand All @@ -58,32 +61,64 @@ class PeachJam {
}
}

createComponents () {
document.querySelectorAll('[data-component]').forEach((el) => {
const name: string | null = el.getAttribute('data-component');
if (name && components[name]) {
// create the component and attached it to the HTML element
(el as any).component = new components[name](el);
this.components.push((el as any).component);
setupHtmx () {
window.htmx = htmx;
// htmx:load is fired both when the page loads (weird) and when new content is loaded. We only care about the latter
// case. See https://github.com/bigskysoftware/htmx/issues/1500
const htmxHelper = { firstLoad: true};
document.body.addEventListener('htmx:load', (e) => {
if (htmxHelper.firstLoad) {
htmxHelper.firstLoad = false;
return;
}
// mount components on new elements
this.createComponents(e.target as HTMLElement);
this.createVueComponents(e.target as HTMLElement);
});
}

createComponents (root: HTMLElement) {
if (root.getAttribute('data-component')) {
this.createComponent(root);
}
// @ts-ignore
for (const element of root.querySelectorAll('[data-component]')) {
this.createComponent(element);
}
}

createVueComponents (root: HTMLElement) {
// create vue-based components
document.querySelectorAll('[data-vue-component]').forEach((el) => {
const name = el.getAttribute('data-vue-component');
if (name && components[name]) {
const vueComp = components[name];
createAndMountApp({
component: vueComp,
// pass in the element's data attributes as props
props: { ...(el as HTMLElement).dataset },
use: [vueI18n],
mountTarget: el as HTMLElement
});
(el as any).component = vueComp;
this.components.push(vueComp);
}
});
// @ts-ignore
for (const element of root.querySelectorAll('[data-vue-component]')) {
this.createVueComponent(element);
}
}

createComponent (el: HTMLElement) {
const name: string | null = el.getAttribute('data-component');
if (name && components[name]) {
// create the component and attached it to the HTML element
(el as any).component = new components[name](el);
this.components.push((el as any).component);
}
}

createVueComponent (el: HTMLElement) {
// create vue-based components
const name = el.getAttribute('data-vue-component');
if (name && components[name]) {
const vueComp = components[name];
createAndMountApp({
component: vueComp,
// pass in the element's data attributes as props
props: { ...(el as HTMLElement).dataset },
use: [vueI18n],
mountTarget: el as HTMLElement
});
(el as any).component = vueComp;
this.components.push(vueComp);
}
}

setupSentry () {
Expand Down
2 changes: 1 addition & 1 deletion peachjam/static/js/app-prod.js

Large diffs are not rendered by default.

22 changes: 19 additions & 3 deletions peachjam/templates/peachjam/_document_table.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
{% load i18n peachjam %}
<div class="table-responsive" id="doc-table">
<div class="table-responsive"
id="doc-table"
data-component="DocumentTable">
<table class="doc-table {% if doc_table_toggle %}doc-table--toggle{% endif %} {% if doc_table_citations %}doc-table--citation{% endif %} {{ doc_table_classes }}">
<thead>
<tr>
{% if doc_table_toggle %}<th class="cell-toggle"></th>{% endif %}
<th scope="col" class="cell-title">{% trans 'Title' %}</th>
<th scope="col" class="cell-title">
<div class="align-items-center"
role="button"
data-sort="{% if form.sort.value == "title" %}-title{% else %}title{% endif %}">
{% trans 'Title' %}
<i class="bi ms-2 {% if form.sort.value == "title" %}bi-sort-up{% endif %} {% if form.sort.value == "-title" %}bi-sort-down{% endif %}"></i>
</div>
</th>
{% if doc_table_citations %}<th scope="col" class="cell-citation"></th>{% endif %}
{% if doc_table_show_jurisdiction %}
{% if MULTIPLE_JURISDICTIONS or MULTIPLE_LOCALITIES %}
Expand All @@ -14,7 +23,14 @@
{% if doc_table_show_author %}<th scope="col"></th>{% endif %}
{% if doc_table_show_court %}<th scope="col"></th>{% endif %}
{% if doc_table_show_doc_type %}<th scope="col"></th>{% endif %}
<th scope="col" class="cell-date">{% trans 'Date' %}</th>
<th scope="col" class="cell-date">
<div class="align-items-center"
role="button"
data-sort="{% if form.sort.value == "date" %}-date{% else %}date{% endif %}">
{% trans 'Date' %}
<i class="bi ms-2 {% if form.sort.value == "-date" %}bi-sort-up{% endif %} {% if form.sort.value == "date" %}bi-sort-down{% endif %}"></i>
</div>
</th>
</tr>
</thead>
{% for document in documents %}
Expand Down
86 changes: 44 additions & 42 deletions peachjam/templates/peachjam/faceted_doc_table.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{% load i18n %}
<div class="row" id="faceted-table">
<div class="col-lg-3 d-none d-lg-block">
<div>
{% block desktop-taxonomy-list %}{% endblock %}
</div>
<div class="pocketlaw-hidden">
<form method="get" id="filter-form">
<form method="get" id="filter-form" hx-include="#filter-form">
<div class="row" id="faceted-table">
<div class="col-lg-3 d-none d-lg-block">
<div>
{% block desktop-taxonomy-list %}{% endblock %}
</div>
<div class="pocketlaw-hidden">
<ul class="list-group">
<li class="position-relative list-group-item bg-light d-flex justify-content-between align-items-center">
<strong>{% trans 'Filters' %}</strong>
Expand Down Expand Up @@ -67,42 +67,44 @@
{% endif %}
{% endfor %}
</ul>
</form>
</div>
</div>
</div>
<div class="col-lg-9">
<div class="position-relative">
{% block content %}
{% if documents %}
{% block filter-documents %}
<div class="row">
<div class="col">
<input id="filter-input"
form="filter-form"
aria-label="Filter"
placeholder="Filter documents"
class="form-control"
type="text"
name="q"/>
</div>
<div class="col-auto ms-0 ps-0">
<button hx-get="{{ request.path }}"
hx-target="#doc-table"
hx-push-url="true"
hx-include="#facetd-table"
class="btn btn-primary"
type="submit"
value="Filter">
Filter
</button>
<div class="col-lg-9">
<div class="position-relative">
{% block content %}
{% if documents %}
{% block filter-documents %}
<div class="mb-2 d-flex" hx-target="#doc-table" hx-push-url="true">
<div class="flex-grow-1 me-3">
<input id="filter-input"
hx-get="{{ request.path }}"
hx-trigger="keyup changed delay:300ms"
aria-label="{% trans "Filter documents" %}"
placeholder="{% trans "Filter documents" %}"
class="form-control"
type="text"
name="q"/>
</div>
<div class="me-2 d-flex align-items-center">
<div class="d-none d-md-block me-2 text-nowrap">{% trans "Sort by" %}:</div>
<select class="form-control" hx-get="{{ request.path }}" name="sort">
{% for opt in form.sort %}{{ opt }}{% endfor %}
</select>
</div>
<div>
<button class="btn btn-primary"
hx-get="{{ request.path }}"
type="submit"
value="Filter">Filter</button>
</div>
</div>
</div>
{% endblock %}
{% include 'peachjam/_document_table.html' %}
{% else %}
<p>{% trans 'No documents found.' %}</p>
{% endif %}
{% endblock %}
{% endblock %}
{% include 'peachjam/_document_table.html' %}
{% else %}
<p>{% trans 'No documents found.' %}</p>
{% endif %}
{% endblock %}
</div>
</div>
</div>
</div>
</form>
2 changes: 1 addition & 1 deletion peachjam/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class BaseDocumentFilterFormTestCase(TestCase):
def test_years_filter_with_single_year(self):
response = self.client.get("/legal_instruments/?years=2007")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["facet_data"]["years"], [2007])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2007"])

def test_alphabet_filter(self):
response = self.client.get("/legal_instruments/?alphabet=a")
Expand Down
7 changes: 4 additions & 3 deletions peachjam/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ def test_legislation_listing(self):
documents,
)
self.assertEqual(
[1969, 2005, 2010, 2020], sorted(response.context["facet_data"]["years"])
["1969", "2005", "2010", "2020"],
sorted(response.context["facet_data"]["years"]["options"]),
)

def test_legislation_detail(self):
Expand All @@ -126,7 +127,7 @@ def test_legal_instrument_listing(self):
"African Charter on Democracy, Elections and Governance",
documents,
)
self.assertEqual(response.context["facet_data"]["years"], [2007])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2007"])

def test_legal_instrument_detail(self):
response = self.client.get(
Expand All @@ -150,7 +151,7 @@ def test_generic_document_listing(self):
"Activity Report of the Pan-African Parliament, July 2016 to June 2017",
documents,
)
self.assertEqual(response.context["facet_data"]["years"], [2017])
self.assertEqual(response.context["facet_data"]["years"]["options"], ["2017"])

def test_generic_document_detail(self):
response = self.client.get(
Expand Down
9 changes: 8 additions & 1 deletion peachjam/views/generic_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ def __init__(self, title):

return docs

def get_template_names(self):
if self.request.htmx:
if self.request.htmx.target == "doc-table":
return ["peachjam/_document_table.html"]
return ["peachjam/faceted_doc_table.html"]
return super().get_template_names()


class FilteredDocumentListView(DocumentListView):
"""Generic list view for filtered document lists."""
Expand Down Expand Up @@ -115,7 +122,7 @@ def filter_queryset(self, qs):
return self.form.filter_queryset(qs)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context = super().get_context_data(form=self.form, **kwargs)

self.add_facets(context)
context["doc_count"] = context["paginator"].count
Expand Down

0 comments on commit 749fbba

Please sign in to comment.