@@ -9,10 +9,12 @@ if (LIVE_RELOAD) {
9
9
. addEventListener ( "change" , ( ) => location . reload ( ) ) ;
10
10
}
11
11
import { dictionary } from "../dictionary/dictionary.ts" ;
12
+ import { dictionaryParser } from "../dictionary/parser.ts" ;
12
13
import PROJECT_DATA from "../project_data.json" with { type : "json" } ;
13
14
import { loadCustomDictionary } from "./dictionary.ts" ;
14
15
import { checkLocalStorage , setIgnoreError } from "./local_storage.ts" ;
15
16
import { translate } from "./mod.ts" ;
17
+ import { PositionedError } from "./parser/parser_lib.ts" ;
16
18
import { settings } from "./settings.ts" ;
17
19
import {
18
20
loadFromElements ,
@@ -21,6 +23,11 @@ import {
21
23
resetElementsToDefault ,
22
24
} from "./settings_frontend.ts" ;
23
25
26
+ const DICTIONARY_AUTO_PARSE_THRESHOLD = 9000 ;
27
+
28
+ // never change this
29
+ const DICTIONARY_KEY = "dictionary" ;
30
+
24
31
const TRANSLATE_LABEL = "Translate" ;
25
32
const TRANSLATE_LABEL_MULTILINE = "Translate (Ctrl + Enter)" ;
26
33
@@ -31,31 +38,27 @@ const SINGULAR_ERROR_MESSAGE = "An error has been found:";
31
38
const MULTIPLE_ERROR_MESSAGE = "Multiple errors has been found:" ;
32
39
33
40
const DEFAULT_CUSTOM_DICTIONARY_MESSAGE = `\
34
- ====================================
35
- Welcome to Custom Dictionary Editor!
36
- ====================================
37
-
38
- Here you can customize the dictionary
39
- used in ilo Token. You may change the
40
- definitions of existing words and
41
- even extend ilo Token with more
42
- non-pu words. Just know that the
43
- custom dictionary comes with
44
- limitations. Press Help above to get
45
- started.` ;
41
+ # ====================================
42
+ # Welcome to Custom Dictionary Editor!
43
+ # ====================================
44
+ #
45
+ # Here you can customize the dictionary
46
+ # used in ilo Token. You may change the
47
+ # definitions of existing words and
48
+ # even extend ilo Token with more
49
+ # non-pu words. Just know that the
50
+ # custom dictionary comes with
51
+ # limitations. Press Help above to get
52
+ # started.
53
+ ` ;
46
54
47
55
const DICTIONARY_LOADING_FAILED_MESSAGE =
48
56
"Failed to load custom dictionary. This is mostly likely because the " +
49
57
"syntax has been updated and your custom dictionary still uses the old " +
50
58
"syntax. Please fix it. Apologies for the inconvenience." ;
51
59
const NO_WORD_MESSAGE = "Please provide a word" ;
52
60
const WORD_NOT_FOUND_MESSAGE = "Word not found" ;
53
-
54
- const DICTIONARY_ERROR_MESSAGE =
55
- "Please fix these errors before saving.\n(You may remove these when fixed)" ;
56
-
57
- // never change this
58
- const DICTIONARY_KEY = "dictionary" ;
61
+ const DICTIONARY_ERROR_MESSAGE = "Please fix the errors before saving" ;
59
62
60
63
function main ( ) : void {
61
64
// load elements
@@ -106,6 +109,12 @@ function main(): void {
106
109
const customDictionaryTextBox = document . getElementById (
107
110
"custom-dictionary" ,
108
111
) as HTMLTextAreaElement ;
112
+ const customDictionaryErrorSummary = document . getElementById (
113
+ "custom-dictionary-error-summary" ,
114
+ ) as HTMLElement ;
115
+ const customDictionaryErrorList = document . getElementById (
116
+ "custom-dictionary-error-list" ,
117
+ ) as HTMLUListElement ;
109
118
const discardButton = document . getElementById (
110
119
"discard-button" ,
111
120
) as HTMLButtonElement ;
@@ -151,14 +160,21 @@ function main(): void {
151
160
// load settings
152
161
loadFromLocalStorage ( ) ;
153
162
154
- // load custom dictionary
155
- const customDictionary = checkLocalStorage ( )
163
+ // states for storing previous dictionary states for discarding dictionary edits
164
+ let lastSavedText = checkLocalStorage ( )
156
165
? localStorage . getItem ( DICTIONARY_KEY ) ?? ""
157
166
: customDictionaryTextBox . value ;
158
- if ( customDictionary . trim ( ) !== "" ) {
159
- if ( loadCustomDictionary ( customDictionary ) != null ) {
160
- showMessage ( DICTIONARY_LOADING_FAILED_MESSAGE ) ;
161
- }
167
+ let lastSavedDictionary = dictionaryParser . parse ( lastSavedText ) ;
168
+
169
+ // this variable also holds error messages
170
+ let currentDictionary = lastSavedDictionary ;
171
+
172
+ // load custom dictionary
173
+ if ( ! currentDictionary . isError ( ) ) {
174
+ loadCustomDictionary ( currentDictionary . array [ 0 ] ) ;
175
+ } else {
176
+ showDictionaryError ( ) ;
177
+ showMessage ( DICTIONARY_LOADING_FAILED_MESSAGE ) ;
162
178
}
163
179
164
180
// initial text area size
@@ -176,6 +192,29 @@ function main(): void {
176
192
: TRANSLATE_LABEL ;
177
193
}
178
194
195
+ // show custom dictionary errors
196
+ function showDictionaryError ( ) : void {
197
+ customDictionaryErrorSummary . innerText =
198
+ `Errors (${ currentDictionary . errors . length } ):` ;
199
+ customDictionaryErrorList . innerHTML = "" ;
200
+ for ( const error of currentDictionary . errors ) {
201
+ const element = document . createElement ( "li" ) ;
202
+ element . innerText = error . message ;
203
+ if ( error instanceof PositionedError && error . position != null ) {
204
+ const { position, length } = error . position ;
205
+ element . addEventListener ( "click" , ( ) => {
206
+ customDictionaryTextBox . focus ( ) ;
207
+ customDictionaryTextBox . setSelectionRange (
208
+ position ,
209
+ position + length ,
210
+ ) ;
211
+ } ) ;
212
+ } else {
213
+ throw new Error ( "error without position" ) ;
214
+ }
215
+ customDictionaryErrorList . appendChild ( element ) ;
216
+ }
217
+ }
179
218
// add all event listener
180
219
translateButton . addEventListener ( "click" , updateOutput ) ;
181
220
inputTextBox . addEventListener ( "input" , resizeTextarea ) ;
@@ -239,7 +278,7 @@ function main(): void {
239
278
customDictionaryDialogBox . showModal ( ) ;
240
279
if ( checkLocalStorage ( ) ) {
241
280
customDictionaryTextBox . value = localStorage . getItem ( DICTIONARY_KEY ) ??
242
- ` ${ asComment ( DEFAULT_CUSTOM_DICTIONARY_MESSAGE ) } \n` ;
281
+ DEFAULT_CUSTOM_DICTIONARY_MESSAGE ;
243
282
}
244
283
} ) ;
245
284
importWordButton . addEventListener ( "click" , importWord ) ;
@@ -249,43 +288,61 @@ function main(): void {
249
288
importWord ( ) ;
250
289
}
251
290
} ) ;
252
- function displayToCustomDictionary ( message : string ) : void {
253
- const original = customDictionaryTextBox . value . trimEnd ( ) ;
254
- const append = original === "" ? "" : "\n\n" ;
255
- customDictionaryTextBox . value =
256
- `${ original } ${ append } ${ message . trimEnd ( ) } \n` ;
257
- customDictionaryTextBox . scrollTo ( 0 , customDictionaryTextBox . scrollHeight ) ;
258
- }
259
291
function importWord ( ) : void {
260
292
const word = importWordTextBox . value . trim ( ) ;
261
293
if ( word === "" ) {
262
294
showMessage ( NO_WORD_MESSAGE ) ;
263
295
} else {
264
296
const definitions = dictionary . get ( word ) ?. source ;
265
297
if ( definitions != null ) {
266
- displayToCustomDictionary ( `${ word } :${ definitions } ` ) ;
298
+ const original = customDictionaryTextBox . value . trimEnd ( ) ;
299
+ const append = original === "" ? "" : "\n\n" ;
300
+ customDictionaryTextBox . value =
301
+ `${ original } ${ append } ${ word } :${ definitions . trimEnd ( ) } \n` ;
302
+ customDictionaryTextBox . scrollTo (
303
+ 0 ,
304
+ customDictionaryTextBox . scrollHeight ,
305
+ ) ;
267
306
} else {
268
307
showMessage ( WORD_NOT_FOUND_MESSAGE ) ;
269
308
}
270
309
}
271
310
}
311
+ customDictionaryTextBox . addEventListener ( "input" , ( ) => {
312
+ if (
313
+ customDictionaryTextBox . value . length <= DICTIONARY_AUTO_PARSE_THRESHOLD
314
+ ) {
315
+ updateDictionary ( ) ;
316
+ }
317
+ } ) ;
272
318
discardButton . addEventListener ( "click" , ( ) => {
273
- customDictionaryDialogBox . close ( ) ;
319
+ customDictionaryTextBox . value = lastSavedText ;
320
+ currentDictionary = lastSavedDictionary ;
321
+ tryCloseDictionary ( ) ;
274
322
} ) ;
275
323
saveButton . addEventListener ( "click" , ( ) => {
276
- const { value } = customDictionaryTextBox ;
277
- const errors = loadCustomDictionary ( value ) ;
278
- if ( errors == null ) {
279
- setIgnoreError ( DICTIONARY_KEY , value ) ;
324
+ if (
325
+ customDictionaryTextBox . value . length > DICTIONARY_AUTO_PARSE_THRESHOLD
326
+ ) {
327
+ updateDictionary ( ) ;
328
+ }
329
+ tryCloseDictionary ( ) ;
330
+ } ) ;
331
+ function updateDictionary ( ) : void {
332
+ currentDictionary = dictionaryParser . parse ( customDictionaryTextBox . value ) ;
333
+ showDictionaryError ( ) ;
334
+ }
335
+ function tryCloseDictionary ( ) : void {
336
+ if ( ! currentDictionary . isError ( ) ) {
337
+ lastSavedText = customDictionaryTextBox . value ;
338
+ lastSavedDictionary = currentDictionary ;
339
+ loadCustomDictionary ( currentDictionary . array [ 0 ] ) ;
340
+ setIgnoreError ( DICTIONARY_KEY , customDictionaryTextBox . value ) ;
280
341
customDictionaryDialogBox . close ( ) ;
281
342
} else {
282
- const errorListMessage = errors
283
- . map ( ( error ) => `\n- ${ error . message . replaceAll ( / \r ? \n / g, "$& " ) } ` ) ;
284
- displayToCustomDictionary (
285
- asComment ( `${ DICTIONARY_ERROR_MESSAGE } ${ errorListMessage } ` ) ,
286
- ) ;
343
+ showMessage ( DICTIONARY_ERROR_MESSAGE ) ;
287
344
}
288
- } ) ;
345
+ }
289
346
closeButton . addEventListener ( "click" , ( ) => {
290
347
alertBox . close ( ) ;
291
348
} ) ;
@@ -311,8 +368,3 @@ const unused = [...new Array(localStorage.length).keys()]
311
368
for ( const key of unused ) {
312
369
localStorage . removeItem ( key ) ;
313
370
}
314
- export function asComment ( text : string ) : string {
315
- return text
316
- . replaceAll ( / ^ / mg, "# " )
317
- . replaceAll ( / ^ # \s + $ / mg, "#" ) ;
318
- }
0 commit comments