Passed
Push — master ( 17fae3...e5a7e5 )
by Jesús
02:17
created

src/modules/wordInput/infrastructure/wordInput.ts   A

Complexity

Total Complexity 20
Complexity/F 2.5

Size

Lines of Code 119
Function Count 8

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 20
eloc 98
mnd 12
bc 12
fnc 8
dl 0
loc 119
rs 10
bpm 1.5
cpm 2.5
noi 0
c 0
b 0
f 0

8 Functions

Rating   Name   Duplication   Size   Complexity  
A wordInput.ts ➔ handleWordInputBlur 0 4 1
A wordInput.ts ➔ toggleClearButton 0 10 3
A wordInput.ts ➔ handleClearInput 0 9 1
A wordInput.ts ➔ clearWordInput 0 6 1
A wordInput.ts ➔ handleWordInput 0 25 4
A wordInput.ts ➔ syncWordInputFromState 0 15 5
A wordInput.ts ➔ setupWordInput 0 17 3
A wordInput.ts ➔ selectWord 0 12 2
1
import { elements, resetBoxes, setStateFromIndex, state } from '../../bip39';
2
import { setSyncWordInputCallback, updateDisplay } from '../../display';
3
import { binaryValueToIndex, getWordByIndex, getWordIndex } from '../domain/wordInputHelpers';
4
import { validateWordInput } from './validation';
5
import { showSuggestions, hideSuggestions } from './suggestions';
6
import { handleKeydown as handleKeyboardNavigation } from './keyboard';
7
8
export function setupWordInput(): void {
9
  setSyncWordInputCallback(syncWordInputFromState);
10
11
  elements.wordInput.addEventListener('input', handleWordInput);
12
  elements.wordInput.addEventListener('keydown', e => handleKeyboardNavigation(e, selectWord));
13
  elements.wordInput.addEventListener('focus', handleWordInput);
14
  elements.wordInput.addEventListener('blur', handleWordInputBlur);
15
16
  const clearBtn = document.getElementById('clear-input-btn');
17
  if (clearBtn) {
18
    clearBtn.addEventListener('click', handleClearInput);
19
  }
20
21
  document.addEventListener('click', e => {
22
    if (!elements.wordInput.contains(e.target as Node) && !elements.wordSuggestions.contains(e.target as Node)) {
23
      hideSuggestions();
24
    }
25
  });
26
}
27
28
function handleClearInput(): void {
29
  elements.wordInput.value = '';
30
  elements.wordInput.classList.remove('error');
31
  resetBoxes();
32
  updateDisplay();
33
  hideSuggestions();
34
  toggleClearButton(false);
35
  elements.wordInput.focus();
36
}
37
38
function handleWordInputBlur(): void {
39
  hideSuggestions();
40
  validateWordInput();
41
}
42
43
function handleWordInput(): void {
44
  const value = elements.wordInput.value.trim().toLowerCase();
45
46
  toggleClearButton(elements.wordInput.value.length > 0);
47
48
  if (!value) {
49
    hideSuggestions();
50
    return;
51
  }
52
53
  const matches = state.wordlist.filter(word => word.toLowerCase().startsWith(value));
54
55
  if (matches.length === 0) {
56
    hideSuggestions();
57
    return;
58
  }
59
60
  // Hide suggestions if only 1 match and it's an exact match
61
  if (matches.length === 1 && matches[0].toLowerCase() === value) {
62
    hideSuggestions();
63
    return;
64
  }
65
66
  showSuggestions(matches.slice(0, 10), selectWord);
67
}
68
69
function selectWord(word: string): void {
70
  const wordIndex = getWordIndex(word, state.wordlist);
71
72
  if (wordIndex === -1) return;
73
74
  elements.wordInput.value = word;
75
  elements.wordInput.classList.remove('error');
76
  setStateFromIndex(wordIndex);
77
  updateDisplay();
78
  hideSuggestions();
79
  elements.wordInput.blur();
80
}
81
82
export function clearWordInput(): void {
83
  elements.wordInput.value = '';
84
  elements.wordInput.classList.remove('error');
85
  hideSuggestions();
86
  toggleClearButton(false);
87
}
88
89
function toggleClearButton(show: boolean): void {
90
  const clearBtn = document.getElementById('clear-input-btn') as HTMLButtonElement | null;
91
  if (clearBtn) {
92
    if (show) {
93
      clearBtn.disabled = false;
94
      clearBtn.removeAttribute('aria-disabled');
95
    } else {
96
      clearBtn.disabled = true;
97
      clearBtn.setAttribute('aria-disabled', 'true');
98
    }
99
  }
100
}
101
102
export function syncWordInputFromState(): void {
103
  const index = state.boxes.reduce((acc, val, i) => acc + (val ? Math.pow(2, 11 - i) : 0), 0);
104
105
  if (index > 0 && index <= state.wordlist.length) {
106
    const wordIndex = binaryValueToIndex(index);
107
    const word = getWordByIndex(wordIndex, state.wordlist);
108
    if (word && elements.wordInput.value !== word) {
109
      elements.wordInput.value = word;
110
      toggleClearButton(true);
111
    }
112
  } else {
113
    if (elements.wordInput.value !== '') {
114
      elements.wordInput.value = '';
115
      toggleClearButton(false);
116
    }
117
  }
118
}
119