diff --git a/index.html b/index.html
index 19014b96..2a5e9214 100644
--- a/index.html
+++ b/index.html
@@ -6096,6 +6096,7 @@
+
diff --git a/modules/dynamic/editors/cultures-editor.js b/modules/dynamic/editors/cultures-editor.js
index fddb8bb5..7ef8f1e3 100644
--- a/modules/dynamic/editors/cultures-editor.js
+++ b/modules/dynamic/editors/cultures-editor.js
@@ -1,4 +1,4 @@
-const body = insertEditorHtml();
+const $body = insertEditorHtml();
addListeners();
const cultureTypes = ["Generic", "River", "Lake", "Naval", "Nomadic", "Hunting", "Highland"];
@@ -20,7 +20,7 @@ export function open() {
close: closeCulturesEditor,
position: {my: "right top", at: "right-10 top+10", of: "svg"}
});
- body.focus();
+ $body.focus();
}
function insertEditorHtml() {
@@ -85,29 +85,27 @@ function insertEditorHtml() {
`;
- const dialogs = document.getElementById("dialogs");
- dialogs.insertAdjacentHTML("beforeend", editorHtml);
-
- return document.getElementById("culturesBody");
+ byId("dialogs").insertAdjacentHTML("beforeend", editorHtml);
+ return byId("culturesBody");
}
function addListeners() {
applySortingByHeader("culturesHeader");
- document.getElementById("culturesEditorRefresh").addEventListener("click", refreshCulturesEditor);
- document.getElementById("culturesEditStyle").addEventListener("click", () => editStyle("cults"));
- document.getElementById("culturesLegend").addEventListener("click", toggleLegend);
- document.getElementById("culturesPercentage").addEventListener("click", togglePercentageMode);
- document.getElementById("culturesHeirarchy").addEventListener("click", showHierarchy);
- document.getElementById("culturesRecalculate").addEventListener("click", () => recalculateCultures(true));
- document.getElementById("culturesManually").addEventListener("click", enterCultureManualAssignent);
- document.getElementById("culturesManuallyApply").addEventListener("click", applyCultureManualAssignent);
- document.getElementById("culturesManuallyCancel").addEventListener("click", () => exitCulturesManualAssignment());
- document.getElementById("culturesEditNamesBase").addEventListener("click", editNamesbase);
- document.getElementById("culturesAdd").addEventListener("click", enterAddCulturesMode);
- document.getElementById("culturesExport").addEventListener("click", downloadCulturesData);
- document.getElementById("culturesImport").addEventListener("click", () => document.getElementById("culturesCSVToLoad").click());
- document.getElementById("culturesCSVToLoad").addEventListener("change", uploadCulturesData);
+ byId("culturesEditorRefresh").on("click", refreshCulturesEditor);
+ byId("culturesEditStyle").on("click", () => editStyle("cults"));
+ byId("culturesLegend").on("click", toggleLegend);
+ byId("culturesPercentage").on("click", togglePercentageMode);
+ byId("culturesHeirarchy").on("click", showHierarchy);
+ byId("culturesRecalculate").on("click", () => recalculateCultures(true));
+ byId("culturesManually").on("click", enterCultureManualAssignent);
+ byId("culturesManuallyApply").on("click", applyCultureManualAssignent);
+ byId("culturesManuallyCancel").on("click", () => exitCulturesManualAssignment());
+ byId("culturesEditNamesBase").on("click", editNamesbase);
+ byId("culturesAdd").on("click", enterAddCulturesMode);
+ byId("culturesExport").on("click", downloadCulturesCsv);
+ byId("culturesImport").on("click", () => byId("culturesCSVToLoad").click());
+ byId("culturesCSVToLoad").on("change", uploadCulturesData);
}
function refreshCulturesEditor() {
@@ -137,7 +135,7 @@ function culturesEditorAddLines() {
let totalArea = 0;
let totalPopulation = 0;
- const emblemShapeGroup = document.getElementById("emblemShape")?.selectedOptions[0]?.parentNode?.label;
+ const emblemShapeGroup = byId("emblemShape")?.selectedOptions[0]?.parentNode?.label;
const selectShape = emblemShapeGroup === "Diversiform";
for (const c of pack.cultures) {
@@ -225,38 +223,39 @@ function culturesEditorAddLines() {
`;
}
- body.innerHTML = lines;
+ $body.innerHTML = lines;
// update footer
- document.getElementById("culturesFooterCultures").innerHTML = pack.cultures.filter(c => c.i && !c.removed).length;
- document.getElementById("culturesFooterCells").innerHTML = pack.cells.h.filter(h => h >= 20).length;
- document.getElementById("culturesFooterArea").innerHTML = `${si(totalArea)} ${unit}`;
- document.getElementById("culturesFooterPopulation").innerHTML = si(totalPopulation);
- document.getElementById("culturesFooterArea").dataset.area = totalArea;
- document.getElementById("culturesFooterPopulation").dataset.population = totalPopulation;
+ byId("culturesFooterCultures").innerHTML = pack.cultures.filter(c => c.i && !c.removed).length;
+ byId("culturesFooterCells").innerHTML = pack.cells.h.filter(h => h >= 20).length;
+ byId("culturesFooterArea").innerHTML = `${si(totalArea)} ${unit}`;
+ byId("culturesFooterPopulation").innerHTML = si(totalPopulation);
+ byId("culturesFooterArea").dataset.area = totalArea;
+ byId("culturesFooterPopulation").dataset.population = totalPopulation;
// add listeners
- body.querySelectorAll("div.cultures").forEach(el => el.addEventListener("mouseenter", cultureHighlightOn));
- body.querySelectorAll("div.cultures").forEach(el => el.addEventListener("mouseleave", cultureHighlightOff));
- body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectCultureOnLineClick));
- body.querySelectorAll("fill-box").forEach(el => el.addEventListener("click", cultureChangeColor));
- body.querySelectorAll("div > input.cultureName").forEach(el => el.addEventListener("input", cultureChangeName));
- body.querySelectorAll("div > span.icon-cw").forEach(el => el.addEventListener("click", cultureRegenerateName));
- body.querySelectorAll("div > input.cultureExpan").forEach(el => el.addEventListener("input", cultureChangeExpansionism));
- body.querySelectorAll("div > select.cultureType").forEach(el => el.addEventListener("change", cultureChangeType));
- body.querySelectorAll("div > select.cultureBase").forEach(el => el.addEventListener("change", cultureChangeBase));
- body.querySelectorAll("div > select.cultureEmblems").forEach(el => el.addEventListener("change", cultureChangeEmblemsShape));
- body.querySelectorAll("div > div.culturePopulation").forEach(el => el.addEventListener("click", changePopulation));
- body.querySelectorAll("div > span.icon-arrows-cw").forEach(el => el.addEventListener("click", cultureRegenerateBurgs));
- body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.addEventListener("click", cultureRemove));
+ $body.querySelectorAll("div.cultures").forEach(el => el.on("mouseenter", cultureHighlightOn));
+ $body.querySelectorAll("div.cultures").forEach(el => el.on("mouseleave", cultureHighlightOff));
+ $body.querySelectorAll("div.states").forEach(el => el.on("click", selectCultureOnLineClick));
+ $body.querySelectorAll("fill-box").forEach(el => el.on("click", cultureChangeColor));
+ $body.querySelectorAll("div > input.cultureName").forEach(el => el.on("input", cultureChangeName));
+ $body.querySelectorAll("div > span.icon-cw").forEach(el => el.on("click", cultureRegenerateName));
+ $body.querySelectorAll("div > input.cultureExpan").forEach(el => el.on("input", cultureChangeExpansionism));
+ $body.querySelectorAll("div > select.cultureType").forEach(el => el.on("change", cultureChangeType));
+ $body.querySelectorAll("div > select.cultureBase").forEach(el => el.on("change", cultureChangeBase));
+ $body.querySelectorAll("div > select.cultureEmblems").forEach(el => el.on("change", cultureChangeEmblemsShape));
+ $body.querySelectorAll("div > div.culturePopulation").forEach(el => el.on("click", changePopulation));
+ $body.querySelectorAll("div > span.icon-arrows-cw").forEach(el => el.on("click", cultureRegenerateBurgs));
+ $body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.on("click", cultureRemove));
- culturesHeader.querySelector("div[data-sortby='emblems']").style.display = selectShape ? "inline-block" : "none";
+ const $culturesHeader = byId("culturesHeader");
+ $culturesHeader.querySelector("div[data-sortby='emblems']").style.display = selectShape ? "inline-block" : "none";
- if (body.dataset.type === "percentage") {
- body.dataset.type = "absolute";
+ if ($body.dataset.type === "percentage") {
+ $body.dataset.type = "absolute";
togglePercentageMode();
}
- applySorting(culturesHeader);
+ applySorting($culturesHeader);
$("#culturesEditor").dialog({width: fitContent()});
}
@@ -284,8 +283,8 @@ function getShapeOptions(selectShape, selected) {
function cultureHighlightOn(event) {
const culture = +event.target.dataset.id;
- const info = document.getElementById("cultureInfo");
- if (info) {
+ const $info = byId("cultureInfo");
+ if ($info) {
d3.select("#hierarchy")
.select("g[data-id='" + culture + "'] > path")
.classed("selected", 1);
@@ -293,7 +292,7 @@ function cultureHighlightOn(event) {
const rural = c.rural * populationRate;
const urban = c.urban * populationRate * urbanization;
const population = rural + urban > 0 ? si(rn(rural + urban)) + " people" : "Extinct";
- info.innerHTML = `${c.name} culture. ${c.type}. ${population}`;
+ $info.innerHTML = `${c.name} culture. ${c.type}. ${population}`;
tip("Drag to change parent, drag to itself to move to the top level. Hold CTRL and click to change abbreviation");
}
@@ -317,12 +316,12 @@ function cultureHighlightOn(event) {
function cultureHighlightOff(event) {
const culture = +event.target.dataset.id;
- const info = document.getElementById("cultureInfo");
- if (info) {
+ const $info = byId("cultureInfo");
+ if ($info) {
d3.select("#hierarchy")
.select("g[data-id='" + culture + "'] > path")
.classed("selected", 0);
- info.innerHTML = "";
+ $info.innerHTML = "";
tip("");
}
@@ -340,12 +339,12 @@ function cultureHighlightOff(event) {
}
function cultureChangeColor() {
- const el = this;
- const currentFill = el.getAttribute("fill");
- const culture = +el.parentNode.dataset.id;
+ const $el = this;
+ const currentFill = $el.getAttribute("fill");
+ const culture = +$el.parentNode.dataset.id;
const callback = newFill => {
- el.fill = newFill;
+ $el.fill = newFill;
pack.cultures[culture].color = newFill;
cults
.select("#culture" + culture)
@@ -400,9 +399,9 @@ function cultureChangeEmblemsShape() {
this.parentNode.dataset.emblems = pack.cultures[culture].shield = shape;
const rerenderCOA = (id, coa) => {
- const coaEl = document.getElementById(id);
- if (!coaEl) return; // not rendered
- coaEl.remove();
+ const $coa = byId(id);
+ if (!$coa) return; // not rendered
+ $coa.remove();
COArenderer.trigger(id, coa);
};
@@ -570,12 +569,12 @@ function drawCultureCenters() {
.attr("cy", d => pack.cells.p[d.center][1])
.on("mouseenter", d => {
tip(tooltip, true);
- body.querySelector(`div[data-id='${d.i}']`).classList.add("selected");
+ $body.querySelector(`div[data-id='${d.i}']`).classList.add("selected");
cultureHighlightOn(event);
})
.on("mouseleave", d => {
tip("", true);
- body.querySelector(`div[data-id='${d.i}']`).classList.remove("selected");
+ $body.querySelector(`div[data-id='${d.i}']`).classList.remove("selected");
cultureHighlightOff(event);
})
.call(d3.drag().on("start", cultureCenterDrag));
@@ -606,19 +605,19 @@ function toggleLegend() {
}
function togglePercentageMode() {
- if (body.dataset.type === "absolute") {
- body.dataset.type = "percentage";
+ if ($body.dataset.type === "absolute") {
+ $body.dataset.type = "percentage";
const totalCells = +culturesFooterCells.innerHTML;
const totalArea = +culturesFooterArea.dataset.area;
const totalPopulation = +culturesFooterPopulation.dataset.population;
- body.querySelectorAll(":scope > div").forEach(function (el) {
+ $body.querySelectorAll(":scope > div").forEach(function (el) {
el.querySelector(".cultureCells").innerHTML = rn((+el.dataset.cells / totalCells) * 100) + "%";
el.querySelector(".cultureArea").innerHTML = rn((+el.dataset.area / totalArea) * 100) + "%";
el.querySelector(".culturePopulation").innerHTML = rn((+el.dataset.population / totalPopulation) * 100) + "%";
});
} else {
- body.dataset.type = "absolute";
+ $body.dataset.type = "absolute";
culturesEditorAddLines();
}
}
@@ -790,12 +789,12 @@ function enterCultureManualAssignent() {
customization = 4;
cults.append("g").attr("id", "temp");
document.querySelectorAll("#culturesBottom > *").forEach(el => (el.style.display = "none"));
- document.getElementById("culturesManuallyButtons").style.display = "inline-block";
+ byId("culturesManuallyButtons").style.display = "inline-block";
debug.select("#cultureCenters").style("display", "none");
culturesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden"));
culturesFooter.style.display = "none";
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
$("#culturesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}});
tip("Click on culture to select, drag the circle to change culture", true);
@@ -805,12 +804,12 @@ function enterCultureManualAssignent() {
.call(d3.drag().on("start", dragCultureBrush))
.on("touchmove mousemove", moveCultureBrush);
- body.querySelector("div").classList.add("selected");
+ $body.querySelector("div").classList.add("selected");
}
function selectCultureOnLineClick(i) {
if (customization !== 4) return;
- body.querySelector("div.selected").classList.remove("selected");
+ $body.querySelector("div.selected").classList.remove("selected");
this.classList.add("selected");
}
@@ -822,8 +821,8 @@ function selectCultureOnMapClick() {
const assigned = cults.select("#temp").select("polygon[data-cell='" + i + "']");
const culture = assigned.size() ? +assigned.attr("data-culture") : pack.cells.culture[i];
- body.querySelector("div.selected").classList.remove("selected");
- body.querySelector("div[data-id='" + culture + "']").classList.add("selected");
+ $body.querySelector("div.selected").classList.remove("selected");
+ $body.querySelector("div[data-id='" + culture + "']").classList.add("selected");
}
function dragCultureBrush() {
@@ -842,7 +841,7 @@ function dragCultureBrush() {
function changeCultureForSelection(selection) {
const temp = cults.select("#temp");
- const selected = body.querySelector("div.selected");
+ const selected = $body.querySelector("div.selected");
const cultureNew = +selected.dataset.id;
const color = pack.cultures[cultureNew].color || "#ffffff";
@@ -887,17 +886,17 @@ function exitCulturesManualAssignment(close) {
cults.select("#temp").remove();
removeCircle();
document.querySelectorAll("#culturesBottom > *").forEach(el => (el.style.display = "inline-block"));
- document.getElementById("culturesManuallyButtons").style.display = "none";
+ byId("culturesManuallyButtons").style.display = "none";
culturesEditor.querySelectorAll(".hide").forEach(el => el.classList.remove("hidden"));
culturesFooter.style.display = "block";
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
if (!close) $("#culturesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}});
debug.select("#cultureCenters").style("display", null);
restoreDefaultEvents();
clearMainTip();
- const selected = body.querySelector("div.selected");
+ const selected = $body.querySelector("div.selected");
if (selected) selected.classList.remove("selected");
}
@@ -908,14 +907,14 @@ function enterAddCulturesMode() {
this.classList.add("pressed");
tip("Click on the map to add a new culture", true);
viewbox.style("cursor", "crosshair").on("click", addCulture);
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
}
function exitAddCultureMode() {
customization = 0;
restoreDefaultEvents();
clearMainTip();
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
if (culturesAdd.classList.contains("pressed")) culturesAdd.classList.remove("pressed");
}
@@ -934,26 +933,20 @@ function addCulture() {
culturesEditorAddLines();
}
-function downloadCulturesData() {
- let data = `Id,Culture,Color,Cells,Expansionism,Type,Area ${getAreaUnit("2")},Population,Namesbase,Emblems Shape,Origin\n`; // headers
-
- body.querySelectorAll(":scope > div").forEach(function (el) {
- data += el.dataset.id + ",";
- data += el.dataset.name + ",";
- data += el.dataset.color + ",";
- data += el.dataset.cells + ",";
- data += el.dataset.expansionism + ",";
- data += el.dataset.type + ",";
- data += el.dataset.area + ",";
- data += el.dataset.population + ",";
- const base = +el.dataset.base;
- data += nameBases[base].name + ",";
- data += el.dataset.emblems + ",";
- data += pack.cultures[+el.dataset.id].origin + "\n";
+function downloadCulturesCsv() {
+ const unit = getAreaUnit("2");
+ const headers = `Id,Name,Color,Cells,Expansionism,Type,Area ${unit},Population,Namesbase,Emblems Shape,Origin`;
+ const lines = Array.from($body.querySelectorAll(":scope > div"));
+ const data = lines.map($line => {
+ const {id, name, color, cells, expansionism, type, area, population, emblems, base} = $line.dataset;
+ const namesbase = nameBases[+base].name;
+ const {origin} = pack.cultures[+id];
+ return [id, name, color, cells, expansionism, type, area, population, namesbase, emblems, origin].join(",");
});
+ const csvData = [headers].concat(data).join("\n");
const name = getFileName("Cultures") + ".csv";
- downloadFile(data, name);
+ downloadFile(csvData, name);
}
function closeCulturesEditor() {
diff --git a/modules/dynamic/editors/states-editor.js b/modules/dynamic/editors/states-editor.js
index 28aa0f7c..ea97aec0 100644
--- a/modules/dynamic/editors/states-editor.js
+++ b/modules/dynamic/editors/states-editor.js
@@ -1,4 +1,4 @@
-const body = insertEditorHtml();
+const $body = insertEditorHtml();
addListeners();
export function open() {
@@ -119,38 +119,35 @@ function insertEditorHtml() {
`;
- const dialogs = document.getElementById("dialogs");
- dialogs.insertAdjacentHTML("beforeend", editorHtml);
-
- return document.getElementById("statesBodySection");
+ byId("dialogs").insertAdjacentHTML("beforeend", editorHtml);
+ return byId("statesBodySection");
}
function addListeners() {
applySortingByHeader("statesHeader");
- document.getElementById("statesEditorRefresh").addEventListener("click", refreshStatesEditor);
- document.getElementById("statesEditStyle").addEventListener("click", () => editStyle("regions"));
- document.getElementById("statesLegend").addEventListener("click", toggleLegend);
- document.getElementById("statesPercentage").addEventListener("click", togglePercentageMode);
- document.getElementById("statesChart").addEventListener("click", showStatesChart);
- document.getElementById("statesRegenerate").addEventListener("click", openRegenerationMenu);
- document.getElementById("statesRegenerateBack").addEventListener("click", exitRegenerationMenu);
- document.getElementById("statesRecalculate").addEventListener("click", () => recalculateStates(true));
- document.getElementById("statesRandomize").addEventListener("click", randomizeStatesExpansion);
- document.getElementById("statesNeutral").addEventListener("input", changeStatesGrowthRate);
- document.getElementById("statesNeutralNumber").addEventListener("change", changeStatesGrowthRate);
- document.getElementById("statesManually").addEventListener("click", enterStatesManualAssignent);
- document.getElementById("statesManuallyApply").addEventListener("click", applyStatesManualAssignent);
- document.getElementById("statesManuallyCancel").addEventListener("click", () => exitStatesManualAssignment());
- document.getElementById("statesAdd").addEventListener("click", enterAddStateMode);
- document.getElementById("statesExport").addEventListener("click", downloadStatesData);
+ byId("statesEditorRefresh").on("click", refreshStatesEditor);
+ byId("statesEditStyle").on("click", () => editStyle("regions"));
+ byId("statesLegend").on("click", toggleLegend);
+ byId("statesPercentage").on("click", togglePercentageMode);
+ byId("statesChart").on("click", showStatesChart);
+ byId("statesRegenerate").on("click", openRegenerationMenu);
+ byId("statesRegenerateBack").on("click", exitRegenerationMenu);
+ byId("statesRecalculate").on("click", () => recalculateStates(true));
+ byId("statesRandomize").on("click", randomizeStatesExpansion);
+ byId("statesNeutral").on("input", changeStatesGrowthRate);
+ byId("statesNeutralNumber").on("change", changeStatesGrowthRate);
+ byId("statesManually").on("click", enterStatesManualAssignent);
+ byId("statesManuallyApply").on("click", applyStatesManualAssignent);
+ byId("statesManuallyCancel").on("click", () => exitStatesManualAssignment(false));
+ byId("statesAdd").on("click", enterAddStateMode);
+ byId("statesExport").on("click", downloadStatesCsv);
- body.addEventListener("click", function (event) {
- const element = event.target;
- const classList = element.classList;
- const line = element.parentNode;
- const state = +line.dataset.id;
- if (element.tagName === "FILL-BOX") stateChangeFill(element);
+ $body.on("click", event => {
+ const $element = event.target;
+ const classList = $element.classList;
+ const state = +$element.parentNode?.dataset?.id;
+ if ($element.tagName === "FILL-BOX") stateChangeFill($element);
else if (classList.contains("name")) editStateName(state);
else if (classList.contains("coaIcon")) editEmblem("state", "stateCOA" + state, pack.states[state]);
else if (classList.contains("icon-star-empty")) stateCapitalZoomIn(state);
@@ -159,22 +156,22 @@ function addListeners() {
else if (classList.contains("icon-trash-empty")) stateRemovePrompt(state);
});
- body.addEventListener("input", function (ev) {
- const element = ev.target;
- const classList = element.classList;
- const line = element.parentNode;
+ $body.on("input", function (ev) {
+ const $element = ev.target;
+ const classList = $element.classList;
+ const line = $element.parentNode;
const state = +line.dataset.id;
- if (classList.contains("stateCapital")) stateChangeCapitalName(state, line, element.value);
- else if (classList.contains("cultureType")) stateChangeType(state, line, element.value);
- else if (classList.contains("statePower")) stateChangeExpansionism(state, line, element.value);
+ if (classList.contains("stateCapital")) stateChangeCapitalName(state, line, $element.value);
+ else if (classList.contains("cultureType")) stateChangeType(state, line, $element.value);
+ else if (classList.contains("statePower")) stateChangeExpansionism(state, line, $element.value);
});
- body.addEventListener("change", function (ev) {
- const element = ev.target;
- const classList = element.classList;
- const line = element.parentNode;
+ $body.on("change", function (ev) {
+ const $element = ev.target;
+ const classList = $element.classList;
+ const line = $element.parentNode;
const state = +line.dataset.id;
- if (classList.contains("stateCulture")) stateChangeCulture(state, line, element.value);
+ if (classList.contains("stateCulture")) stateChangeCulture(state, line, $element.value);
});
}
@@ -186,11 +183,11 @@ function refreshStatesEditor() {
// add line for each state
function statesEditorAddLines() {
const unit = getAreaUnit();
- const hidden = statesRegenerateButtons.style.display === "block" ? "" : "hidden"; // show/hide regenerate columns
- let lines = "",
- totalArea = 0,
- totalPopulation = 0,
- totalBurgs = 0;
+ const hidden = byId("statesRegenerateButtons").style.display === "block" ? "" : "hidden"; // toggle regenerate columns
+ let lines = "";
+ let totalArea = 0;
+ let totalPopulation = 0;
+ let totalBurgs = 0;
for (const s of pack.states) {
if (s.removed) continue;
@@ -283,25 +280,26 @@ function statesEditorAddLines() {
`;
}
- body.innerHTML = lines;
+ $body.innerHTML = lines;
// update footer
- statesFooterStates.innerHTML = pack.states.filter(s => s.i && !s.removed).length;
- statesFooterCells.innerHTML = pack.cells.h.filter(h => h >= 20).length;
- statesFooterBurgs.innerHTML = totalBurgs;
- statesFooterArea.innerHTML = `${si(totalArea)} ${unit}`;
- statesFooterPopulation.innerHTML = si(totalPopulation);
- statesFooterArea.dataset.area = totalArea;
- statesFooterPopulation.dataset.population = totalPopulation;
+ byId("statesFooterStates").innerHTML = pack.states.filter(s => s.i && !s.removed).length;
+ byId("statesFooterCells").innerHTML = pack.cells.h.filter(h => h >= 20).length;
+ byId("statesFooterBurgs").innerHTML = totalBurgs;
+ byId("statesFooterArea").innerHTML = si(totalArea) + unit;
+ byId("statesFooterArea").dataset.area = totalArea;
+ byId("statesFooterPopulation").innerHTML = si(totalPopulation);
+ byId("statesFooterPopulation").dataset.population = totalPopulation;
- body.querySelectorAll("div.states").forEach(el => {
- el.addEventListener("click", selectStateOnLineClick);
- el.addEventListener("mouseenter", ev => stateHighlightOn(ev));
- el.addEventListener("mouseleave", ev => stateHighlightOff(ev));
+ // add listeners
+ $body.querySelectorAll("div.states").forEach(el => {
+ el.on("click", selectStateOnLineClick);
+ el.on("mouseenter", stateHighlightOn);
+ el.on("mouseleave", stateHighlightOff);
});
- if (body.dataset.type === "percentage") {
- body.dataset.type = "absolute";
+ if ($body.dataset.type === "percentage") {
+ $body.dataset.type = "absolute";
togglePercentageMode();
}
applySorting(statesHeader);
@@ -343,15 +341,13 @@ function stateHighlightOn(event) {
.attr("opacity", 1)
.attr("filter", "url(#blur1)");
- const l = path.node().getTotalLength(),
- dur = (l + 5000) / 2;
- const i = d3.interpolateString("0," + l, l + "," + l);
+ const totalLength = path.node().getTotalLength();
+ const duration = (totalLength + 5000) / 2;
+ const interpolate = d3.interpolateString(`0, ${totalLength}`, `${totalLength}, ${totalLength}`);
path
.transition()
- .duration(dur)
- .attrTween("stroke-dasharray", function () {
- return t => i(t);
- });
+ .duration(duration)
+ .attrTween("stroke-dasharray", () => interpolate);
}
function stateHighlightOff() {
@@ -395,10 +391,10 @@ function editStateName(state) {
}
const s = pack.states[state];
- document.getElementById("stateNameEditor").dataset.state = state;
- document.getElementById("stateNameEditorShort").value = s.name || "";
+ byId("stateNameEditor").dataset.state = state;
+ byId("stateNameEditorShort").value = s.name || "";
applyOption(stateNameEditorSelectForm, s.formName);
- document.getElementById("stateNameEditorFull").value = s.fullName || "";
+ byId("stateNameEditorFull").value = s.fullName || "";
$("#stateNameEditor").dialog({
resizable: false,
@@ -419,23 +415,23 @@ function editStateName(state) {
modules.editStateName = true;
// add listeners
- document.getElementById("stateNameEditorShortCulture").addEventListener("click", regenerateShortNameCuture);
- document.getElementById("stateNameEditorShortRandom").addEventListener("click", regenerateShortNameRandom);
- document.getElementById("stateNameEditorAddForm").addEventListener("click", addCustomForm);
- document.getElementById("stateNameEditorCustomForm").addEventListener("change", addCustomForm);
- document.getElementById("stateNameEditorFullRegenerate").addEventListener("click", regenerateFullName);
+ byId("stateNameEditorShortCulture").on("click", regenerateShortNameCuture);
+ byId("stateNameEditorShortRandom").on("click", regenerateShortNameRandom);
+ byId("stateNameEditorAddForm").on("click", addCustomForm);
+ byId("stateNameEditorCustomForm").on("change", addCustomForm);
+ byId("stateNameEditorFullRegenerate").on("click", regenerateFullName);
function regenerateShortNameCuture() {
const state = +stateNameEditor.dataset.state;
const culture = pack.states[state].culture;
const name = Names.getState(Names.getCultureShort(culture), culture);
- document.getElementById("stateNameEditorShort").value = name;
+ byId("stateNameEditorShort").value = name;
}
function regenerateShortNameRandom() {
const base = rand(nameBases.length - 1);
const name = Names.getState(Names.getBase(base), undefined, base);
- document.getElementById("stateNameEditorShort").value = name;
+ byId("stateNameEditorShort").value = name;
}
function addCustomForm() {
@@ -448,9 +444,9 @@ function editStateName(state) {
}
function regenerateFullName() {
- const short = document.getElementById("stateNameEditorShort").value;
- const form = document.getElementById("stateNameEditorSelectForm").value;
- document.getElementById("stateNameEditorFull").value = getFullName();
+ const short = byId("stateNameEditorShort").value;
+ const form = byId("stateNameEditorSelectForm").value;
+ byId("stateNameEditorFull").value = getFullName();
function getFullName() {
if (!form) return short;
@@ -462,9 +458,9 @@ function editStateName(state) {
}
function applyNameChange(s) {
- const nameInput = document.getElementById("stateNameEditorShort");
- const formSelect = document.getElementById("stateNameEditorSelectForm");
- const fullNameInput = document.getElementById("stateNameEditorFull");
+ const nameInput = byId("stateNameEditorShort");
+ const formSelect = byId("stateNameEditorSelectForm");
+ const fullNameInput = byId("stateNameEditorFull");
const nameChanged = nameInput.value !== s.name;
const formChanged = formSelect.value !== s.formName;
@@ -629,7 +625,7 @@ function stateRemove(state) {
// remove emblem
const coaId = "stateCOA" + state;
- document.getElementById(coaId).remove();
+ byId(coaId).remove();
emblems.select(`#stateEmblems > use[data-i='${state}']`).remove();
// remove provinces
@@ -640,7 +636,7 @@ function stateRemove(state) {
});
const coaId = "provinceCOA" + p;
- if (document.getElementById(coaId)) document.getElementById(coaId).remove();
+ if (byId(coaId)) byId(coaId).remove();
emblems.select(`#provinceEmblems > use[data-i='${p}']`).remove();
const g = provs.select("#provincesBody");
g.select("#province" + p).remove();
@@ -684,21 +680,21 @@ function toggleLegend() {
}
function togglePercentageMode() {
- if (body.dataset.type === "absolute") {
- body.dataset.type = "percentage";
+ if ($body.dataset.type === "absolute") {
+ $body.dataset.type = "percentage";
const totalCells = +statesFooterCells.innerHTML;
const totalBurgs = +statesFooterBurgs.innerHTML;
const totalArea = +statesFooterArea.dataset.area;
const totalPopulation = +statesFooterPopulation.dataset.population;
- body.querySelectorAll(":scope > div").forEach(function (el) {
+ $body.querySelectorAll(":scope > div").forEach(function (el) {
el.querySelector(".stateCells").innerHTML = rn((+el.dataset.cells / totalCells) * 100) + "%";
el.querySelector(".stateBurgs").innerHTML = rn((+el.dataset.burgs / totalBurgs) * 100) + "%";
el.querySelector(".stateArea").innerHTML = rn((+el.dataset.area / totalArea) * 100) + "%";
el.querySelector(".statePopulation").innerHTML = rn((+el.dataset.population / totalPopulation) * 100) + "%";
});
} else {
- body.dataset.type = "absolute";
+ $body.dataset.type = "absolute";
statesEditorAddLines();
}
}
@@ -741,7 +737,7 @@ function showStatesChart() {
.attr("text-anchor", "middle")
.attr("dominant-baseline", "central");
const graph = svg.append("g").attr("transform", `translate(-50, 0)`);
- document.getElementById("statesTreeType").addEventListener("change", updateChart);
+ byId("statesTreeType").on("change", updateChart);
treeLayout(root);
@@ -799,7 +795,7 @@ function showStatesChart() {
function hideInfo(ev) {
stateHighlightOff(ev);
- if (!document.getElementById("statesInfo")) return;
+ if (!byId("statesInfo")) return;
statesInfo.innerHTML = "";
d3.select(ev.target).select("circle").classed("selected", 0);
}
@@ -847,10 +843,14 @@ function showStatesChart() {
}
function openRegenerationMenu() {
- statesBottom.querySelectorAll(":scope > button").forEach(el => (el.style.display = "none"));
- statesRegenerateButtons.style.display = "block";
+ byId("statesBottom")
+ .querySelectorAll(":scope > button")
+ .forEach(el => (el.style.display = "none"));
+ byId("statesRegenerateButtons").style.display = "block";
- statesEditor.querySelectorAll(".show").forEach(el => el.classList.remove("hidden"));
+ byId("statesEditor")
+ .querySelectorAll(".show")
+ .forEach(el => el.classList.remove("hidden"));
$("#statesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
}
@@ -870,8 +870,8 @@ function recalculateStates(must) {
function changeStatesGrowthRate() {
const growthRate = +this.value;
- document.getElementById("statesNeutral").value = growthRate;
- document.getElementById("statesNeutralNumber").value = growthRate;
+ byId("statesNeutral").value = growthRate;
+ byId("statesNeutralNumber").value = growthRate;
statesNeutral = growthRate;
tip("Growth rate: " + growthRate);
recalculateStates(false);
@@ -882,15 +882,19 @@ function randomizeStatesExpansion() {
if (!s.i || s.removed) return;
const expansionism = rn(Math.random() * 4 + 1, 1);
s.expansionism = expansionism;
- body.querySelector("div.states[data-id='" + s.i + "'] > input.statePower").value = expansionism;
+ $body.querySelector("div.states[data-id='" + s.i + "'] > input.statePower").value = expansionism;
});
recalculateStates(true, true);
}
function exitRegenerationMenu() {
- statesBottom.querySelectorAll(":scope > button").forEach(el => (el.style.display = "inline-block"));
- statesRegenerateButtons.style.display = "none";
- statesEditor.querySelectorAll(".show").forEach(el => el.classList.add("hidden"));
+ byId("statesBottom")
+ .querySelectorAll(":scope > button")
+ .forEach(el => (el.style.display = "inline-block"));
+ byId("statesRegenerateButtons").style.display = "none";
+ byId("statesEditor")
+ .querySelectorAll(".show")
+ .forEach(el => el.classList.add("hidden"));
$("#statesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
}
@@ -899,24 +903,26 @@ function enterStatesManualAssignent() {
customization = 2;
statesBody.append("g").attr("id", "temp");
document.querySelectorAll("#statesBottom > button").forEach(el => (el.style.display = "none"));
- document.getElementById("statesManuallyButtons").style.display = "inline-block";
- document.getElementById("statesHalo").style.display = "none";
+ byId("statesManuallyButtons").style.display = "inline-block";
+ byId("statesHalo").style.display = "none";
- statesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden"));
+ byId("statesEditor")
+ .querySelectorAll(".hide")
+ .forEach(el => el.classList.add("hidden"));
statesFooter.style.display = "none";
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
$("#statesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
tip("Click on state to select, drag the circle to change state", true);
viewbox.style("cursor", "crosshair").on("click", selectStateOnMapClick).call(d3.drag().on("start", dragStateBrush)).on("touchmove mousemove", moveStateBrush);
- body.querySelector("div").classList.add("selected");
+ $body.querySelector("div").classList.add("selected");
}
function selectStateOnLineClick() {
if (customization !== 2) return;
if (this.parentNode.id !== "statesBodySection") return;
- body.querySelector("div.selected").classList.remove("selected");
+ $body.querySelector("div.selected").classList.remove("selected");
this.classList.add("selected");
}
@@ -928,8 +934,8 @@ function selectStateOnMapClick() {
const assigned = statesBody.select("#temp").select("polygon[data-cell='" + i + "']");
const state = assigned.size() ? +assigned.attr("data-state") : pack.cells.state[i];
- body.querySelector("div.selected").classList.remove("selected");
- body.querySelector("div[data-id='" + state + "']").classList.add("selected");
+ $body.querySelector("div.selected").classList.remove("selected");
+ $body.querySelector("div[data-id='" + state + "']").classList.add("selected");
}
function dragStateBrush() {
@@ -949,9 +955,9 @@ function dragStateBrush() {
// change state within selection
function changeStateForSelection(selection) {
const temp = statesBody.select("#temp");
- const selected = body.querySelector("div.selected");
- const stateNew = +selected.dataset.id;
+ const $selected = $body.querySelector("div.selected");
+ const stateNew = +$selected.dataset.id;
const color = pack.states[stateNew].color || "#ffffff";
selection.forEach(function (i) {
@@ -999,7 +1005,7 @@ function applyStatesManualAssignent() {
if (layerIsOn("toggleProvinces")) drawProvinces();
}
- exitStatesManualAssignment();
+ exitStatesManualAssignment(false);
}
function adjustProvinces(affectedProvinces) {
@@ -1139,17 +1145,19 @@ function exitStatesManualAssignment(close) {
statesBody.select("#temp").remove();
removeCircle();
document.querySelectorAll("#statesBottom > button").forEach(el => (el.style.display = "inline-block"));
- document.getElementById("statesManuallyButtons").style.display = "none";
- document.getElementById("statesHalo").style.display = "block";
+ byId("statesManuallyButtons").style.display = "none";
+ byId("statesHalo").style.display = "block";
- statesEditor.querySelectorAll(".hide:not(.show)").forEach(el => el.classList.remove("hidden"));
+ byId("statesEditor")
+ .querySelectorAll(".hide:not(.show)")
+ .forEach(el => el.classList.remove("hidden"));
statesFooter.style.display = "block";
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
if (!close) $("#statesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
restoreDefaultEvents();
clearMainTip();
- const selected = body.querySelector("div.selected");
+ const selected = $body.querySelector("div.selected");
if (selected) selected.classList.remove("selected");
}
@@ -1162,7 +1170,7 @@ function enterAddStateMode() {
this.classList.add("pressed");
tip("Click on the map to create a new capital or promote an existing burg", true);
viewbox.style("cursor", "crosshair").on("click", addState);
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "none"));
}
function addState() {
@@ -1276,41 +1284,30 @@ function exitAddStateMode() {
customization = 0;
restoreDefaultEvents();
clearMainTip();
- body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
+ $body.querySelectorAll("div > input, select, span, svg").forEach(e => (e.style.pointerEvents = "all"));
if (statesAdd.classList.contains("pressed")) statesAdd.classList.remove("pressed");
}
-function downloadStatesData() {
+function downloadStatesCsv() {
const unit = getAreaUnit("2");
- let data =
- "Id,State,Full Name,Form,Color,Capital,Culture,Type,Expansionism,Cells,Burgs,Area " + unit + ",Total Population,Rural Population,Urban Population\n"; // headers
- body.querySelectorAll(":scope > div").forEach(function (el) {
- const key = parseInt(el.dataset.id);
- const statePack = pack.states[key];
- data += el.dataset.id + ",";
- data += el.dataset.name + ",";
- data += (statePack.fullName ? statePack.fullName : "") + ",";
- data += el.dataset.form + ",";
- data += el.dataset.color + ",";
- data += el.dataset.capital + ",";
- data += el.dataset.culture + ",";
- data += el.dataset.type + ",";
- data += el.dataset.expansionism + ",";
- data += el.dataset.cells + ",";
- data += el.dataset.burgs + ",";
- data += el.dataset.area + ",";
- data += el.dataset.population + ",";
- data += `${Math.round(statePack.rural * populationRate)},`;
- data += `${Math.round(statePack.urban * populationRate * urbanization)}\n`;
+ const headers = `Id,State,Full Name,Form,Color,Capital,Culture,Type,Expansionism,Cells,Burgs,Area ${unit},Total Population,Rural Population,Urban Population`;
+ const lines = Array.from($body.querySelectorAll(":scope > div"));
+ const data = lines.map($line => {
+ const {id, name, form, color, capital, culture, type, expansionism, cells, burgs, area, population} = $line.dataset;
+ const {fullName = "", rural, urban} = pack.states[+id];
+ const ruralPopulation = Math.round(rural * populationRate);
+ const urbanPopulation = Math.round(urban * populationRate * urbanization);
+ return [id, name, fullName, form, color, capital, culture, type, expansionism, cells, burgs, area, population, ruralPopulation, urbanPopulation].join(",");
});
+ const csvData = [headers].concat(data).join("\n");
const name = getFileName("States") + ".csv";
- downloadFile(data, name);
+ downloadFile(csvData, name);
}
function closeStatesEditor() {
- if (customization === 2) exitStatesManualAssignment("close");
+ if (customization === 2) exitStatesManualAssignment(true);
if (customization === 3) exitAddStateMode();
debug.selectAll(".highlight").remove();
- body.innerHTML = "";
+ $body.innerHTML = "";
}
diff --git a/modules/ui/editors.js b/modules/ui/editors.js
index f8172db5..494a6270 100644
--- a/modules/ui/editors.js
+++ b/modules/ui/editors.js
@@ -1119,12 +1119,12 @@ function refreshAllEditors() {
// dynamically loaded editors
async function editStates() {
if (customization) return;
- const StateEditor = await import("../dynamic/editors/states-editor.js?v=18052022");
+ const StateEditor = await import("../dynamic/editors/states-editor.js?v=20052022");
StateEditor.open();
}
async function editCultures() {
if (customization) return;
- const CulturesEditor = await import("../dynamic/editors/cultures-editor.js");
+ const CulturesEditor = await import("../dynamic/editors/cultures-editor.js?v=20052022");
CulturesEditor.open();
}
diff --git a/utils/shorthands.js b/utils/shorthands.js
new file mode 100644
index 00000000..043599fc
--- /dev/null
+++ b/utils/shorthands.js
@@ -0,0 +1,9 @@
+const byId = document.getElementById.bind(document);
+
+Node.prototype.on = function (name, fn, options) {
+ this.addEventListener(name, fn, options);
+};
+
+Node.prototype.off = function (name, fn) {
+ this.removeEventListener(name, fn);
+};
diff --git a/versioning.js b/versioning.js
index 767559d4..ee337422 100644
--- a/versioning.js
+++ b/versioning.js
@@ -1,7 +1,7 @@
"use strict";
// version and caching control
-const version = "1.82.04"; // generator version, update each time
+const version = "1.82.05"; // generator version, update each time
{
document.title += " v" + version;