@@ -12,13 +12,51 @@ type CountRunesResult = {
1212 decodeErrorCount : number
1313}
1414
15- type CharsetKey = 'utf8' | 'utf16' | 'latin1'
16-
17- const charsetToEncoding : Record < CharsetKey , string > = {
18- utf8 : 'utf-8' ,
19- utf16 : 'utf-16le' ,
20- latin1 : 'iso-8859-1' ,
21- }
15+ const charsetOptions = [
16+ { value : 'utf-8' , label : 'utf-8' } ,
17+ { value : 'utf-16le' , label : 'utf-16le' } ,
18+ { value : 'utf-16be' , label : 'utf-16be' } ,
19+ { value : 'ibm866' , label : 'ibm866' } ,
20+ { value : 'iso-8859-1' , label : 'iso-8859-1' } ,
21+ { value : 'iso-8859-2' , label : 'iso-8859-2' } ,
22+ { value : 'iso-8859-3' , label : 'iso-8859-3' } ,
23+ { value : 'iso-8859-4' , label : 'iso-8859-4' } ,
24+ { value : 'iso-8859-5' , label : 'iso-8859-5' } ,
25+ { value : 'iso-8859-6' , label : 'iso-8859-6' } ,
26+ { value : 'iso-8859-7' , label : 'iso-8859-7' } ,
27+ { value : 'iso-8859-8' , label : 'iso-8859-8' } ,
28+ { value : 'iso-8859-8-i' , label : 'iso-8859-8-i' } ,
29+ { value : 'iso-8859-10' , label : 'iso-8859-10' } ,
30+ { value : 'iso-8859-13' , label : 'iso-8859-13' } ,
31+ { value : 'iso-8859-14' , label : 'iso-8859-14' } ,
32+ { value : 'iso-8859-15' , label : 'iso-8859-15' } ,
33+ { value : 'iso-8859-16' , label : 'iso-8859-16' } ,
34+ { value : 'koi8-r' , label : 'koi8-r' } ,
35+ { value : 'koi8-u' , label : 'koi8-u' } ,
36+ { value : 'macintosh' , label : 'macintosh' } ,
37+ { value : 'windows-874' , label : 'windows-874' } ,
38+ { value : 'windows-1250' , label : 'windows-1250' } ,
39+ { value : 'windows-1251' , label : 'windows-1251' } ,
40+ { value : 'windows-1252' , label : 'windows-1252' } ,
41+ { value : 'windows-1253' , label : 'windows-1253' } ,
42+ { value : 'windows-1254' , label : 'windows-1254' } ,
43+ { value : 'windows-1255' , label : 'windows-1255' } ,
44+ { value : 'windows-1256' , label : 'windows-1256' } ,
45+ { value : 'windows-1257' , label : 'windows-1257' } ,
46+ { value : 'windows-1258' , label : 'windows-1258' } ,
47+ { value : 'x-mac-cyrillic' , label : 'x-mac-cyrillic' } ,
48+ { value : 'gbk' , label : 'gbk' } ,
49+ { value : 'gb18030' , label : 'gb18030' } ,
50+ { value : 'big5' , label : 'big5' } ,
51+ { value : 'euc-jp' , label : 'euc-jp' } ,
52+ { value : 'iso-2022-jp' , label : 'iso-2022-jp' } ,
53+ { value : 'shift_jis' , label : 'shift_jis' } ,
54+ { value : 'euc-kr' , label : 'euc-kr' } ,
55+ { value : 'x-user-defined' , label : 'x-user-defined' } ,
56+ ] as const
57+
58+ type CharsetKey = ( typeof charsetOptions ) [ number ] [ 'value' ]
59+ const charsetValues = new Set < CharsetKey > ( charsetOptions . map ( ( option ) => option . value ) )
2260
2361document . querySelector < HTMLDivElement > ( '#app' ) ! . innerHTML = `
2462<main class="min-h-screen bg-base-200" data-theme="light">
@@ -41,18 +79,17 @@ document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
4179 <div class="label">
4280 <span class="label-text">Character set</span>
4381 </div>
44- <select id="charset-select" name="charset" class="select select-bordered w-full">
45- <option value="utf8" selected>UTF-8</option>
46- <option value="utf16">UTF-16</option>
47- <option value="latin1">Latin-1</option>
48- </select>
82+ <select id="charset-select" name="charset" class="select select-bordered w-full"></select>
4983 </label>
5084
5185 <div id="form-error" class="alert alert-error hidden" role="alert" aria-live="polite"></div>
5286 </form>
5387
5488 <section id="results" class="mt-8 hidden">
55- <h2 class="text-xl font-semibold">Character Counts</h2>
89+ <div class="flex items-center gap-3">
90+ <h2 class="text-xl font-semibold">Character Counts</h2>
91+ <button id="clear-results-button" type="button" class="btn btn-sm ml-auto">Clear</button>
92+ </div>
5693 <p id="results-summary" class="mt-2 text-base-content/70"></p>
5794
5895 <div class="mt-4 overflow-x-auto">
@@ -81,6 +118,7 @@ const formError = document.querySelector<HTMLDivElement>('#form-error')
81118const resultsSection = document . querySelector < HTMLElement > ( '#results' )
82119const resultsSummary = document . querySelector < HTMLParagraphElement > ( '#results-summary' )
83120const resultsBody = document . querySelector < HTMLTableSectionElement > ( '#results-body' )
121+ const clearResultsButton = document . querySelector < HTMLButtonElement > ( '#clear-results-button' )
84122let errorTimeoutId : number | undefined
85123
86124const hideError = ( ) => {
@@ -116,12 +154,18 @@ const showError = (message: string) => {
116154 document . addEventListener ( 'click' , hideError , { once : true } )
117155}
118156
119- const isCharsetKey = ( value : string ) : value is CharsetKey => value in charsetToEncoding
157+ const isCharsetKey = ( value : string ) : value is CharsetKey => charsetValues . has ( value as CharsetKey )
158+
159+ if ( charsetSelect ) {
160+ charsetSelect . innerHTML = charsetOptions
161+ . map ( ( option ) => `<option value="${ option . value } "${ option . value === 'utf-8' ? ' selected' : '' } >${ option . label } </option>` )
162+ . join ( '' )
163+ }
120164
121165const countRunes = async ( file : File , charset : CharsetKey ) : Promise < CountRunesResult > => {
122166 const runeCounts = new Map < number , RuneStats > ( )
123167 const fileBuffer = await file . arrayBuffer ( )
124- const text = new TextDecoder ( charsetToEncoding [ charset ] ) . decode ( fileBuffer )
168+ const text = new TextDecoder ( charset ) . decode ( fileBuffer )
125169 let decodeErrorCount = 0
126170
127171 let runeOffset = 0
@@ -229,7 +273,7 @@ const renderRuneTable = (runeCounts: Map<number, RuneStats>, totalRunes: number,
229273
230274const runCount = async ( ) => {
231275 const selectedFile = fileInput ?. files ?. [ 0 ]
232- const selectedCharset = charsetSelect ?. value ?? 'utf8 '
276+ const selectedCharset = charsetSelect ?. value ?? 'utf-8 '
233277
234278 if ( ! selectedFile ) {
235279 resultsSection ?. classList . add ( 'hidden' )
@@ -268,6 +312,18 @@ const runCount = async () => {
268312 }
269313}
270314
315+ clearResultsButton ?. addEventListener ( 'click' , ( ) => {
316+ if ( resultsBody ) {
317+ resultsBody . innerHTML = ''
318+ }
319+
320+ if ( resultsSummary ) {
321+ resultsSummary . textContent = ''
322+ }
323+
324+ resultsSection ?. classList . add ( 'hidden' )
325+ } )
326+
271327fileInput ?. addEventListener ( 'change' , ( ) => {
272328 void runCount ( )
273329} )
0 commit comments