Convert add_purchase.js to TypeScript; drop dead add_edition.js (issue #17)

- Add ts/add_purchase.ts: typed port of add_purchase.js. Replaces getEl with
  document.querySelector; types the search-select:change CustomEvent detail
  (SearchSelectChangeDetail / SearchSelectOption)
- Point add_purchase / edit_purchase views at compiled dist/add_purchase.js
- Delete add_edition.js: no Edition model/view/url/template references it
  (feature was removed; the script was dead)
- Delete the now-superseded add_game.js / add_purchase.js source files
- Tighten test_rendered_pages assertions to the dist/ script paths

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 13:27:05 +02:00
parent b03d9241fc
commit daae9b8944
5 changed files with 35 additions and 59 deletions
-24
View File
@@ -1,24 +0,0 @@
import { syncSelectInputUntilChanged } from "./utils.js";
let syncData = [
{
source: "#id_game",
source_value: "dataset.name",
target: "#id_name",
target_value: "value",
},
{
source: "#id_game",
source_value: "textContent",
target: "#id_sort_name",
target_value: "value",
},
{
source: "#id_game",
source_value: "dataset.year",
target: "#id_year_released",
target_value: "value",
},
];
syncSelectInputUntilChanged(syncData, "form");
-12
View File
@@ -1,12 +0,0 @@
import { syncSelectInputUntilChanged } from "./utils.js";
let syncData = [
{
source: "#id_name",
source_value: "value",
target: "#id_sort_name",
target_value: "value",
},
];
syncSelectInputUntilChanged(syncData, "form");
-63
View File
@@ -1,63 +0,0 @@
import { getEl, disableElementsWhenTrue, onSwap } from "./utils.js";
// Switch between a single bundle price and one price per game. The per-game
// inputs are the selection-fields element; this only sets the policy: the
// hidden pricing_mode the view reads, the element's "active" flag, and whether
// the bundle Price field is shown.
function applyPricingMode(separate) {
const pricingMode = getEl("#id_pricing_mode");
if (pricingMode) pricingMode.value = separate ? "per_game" : "combined";
const selectionFields = document.querySelector("selection-fields");
if (selectionFields)
selectionFields.setAttribute("active", separate ? "true" : "false");
const priceInput = getEl("#id_price");
if (priceInput) {
const wrapper = priceInput.closest("div");
if (wrapper) wrapper.classList.toggle("hidden", separate);
}
}
// The games field is now a SearchSelect widget (a <div>, not a <select>), so we
// react to its custom "search-select:change" event instead of syncing a select.
document.addEventListener("search-select:change", (event) => {
if (event.detail.name !== "games") return;
// Auto-fill platform from the clicked option's data-platform.
const last = event.detail.last;
const platformId = last && last.data ? last.data.platform : "";
if (platformId) {
const platformEl = getEl("#id_platform");
if (platformEl) platformEl.value = platformId;
}
// The combined/per-game choice is only meaningful with 2+ games. Reveal the
// checkbox there; below the threshold, fall back to a single bundle price.
const separateRow = getEl("#separate-prices-row");
const multipleGames = event.detail.values.length >= 2;
if (separateRow) separateRow.classList.toggle("hidden", !multipleGames);
if (!multipleGames) {
const checkbox = getEl("#id_separate_prices");
if (checkbox) checkbox.checked = false;
applyPricingMode(false);
}
});
onSwap("#id_separate_prices", (checkbox) => {
checkbox.addEventListener("change", () => applyPricingMode(checkbox.checked));
});
function setupElementHandlers() {
disableElementsWhenTrue("#id_type", "game", [
"#id_name",
"#id_related_game",
]);
}
onSwap("#id_type", (typeSelect) => {
setupElementHandlers();
typeSelect.addEventListener("change", () => {
setupElementHandlers();
});
});
+3 -3
View File
@@ -194,7 +194,7 @@ def _pricing_controls() -> Node:
By default the form's own single Price field is the bundle price. When 2+
games are selected and "Separate price per game" is checked, the per-game
inputs (the general ``selection-fields`` element) take over and the bundle
Price is hidden. Toggle/visibility wiring lives in add_purchase.js; the
Price is hidden. Toggle/visibility wiring lives in ts/add_purchase.ts; the
hidden ``pricing_mode`` tells the view which path to take.
"""
return Div(attributes=[("id", "pricing-controls")])[
@@ -301,7 +301,7 @@ def add_purchase(request: HttpRequest, game_id: int = 0) -> HttpResponse:
),
title="Add New Purchase",
scripts=mark_safe(
ModuleScript("search_select.js") + ModuleScript("add_purchase.js")
ModuleScript("search_select.js") + ModuleScript("dist/add_purchase.js")
),
)
@@ -319,7 +319,7 @@ def edit_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
AddForm(form, request=request, additional_row=_purchase_additional_row()),
title="Edit Purchase",
scripts=mark_safe(
ModuleScript("search_select.js") + ModuleScript("add_purchase.js")
ModuleScript("search_select.js") + ModuleScript("dist/add_purchase.js")
),
)