@@ -124,7 +124,6 @@ function getCalculatorHTML() {
124124function initCalculator ( ) {
125125 const display = document . getElementById ( "calcDisplay" ) ;
126126 if ( ! display ) return ;
127-
128127 let expression = "" ;
129128
130129 function update ( ) {
@@ -140,7 +139,11 @@ function initCalculator() {
140139
141140 function safeEval ( expr ) {
142141 try {
143- return String ( eval ( format ( expr ) ) ) ;
142+ if ( ! expr ) return "" ;
143+ let result = eval ( format ( expr ) ) ;
144+ if ( result === undefined ) return "" ;
145+ if ( isNaN ( result ) ) return "Error" ;
146+ return String ( result ) ;
144147 } catch {
145148 return "Error" ;
146149 }
@@ -149,48 +152,64 @@ function initCalculator() {
149152 function applyFunction ( type ) {
150153 try {
151154 let value = eval ( format ( expression || "0" ) ) ;
152-
155+ let result ;
153156 switch ( type ) {
154- case "sin" : return String ( Math . sin ( value ) ) ;
155- case "cos" : return String ( Math . cos ( value ) ) ;
156- case "tan" : return String ( Math . tan ( value ) ) ;
157- case "sqrt" : return String ( Math . sqrt ( value ) ) ;
158- case "square" : return String ( value * value ) ;
159- case "inv" : return value === 0 ? "Error" : String ( 1 / value ) ;
157+ case "sin" : result = Math . sin ( value ) ; break ;
158+ case "cos" : result = Math . cos ( value ) ; break ;
159+ case "tan" : result = Math . tan ( value ) ; break ;
160+ case "sqrt" : result = Math . sqrt ( value ) ; break ;
161+ case "square" : result = value * value ; break ;
162+ case "inv" : result = 1 / value ; break ;
160163 }
164+ if ( isNaN ( result ) ) return "Error" ;
165+ return String ( result ) ;
161166 } catch {
162167 return "Error" ;
163168 }
164169 }
165170
166- document . querySelectorAll ( ".calc-btn" ) . forEach ( btn => {
167- btn . addEventListener ( "click" , ( ) => {
171+
172+ function clearIfFinished ( ) {
173+ if ( expression === "Error" || expression === "NaN" ) {
174+ expression = "" ;
175+ }
176+ }
168177
178+ document . querySelectorAll ( ".calc-btn" ) . forEach ( ( btn ) => {
179+ btn . addEventListener ( "click" , ( ) => {
180+ clearIfFinished ( ) ;
181+
169182 const value = btn . dataset . value ;
170183 const action = btn . dataset . action ;
171184
172185 if ( value !== undefined ) {
186+ if ( value === "." ) {
187+
188+ const lastOperand = expression . split ( / [ \+ \- \* \/ \^ \( \) ] / ) . pop ( ) ;
189+ if ( lastOperand . includes ( "." ) ) return ;
190+ }
173191 expression += value ;
174192 update ( ) ;
175193 return ;
176194 }
177195
178196 if ( ! action ) return ;
179197
198+
180199 switch ( action ) {
181-
182200 case "clear" :
183201 expression = "" ;
184202 break ;
185-
186203 case "delete" :
187- expression = expression . slice ( 0 , - 1 ) ;
204+ if ( expression === "Infinity" || expression === "-Infinity" ) {
205+ expression = "" ;
206+ } else {
207+ expression = expression . slice ( 0 , - 1 ) ;
208+ }
188209 break ;
189-
190210 case "=" :
191211 expression = safeEval ( expression ) ;
192212 break ;
193-
194213 case "sin" :
195214 case "cos" :
196215 case "tan" :
@@ -199,11 +218,19 @@ function initCalculator() {
199218 case "inv" :
200219 expression = applyFunction ( action ) ;
201220 break ;
202-
203221 case "^" :
204- expression += "^" ;
222+ case "+" :
223+ case "-" :
224+ case "*" :
225+ case "/" :
226+
227+ const lastChar = expression . slice ( - 1 ) ;
228+ if ( [ "+" , "-" , "*" , "/" , "^" ] . includes ( lastChar ) ) {
229+ expression = expression . slice ( 0 , - 1 ) + action ;
230+ } else {
231+ expression += action ;
232+ }
205233 break ;
206-
207234 default :
208235 expression += action ;
209236 }
@@ -212,54 +239,48 @@ function initCalculator() {
212239 } ) ;
213240
214241 document . addEventListener ( "keydown" , ( e ) => {
215-
216- const key = e . key ;
217- if ( ! document . getElementById ( "calcDisplay" ) ) return ;
218- if ( key === "Enter" ||
219- key === "Backspace" ||
220- key === "Escape" ||
221- key === "=" ||
222- [ "+" , "-" , "*" , "/" , "^" , "." , "(" , ")" ] . includes ( key ) ||
223- / ^ [ 0 - 9 ] $ / . test ( key )
224- ) {
225- e . preventDefault ( )
226- }
227- if ( / ^ [ 0 - 9 ] $ / . test ( key ) ) {
228- expression += key ;
229- }
230- else if ( key === "." ) {
231- expression += "." ;
232- }
233- else if ( [ "+" , "-" , "*" , "/" ] . includes ( key ) ) {
234- expression += key ;
242+ const key = e . key ;
243+ if ( ! document . getElementById ( "calcDisplay" ) ) return ;
244+
245+ // Whitelist allowed keys to prevent typing letters
246+ const allowedKeys = [ "Enter" , "Backspace" , "Escape" , "=" , "+" , "-" , "*" , "/" , "^" , "." , "(" , ")" ] ;
247+ if ( allowedKeys . includes ( key ) || / ^ [ 0 - 9 ] $ / . test ( key ) ) {
248+ e . preventDefault ( ) ;
249+ } else {
250+ return ;
235251 }
236- else if ( key === ")" || key === "(" ) {
237- expression += key ;
238- }
239- else if ( key === "^" ) {
240- expression += "^" ;
241- }
242- else if ( key === "Enter" || key === "=" ) {
243- expression = safeEval ( expression ) ;
244- }
245- else if ( key === "Backspace" ) {
246- expression = expression . slice ( 0 , - 1 ) ;
247- }
248- else if ( key === "Escape" || key . toLowerCase ( ) === "c" ) {
249- expression = "" ;
250- }
251- update ( ) ;
252- // if (!isNaN(e.key) || e.key === ".") expression += e.key;
253-
254- // if (["+", "-", "*", "/"].includes(e.key)) expression += e.key;
255-
256- // if (e.key === "^") expression += "^";
257-
258- // if (e.key === "Enter") expression = safeEval(expression);
259252
260- // if (e.key === "Backspace") expression = expression.slice(0, -1 );
253+ clearIfFinished ( ) ;
261254
255+ if ( / ^ [ 0 - 9 ] $ / . test ( key ) ) {
256+ expression += key ;
257+ } else if ( key === "." ) {
258+ const lastOperand = expression . split ( / [ \+ \- \* \/ \^ \( \) ] / ) . pop ( ) ;
259+ if ( ! lastOperand . includes ( "." ) ) {
260+ expression += "." ;
261+ }
262+ } else if ( [ "+" , "-" , "*" , "/" , "^" ] . includes ( key ) ) {
263+ const lastChar = expression . slice ( - 1 ) ;
264+ if ( [ "+" , "-" , "*" , "/" , "^" ] . includes ( lastChar ) ) {
265+ expression = expression . slice ( 0 , - 1 ) + key ;
266+ } else {
267+ expression += key ;
268+ }
269+ } else if ( key === ")" || key === "(" ) {
270+ expression += key ;
271+ } else if ( key === "Enter" || key === "=" ) {
272+ expression = safeEval ( expression ) ;
273+ } else if ( key === "Backspace" ) {
274+ if ( expression === "Infinity" || expression === "-Infinity" ) {
275+ expression = "" ;
276+ } else {
277+ expression = expression . slice ( 0 , - 1 ) ;
278+ }
279+ } else if ( key === "Escape" || key . toLowerCase ( ) === "c" ) {
280+ expression = "" ;
281+ }
282+ update ( ) ;
262283 } ) ;
263-
284+
264285 update ( ) ;
265- }
286+ }
0 commit comments