Compare commits

..

4 Commits

15 changed files with 2037 additions and 48 deletions

View File

@ -79,8 +79,9 @@
<label>Word<span class="red">*</span><br>
<input id="wordName">
</label>
<label>Pronunciation<a class="label-button">IPA Chart</a><br>
<input id="wordPronunciation">
<label>Pronunciation<a class="label-button ipa-table-button">IPA Chart</a><br>
<input id="wordPronunciation" class="ipa-field"><br>
<a class="label-help-button ipa-field-help-button">Field Help</a>
</label>
<label>Part of Speech<br>
<select id="wordPartOfSpeech" class="part-of-speech-select"></select>
@ -144,7 +145,7 @@
<section>
<form>
<label>Use IPA Auto-Fill
<input type="checkbox" checked><br />
<input id="settingsUseIPA" type="checkbox" checked><br />
<small>Check this to use character combinations to input International Phonetic Alphabet characters into
Pronunciation fields.</small>
</label>
@ -202,17 +203,23 @@
<div class="split three">
<div>
<label>Consonants<br>
<input id="editConsonants">
<input id="editConsonants" class="ipa-field"><br>
<a class="label-help-button ipa-field-help-button">Field Help</a>
<a class="label-button ipa-table-button">IPA Chart</a>
</label>
</div>
<div>
<label>Vowels<br>
<input id="editVowels">
<input id="editVowels" class="ipa-field"><br>
<a class="label-help-button ipa-field-help-button">Field Help</a>
<a class="label-button ipa-table-button">IPA Chart</a>
</label>
</div>
<div>
<label>Polyphthongs&nbsp;/ Blends<br>
<input id="editBlends">
<input id="editBlends" class="ipa-field"><br>
<a class="label-help-button ipa-field-help-button">Field Help</a>
<a class="label-button ipa-table-button">IPA Chart</a>
</label>
</div>
</div>

View File

@ -54,6 +54,11 @@ export const DEFAULT_DICTIONARY = {
version: MIGRATE_VERSION,
};
export const DEFAULT_SETTINGS = {
useIPAPronunciationField: true,
};
export const DEFAULT_PAGE_SIZE = 50;
export const LOCAL_STORAGE_KEY = 'dictionary';
export const SETTINGS_KEY = 'settings';

View File

@ -4,10 +4,12 @@ import setupListeners from './js/setupListeners';
import { renderAll } from './js/render';
import { generateRandomWords, addMessage } from './js/utilities';
import { loadDictionary } from './js/dictionaryManagement';
import { loadSettings } from './js/settings';
function initialize() {
addMessage('Loading!');
addMessage('Loading...');
loadDictionary();
loadSettings();
// generateRandomWords(100);
setupListeners();
renderAll();

View File

@ -0,0 +1,373 @@
{
"!*": "ǃ",
"!/": "¡",
"\"^": "̋",
"\"_": "̏",
"#_": "̻",
"''": "ˈ",
"')": "ʼ",
"'-": "˔",
"'^": "́",
"'_": "̀",
"((": "͡",
"(_": "̜",
"))": "͜",
")_": "̹",
"+_": "̟",
"+|": "ꜛ",
",,": "ˌ",
",-": "˕",
"-'": "˔",
"-,": "˕",
"-?": "ʡ",
"-E": "ɘ",
"-H": "ħ",
"-I": "ɨ",
"-J": "ɟ",
"-L": "ɬ",
"-O": "ɵ",
"-U": "ʉ",
"-^": "̄",
"-e": "ɘ",
"-h": "ħ",
"-i": "ɨ",
"-j": "ɟ",
"-l": "ɬ",
"-o": "ɵ",
"-u": "ʉ",
"-|": "ꜜ",
"-ʔ": "ʡ",
"-ʕ": "ʢ",
"-ʡ": "ʔ",
"-ʢ": "ʕ",
"-ː": "ˑ",
"-ˑ": "ː",
"/>": "↗",
"/\\": "ʌ",
"/^": "↗",
"1|": "˩",
"2|": "˨",
"3|": "˧",
"4|": "˦",
"5|": "˥",
"::": "ː",
":^": "̈",
":_": "̤",
"<|": "⊣",
"=*": "ǁ",
">/": "↗",
">R": "˞",
">\\": "↘",
">^": "̚",
">r": "˞",
">|": "⊢",
"?-": "ʡ",
"?/": "ʕ",
"??": "ʔ",
"A/": "ɐ",
"AA": "ɑ",
"AE": "æ",
"A|": "ɑ",
"B(": "ɓ",
"BB": "ʙ",
"BH": "β",
"C,": "ç",
"C/": "ɔ",
"CE": "ɶ",
"D(": "ɗ",
"D)": "ɖ",
"DH": "ð",
"E-": "ɘ",
"E/": "ə",
"EB": "ɞ",
"EE": "ɛ",
"G(": "ɠ",
"GG": "ɢ",
"H,": "ɦ",
"H-": "ħ",
"H/": "ɥ",
"HH": "ʜ",
"H^": "ʰ",
"I-": "ɨ",
"II": "ɪ",
"J(": "ʄ",
"J,": "ʝ",
"J-": "ɟ",
"J^": "ʲ",
"K/": "ʞ",
"L)": "ɭ",
"L-": "ɬ",
"LL": "ʟ",
"LR": "ɺ",
"LZ": "ɮ",
"L^": "ˡ",
"Lɾ": "ɺ",
"M,": "ɱ",
"M/": "ɯ",
"M^": "ᵐ",
"N)": "ɳ",
"N,": "ŋ",
"NN": "ɴ",
"N^": "ⁿ",
"O*": "ʘ",
"O-": "ɵ",
"O.": "ʘ",
"O/": "ø",
"OE": "œ",
"OO": "ɞ",
"OX": "ɤ",
"O^": "̊",
"O_": "̥",
"O|": "ɑ",
"PH": "ɸ",
"R)": "ɽ",
"R/": "ɹ",
"R0": "ɾ",
"R>": "˞",
"RL": "ɺ",
"RO": "ɾ",
"RR": "ʀ",
"S)": "ʂ",
"SH": "ʃ",
"SJ": "ɕ",
"T)": "ʈ",
"TH": "θ",
"U-": "ʉ",
"UU": "ʊ",
"U^": "̆",
"U_": "̮",
"V,": "ⱱ",
"V/": "ʌ",
"V0": "ʋ",
"VO": "ʋ",
"V^": "̌",
"V_": "̬",
"W,": "ɰ",
"W/": "ʍ",
"W^": "ʷ",
"W|": "ɰ",
"X,": "ɣ",
"XO": "ɤ",
"XX": "χ",
"X^": "̽",
"Xʃ": "ɧ",
"Y/": "ʎ",
"YY": "ʏ",
"Z)": "ʐ",
"ZH": "ʒ",
"ZJ": "ʑ",
"[]": "̻",
"[_": "̪",
"\\>": "↘",
"\\V": "↘",
"\\v": "↘",
"]_": "̺",
"^\"": "̋",
"^'": "́",
"^-": "̄",
"^/": "↗",
"^:": "̈",
"^>": "̚",
"^H": "ʰ",
"^J": "ʲ",
"^L": "ˡ",
"^M": "ᵐ",
"^N": "ⁿ",
"^O": "̊",
"^U": "̆",
"^V": "̌",
"^W": "ʷ",
"^X": "̽",
"^^": "̂",
"^_": "̯",
"^h": "ʰ",
"^j": "ʲ",
"^l": "ˡ",
"^m": "ᵐ",
"^n": "ⁿ",
"^o": "̊",
"^u": "̆",
"^v": "̌",
"^w": "ʷ",
"^x": "̽",
"^|": "̍",
"^~": "̃",
"^ŋ": "ᵑ",
"^ɣ": "ˠ",
"^ɥ": "ᶣ",
"^ʋ": "ᶹ",
"^ʕ": "ˤ",
"_\"": "̏",
"_#": "̻",
"_'": "̀",
"_(": "̜",
"_)": "̹",
"_+": "̟",
"_:": "̤",
"_O": "̥",
"_U": "̮",
"_V": "̬",
"_[": "̪",
"_]": "̺",
"_^": "̯",
"__": "̠",
"_o": "̥",
"_u": "̮",
"_v": "̬",
"_{": "̼",
"_|": "̩",
"_~": "̰",
"_˔": "̝",
"_˕": "̞",
"_⊢": "̙",
"_⊣": "̘",
"a/": "ɐ",
"a|": "ɑ",
"b(": "ɓ",
"c,": "ç",
"c/": "ɔ",
"d(": "ɗ",
"d)": "ɖ",
"e-": "ɘ",
"e/": "ə",
"g(": "ɠ",
"h,": "ɦ",
"h-": "ħ",
"h/": "ɥ",
"h^": "ʰ",
"i-": "ɨ",
"j(": "ʄ",
"j,": "ʝ",
"j-": "ɟ",
"j^": "ʲ",
"k/": "ʞ",
"l)": "ɭ",
"l-": "ɬ",
"l^": "ˡ",
"lɾ": "ɺ",
"m,": "ɱ",
"m/": "ɯ",
"m^": "ᵐ",
"n)": "ɳ",
"n,": "ŋ",
"n^": "ⁿ",
"o*": "ʘ",
"o-": "ɵ",
"o.": "ʘ",
"o/": "ø",
"o^": "̊",
"o_": "̥",
"o|": "ɑ",
"r)": "ɽ",
"r/": "ɹ",
"r0": "ɾ",
"r>": "˞",
"rO": "ɾ",
"s)": "ʂ",
"t)": "ʈ",
"u-": "ʉ",
"u^": "̆",
"u_": "̮",
"v,": "ⱱ",
"v/": "ʌ",
"v0": "ʋ",
"vO": "ʋ",
"v^": "̌",
"v_": "̬",
"w,": "ɰ",
"w/": "ʍ",
"w^": "ʷ",
"w|": "ɰ",
"x,": "ɣ",
"x^": "̽",
"xʃ": "ɧ",
"y/": "ʎ",
"z)": "ʐ",
"{_": "̼",
"|*": "ǀ",
"|-": "ꜜ",
"|<": "⊣",
"|=": "ǂ",
"|>": "⊢",
"|A": "ɒ",
"|O": "ɒ",
"|^": "̍",
"|_": "̩",
"|a": "ɒ",
"|o": "ɒ",
"||": "‖",
"~^": "̃",
"~_": "̰",
"~~": "̴",
"ŋ,": "ɲ",
"ŋ^": "ᵑ",
"ŋᵑ": "^",
"ɑ/": "ɒ",
"ɒ/": "ɑ",
"ɖ(": "ᶑ",
"ɗ)": "ᶑ",
"ɛ/": "ɜ",
"ɜ(": "ɞ",
"ɜ/": "ɛ",
"ɞ(": "ɜ",
"ɟ(": "ʄ",
"ɢ(": "ʛ",
"ɣ,": "χ",
"ɣ^": "ˠ",
"ɣˠ": "^",
"ɥ^": "ᶣ",
"ɥᶣ": "^",
"ɧX": "ʃ",
"ɧx": "ʃ",
"ɧʃ": "x",
"ɲ,": "ŋ",
"ɹ)": "ɻ",
"ɺL": "ɾ",
"ɺl": "ɾ",
"ɺɾ": "l",
"ɻ)": "ɹ",
"ɽ)": "ɾ",
"ɾ)": "ɽ",
"ɾL": "ɺ",
"ɾl": "ɺ",
"ʀ/": "ʁ",
"ʁ/": "ʀ",
"ʃX": "ɧ",
"ʃx": "ɧ",
"ʄ(": "ɟ",
"ʋ^": "ᶹ",
"ʋᶹ": "^",
"ʔ-": "ʡ",
"ʔ/": "ʕ",
"ʕ-": "ʢ",
"ʕ/": "ʔ",
"ʕ^": "ˤ",
"ʕˤ": "^",
"ʛ(": "ɢ",
"ʡ-": "ʔ",
"ʢ-": "ʕ",
"ː-": "ˑ",
"ˑ-": "ː",
"˔_": "̝",
"˔̝": "_",
"˕_": "̞",
"˕̞": "_",
"ˠɣ": "^",
"ˤʕ": "^",
"̘⊣": "_",
"̙⊢": "_",
"̝˔": "_",
"̞˕": "_",
"͜)": "‿",
"χ,": "ɣ",
"ᵑŋ": "^",
"ᶑ(": "ɖ",
"ᶑ)": "ɗ",
"ᶣɥ": "^",
"ᶹʋ": "^",
"‿)": "͜",
"⊢_": "̙",
"⊢̙": "_",
"⊣_": "̘",
"⊣̘": "_"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
import digraphs from './digraphs.json';
import { setSelectionRange, insertAtCursor } from '../../StackOverflow/inputCursorManagement.js';
export function usePhondueDigraphs(event) {
let val = event.target.value;
let pos = event.target.selectionStart || val.length;
const key = typeof event.which !== "undefined" ? event.which : event.keyCode,
digraph = digraphs[val.substr(pos - 1, 1) + String.fromCharCode(key)];
if (digraph) {
event.preventDefault();
insertAtCursor(event.target, digraph, -1);
}
}

View File

@ -0,0 +1,126 @@
<h1>Pronunciation Field Help</h1>
<p>The Pronunciation field in Lexiconga utilizes <a href='https://github.com/KeyboardFire/phondue' target='_blank'>KeyboardFire's
Phondue</a> web script to make typing IPA pronunciations much more convenient. While you
can still point and click to select IPA characters using the IPA table,
Phondue provides many two-key keyboard shortcuts called <strong>digraphs</strong>
that allow you to type any IPA symbol with only a standard keyboard.</p>
<p>These symbols were decided to be intuitive as possible:</p>
<ul>
<li>
<p>Many symbols that look similar to letters of the English alphabet (such as
small caps) can be produced by doubling the capital letter:</p>
<pre><code> GG -&gt; ɢ ?? -&gt; ʔ NN -&gt; ɴ BB -&gt; ʙ RR -&gt; ʀ XX -&gt; χ
LL -&gt; ʟ II -&gt; ɪ YY -&gt; ʏ UU -&gt; ʊ EE -&gt; ɛ OO -&gt; ɞ
AA -&gt; ɑ '' -&gt; ˈ ,, -&gt; ˌ :: -&gt; ː
</code></pre>
</li>
<li>
<p>The slash is used to &quot;reflect,&quot; &quot;rotate,&quot; or otherwise flip around a given
symbol:</p>
<pre><code> ʀ/ -&gt; ʁ ʔ/ -&gt; ʕ ?/ -&gt; ʕ r/ -&gt; ɹ y/ -&gt; ʎ m/ -&gt; ɯ
o/ -&gt; ø e/ -&gt; ə ɛ/ -&gt; ɜ c/ -&gt; ɔ a/ -&gt; ɐ ɑ/ -&gt; ɒ
w/ -&gt; ʍ h/ -&gt; ɥ k/ -&gt; ʞ !/ -&gt; ¡ v/ -&gt; ʌ
</code></pre>
<p>Also note that for any digraph, if either of the two characters that
compose it are not &quot;standard&quot; letters you can find on your keyboard, the
digraph can be done in reverse order—so since ʀ/ produces ʁ, you can press
/ again to go back to ʀ in case of accidental flippage (it's also weirdly
amusing to press RR///////).</p>
<p>This sometimes makes it easier to enter certain pairs; you may prefer to
use <code>AA</code> for <code>ɑ</code> and <code>AA/</code> for <code>ɒ</code> instead of the
visual <code>o|</code> and <code>|o</code>.</p>
</li>
<li>
<p>Digraphs have also been designed for when a symbol looks like two overlayed
characters, or two characters next to each other. This includes &quot;hooked&quot;
letters (such as ŋ), produced with the original letter and a comma, and
&quot;stroked&quot; letters (such as ɟ), produced with the original letter and a dash:</p>
<pre><code> m, -&gt; ɱ n, -&gt; ŋ ŋ, -&gt; ɲ v, -&gt; ⱱ c, -&gt; ç j, -&gt; ʝ
x, -&gt; ɣ ɣ, -&gt; χ h, -&gt; ɦ w, -&gt; ɰ
j- -&gt; ɟ h- -&gt; ħ l- -&gt; ɬ i- -&gt; ɨ u- -&gt; ʉ e- -&gt; ɘ
o- -&gt; ɵ ʕ- -&gt; ʢ ?- -&gt; ʡ ʔ- -&gt; ʡ
LZ -&gt; ɮ OX -&gt; ɤ XO -&gt; ɤ OE -&gt; œ EB -&gt; ɞ AE -&gt; æ
CE -&gt; ɶ RL -&gt; ɺ LR -&gt; ɺ ɾl -&gt; ɺ lɾ -&gt; ɺ
w| -&gt; ɰ o/ -&gt; ø ɜ( -&gt; ɞ /\ -&gt; ʌ o| -&gt; ɑ a| -&gt; ɑ
|o -&gt; ɒ |a -&gt; ɒ
o. -&gt; ʘ |= -&gt; ǂ || -&gt; ‖ /^ -&gt; ↗ /&gt; -&gt; ↗ \v -&gt;
\&gt; -&gt;
</code></pre>
</li>
<li>
<p>Others are based on pronunciation:</p>
<pre><code> PH -&gt; ɸ BH -&gt; β TH -&gt; θ DH -&gt; ð SH -&gt; ʃ ZH -&gt; ʒ
SJ -&gt; ɕ ZJ -&gt; ʑ ʃx -&gt; ɧ xʃ -&gt; ɧ
</code></pre>
<p>It may be worth noting at this point that digraphs of two lowercase letters
were intentionally avoided to prevent interference with regular typing. If
you need to type a sequence without it turning into a digraph (maybe you
want to type an actual <code>ʃx</code>), place a backslash between the two characters
(so, type <code>ʃ\x</code>).</p>
<p>In fact, [backslash][anything] is treated as a digraph that simply resolves
to the second character.</p>
</li>
<li>
<p>A few digraphs are based on shape:</p>
<pre><code> rO -&gt; ɾ r0 -&gt; ɾ vO -&gt; ʋ v0 -&gt; ʋ
</code></pre>
<p>Another related point: digraphs that contain a lowercase letter can also be
typed with that letter as uppercase. So, if <code>RO</code> is easier to type than
<code>rO</code>, that works as well.</p>
</li>
<li>
<p>Retroflex and nonpulmonic symbols have their own categories:</p>
<pre><code> retroflex: ) looks like the shape of the tongue
t) -&gt; ʈ d) -&gt; ɖ n) -&gt; ɳ r) -&gt; ɽ ɾ) -&gt; ɽ s) -&gt; ʂ
z) -&gt; ʐ ɹ) -&gt; ɻ l) -&gt; ɭ ɗ) -&gt;
clicks: clicking noise reminiscent of a *
o* -&gt; ʘ |* -&gt; ǀ !* -&gt; ǃ =* -&gt; ǁ
implosives and ejective marker: direction of airflow
b( -&gt; ɓ d( -&gt; ɗ j( -&gt; ʄ ɟ( -&gt; ʄ g( -&gt; ɠ ɢ( -&gt; ʛ
ɖ( -&gt; ᶑ ') -&gt; ʼ
</code></pre>
</li>
<li>
<p>Superscripts and diacritics that go above the letter use <code>^</code>, diacritics that
go below use <code>_</code>, and miscellaneous &quot;moved&quot; symbols
use <code>&lt;</code> or <code>&gt;</code>:</p>
<pre><code> ^h -&gt; ʰ ^n -&gt; ⁿ ^m -&gt; ᵐ ^ŋ -&gt; ᵑ ^l -&gt; ˡ ^w -&gt; ʷ
^j -&gt; ʲ ^ɥ -&gt; ᶣ ^ʋ -&gt; ᶹ ^ɣ -&gt; ˠ ^ʕ -&gt; ˤ
_| -&gt; ◌̩ ^| -&gt; ◌̍ _o -&gt; ◌̥ ^o -&gt; ◌̊ _v -&gt; ◌̬ ^v -&gt; ◌̌
_^ -&gt; ◌̯ _: -&gt; ◌̤ _~ -&gt; ◌̰ _[ -&gt; ◌̪ _] -&gt; ◌̺ _{ -&gt; ◌̼
_+ -&gt; ◌̟ __ -&gt; ◌̠ _) -&gt; ◌̹ _( -&gt; ◌̜ _# -&gt; ◌̻ [] -&gt; ◌̻
^&gt; -&gt; ◌̚ ^: -&gt; ◌̈ ^x -&gt; ◌̽ ^~ -&gt; ◌̃
-' -&gt; ˔ _˔ -&gt; ◌̝ -, -&gt; ˕ _˕ -&gt; ◌̞ &lt;| -&gt; ⊣ _⊣ -&gt; ◌̘
&gt;| -&gt; ⊢ _⊢ -&gt; ◌̙
~~ -&gt; ◌̴ &gt;r -&gt; ˞
</code></pre>
<p>Note that all of these sequences can be flipped in order—that is, <code>^h</code>
produces the same thing as <code>h^</code>. This allows usage such as <code>|&lt;_</code> to produce
<code>⊣_</code> which becomes ◌̘.</p>
</li>
<li>
<p>Tonal countours use numbers plus <code>|</code>:</p>
<pre><code> 5| -&gt; ˥ 4| -&gt; ˦ 3| -&gt; ˧ 2| -&gt; ˨ 1| -&gt; ˩
+| -&gt; ꜛ -| -&gt;
</code></pre>
</li>
<li>
<p>Finally, some digraphs simply have unique mnemonics:</p>
<pre><code> ː- -&gt; ˑ &quot;chop off&quot; the bottom triangle
(( -&gt; ◌͡◌ two parens for a tie that connects 2 chars
)) -&gt; ◌͜◌
◌͜◌) -&gt; ‿ one more paren to make it a little bit longer
</code></pre>
</li>
</ul>

View File

@ -0,0 +1,81 @@
export function insertAtCursor(myField, myValue, adjustStart = 0) {
// http://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
// IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
const selection = getInputSelection(myField);
selection.start += adjustStart;
myField.value = myField.value.substring(0, selection.start)
+ myValue
+ myField.value.substring(selection.end, myField.value.length);
myField.selectionStart = selection.start + myValue.length;
myField.selectionEnd = selection.start + myValue.length;
} else {
myField.value += myValue;
}
setSelectionRange(myField, myField.selectionEnd, myField.selectionEnd);
}
export function getInputSelection(el) {
// Retrieved from http://stackoverflow.com/a/4207763
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
el.focus();
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return { start, end };
}
export function setSelectionRange(input, selectionStart, selectionEnd) {
// Retrieved from http://stackoverflow.com/a/17858641/3508346
if (input.setSelectionRange) {
input.focus();
input.setSelectionRange(selectionStart, selectionEnd);
}
else if (input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd('character', selectionEnd);
range.moveStart('character', selectionStart);
range.select();
}
}

View File

@ -1,6 +1,7 @@
import { renderDictionaryDetails, renderPartsOfSpeech } from "./render";
import { removeTags, cloneObject, getTimestampInSeconds } from "../helpers";
import { LOCAL_STORAGE_KEY, DEFAULT_DICTIONARY, MIGRATE_VERSION } from "../constants";
import { addMessage } from "./utilities";
export function updateDictionary () {
@ -62,6 +63,7 @@ export function saveEditModal() {
window.currentDictionary.settings.isComplete = document.getElementById('editIsComplete').checked;
window.currentDictionary.settings.isPublic = document.getElementById('editIsPublic').checked;
addMessage('Saved ' + window.currentDictionary.specification + ' Successfully');
saveDictionary();
renderDictionaryDetails();
renderPartsOfSpeech();

View File

@ -3,7 +3,17 @@ import { removeTags, slugify } from '../helpers';
import { getWordsStats, wordExists } from './utilities';
import { getMatchingSearchWords, highlightSearchTerm, getSearchFilters, getSearchTerm } from './search';
import { showSection } from './displayToggles';
import { setupSearchFilters, setupWordOptionButtons, setupPagination, setupWordOptionSelections, setupWordEditFormButtons, setupMaximizeModal, setupInfoModal } from './setupListeners';
import {
setupSearchFilters,
setupWordOptionButtons,
setupPagination,
setupWordOptionSelections,
setupWordEditFormButtons,
setupMaximizeModal,
setupInfoModal,
setupIPATable,
setupIPAFields
} from './setupListeners';
import { getPaginationData } from './pagination';
import { getOpenEditForms } from './wordManagement';
@ -221,13 +231,18 @@ export function renderEditForm(wordId = false) {
wordId = typeof wordId.target === 'undefined' ? wordId : parseInt(this.id.replace('edit_', ''));
const word = window.currentDictionary.words.find(w => w.wordId === wordId);
if (word) {
const ipaPronunciationField = `<label>Pronunciation<a class="label-button ipa-table-button">IPA Chart</a><br>
<input id="wordPronunciation_${wordId}" class="ipa-field" value="${word.pronunciation}"><br>
<a class="label-help-button ipa-field-help-button">Field Help</a>
</label>`;
const plainPronunciationField = `<label>Pronunciation<br>
<input id="wordPronunciation_${wordId}" value="${word.pronunciation}">
</label>`;
const editForm = `<form id="editForm_${wordId}" class="edit-form">
<label>Word<span class="red">*</span><br>
<input id="wordName_${wordId}" value="${word.name}">
</label>
<label>Pronunciation<a class="label-button">IPA Chart</a><br>
<input id="wordPronunciation_${wordId}" value="${word.pronunciation}">
</label>
${window.settings.useIPAPronunciationField ? ipaPronunciationField : plainPronunciationField}
<label>Part of Speech<br>
<select id="wordPartOfSpeech_${wordId}" class="part-of-speech-select">
<option value="${word.partOfSpeech}" selected>${word.partOfSpeech}</option>
@ -249,22 +264,45 @@ export function renderEditForm(wordId = false) {
}
}
export function renderIPATable(ipaTableButton) {
ipaTableButton = typeof ipaTableButton.target === 'undefined' ? ipaTableButton : ipaTableButton.target;
// const label = ipaTableButton.parentElement.innerText.replace(/(\*|Maximize)/g, '').trim();
const textBox = ipaTableButton.parentElement.querySelector('input');
import('./KeyboardFire/phondue/ipa-table.html').then(html => {
const modalElement = document.createElement('section');
modalElement.classList.add('modal', 'ipa-table-modal');
modalElement.innerHTML = `<div class="modal-background"></div>
<div class="modal-content">
<a class="close-button">&times;&#xFE0E;</a>
<header><label>Pronunciation <input value="${textBox.value}" class="ipa-field"></label></header>
<section>
${html}
</section>
<footer><a class="button done-button">Done</a></footer>
</div>`;
document.body.appendChild(modalElement);
setupIPAFields();
setupIPATable(modalElement, textBox);
});
}
export function renderMaximizedTextbox(maximizeButton) {
maximizeButton = typeof maximizeButton.target === 'undefined' ? maximizeButton : maximizeButton.target;
const label = maximizeButton.parentElement.innerText.replace(/(\*|Maximize)/g, '').trim();
const textBox = maximizeButton.parentElement.querySelector('textarea');
const modalElement = document.createElement('section');
modalElement.classList.add('modal');
modalElement.innerHTML = `<section class="modal maximize-modal"><div class="modal-background"></div>
<div class="modal-content">
<a class="close-button">&times;&#xFE0E;</a>
<header><h3>${label}</h3></header>
<section>
<textarea>${textBox.value}</textarea>
</section>
<footer><a class="button done-button">Done</a></footer>
</div>
</section>`;
modalElement.classList.add('modal', 'maximize-modal');
modalElement.innerHTML = `<div class="modal-background"></div>
<div class="modal-content">
<a class="close-button">&times;&#xFE0E;</a>
<header><h3>${label}</h3></header>
<section>
<textarea>${textBox.value}</textarea>
</section>
<footer><a class="button done-button">Done</a></footer>
</div>`;
document.body.appendChild(modalElement);
@ -273,17 +311,16 @@ export function renderMaximizedTextbox(maximizeButton) {
export function renderInfoModal(content) {
const modalElement = document.createElement('section');
modalElement.classList.add('modal');
modalElement.innerHTML = `<section class="modal maximize-modal"><div class="modal-background"></div>
<div class="modal-content">
<a class="close-button">&times;&#xFE0E;</a>
<section class="info-modal">
<div class="content">
${content}
</div>
</section>
</div>
</section>`;
modalElement.classList.add('modal', 'info-modal');
modalElement.innerHTML = `<div class="modal-background"></div>
<div class="modal-content">
<a class="close-button">&times;&#xFE0E;</a>
<section class="info-modal">
<div class="content">
${content}
</div>
</section>
</div>`;
document.body.appendChild(modalElement);

57
src/js/settings.js Normal file
View File

@ -0,0 +1,57 @@
import { SETTINGS_KEY, DEFAULT_SETTINGS } from "../constants";
import { cloneObject } from "../helpers";
import { usePhondueDigraphs } from "./KeyboardFire/phondue/ipaField";
import { renderWords } from "./render";
import { addMessage } from "./utilities";
export function loadSettings() {
const storedSettings = window.localStorage.getItem(SETTINGS_KEY);
window.settings = storedSettings ? JSON.parse(storedSettings) : cloneObject(DEFAULT_SETTINGS);
toggleIPAPronunciationFields();
}
export function saveSettings() {
window.localStorage.setItem(SETTINGS_KEY, JSON.stringify(window.settings));
addMessage('Settings Saved!');
}
export function openSettingsModal() {
const { useIPAPronunciationField } = window.settings;
document.getElementById('settingsUseIPA').checked = useIPAPronunciationField;
document.getElementById('settingsModal').style.display = '';
}
export function saveSettingsModal() {
window.settings.useIPAPronunciationField = document.getElementById('settingsUseIPA').checked;
saveSettings();
toggleIPAPronunciationFields();
}
export function saveAndCloseSettingsModal() {
saveSettingsModal();
document.getElementById('settingsModal').style.display = 'none';
}
export function toggleIPAPronunciationFields() {
const ipaButtons = document.querySelectorAll('.ipa-table-button, .ipa-field-help-button'),
ipaFields = document.querySelectorAll('.ipa-field');
if (!window.settings.useIPAPronunciationField) {
Array.from(ipaButtons).forEach(button => {
button.style.display = 'none';
});
Array.from(ipaFields).forEach(field => {
field.removeEventListener('keypress', usePhondueDigraphs);
});
} else {
Array.from(ipaButtons).forEach(button => {
button.style.display = '';
});
Array.from(ipaFields).forEach(field => {
field.addEventListener('keypress', usePhondueDigraphs);
});
}
renderWords();
}

View File

@ -1,10 +1,13 @@
import {showSection} from './displayToggles';
import { renderWords, renderEditForm, renderMaximizedTextbox, renderInfoModal } from './render';
import { renderWords, renderEditForm, renderMaximizedTextbox, renderInfoModal, renderIPATable } from './render';
import { validateWord, addWord, confirmEditWord, cancelEditWord, confirmDeleteWord } from './wordManagement';
import { removeTags } from '../helpers';
import { getNextId } from './utilities';
import { openEditModal, saveEditModal, saveAndCloseEditModal } from './dictionaryManagement';
import { goToNextPage, goToPreviousPage, goToPage } from './pagination';
import { insertAtCursor } from './StackOverflow/inputCursorManagement';
import { usePhondueDigraphs } from './KeyboardFire/phondue/ipaField';
import { openSettingsModal, saveSettingsModal, saveAndCloseSettingsModal } from './settings';
export default function setupListeners() {
setupDetailsTabs();
@ -163,6 +166,7 @@ function setupWordForm() {
}
});
setupIPAFields();
setupMaximizeButtons();
}
@ -209,9 +213,9 @@ export function setupWordOptionSelections() {
}
export function setupSettingsModal() {
document.getElementById('settingsButton').addEventListener('click', () => {
document.getElementById('settingsModal').style.display = '';
});
document.getElementById('settingsButton').addEventListener('click', openSettingsModal);
document.getElementById('settingsSave').addEventListener('click', saveSettingsModal);
document.getElementById('settingsSaveAndClose').addEventListener('click', saveAndCloseSettingsModal);
}
export function setupWordEditFormButtons() {
@ -226,6 +230,7 @@ export function setupWordEditFormButtons() {
button.addEventListener('click', cancelEditWord);
});
setupIPAFields();
setupMaximizeButtons();
}
@ -264,6 +269,65 @@ export function setupPagination() {
});
}
export function setupIPAFields() {
if (window.settings.useIPAPronunciationField) {
const ipaFields = document.getElementsByClassName('ipa-field');
Array.from(ipaFields).forEach(field => {
field.removeEventListener('keypress', usePhondueDigraphs);
field.addEventListener('keypress', usePhondueDigraphs);
});
}
setupIPAButtons();
}
export function setupIPAButtons() {
const ipaTableButtons = document.getElementsByClassName('ipa-table-button'),
ipaFieldHelpButtons = document.getElementsByClassName('ipa-field-help-button');
Array.from(ipaTableButtons).forEach(button => {
button.removeEventListener('click', renderIPATable);
button.addEventListener('click', renderIPATable);
});
const renderIPAHelp = () => {
import('./KeyboardFire/phondue/usage.html').then(html => {
renderInfoModal(html);
});
}
Array.from(ipaFieldHelpButtons).forEach(button => {
button.removeEventListener('click', renderIPAHelp);
button.addEventListener('click', renderIPAHelp);
});
}
export function setupIPATable(modal, textBox) {
const closeElements = modal.querySelectorAll('.modal-background, .close-button, .done-button'),
headerTextBox = modal.querySelector('header input'),
ipaButtons = modal.querySelectorAll('.td-btn button');
Array.from(closeElements).forEach(close => {
close.addEventListener('click', () => {
modal.parentElement.removeChild(modal);
});
});
headerTextBox.addEventListener('change', () => {
textBox.value = headerTextBox.value;
});
Array.from(ipaButtons).forEach(button => {
button.addEventListener('click', () => {
console.log(button);
insertAtCursor(headerTextBox, button.innerText);
textBox.value = headerTextBox.value;
});
});
setTimeout(() => {
headerTextBox.focus();
}, 1);
}
export function setupMaximizeButtons() {
const maximizeButtons = document.getElementsByClassName('maximize-button');
Array.from(maximizeButtons).forEach(button => {

View File

@ -1,5 +1,5 @@
import { renderWords } from "./render";
import { wordExists } from "./utilities";
import { wordExists, addMessage } from "./utilities";
import removeDiacritics from "./StackOverflow/removeDiacritics";
import { removeTags } from "../helpers";
import { saveDictionary } from "./dictionaryManagement";
@ -48,6 +48,7 @@ export function sortWords(render) {
export function addWord(word, render = true) {
window.currentDictionary.words.push(word);
addMessage('Word Created Successfully');
sortWords(render);
}
@ -57,6 +58,7 @@ export function deleteWord(wordId) {
console.error('Could not find word to delete');
} else {
window.currentDictionary.words.splice(wordIndex, 1);
addMessage('Word Deleted Successfully');
sortWords(true);
}
}
@ -68,6 +70,7 @@ export function updateWord(word, wordId) {
console.error('Could not find word to update');
} else {
window.currentDictionary.words[wordIndex] = word;
addMessage('Word Updated Successfully');
sortWords(true);
}
}

View File

@ -22,6 +22,11 @@ label {
font-weight: normal;
}
input:not([type="checkbox"]):not([type="radio"]) {
padding-bottom: 2px;
line-height: 130%;
}
input:not([type="checkbox"]):not([type="radio"]),
select, textarea {
font-weight: normal;
@ -38,6 +43,16 @@ label {
line-height: 80% !important;
padding: 3px 3px 5px;
}
.label-help-button {
@extend .button;
font-size: 70%;
font-weight: normal;
cursor: pointer;
line-height: 70% !important;
padding: 2px 2px 4px;
}
}
ul {
@ -103,7 +118,7 @@ span .tag {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 700px;
width: 800px;
max-width: 100%;
height: 600px;
max-height: 100%;
@ -115,6 +130,7 @@ span .tag {
position: absolute;
top: 0;
right: 10px;
z-index: 1;
font-size: 200%;
cursor: pointer;
user-select: none;

View File

@ -206,8 +206,10 @@
}
}
#editModal {
$nav-font-height: 16px;
$nav-font-height: 16px;
#editModal,
.ipa-table-modal,
.maximize-modal {
nav {
padding-top: $general-padding;
@ -221,16 +223,16 @@
}
}
}
section, footer {
header, section, footer {
position: absolute;
width: 100%;
}
section {
top: ($general-padding * 2) + $nav-font-height + 10px;;
bottom: ($general-padding * 2) + $nav-font-height + 16px;
padding: $general-padding;
overflow-y: auto;
header {
top: 0;
}
footer {
bottom: 0;
@ -239,17 +241,61 @@
line-height: $nav-font-height;
}
}
}
#editModal {
section {
top: ($general-padding * 2) + $nav-font-height + 10px;;
bottom: ($general-padding * 2) + $nav-font-height + 16px;
padding: $general-padding;
overflow-y: auto;
}
#editDescription {
width: 100%;
height: 280px;
}
}
.ipa-table-modal,
.maximize-modal {
.modal-content {
width: 1000px !important;
}
}
.ipa-table-modal {
.modal-content {
overflow: auto;
header * {
font-size: $nav-font-height;
line-height: $nav-font-height;
}
section {
top: $general-padding + ($nav-font-height * 2) + 10px;
bottom: ($general-padding * 2) + $nav-font-height + 16px;
padding: 0 $general-padding $general-padding;
overflow-y: auto;
}
}
}
.maximize-modal {
section {
top: ($general-padding * 2) + $nav-font-height + 13px;;
bottom: ($general-padding * 2) + $nav-font-height + 10px;
overflow: hidden;
padding: 0;
}
textarea {
position: relative;
width: 100%;
max-width: 100%;
min-height: 400px;
height: 100%;
// min-height: 400px;
border: none;
padding: $general-padding;
}