diff --git a/icons.css b/icons.css
index eab23067..008faebc 100644
--- a/icons.css
+++ b/icons.css
@@ -252,17 +252,8 @@
.icon-if:before {font-style: italic; font-weight: bold;content:'if';}
.icon-coa:before {content:'\f3ed'; font-size: .9em; color: #999;} /* '' */
.icon-half:before {font-weight: bold;content:'½';}
-.icon-curve:before {content: 'C';}
-.icon-area:before {content: 'O';}
-.icon-curve:before,
-.icon-area:before {
- font-size: 1.5em;
- padding: 0;
- writing-mode: tb-rl;
- margin-left: 1px;
- width: .6em;
- font-family: monospace;
-}
+.icon-voice:before {content:'🔊';}
+
.icon-die:before {content:'🎲';}
.icon-button-die:before {content:'🎲'; padding-right: .4em;}
.icon-button-power:before {content:'💪'; padding-right: .6em;}
diff --git a/index.css b/index.css
index a7e09155..386e2ba5 100644
--- a/index.css
+++ b/index.css
@@ -76,10 +76,14 @@ input, button, select, a, textarea {
outline: none;
}
-button, select, a, .pointer {
+button, select, a {
cursor: pointer;
}
+.pointer {
+ cursor: pointer !important;
+}
+
#prec text {
font-size: 32px;
stroke: none;
@@ -1464,9 +1468,7 @@ div.states > .coaIcon > use {
}
.burgFeature {
- font-size: 1.2em;
- padding: 1px 2px;
- color: #555;
+ padding: 1px;
cursor: pointer;
}
@@ -2141,6 +2143,11 @@ svg.button {
border: dashed 1px #5d4651;
}
+.speaker {
+ font-size: .9em;
+ cursor: pointer;
+}
+
#prompt {
position: absolute;
left: 50%;
diff --git a/index.html b/index.html
index 03b5c1a7..31d5b62f 100644
--- a/index.html
+++ b/index.html
@@ -1863,6 +1863,17 @@
+
|
Zoom extent |
@@ -2163,6 +2174,7 @@
+ 🔊
@@ -2186,6 +2198,7 @@
+
🔊
@@ -2420,27 +2433,36 @@
-
+
+
+
-
+
-
-
Features:
-
-
-
-
-
-
-
+
+
+
+
Features:
+
+
+
+
+
+
+
+
@@ -2463,7 +2485,7 @@
-
+
@@ -2516,6 +2538,7 @@
+ 🔊
@@ -2968,6 +2991,7 @@
@@ -3030,6 +3054,7 @@
@@ -3118,13 +3143,14 @@
Form name:
-
@@ -3237,6 +3264,7 @@
+
@@ -3285,9 +3313,11 @@
Object name:
+ 🔊
+
diff --git a/modules/coa-generator.js b/modules/coa-generator.js
index 2cf3de72..d8bab364 100644
--- a/modules/coa-generator.js
+++ b/modules/coa-generator.js
@@ -361,9 +361,9 @@
coa.ordinaries ? coa.ordinaries.push(canton) : coa.ordinaries = [canton];
- console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(coa)}`));
- console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(parent)}`));
- console.log("-------");
+ // console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(coa)}`));
+ // console.log(encodeURI(`https://azgaar.github.io/Armoria/?coa=${JSON.stringify(parent)}`));
+ // console.log("-------");
}
function selectCharge(set) {
diff --git a/modules/coa-renderer.js b/modules/coa-renderer.js
index 8c212658..1dd3cb81 100644
--- a/modules/coa-renderer.js
+++ b/modules/coa-renderer.js
@@ -879,7 +879,7 @@
// async render coa if it does not exist
const trigger = function(id, coa) {
if (!coa) {
- console.warn(id, "emblem is undefined");
+ console.warn(`Emblem ${id} is undefined`);
return;
}
if (!document.getElementById(id)) draw(id, coa);
diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js
index 08c283d8..38c2d886 100644
--- a/modules/ui/burg-editor.js
+++ b/modules/ui/burg-editor.js
@@ -31,8 +31,9 @@ function editBurg(id) {
document.getElementById("burgRemoveGroup").addEventListener("click", removeBurgsGroup);
document.getElementById("burgName").addEventListener("input", changeName);
- document.getElementById("burgNameReCulture").addEventListener("click", generateNameCulture);
document.getElementById("burgNameReRandom").addEventListener("click", generateNameRandom);
+ document.getElementById("burgCulture").addEventListener("input", changeCulture);
+ document.getElementById("burgNameReCulture").addEventListener("click", generateNameCulture);
document.getElementById("burgPopulation").addEventListener("change", changePopulation);
burgBody.querySelectorAll(".burgFeature").forEach(el => el.addEventListener("click", toggleFeature));
@@ -43,7 +44,7 @@ function editBurg(id) {
document.getElementById("burgEditAnchorStyle").addEventListener("click", editGroupAnchorStyle);
document.getElementById("burgSeeInMFCG").addEventListener("click", openInMFCG);
- document.getElementById("burgOpenCOA").addEventListener("click", editCOA);
+ document.getElementById("burgEditEmblem").addEventListener("click", openEmblemEdit);
document.getElementById("burgRelocate").addEventListener("click", toggleRelocateBurg);
document.getElementById("burglLegend").addEventListener("click", editBurgLegend);
document.getElementById("burgRemove").addEventListener("click", removeSelectedBurg);
@@ -55,6 +56,12 @@ function editBurg(id) {
document.getElementById("burgPopulation").value = rn(b.population * populationRate.value * urbanization.value);
document.getElementById("burgEditAnchorStyle").style.display = +b.port ? "inline-block" : "none";
+ // update list and select culture
+ const cultureSelect = document.getElementById("burgCulture");
+ cultureSelect.options.length = 0;
+ const cultures = pack.cultures.filter(c => !c.removed);
+ cultures.forEach(c => cultureSelect.options.add(new Option(c.name, c.i, false, c.i === b.culture)));
+
// toggle features
if (b.capital) document.getElementById("burgCapital").classList.remove("inactive");
else document.getElementById("burgCapital").classList.add("inactive");
@@ -79,6 +86,11 @@ function editBurg(id) {
burgLabels.selectAll("g").each(function() {
select.options.add(new Option(this.id, this.id, false, this.id === group));
});
+
+ // set emlem image
+ const coaID = "burgCOA"+id;
+ COArenderer.trigger(coaID, b.coa);
+ document.getElementById("burgEmblem").setAttribute("href", "#" + coaID);
}
function dragBurgLabel() {
@@ -220,6 +232,17 @@ function editBurg(id) {
elSelected.text(burgName.value);
}
+ function generateNameRandom() {
+ const base = rand(nameBases.length-1);
+ burgName.value = Names.getBase(base);
+ changeName();
+ }
+
+ function changeCulture() {
+ const id = +elSelected.attr("data-id");
+ pack.burgs[id].culture = +this.value;
+ }
+
function generateNameCulture() {
const id = +elSelected.attr("data-id");
const culture = pack.burgs[id].culture;
@@ -227,12 +250,6 @@ function editBurg(id) {
changeName();
}
- function generateNameRandom() {
- const base = rand(nameBases.length-1);
- burgName.value = Names.getBase(base);
- changeName();
- }
-
function changePopulation() {
const id = +elSelected.attr("data-id");
pack.burgs[id].population = rn(burgPopulation.value / populationRate.value / urbanization.value, 4);
@@ -326,10 +343,9 @@ function editBurg(id) {
}
}
- function editCOA() {
- const id = elSelected.attr("data-id"), burg = pack.burgs[id];
- const coa = COA.toString(burg.coa);
- openURL("http://azgaar.github.io/Armoria/?coa=" + coa);
+ function openEmblemEdit() {
+ const id = +elSelected.attr("data-id"), burg = pack.burgs[id];
+ editEmblem("burg", "burgCOA"+id, burg);
}
function toggleRelocateBurg() {
diff --git a/modules/ui/general.js b/modules/ui/general.js
index 99a7d3fc..03a1cbfb 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -367,6 +367,22 @@ function stored(option) {
return localStorage.getItem(option);
}
+// assign skeaker behaviour
+Array.from(document.getElementsByClassName("speaker")).forEach(el => {
+ const input = el.previousElementSibling;
+ el.addEventListener("click", () => speak(input.value));
+});
+
+function speak(text) {
+ const speaker = new SpeechSynthesisUtterance(text);
+ const voices = speechSynthesis.getVoices();
+ if (voices.length) {
+ const voiceId = +document.getElementById("speakerVoice").value;
+ speaker.voice = voices[voiceId];
+ }
+ speechSynthesis.speak(speaker);
+}
+
// apply drop-down menu option. If the value is not in options, add it
function applyOption(select, id, name = id) {
const custom = !Array.from(select.options).some(o => o.value == id);
diff --git a/modules/ui/namesbase-editor.js b/modules/ui/namesbase-editor.js
index baf0acb5..03149a13 100644
--- a/modules/ui/namesbase-editor.js
+++ b/modules/ui/namesbase-editor.js
@@ -22,6 +22,7 @@ function editNamesbase() {
document.getElementById("namesbaseDownload").addEventListener("click", namesbaseDownload);
document.getElementById("namesbaseUpload").addEventListener("click", () => namesbaseToLoad.click());
document.getElementById("namesbaseToLoad").addEventListener("change", function() {uploadFile(this, namesbaseUpload)});
+ document.getElementById("namesbaseSpeak").addEventListener("click", () => speak(namesbaseExamples.textContent));
createBasesList();
updateInputs();
diff --git a/modules/ui/notes-editor.js b/modules/ui/notes-editor.js
index c273c61e..caa4a59f 100644
--- a/modules/ui/notes-editor.js
+++ b/modules/ui/notes-editor.js
@@ -38,7 +38,7 @@ function editNotes(id, name) {
// open a dialog
$("#notesEditor").dialog({
- title: "Notes Editor", minWidth: "40em",
+ title: "Notes Editor", minWidth: "40em", width: "50vw",
position: {my: "center", at: "center", of: "svg"},
close: () => notesText.innerHTML = ""
});
@@ -50,6 +50,7 @@ function editNotes(id, name) {
document.getElementById("notesSelect").addEventListener("change", changeObject);
document.getElementById("notesName").addEventListener("input", changeName);
document.getElementById("notesPin").addEventListener("click", () => options.pinNotes = !options.pinNotes);
+ document.getElementById("notesSpeak").addEventListener("click", () => speak(editor.content.innerHTML));
document.getElementById("notesFocus").addEventListener("click", validateHighlightElement);
document.getElementById("notesDownload").addEventListener("click", downloadLegends);
document.getElementById("notesUpload").addEventListener("click", () => legendsToLoad.click());
diff --git a/modules/ui/options.js b/modules/ui/options.js
index 63a7f75f..b6e6a139 100644
--- a/modules/ui/options.js
+++ b/modules/ui/options.js
@@ -140,6 +140,7 @@ optionsContent.addEventListener("click", function(event) {
else if (id === "optionsEraRegenerate") regenerateEra();
else if (id === "zoomExtentDefault") restoreDefaultZoomExtent();
else if (id === "translateExtent") toggleTranslateExtent(event.target);
+ else if (id === "speakerTest") testSpeaker();
});
function mapSizeInputChange() {
@@ -198,6 +199,30 @@ function toggleTranslateExtent(el) {
else zoom.translateExtent([[0, 0], [graphWidth, graphHeight]]);
}
+// add voice options
+const voiceInterval = setInterval(function() {
+ const voices = speechSynthesis.getVoices();
+ if (voices.length) clearInterval(voiceInterval); else return;
+
+ const select = document.getElementById("speakerVoice");
+ voices.forEach((voice, i) => {
+ select.options.add(new Option(voice.name, i, false));
+ });
+ if (stored("speakerVoice")) select.value = localStorage.getItem("speakerVoice"); // se voice to store
+ else select.value = voices.findIndex(voice => voice.lang === "en-US"); // or to first found English-US
+}, 1000);
+
+function testSpeaker() {
+ const text = `${mapName.value}, ${options.year} ${options.era}`;
+ const speaker = new SpeechSynthesisUtterance(text);
+ const voices = speechSynthesis.getVoices();
+ if (voices.length) {
+ const voiceId = +document.getElementById("speakerVoice").value;
+ speaker.voice = voices[voiceId];
+ }
+ speechSynthesis.speak(speaker);
+}
+
function generateMapWithSeed() {
if (optionsSeed.value == seed) {
tip("The current map already has this seed", false, "error");
@@ -331,6 +356,7 @@ function applyStoredOptions() {
for (let i=0; i < localStorage.length; i++) {
const stored = localStorage.key(i), value = localStorage.getItem(stored);
+ if (stored === "speakerVoice") continue;
const input = document.getElementById(stored+"Input") || document.getElementById(stored);
const output = document.getElementById(stored+"Output");
if (input) input.value = value;
diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js
index 44a16e9c..54893fa2 100644
--- a/modules/ui/provinces-editor.js
+++ b/modules/ui/provinces-editor.js
@@ -383,7 +383,7 @@ function editProvinces() {
document.getElementById("provinceNameEditorFull").value = p.fullName;
$("#provinceNameEditor").dialog({
- resizable: false, title: "Change province name", width: "22em", buttons: {
+ resizable: false, title: "Change province name", buttons: {
Apply: function() {applyNameChange(p); $(this).dialog("close");},
Cancel: function() {$(this).dialog("close");}
}, position: {my: "center", at: "center", of: "svg"}
diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js
index 99a0c02a..7e87b7cc 100644
--- a/modules/ui/states-editor.js
+++ b/modules/ui/states-editor.js
@@ -232,7 +232,7 @@ function editStates() {
document.getElementById("stateNameEditorFull").value = s.fullName || "";
$("#stateNameEditor").dialog({
- resizable: false, title: "Change state name", width: "22em", buttons: {
+ resizable: false, title: "Change state name", buttons: {
Apply: function() {applyNameChange(s); $(this).dialog("close");},
Cancel: function() {$(this).dialog("close");}
}, position: {my: "center", at: "center", of: "svg"}