Skip to content

Commit 51f2384

Browse files
committed
Add basic route attribute filters
1 parent 162e71e commit 51f2384

File tree

1 file changed

+63
-11
lines changed

1 file changed

+63
-11
lines changed

pages/routes.html

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
{% for route in sorted_routes %}
7979
<tr>
8080
<td>
81-
<a href="{{ route.id }}" title="{{ route.id }}">
81+
<a href="{{ route.id }}/" title="{{ route.id }}">
8282
<span class="name">{{ route.name }}</span>
8383
</a>
8484
{% if route.gpx %}
@@ -117,6 +117,7 @@
117117

118118
Tabulator.registerModule([EditModule, FormatModule, InteractionModule, MutatorModule, ResizeColumnsModule, ResizeTableModule, SortModule, SelectRowModule, FilterModule]);
119119

120+
let searched = false
120121
document.addEventListener("DOMContentLoaded", () => {
121122
let table = new Tabulator("#routes table", {
122123
columns:
@@ -217,23 +218,74 @@
217218
let previousTimeout = null;
218219
document.getElementById("filter-search").addEventListener("input", (event) => {
219220
if (previousTimeout) {
220-
clearTimeout(previousTimeout);
221+
clearTimeout(previousTimeout);
221222
}
222-
// Debounce 100ms
223-
previousTimeout = setTimeout(() => {
224-
// Update query parameter
225-
const url = new URL(window.location);
226-
url.searchParams.set("q", event.target.value);
227-
window.history.replaceState({}, "", url);
228-
table.setFilter("name", "like", event.target.value);
229-
}, 100);
223+
224+
// Debounce
225+
previousTimeout = setTimeout(() => {
226+
if (window.goatcounter && !searched) {
227+
window.goatcounter.count({path: "searched", event: true});
228+
searched = true;
229+
}
230+
const query = event.target.value;
231+
const url = new URL(window.location);
232+
233+
// Update query parameter
234+
url.searchParams.set("q", query);
235+
window.history.replaceState({}, "", url);
236+
237+
const startMatch = query.match(/start:([^ ]+)/);
238+
const endMatch = query.match(/end:([^ ]+)/);
239+
const distanceMatches = [...query.matchAll(/distance:(<=|>=|<|>|)?([0-9.]+)/g)];
240+
const neighborhoodMatches = [...query.matchAll(/neighborhood:(['"]([^'"]+)['"]|[^ ]+)/g)];
241+
const nameQuery = query
242+
.replace(/start:[^ ]+/, "")
243+
.replace(/end:[^ ]+/, "")
244+
.replace(/distance:(<=|>=|<|>|)?[0-9.]+/, "")
245+
.replace(/neighborhood:(['"]([^'"]+)['"]|[^ ]+)/g, "")
246+
.trim();
247+
248+
// Remove only relevant filters
249+
table.getFilters().forEach((filter) => {
250+
console.log(filter);
251+
if (
252+
["start", "end", "distance_mi", "name", "neighborhoods"].includes(filter.field)
253+
) {
254+
table.removeFilter(filter.field, filter.type, filter.value);
255+
}
256+
});
257+
258+
if (startMatch) {
259+
table.addFilter("start", "starts", startMatch[1]);
260+
}
261+
262+
if (endMatch) {
263+
table.addFilter("end", "starts", endMatch[1]);
264+
}
265+
266+
if (neighborhoodMatches.length > 0) {
267+
table.addFilter("neighborhoods", "keywords", neighborhoodMatches.map((match) => match[2] || match[1]).join(","), {matchAll: true, separator: ","});
268+
}
269+
270+
271+
// FIXME: Only one actually works
272+
distanceMatches.forEach((match) => {
273+
const operator = match[1] || "="; // Default operator is "=" if not provided
274+
const value = Number.parseFloat(match[2]);
275+
table.addFilter("distance_mi", operator, value);
276+
});
277+
278+
if (nameQuery) {
279+
table.addFilter("name", "like", nameQuery);
280+
}
281+
}, 150);
230282

231283
});
232284
document.getElementById("filter-deprecated").addEventListener("change", (event) => {
233285
if (event.target.checked) {
234286
table.removeFilter("deprecated", "!=", true);
235287
} else {
236-
table.setFilter("deprecated", "!=", true);
288+
table.addFilter("deprecated", "!=", true);
237289
}
238290
table.redraw();
239291
});

0 commit comments

Comments
 (0)