-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
223 lines (195 loc) · 7.51 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"use strict";
const calculatorElement = document.querySelector("[data-calculator]")
const numbers = calculatorElement.querySelectorAll("[data-number]")
const operations = calculatorElement.querySelectorAll("[data-operation]")
const allClearButton = calculatorElement.querySelector("[data-all-clear]")
const deleteButton = calculatorElement.querySelector("[data-delete]")
const equalsButton = calculatorElement.querySelector("[data-equals]")
const output = calculatorElement.querySelector("[data-output]")
const previousOperandText = calculatorElement.querySelector("[data-previous]")
const currentOperandText = calculatorElement.querySelector("[data-current]")
class Calculator {
constructor(currentOperandText, previousOperandText) {
this.currentOperandText = currentOperandText
this.previousOperandText = previousOperandText
// Clear values whenever an instance of the calculator class is called
this.clear()
}
clear() {
this.currentOperand = ''
this.previousOperand = ''
this.previousOperandText.textContent = ''
this.operation = null
}
// Delete the current operand by removing the last character using the slice string method
delete() {
if (this.currentOperand === "") {
return
}
this.currentOperand = this.currentOperand.toString().slice(0, -1)
}
// Method to append a number onto the calculator's updateDisplay
// making sure that as many numbers as possible can be typed
appendNumber(number) {
// if there's already a decimal point and the user is still clicking a point then just do nothing
if (number === "." && this.currentOperand.includes("."))
return
if (this.overwrite) {
this.currentOperand = number
this.overwrite = false
} else {
this.currentOperand = this.currentOperand.toString() + number.toString()
}
}
// Method to select an operation to carry out the required mathematical calculation
chooseOpertion(operation) {
// When user mistakenly chooses the wrong operation and wants to overwrite it or change it
if (this.previousOperand !== "" && this.operation) {
this.operation = operation
}
// If there's no current operand then do nothing
if (this.currentOperand === "")
return
// If there's already a previous value then calculate the result
if (this.previousOperand !== '') {
this.evaluate()
}
// Set the operation to the operation chosen by the user
this.operation = operation
// Set the previous operand to the current operand since the user is going to add a new current operand
this.previousOperand = this.currentOperand
// Set the current operand to something falsy
this.currentOperand = ''
}
// Method to include commas if the number is greater than 3 digits e.g 1000 => 1,000
formatNumber(number) {
// Turn the number into a string
let stringNumber = number.toString()
// to be able to split at where the decimal point is
// the integerPart is the part that comes first in the array i.e. "44.2323" => ["44", "2323"], => 44
let integerPart = parseFloat(stringNumber.split(".")[0])
let decimalPart = stringNumber.split(".")[1]
// Create a display for the integerPart
let integerDisplay = '';
// Check if the integerPart is not a number
if (isNaN(integerPart)) {
integerDisplay = ''
} else {
// Set the integerDisplay to a locale, in this case "en"
integerDisplay = integerPart.toLocaleString("en", {
maximumFractionDigits: 0
})
}
// If there's a decimalPart then add a decimal point between the integerDisplay and the decimalPart
if (decimalPart) {
return `${integerDisplay}.${decimalPart}`
} else {
// If there's no d.p then return the integerDisplay as it is
return integerDisplay
}
}
// Method to compute values
evaluate() {
// Turn the "string" numbers into actual numbers
let integerCurrent = parseFloat(this.currentOperand)
let integerPrevious = parseFloat(this.previousOperand)
// Intialize a computedValue
let computedValue = 0
// If the current and previous operands are not numbers then do nothing
if (isNaN(integerCurrent) || isNaN(integerPrevious))
return
// Perform the operation based on the mathematical symbol
switch (this.operation) {
case "+":
computedValue = integerPrevious + integerCurrent
break;
case "-":
computedValue = integerPrevious - integerCurrent
break;
case "*":
computedValue = integerCurrent * integerPrevious
break;
case "/":
computedValue = integerPrevious / integerCurrent
break;
default:
return
}
// If the computedValue dies not contain decimals then return is as a whole number else round it to 3 d.p
if (!computedValue.toString().includes(".")) {
this.currentOperand = computedValue
} else {
this.currentOperand = computedValue.toFixed(3)
}
// set the previous operand to nothing and also the operation
this.previousOperand = ''
this.operation = ''
this.overwrite = true
}
// This is the method that shows the user what they're doing
updateDisplay() {
this.currentOperandText.textContent = this.formatNumber(this.currentOperand)
// While updating the display, if there is an operation, then concatenate it with the previous operand
if (this.operation != null) {
this.previousOperandText.textContent = `${this.formatNumber(this.previousOperand)} ${this.operation}`
}
}
}
// Call an instance of the calculator class and pass in the previous and current text elements
const calculator = new Calculator(currentOperandText,previousOperandText)
// Get the number elements and use their text contents as the argument to the appendNumber() method
// then update the display
numbers.forEach(number=>{
number.addEventListener("click", ()=>{
calculator.appendNumber(number.innerText)
calculator.updateDisplay()
}
)
}
)
operations.forEach(operation=>{
operation.addEventListener("click", ()=>{
calculator.chooseOpertion(operation.innerText)
calculator.updateDisplay()
}
)
}
)
allClearButton.addEventListener("click", ()=>{
calculator.clear()
calculator.updateDisplay()
output.classList.add("animate")
output.addEventListener("animationend", ()=>{
console.log("animation ended")
output.classList.remove("animate")
}
)
}
)
deleteButton.addEventListener("click", ()=>{
calculator.delete()
calculator.updateDisplay()
}
)
equalsButton.addEventListener("click", ()=>{
calculator.evaluate()
calculator.updateDisplay()
}
)
// Code to allow number appending via keyboard
document.addEventListener("keydown", (e)=>{
let keyPressed = e.key
let alphabetRegex = /[a-zA-Z]/
if (keyPressed.match(alphabetRegex)) {
console.log("yeah it's an alphabet")
return
} else {
if (isNaN(keyPressed)) {
return
} else {
calculator.appendNumber(keyPressed)
calculator.updateDisplay()
}
}
}
)