test interface update

This commit is contained in:
Jurgis Sakalauskas
2026-05-22 14:55:24 +03:00
parent 9094adfda8
commit 02522bbd04
+91 -20
View File
@@ -62,10 +62,10 @@
function okClicked() { function okClicked() {
let path = document.getElementById("endpoint").value; let path = document.getElementById("endpoint").value;
paths = [""]; paths = [""];
loadApiPath(path); loadApiPath(path, "replace");
} }
function loadApiPath(path) { function loadApiPath(path, historyMode) {
$.ajax({ $.ajax({
url: path, url: path,
success: function(result) { success: function(result) {
@@ -75,14 +75,37 @@
} else { } else {
$("#debug").html(""); $("#debug").html("");
} }
// mirror our in-memory navigation into the browser history so the
// back/forward buttons move between views instead of leaving /if
if (historyMode === "push") {
history.pushState({ paths: paths.slice(), url: path }, "");
} else if (historyMode === "replace") {
history.replaceState({ paths: paths.slice(), url: path }, "");
}
processApiResult(result); processApiResult(result);
} }
}); });
} }
window.addEventListener("popstate", function(e) {
if (e.state && e.state.paths) {
paths = e.state.paths.slice();
loadApiPath(e.state.url);
}
});
function processApiResult(result) { function processApiResult(result) {
if (!result) return; //todo error if (!result) return; //todo error
let endpoint = document.getElementById("endpoint").value;
// context-menu actions don't refresh the container by default, so the api
// can return forceUpdate to re-query and re-render the current list
if (result.forceUpdate) {
loadApiPath(endpoint + "?path=" + result.forceUpdate.urlParams.path);
return;
}
if (result.msgBoxOK) { if (result.msgBoxOK) {
$("#modalBody").text(result.msgBoxOK); $("#modalBody").text(result.msgBoxOK);
$("#modal").modal("show"); $("#modal").modal("show");
@@ -91,6 +114,13 @@
if (result.notification) { if (result.notification) {
$("#modalBody").text(result.notification); $("#modalBody").text(result.notification);
$("#modal").modal("show"); $("#modal").modal("show");
if (result.refreshContainer === false) {
paths.pop();
} else {
// reload the current container so the action's effect is visible
loadApiPath(endpoint + "?path=" + paths[paths.length - 1]);
}
return;
} }
if (result.play) { if (result.play) {
@@ -170,7 +200,15 @@
for (let i = 0; i < result.items.length; i++) { for (let i = 0; i < result.items.length; i++) {
let item = result.items[i]; let item = result.items[i];
let itemHtml = "<button type=\"button\" class=\"list-group-item list-group-item-action\""; let hasContextMenus = item.contextMenus && item.contextMenus.length;
// context-menu items live inside a flex row, so the action area is a plain
// button and the row wrapper carries the list-group-item styling
let btnClass = hasContextMenus
? "btn text-start flex-grow-1 border-0 py-2 px-3"
: "list-group-item list-group-item-action";
let itemHtml = "<button type=\"button\" class=\"" + btnClass + "\"";
itemHtml = itemHtml + " data-path=\"" + item.path + "\""; itemHtml = itemHtml + " data-path=\"" + item.path + "\"";
if (item.searchFor) { if (item.searchFor) {
itemHtml = itemHtml + " data-searchfor=\"" + item.searchFor + "\""; itemHtml = itemHtml + " data-searchfor=\"" + item.searchFor + "\"";
@@ -189,6 +227,21 @@
itemHtml = itemHtml + ">"; itemHtml = itemHtml + ">";
itemHtml = itemHtml + itemIcon + " " + item.label + (item.plot ? "<div class=\"fw-lighter\">" + item.plot + "</div>" : "") + "</button>"; itemHtml = itemHtml + itemIcon + " " + item.label + (item.plot ? "<div class=\"fw-lighter\">" + item.plot + "</div>" : "") + "</button>";
if (hasContextMenus) {
let menuHtml = "<div class=\"dropdown me-2\">";
menuHtml = menuHtml + "<button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\"><i class=\"bi-three-dots-vertical\"></i></button>";
menuHtml = menuHtml + "<ul class=\"dropdown-menu dropdown-menu-end\">";
for (let j = 0; j < item.contextMenus.length; j++) {
let cm = item.contextMenus[j];
let cmPath = cm.urlParams ? cm.urlParams.path : cm.path;
menuHtml = menuHtml + "<li><button type=\"button\" class=\"dropdown-item\" data-cm-path=\"" + cmPath + "\">" + cm.name + "</button></li>";
}
menuHtml = menuHtml + "</ul></div>";
itemHtml = "<div class=\"list-group-item d-flex justify-content-between align-items-center p-0\">" + itemHtml + menuHtml + "</div>";
}
itemsHtml = itemsHtml + itemHtml; itemsHtml = itemsHtml + itemHtml;
} }
itemsHtml = itemsHtml + "</div>"; itemsHtml = itemsHtml + "</div>";
@@ -197,30 +250,48 @@
} }
$(document).click("button", function(e) { $(document).click(function(e) {
//todo - disable navigation after click //todo - disable navigation after click
let path = $(e.target).data("path");
let folder = $(e.target).data("folder");
let playable = $(e.target).data("playable");
let action = $(e.target).data("action");
let searchFor = $(e.target).data("searchfor");
let endpoint = document.getElementById("endpoint").value; let endpoint = document.getElementById("endpoint").value;
// a context-menu option was selected -> query its path, same as action "query"
let cmEl = $(e.target).closest("[data-cm-path]");
if (cmEl.length) {
loadApiPath(endpoint + "?path=" + cmEl.attr("data-cm-path"));
return;
}
// resolve the clicked item from the closest element holding item data,
// so clicks on the inner icon/plot still navigate
let itemEl = $(e.target).closest("[data-path]");
if (!itemEl.length) {
return;
}
let path = itemEl.data("path");
let folder = itemEl.data("folder");
let playable = itemEl.data("playable");
let action = itemEl.data("action");
let searchFor = itemEl.data("searchfor");
if (folder && path) { if (folder && path) {
//navigate? //navigate?
if (path === ".." || path === ".") { if (path === "..") {
if (paths.length > 1 && path === "..") { // go up a level via history so browser-back and in-page back stay in
paths.pop(); // sync; popstate restores the parent's paths snapshot and reloads it
} history.back();
return;
path = paths[paths.length - 1];
} else {
paths.push(path);
} }
loadApiPath(endpoint + "?path=" + path); if (path === ".") {
// refresh the current container (e.g. player "Back"), no history change
loadApiPath(endpoint + "?path=" + paths[paths.length - 1]);
return;
}
paths.push(path);
loadApiPath(endpoint + "?path=" + path, "push");
return; return;
} }
@@ -242,7 +313,7 @@
let searchText = prompt("What are you searching for?", iSearchFor); let searchText = prompt("What are you searching for?", iSearchFor);
if (searchText) { if (searchText) {
paths.push(path + "&search=" + searchText); paths.push(path + "&search=" + searchText);
loadApiPath(endpoint + "?path=" + path + "&search=" + searchText); loadApiPath(endpoint + "?path=" + path + "&search=" + searchText, "push");
} }
} }