diff --git a/src/ims/element/incident/incidents_template/template.xhtml b/src/ims/element/incident/incidents_template/template.xhtml
index 34b49d6db..1f23bcfd9 100644
--- a/src/ims/element/incident/incidents_template/template.xhtml
+++ b/src/ims/element/incident/incidents_template/template.xhtml
@@ -60,14 +60,14 @@
All
@@ -82,19 +82,19 @@
All Days
@@ -104,15 +104,12 @@
type="button"
class="btn btn-light btn-sm dropdown-toggle"
data-bs-toggle="dropdown"
+ data-bs-auto-close="outside"
>
-
- All Types
+ Types
diff --git a/src/ims/element/incident/reports_template/template.xhtml b/src/ims/element/incident/reports_template/template.xhtml
index c9aec8f3f..17e733155 100644
--- a/src/ims/element/incident/reports_template/template.xhtml
+++ b/src/ims/element/incident/reports_template/template.xhtml
@@ -60,20 +60,20 @@
All Days
@@ -86,17 +86,17 @@
All Rows
diff --git a/src/ims/element/static/field_reports.js b/src/ims/element/static/field_reports.js
index b34accb7b..200c8d9c2 100644
--- a/src/ims/element/static/field_reports.js
+++ b/src/ims/element/static/field_reports.js
@@ -228,12 +228,13 @@ function initTableButtons() {
.children(".col-sm-6:first")
.replaceWith($("#button_container"));
- const urlParams = new URLSearchParams(window.location.search);
+ const fragment = window.location.hash.startsWith("#") ? window.location.hash.substring(1) : window.location.hash;
+ const fragmentParams = new URLSearchParams(fragment);
// Set button defaults
- showDays(urlParams.get("days")??defaultDaysBack, false);
- showRows(urlParams.get("rows")??defaultRows, false);
+ showDays(fragmentParams.get("days")??defaultDaysBack, false);
+ showRows(fragmentParams.get("rows")??defaultRows, false);
}
@@ -256,7 +257,7 @@ function initSearchField() {
const searchInput = document.getElementById("search_input");
const searchAndDraw = function () {
- pushWindowState();
+ replaceWindowState();
let q = searchInput.value;
let isRegex = false;
if (q.startsWith("/") && q.endsWith("/")) {
@@ -267,8 +268,9 @@ function initSearchField() {
fieldReportsTable.draw();
}
- const urlParams = new URLSearchParams(window.location.search);
- const queryString = urlParams.get("q");
+ const fragment = window.location.hash.startsWith("#") ? window.location.hash.substring(1) : window.location.hash;
+ const fragmentParams = new URLSearchParams(fragment);
+ const queryString = fragmentParams.get("q");
if (queryString) {
searchInput.value = queryString;
searchAndDraw();
@@ -438,6 +440,6 @@ function replaceWindowState() {
// Next step is to create search params for the other filters too
- const newURL = `${urlReplace(url_viewFieldReports)}?${new URLSearchParams(newParams).toString()}`;
+ const newURL = `${urlReplace(url_viewFieldReports)}#${new URLSearchParams(newParams).toString()}`;
window.history.replaceState(null, null, newURL);
}
diff --git a/src/ims/element/static/incidents.js b/src/ims/element/static/incidents.js
index 147e9bff6..8f2c520c4 100644
--- a/src/ims/element/static/incidents.js
+++ b/src/ims/element/static/incidents.js
@@ -312,29 +312,41 @@ function initTableButtons() {
.children(".col-sm-6:first")
.replaceWith($("#button_container"));
+ $(document).on('click', '.dropdown-item-checkable', function(event) {
+ event.preventDefault();
+ $(this).toggleClass('dropdown-item-checked');
+ showCheckedTypes(true);
+ });
+
const $typeFilter = $("#ul_show_type");
for (const i in allIncidentTypes) {
const type = allIncidentTypes[i];
- const $a = $("", {class: "name dropdown-item", href:"#"});
+ const $a = $("", {
+ class: "dropdown-item dropdown-item-checkable dropdown-item-checked",
+ href:"#",
+ });
$a.text(type.toString());
- const $li = $("", {id: "show_type_" + i, onclick: "showType(" + i + ", true)"});
- $li.append($a);
- $typeFilter.append($li);
+ $typeFilter.append($a);
}
- const urlParams = new URLSearchParams(window.location.search);
+ const fragment = window.location.hash.startsWith("#") ? window.location.hash.substring(1) : window.location.hash;
+ const fragmentParams = new URLSearchParams(fragment);
// Set button defaults
- const type = urlParams.get("type");
- if (type && allIncidentTypes.indexOf(type) !== -1) {
- showType(allIncidentTypes.indexOf(type), false);
- } else {
- showType(defaultType, false);
+ const types = fragmentParams.getAll("type");
+ const validTypes = [];
+ for (const t of types) {
+ console.log(`reading type ${t} checking`);
+ if (t && allIncidentTypes.indexOf(t) !== -1) {
+ validTypes.push(t);
+ }
}
- showState(urlParams.get("state")??defaultState, false);
- showDays(urlParams.get("days")??defaultDaysBack, false);
- showRows(urlParams.get("rows")??defaultRows, false);
+ setCheckedTypes(validTypes);
+ showCheckedTypes(false);
+ showState(fragmentParams.get("state")??defaultState, false);
+ showDays(fragmentParams.get("days")??defaultDaysBack, false);
+ showRows(fragmentParams.get("rows")??defaultRows, false);
}
@@ -368,8 +380,9 @@ function initSearchField() {
incidentsTable.draw();
}
- const urlParams = new URLSearchParams(window.location.search);
- const queryString = urlParams.get("q");
+ const fragment = window.location.hash.startsWith("#") ? window.location.hash.substring(1) : window.location.hash;
+ const fragmentParams = new URLSearchParams(fragment);
+ const queryString = fragmentParams.get("q");
if (queryString) {
searchInput.value = queryString;
searchAndDraw();
@@ -456,19 +469,11 @@ function initSearch() {
return false
}
- switch (_showType) {
- case null:
- // fallthrough
- case "all":
- break;
- default:
- if (_showType >= 0 && _showType < allIncidentTypes.length) {
- const st = allIncidentTypes[_showType];
- if (!(incident.incident_types??[]).includes(st)) {
- return false;
- }
- }
- break;
+ if (_showTypes && _showTypes.length > 0) {
+ const intersect = Object.values(incident.incident_types).filter(t => _showTypes.includes(t)).length > 0;
+ if (!intersect) {
+ return false;
+ }
}
return true;
@@ -547,26 +552,34 @@ function showDays(daysBackToShow, replaceState) {
// Show type button handling
//
-// _showType will be one of:
-// "all" or null (meaning show everything)
-// a numeric index into allIncidentTypes
-let _showType = null;
-const defaultType = "all";
-
-function showType(typeToShow, replaceState) {
- // see _showType above for values of "typeToShow"
- const id = typeToShow??defaultType;
+// list of Incident Types to show, in text form
+let _showTypes = [];
- const $menu = $("#show_type");
- const $item = $("#show_type_" + id);
+function setCheckedTypes(types) {
+ for (const $type of $('#ul_show_type > a')) {
+ if (types.length === 0 || types.includes($type.innerHTML)) {
+ $type.classList.add("dropdown-item-checked")
+ } else {
+ $type.classList.remove("dropdown-item-checked")
+ }
+ }
+}
- // Get title from selected item
- const selection = $item.children(".name").html();
+function readCheckedTypes() {
+ const checkedTypes = [];
+ for (const $type of $('#ul_show_type > a')) {
+ if ($type.classList.contains("dropdown-item-checked")) {
+ checkedTypes.push($type.innerHTML);
+ }
+ }
+ return checkedTypes;
+}
- // Update menu title to reflect selected item
- $menu.children(".selection").html(selection);
+function showCheckedTypes(replaceState) {
+ _showTypes = readCheckedTypes();
- _showType = typeToShow;
+ const numTypes = _showTypes.length === allIncidentTypes.length ? "All" : _showTypes.length;
+ document.getElementById("show_type").textContent = `${numTypes} Types`;
if (replaceState) {
replaceWindowState();
@@ -618,8 +631,10 @@ function replaceWindowState() {
if (searchVal) {
newParams.push(["q", searchVal]);
}
- if (_showType != null && _showType !== defaultType) {
- newParams.push(["type", allIncidentTypes[_showType]]);
+ if (_showTypes != null && _showTypes.length !== allIncidentTypes.length) {
+ for (const t of _showTypes) {
+ newParams.push(["type", t]);
+ }
}
if (_showState != null && _showState !== defaultState) {
newParams.push(["state", _showState]);
@@ -631,8 +646,6 @@ function replaceWindowState() {
newParams.push(["rows", _showRows]);
}
- // Next step is to create search params for the other filters too
-
- const newURL = `${viewIncidentsURL}?${new URLSearchParams(newParams).toString()}`;
+ const newURL = `${viewIncidentsURL}#${new URLSearchParams(newParams).toString()}`;
window.history.replaceState(null, null, newURL);
}
diff --git a/src/ims/element/static/style.css b/src/ims/element/static/style.css
index 59fba7bb1..e0c135ce6 100644
--- a/src/ims/element/static/style.css
+++ b/src/ims/element/static/style.css
@@ -316,3 +316,14 @@ h1 {
.hidden {
display: none !important;
}
+
+.dropdown-item-checkable {
+ padding: var(--bs-dropdown-item-padding-y) 1.5rem;
+}
+
+.dropdown-item-checked::before {
+ position: absolute;
+ left: .4rem;
+ content: '✓';
+ font-weight: 600;
+}