mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-29 05:42:33 +00:00
Move plugin sort from dropdown to clickable column headers
Replace the toolbar sort dropdown with sortable Name/Source/Status column headers that cycle ascending, descending, then clear. Add a Source column and a PluginSortKey::None baseline for the cleared state. The whole header cell is the click target and the sort triangle snaps in without a fade.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// why: C++ owns ordering; this file only sends and reflects sort state.
|
||||
|
||||
const DEFAULT_PLUGIN_SORT = { key: "status", order: "asc" };
|
||||
const DEFAULT_PLUGIN_SORT = { key: "none", order: "asc" };
|
||||
// note: SORT_FIELDS are the clickable columns. "none" is the baseline/cleared state, not a field -
|
||||
// it is special-cased in NormalizePluginSort and produced by CyclePluginSort's third click.
|
||||
const SORT_FIELDS = new Set(["status", "name", "source"]);
|
||||
let pluginSort = { ...DEFAULT_PLUGIN_SORT };
|
||||
|
||||
@@ -8,14 +10,14 @@ let pluginSort = { ...DEFAULT_PLUGIN_SORT };
|
||||
function NormalizePluginSort(sortKey, sortOrder) {
|
||||
const key = String(sortKey || "");
|
||||
return {
|
||||
key: SORT_FIELDS.has(key) ? key : DEFAULT_PLUGIN_SORT.key,
|
||||
key: key === "none" ? "none" : (SORT_FIELDS.has(key) ? key : DEFAULT_PLUGIN_SORT.key),
|
||||
order: sortOrder === "desc" ? "desc" : DEFAULT_PLUGIN_SORT.order,
|
||||
};
|
||||
}
|
||||
|
||||
function RequestPluginSort(sortKey, sortOrder) {
|
||||
pluginSort = NormalizePluginSort(sortKey, sortOrder);
|
||||
RenderSortMenuState();
|
||||
RenderSortHeaders();
|
||||
|
||||
if (typeof SendMessage === "function")
|
||||
SendMessage("set_plugin_sort", {
|
||||
@@ -24,67 +26,42 @@ function RequestPluginSort(sortKey, sortOrder) {
|
||||
});
|
||||
}
|
||||
|
||||
let sortMenuEl = null;
|
||||
let sortMenuButton = null;
|
||||
let sortCurrentLabel = null;
|
||||
|
||||
function InitSortDropdown() {
|
||||
sortMenuEl = document.getElementById("sortMenu");
|
||||
sortMenuButton = document.getElementById("sort_menu_btn");
|
||||
sortCurrentLabel = document.getElementById("sort_current_label");
|
||||
if (!sortMenuButton || !sortMenuEl)
|
||||
// why: one click per column cycles asc -> desc -> clear; setting any column clears the previous
|
||||
// one for free because C++ (and pluginSort) only ever hold a single key.
|
||||
function CyclePluginSort(field) {
|
||||
if (!SORT_FIELDS.has(field))
|
||||
return;
|
||||
sortMenuButton.addEventListener("click", ToggleSortMenu);
|
||||
sortMenuEl.addEventListener("click", OnSortMenuClick);
|
||||
RenderSortMenuState();
|
||||
if (pluginSort.key !== field)
|
||||
RequestPluginSort(field, "asc");
|
||||
else if (pluginSort.order === "asc")
|
||||
RequestPluginSort(field, "desc");
|
||||
else
|
||||
RequestPluginSort("none", "asc"); // third click: back to baseline
|
||||
}
|
||||
|
||||
function ToggleSortMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (!sortMenuEl)
|
||||
return;
|
||||
const willShow = sortMenuEl.hidden;
|
||||
// why: our stopPropagation blocks index.js's outside-click handler, so close the sibling explore menu ourselves.
|
||||
if (willShow && typeof HideExploreMenu === "function")
|
||||
HideExploreMenu();
|
||||
sortMenuEl.hidden = !willShow;
|
||||
sortMenuButton.setAttribute("aria-expanded", willShow ? "true" : "false");
|
||||
// why: paints the sort indicator for headers
|
||||
// e.g., when user clicks triangle to change sort order, or change to sort by a new different field
|
||||
function RenderSortHeaders() {
|
||||
document.querySelectorAll(".hdr .sort-th").forEach((th) => {
|
||||
// "" | "asc" | "desc" - renders the triangle via plugin-sort.css [data-sort=...].
|
||||
th.dataset.sort = th.dataset.sortField === pluginSort.key ? pluginSort.order : "";
|
||||
});
|
||||
}
|
||||
|
||||
function HideSortMenu() {
|
||||
if (!sortMenuEl || sortMenuEl.hidden)
|
||||
return;
|
||||
sortMenuEl.hidden = true;
|
||||
sortMenuButton.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
|
||||
function OnSortMenuClick(event) {
|
||||
const item = event.target.closest("[data-sort-field],[data-sort-order]");
|
||||
if (!item)
|
||||
return;
|
||||
event.preventDefault();
|
||||
const sortKey = item.dataset.sortField || pluginSort.key;
|
||||
const sortOrder = item.dataset.sortOrder || pluginSort.order;
|
||||
// why: leave the menu open so the user can set field then order in one visit; outside-click/Escape close it.
|
||||
RequestPluginSort(sortKey, sortOrder);
|
||||
}
|
||||
|
||||
function RenderSortMenuState() {
|
||||
const field = sortMenuEl?.querySelector(`[data-sort-field="${pluginSort.key}"]`);
|
||||
if (sortCurrentLabel)
|
||||
sortCurrentLabel.textContent = field?.textContent.trim() || "Status";
|
||||
sortMenuButton?.classList.toggle("order-desc", pluginSort.order === "desc");
|
||||
sortMenuEl?.querySelectorAll("[data-sort-field]").forEach((el) =>
|
||||
el.setAttribute("aria-checked", el.dataset.sortField === pluginSort.key ? "true" : "false"));
|
||||
sortMenuEl?.querySelectorAll("[data-sort-order]").forEach((el) =>
|
||||
el.setAttribute("aria-checked", el.dataset.sortOrder === pluginSort.order ? "true" : "false"));
|
||||
function InitSortHeaders() {
|
||||
document.querySelectorAll(".hdr .sort-th").forEach((th) => {
|
||||
th.addEventListener("click", () => CyclePluginSort(th.dataset.sortField));
|
||||
// note: role="button" cells need Enter/Space to match the old dropdown's keyboard access.
|
||||
th.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
CyclePluginSort(th.dataset.sortField);
|
||||
}
|
||||
});
|
||||
});
|
||||
RenderSortHeaders(); // paint the initial state (baseline = no triangle)
|
||||
}
|
||||
|
||||
// why: guarded so the module can be loaded in headless syntax checks.
|
||||
// note: owns its own lifecycle + outside-click/Escape, so index.js's OnInit needs no edit.
|
||||
if (typeof document !== "undefined") {
|
||||
document.addEventListener("DOMContentLoaded", InitSortDropdown);
|
||||
document.addEventListener("click", (event) => { if (!event.target.closest(".sort-dropdown")) HideSortMenu(); });
|
||||
document.addEventListener("keydown", (event) => { if (event.key === "Escape") HideSortMenu(); });
|
||||
}
|
||||
if (typeof document !== "undefined")
|
||||
document.addEventListener("DOMContentLoaded", InitSortHeaders);
|
||||
|
||||
Reference in New Issue
Block a user