Suffixes (for verb conjugations)
This commit is contained in:
parent
72c56ec015
commit
6a41d56a82
3 changed files with 108 additions and 17 deletions
|
@ -69,6 +69,11 @@
|
||||||
Meaning:
|
Meaning:
|
||||||
<input id="word_meaning" class="button"/>
|
<input id="word_meaning" class="button"/>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="spacing section">
|
||||||
|
Suffix:
|
||||||
|
<input id="word_suffix_meaning" class="button" />
|
||||||
|
<input id="word_suffix_length" type="number" class="button" value="0" min="0" max="99" />
|
||||||
|
</label>
|
||||||
<textarea id="word_notes" class="button spacing section" placeholder="Notes"></textarea>
|
<textarea id="word_notes" class="button spacing section" placeholder="Notes"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
108
res/script.js
108
res/script.js
|
@ -30,6 +30,8 @@ const wordSymbols = /** @type {SVGElement} */(/** @type {unknown} */(document.qu
|
||||||
const wordSymbolTemplate = /** @type {SVGSVGElement} */(wordSymbols.querySelector('svg'));
|
const wordSymbolTemplate = /** @type {SVGSVGElement} */(wordSymbols.querySelector('svg'));
|
||||||
const wordMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_meaning'));
|
const wordMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_meaning'));
|
||||||
const wordNotesTextarea = /** @type {HTMLTextAreaElement} */(document.getElementById('word_notes'));
|
const wordNotesTextarea = /** @type {HTMLTextAreaElement} */(document.getElementById('word_notes'));
|
||||||
|
const wordSuffixMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_suffix_meaning'));
|
||||||
|
const wordSuffixLengthInput = /** @type {HTMLInputElement} */(document.getElementById('word_suffix_length'));
|
||||||
|
|
||||||
const symbolOuterTopLeftPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_left')));
|
const symbolOuterTopLeftPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_left')));
|
||||||
const symbolOuterTopRightPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_right')));
|
const symbolOuterTopRightPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_right')));
|
||||||
|
@ -441,7 +443,7 @@ panBy(0, 0);
|
||||||
|
|
||||||
/** @typedef {string} GUID */
|
/** @typedef {string} GUID */
|
||||||
|
|
||||||
/** @typedef {{ x: number, y: number, w: number, h: number }} WordData */
|
/** @typedef {{ x: number, y: number, w: number, h: number, suf?: number }} WordData */
|
||||||
|
|
||||||
/** @typedef {{ x: number, y: number, w: number, h: number, v?: number }} SymbolData */
|
/** @typedef {{ x: number, y: number, w: number, h: number, v?: number }} SymbolData */
|
||||||
|
|
||||||
|
@ -489,10 +491,13 @@ const loadPageElements = (pageId) => {
|
||||||
const dictionary = data.dictionary ?? {};
|
const dictionary = data.dictionary ?? {};
|
||||||
if (dictionary) {
|
if (dictionary) {
|
||||||
const wordSymbols = getWordSymbols(pageId, word);
|
const wordSymbols = getWordSymbols(pageId, word);
|
||||||
const dictionaryId = getDictionaryId(wordSymbols);
|
const suffixLength = Math.max(0, word.suf ?? 0);
|
||||||
const dictionaryWord = dictionary[dictionaryId];
|
const wordId = getDictionaryId(wordSymbols.slice(0, wordSymbols.length - suffixLength));
|
||||||
|
const suffixId = getDictionaryId(wordSymbols.slice(-suffixLength), true);
|
||||||
|
const dictionaryWord = dictionary[wordId];
|
||||||
|
const dictionarySuffix = dictionary[suffixId];
|
||||||
|
|
||||||
/** @type {HTMLDivElement} */(el.querySelector('.word-meaning')).textContent = dictionaryWord?.tran ?? '';
|
/** @type {HTMLDivElement} */(el.querySelector('.word-meaning')).textContent = (dictionaryWord?.tran ?? '') + (dictionarySuffix?.tran ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPageElements[id] = el;
|
currentPageElements[id] = el;
|
||||||
|
@ -543,6 +548,22 @@ const loadPageElements = (pageId) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sortRecursive = (obj) => {
|
||||||
|
if (typeof obj == 'object') {
|
||||||
|
const sortedKeys = Object.keys(obj).sort();
|
||||||
|
const copy = { ...obj };
|
||||||
|
|
||||||
|
for (const k in obj)
|
||||||
|
delete obj[k];
|
||||||
|
|
||||||
|
for (const k of sortedKeys)
|
||||||
|
obj[k] = copy[k];
|
||||||
|
|
||||||
|
for (const k of sortedKeys)
|
||||||
|
sortRecursive();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const saveUpdatedData = () => {
|
const saveUpdatedData = () => {
|
||||||
localStorage.setItem('tunic_manual_translation.data', JSON.stringify(data));
|
localStorage.setItem('tunic_manual_translation.data', JSON.stringify(data));
|
||||||
console.debug("Updated data:", JSON.stringify(data));
|
console.debug("Updated data:", JSON.stringify(data));
|
||||||
|
@ -609,10 +630,11 @@ const hideProps = () => {
|
||||||
|
|
||||||
// Words
|
// Words
|
||||||
|
|
||||||
let lastSelectedWord = '';
|
/** @type {{ word: WordData, symbols: number[] } | null} */
|
||||||
|
let lastSelectedWord = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} pageId
|
* @param {string} pageId
|
||||||
* @param {SymbolData} word
|
* @param {SymbolData} word
|
||||||
*/
|
*/
|
||||||
const getWordSymbols = (pageId, word) => {
|
const getWordSymbols = (pageId, word) => {
|
||||||
|
@ -640,8 +662,8 @@ const getWordSymbols = (pageId, word) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @param {number[]} wordSymbols */
|
/** @param {number[]} wordSymbols */
|
||||||
const getDictionaryId = (wordSymbols) => {
|
const getDictionaryId = (wordSymbols, suffix = false) => {
|
||||||
return wordSymbols.map(v => v.toString(36)).join('-');
|
return (suffix ? '-' : '') + wordSymbols.map(v => v.toString(36)).join('-');
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @param {number} symbol */
|
/** @param {number} symbol */
|
||||||
|
@ -656,35 +678,56 @@ const getSymbolMaskForCss = (symbol) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} pageId
|
* @param {string} pageId
|
||||||
* @param {SymbolData} word
|
* @param {SymbolData} word
|
||||||
*/
|
*/
|
||||||
const loadWord = (pageId, word) => {
|
const loadWord = (pageId, word) => {
|
||||||
const selectedWordSymbols = getWordSymbols(pageId, word);
|
lastSelectedWord = { word, symbols: getWordSymbols(pageId, word) };
|
||||||
lastSelectedWord = getDictionaryId(selectedWordSymbols);
|
refreshWord();
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshWord = () => {
|
||||||
|
if (!lastSelectedWord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const suffixLength = Math.max(0, lastSelectedWord.word.suf ?? 0);
|
||||||
|
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
|
||||||
|
const suffixId = getDictionaryId(lastSelectedWord.symbols.slice(-suffixLength), true);
|
||||||
|
|
||||||
while (wordSymbols.firstChild)
|
while (wordSymbols.firstChild)
|
||||||
wordSymbols.firstChild.remove();
|
wordSymbols.firstChild.remove();
|
||||||
|
|
||||||
for (const symbol of selectedWordSymbols) {
|
for (let i = 0; i < lastSelectedWord.symbols.length; i++) {
|
||||||
|
const symbol = lastSelectedWord.symbols[i];
|
||||||
const symbolMask = getSymbolMaskForCss(symbol);
|
const symbolMask = getSymbolMaskForCss(symbol);
|
||||||
const el = /** @type {SVGSVGElement} */(wordSymbolTemplate.cloneNode(true));
|
const el = /** @type {SVGSVGElement} */(wordSymbolTemplate.cloneNode(true));
|
||||||
el.setAttribute('data-symbol', symbolMask);
|
el.setAttribute('data-symbol', symbolMask);
|
||||||
|
el.classList.toggle('suffix', lastSelectedWord.symbols.length - i <= suffixLength);
|
||||||
wordSymbols.appendChild(el);
|
wordSymbols.appendChild(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dictionary = data.dictionary ??= {};
|
const dictionary = data.dictionary ??= {};
|
||||||
const currentWord = dictionary[lastSelectedWord] ??= {};
|
const currentWord = dictionary[wordId] ??= {};
|
||||||
|
const currentSuffix = dictionary[suffixId] ??= {};
|
||||||
|
|
||||||
wordMeaningInput.value = currentWord.tran ?? '';
|
wordMeaningInput.value = currentWord.tran ?? '';
|
||||||
wordNotesTextarea.value = currentWord.note ?? '';
|
wordNotesTextarea.value = currentWord.note ?? '';
|
||||||
|
wordSuffixMeaningInput.value = suffixLength == 0 ? "-" : (currentSuffix.tran ?? '');
|
||||||
|
wordSuffixMeaningInput.disabled = suffixLength == 0;
|
||||||
|
wordSuffixLengthInput.value = String(suffixLength);
|
||||||
};
|
};
|
||||||
|
|
||||||
wordSymbolTemplate.remove();
|
wordSymbolTemplate.remove();
|
||||||
|
|
||||||
wordMeaningInput.addEventListener('keyup', ev => {
|
wordMeaningInput.addEventListener('keyup', ev => {
|
||||||
|
if (!lastSelectedWord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const suffixLength = lastSelectedWord.word.suf ?? 0;
|
||||||
|
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
|
||||||
|
|
||||||
const dictionary = data.dictionary ??= {};
|
const dictionary = data.dictionary ??= {};
|
||||||
const currentWord = dictionary[lastSelectedWord] ??= {};
|
const currentWord = dictionary[wordId] ??= {};
|
||||||
|
|
||||||
if (currentWord.tran != wordMeaningInput.value) {
|
if (currentWord.tran != wordMeaningInput.value) {
|
||||||
currentWord.tran = wordMeaningInput.value;
|
currentWord.tran = wordMeaningInput.value;
|
||||||
|
@ -692,9 +735,42 @@ wordMeaningInput.addEventListener('keyup', ev => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
wordNotesTextarea.addEventListener('keyup', ev => {
|
wordSuffixLengthInput.addEventListener('change', ev => {
|
||||||
|
if (!lastSelectedWord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const suffixLength = Number(wordSuffixLengthInput.value) || 0;
|
||||||
|
lastSelectedWord.word.suf = suffixLength;
|
||||||
|
saveUpdatedData();
|
||||||
|
|
||||||
|
refreshWord();
|
||||||
|
});
|
||||||
|
|
||||||
|
wordSuffixMeaningInput.addEventListener('keyup', ev => {
|
||||||
|
if (!lastSelectedWord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const suffixLength = lastSelectedWord.word.suf ?? 0;
|
||||||
|
const suffixId = getDictionaryId(lastSelectedWord.symbols.slice(-suffixLength), true);
|
||||||
|
|
||||||
const dictionary = data.dictionary ??= {};
|
const dictionary = data.dictionary ??= {};
|
||||||
const currentWord = dictionary[lastSelectedWord] ??= {};
|
const currentSuffix = dictionary[suffixId] ??= {};
|
||||||
|
|
||||||
|
if (currentSuffix.tran != wordSuffixMeaningInput.value) {
|
||||||
|
currentSuffix.tran = wordSuffixMeaningInput.value;
|
||||||
|
saveUpdatedData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wordNotesTextarea.addEventListener('keyup', ev => {
|
||||||
|
if (!lastSelectedWord)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const suffixLength = lastSelectedWord.word.suf ?? 0;
|
||||||
|
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
|
||||||
|
|
||||||
|
const dictionary = data.dictionary ??= {};
|
||||||
|
const currentWord = dictionary[wordId] ??= {};
|
||||||
|
|
||||||
if (currentWord.note != wordNotesTextarea.value) {
|
if (currentWord.note != wordNotesTextarea.value) {
|
||||||
currentWord.note = wordNotesTextarea.value;
|
currentWord.note = wordNotesTextarea.value;
|
||||||
|
|
|
@ -96,6 +96,10 @@ html {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: .2em;
|
border-radius: .2em;
|
||||||
|
|
||||||
|
input[type=number]& {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
textarea& {
|
textarea& {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
|
@ -123,6 +127,12 @@ html {
|
||||||
width: 3em;
|
width: 3em;
|
||||||
margin: 0 calc(-3em / 8);
|
margin: 0 calc(-3em / 8);
|
||||||
|
|
||||||
|
--stroke-color: #fff;
|
||||||
|
|
||||||
|
&.suffix g {
|
||||||
|
--stroke-color: #08f;
|
||||||
|
}
|
||||||
|
|
||||||
.word_middle_line,
|
.word_middle_line,
|
||||||
&[data-symbol*='a'] .word_outer_top_left,
|
&[data-symbol*='a'] .word_outer_top_left,
|
||||||
&[data-symbol*='b'] .word_outer_top_right,
|
&[data-symbol*='b'] .word_outer_top_right,
|
||||||
|
@ -136,7 +146,7 @@ html {
|
||||||
&[data-symbol*='j'] .word_inner_bottom_middle,
|
&[data-symbol*='j'] .word_inner_bottom_middle,
|
||||||
&[data-symbol*='k'] .word_inner_bottom_right,
|
&[data-symbol*='k'] .word_inner_bottom_right,
|
||||||
&[data-symbol*='l'] .word_circle {
|
&[data-symbol*='l'] .word_circle {
|
||||||
stroke: #fff;
|
stroke: var(--stroke-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue