diff --git a/pages/Search/Search.css b/pages/Search/Search.css index 5cbcd271..0cfc38d1 100644 --- a/pages/Search/Search.css +++ b/pages/Search/Search.css @@ -107,7 +107,7 @@ h2 { box-shadow: 0px 15px 0px -14px black; } -.results { +#results { border-collapse: separate; /* This is necessary for borders to stay fixed with position: sticky */ margin: 0; diff --git a/pages/Search/Search.hbs b/pages/Search/Search.hbs index 3657ac45..b5102785 100644 --- a/pages/Search/Search.hbs +++ b/pages/Search/Search.hbs @@ -49,7 +49,7 @@ Click on a header column to sort. - +
@@ -66,44 +66,44 @@ {{!-- Component Fields --}} {{#with sort }} -

Search Results

- + - - - - - - diff --git a/pages/Search/Search.js b/pages/Search/Search.js index e73e1de9..e2038232 100644 --- a/pages/Search/Search.js +++ b/pages/Search/Search.js @@ -1,3 +1,5 @@ +import SortDirectives from '../../scripts/SortDirectives.js' + /** * * @param {URL} url A URL object. @@ -44,20 +46,15 @@ export function Search(req, res) { // Sort - sort = sort - .split(`,`) - .filter(Boolean) - .map(directive => ({ - ascending: !directive.startsWith(`-`), - field: directive.replace(/^-/v, ``), - })) + sort = new SortDirectives(sort) - if (sort.length) { + if (sort.size) { allResults.sort((a, b) => { - const comparisons = sort.map(({ ascending, field }) => { + const comparisons = Array.from(sort.entries()) + .map(([field, direction]) => { const comparison = (a[field] || ``).localeCompare(b[field] || ``) - return ascending ? comparison : comparison * -1 + return direction === `ascending` ? comparison : comparison * -1 }) return comparisons.reduce((state, comparison) => state ? state : comparison, 0) @@ -65,7 +62,6 @@ export function Search(req, res) { }) } - // Pagination limit = Number(limit) @@ -141,10 +137,7 @@ export function Search(req, res) { startIndex: (offset + 1).toLocaleString(), }, results, - sort: sort.reduce((hash, { ascending, field }) => { - hash[field] = ascending ? `ascending` : `descending` - return hash - }, {}), + sort: Object.fromEntries(sort), totalResults: allResults.length.toLocaleString(), }) diff --git a/pages/Search/client.js b/pages/Search/client.js index 750fd6a1..a000f96d 100644 --- a/pages/Search/client.js +++ b/pages/Search/client.js @@ -2,6 +2,7 @@ import Copier from '../../scripts/Copier.js' import SearchBox from './scripts/SearchBox.js' +import Table from './scripts/Table.js' // Initialize button to copy citation information @@ -18,3 +19,9 @@ if (button && el) { const search = new SearchBox search.initialize() + +// Initialize results table + +const table = new Table + +table.initialize() diff --git a/pages/Search/scripts/Table.js b/pages/Search/scripts/Table.js new file mode 100644 index 00000000..fe0e17b3 --- /dev/null +++ b/pages/Search/scripts/Table.js @@ -0,0 +1,36 @@ +/* global document, window */ + +import SortDirectives from '../../../scripts/SortDirectives.js' + +const directivesOrder = [null, `ascending`, `descending`, null] + +export default class Table { + + initialize() { + this.el = document.getElementById(`results`) + if (!this.el) return + this.el.addEventListener(`click`, this.sort.bind(this)) + } + + sort(ev) { + + const button = ev.target.closest(`button`) + + if (!button) return + + const { field } = button.dataset + const th = button.parentNode + const direction = th.ariaSort + const url = new URL(window.location.href) + let sort = url.searchParams.get(`sort`) + const directives = new SortDirectives(sort) + const directive = directivesOrder[directivesOrder.indexOf(direction) + 1] + + directives.add(field, directive) + sort = directives.serialize() + url.searchParams.set(`sort`, sort) + window.location = url.href + + } + +} diff --git a/scripts/SortDirectives.js b/scripts/SortDirectives.js new file mode 100644 index 00000000..2597a05a --- /dev/null +++ b/scripts/SortDirectives.js @@ -0,0 +1,51 @@ +export default class SortDirectives extends Map { + + constructor(directives = ``) { + + super() + + if (!directives) return + + directives.split(`,`) + .filter(Boolean) + .forEach(directive => { + + const field = directive.replace(/^-/v, ``) + const direction = directive.startsWith(`-`) ? `descending` : `ascending` + + this.set(field, direction) + + }) + + } + + /** + * Add a new sort directive to the list of directives. NOTE: The directive will be set as first in the insertion order. + * @param {String} field The field to set a new sort direction for. + * @param {"ascending"|"descending"} direction The sort direction to use for the field. + */ + add(field, direction) { + + this.delete(field) + + const entries = Array.from(this.entries()) + + if (direction) { + entries.unshift([field, direction]) + } + + this.clear() + + for (const [f, d] of entries) { + this.set(f, d) + } + + } + + serialize() { + return Array.from(this.entries()) + .map(([field, direction]) => `${ direction === `descending` ? `-` : `` }${ field }`) + .join(`,`) + } + +}