🛠️ Calculator: Handling other keys 
      We have three more types of keys to handle:
Decimal 
Operator 
Equal 
 
Let’s work on Decimal keys first.
Handling Decimal keys 
First, we include tests that include Decimal keys into test.calculator.js.
const tests = [
  {
    message: 'Number key',
    keys: ['2'],
    result: '2'
  }, {
    message: 'Number Number',
    keys: ['3', '5'],
    result: '35'
  }, {
    message: 'Number Decimal',
    keys: ['4', 'decimal'],
    result: '4.'
  }, {
    message: 'Number Decimal Number',
    keys: ['4', 'decimal', '5'],
    result: '4.5'
  }
]
Errors should show up since we haven’t handled decimal keys yet.
   
We’ll handle Decimal keys by uncommenting the decimal part in handleClick.
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'decimal': handleDecimalKey(calculator); break
        // case 'operator': handleOperatorKeys(calculator, button); break
        // case 'equal': handleEqualKey(calculator); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
This is the code we wrote to handle decimal keys previously:
function handleDecimalKey (calculator) {
  const displayValue = getDisplayValue()
  const { previousButtonType } = calculator.dataset
  if (!displayValue.includes('.')) {
    display.textContent = displayValue + '.'
  }
  if (previousButtonType === 'equal') {
    resetCalculator()
    display.textContent = '0.'
  }
  if (previousButtonType === 'operator') {
    display.textContent = '0.'
  }
}
We will copy this code into Calculator as a method.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleDecimalKey (calculator) {
      const displayValue = getDisplayValue()
      const { previousButtonType } = calculator.dataset
      if (!displayValue.includes('.')) {
        display.textContent = displayValue + '.'
      }
      if (previousButtonType === 'equal') {
        resetCalculator()
        display.textContent = '0.'
      }
      if (previousButtonType === 'operator') {
        display.textContent = '0.'
      }
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
We’ll make the changes we did for other methods:
Change calculator to calculatorElement 
Omit calculatorElement from parameters 
Use calculator.displayValue getters and setters 
Change resetCalculator to calculator.resetCalculator 
 
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleDecimalKey () {
      const displayValue = calculator.displayValue
      const { previousButtonType } = calculatorElement.dataset
      if (!displayValue.includes('.')) {
        calculator.displayValue = displayValue + '.'
      }
      if (previousButtonType === 'operator') {
        calculator.displayValue = '0.'
      }
      if (previousButtonType === 'equal') {
        calculator.resetCalculator()
        calculator.displayValue = '0.'
      }
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
We use handleDecimalKey like this:
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'decimal': calculator.handleDecimalKeys(); break
        // case 'operator': handleOperatorKeys(calculator, button); break
        // case 'equal': handleEqualKey(calculator); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
Errors related to decimal keys should now be gone.
   
We’ll handle operator keys next.
Handling Operator Keys 
First, we uncomment the part we use to handle operator keys.
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'operator': handleOperatorKeys(calculator, button); break
        // case 'equal': handleEqualKey(calculator); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
Here’s the code we wrote to handle operator keys:
function handleOperatorKeys (calculator, button) {
  const displayValue = getDisplayValue()
  const { previousButtonType, firstValue, operator } = calculator.dataset
  const secondValue = displayValue
  button.classList.add('is-pressed')
  if (
    previousButtonType !== 'operator' &&
    previousButtonType !== 'equal' &&
    firstValue &&
    operator
  ) {
    const result = calculate(firstValue, operator, secondValue)
    display.textContent = result
    calculator.dataset.firstValue = result
  } else {
    calculator.dataset.firstValue = displayValue
  }
  calculator.dataset.operator = button.dataset.key
}
We’ll copy this code into Calculator as a method.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleOperatorKeys (calculator, button) {
      const displayValue = getDisplayValue()
      const { previousButtonType, firstValue, operator } = calculator.dataset
      const secondValue = displayValue
      button.classList.add('is-pressed')
      if (
        previousButtonType !== 'operator' &&
    previousButtonType !== 'equal' &&
    firstValue &&
    operator
      ) {
        const result = calculate(firstValue, operator, secondValue)
        display.textContent = result
        calculator.dataset.firstValue = result
      } else {
        calculator.dataset.firstValue = displayValue
      }
      calculator.dataset.operator = button.dataset.key
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
We’ll make the same treatments:
Change calculator to calculatorElement 
Omit calculatorElement from parameters 
Use calculator.displayValue getters and setters 
 
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleOperatorKeys (button) {
      const displayValue = calculator.displayValue
      const { previousButtonType, firstValue, operator } = calculatorElement.dataset
      const secondValue = displayValue
      button.classList.add('is-pressed')
      if (
        previousButtonType !== 'operator' &&
        previousButtonType !== 'equal' &&
        firstValue &&
        operator
      ) {
        const result = calculate(firstValue, operator, secondValue)
        display.textContent = result
        calculatorElement.dataset.firstValue = result
      } else {
        calculatorElement.dataset.firstValue = displayValue
      }
      calculatorElement.dataset.operator = button.dataset.key
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
handleOperatorKeys need a calculate function to work. Here’s what we wrote for calculate previously.
const calculate = (firstValue, operator, secondValue) => {
  firstValue = parseFloat(firstValue)
  secondValue = parseFloat(secondValue)
  if (operator === 'plus') return firstValue + secondValue
  if (operator === 'minus') return firstValue - secondValue
  if (operator === 'times') return firstValue * secondValue
  if (operator === 'divide') return firstValue / secondValue
}
We’ll create a calculate method in Calculator and paste the code in.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    calculate (firstValue, operator, secondValue) {
      firstValue = parseFloat(firstValue)
      secondValue = parseFloat(secondValue)
      if (operator === 'plus') return firstValue + secondValue
      if (operator === 'minus') return firstValue - secondValue
      if (operator === 'times') return firstValue * secondValue
      if (operator === 'divide') return firstValue / secondValue
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
We use calculate like this:
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleOperatorKeys (button) {
      // ...
      if (
        previousButtonType !== 'operator' &&
        previousButtonType !== 'equal' &&
        firstValue &&
        operator
      ) {
        const result = calculator.calculate(firstValue, operator, secondValue)
        // ...
      } else {
        // ...
      }
      // ...
    },
    // Other methods
    // Listeners
  }
  // Add Event Listeners
  // Return the calculator
}
We’ll use handleOperatorKeys like this
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'operator': calculator.handleOperatorKeys(button); break
        // case 'equal': handleEqualKey(calculator); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
Errors related to testClearAfterCalculation should now be gone since we have firstValue and operator in the calculator’s dataset.
At this point, we can include every test we created for the calculator into calculator.test.js.
const tests = [
  // Initial Expressions
  {
    message: 'Number key',
    keys: ['2'],
    result: '2'
  }, {
    message: 'Number Number',
    keys: ['3', '5'],
    result: '35'
  }, {
    message: 'Number Decimal',
    keys: ['4', 'decimal'],
    result: '4.'
  }, {
    message: 'Number Decimal Number',
    keys: ['4', 'decimal', '5'],
    result: '4.5'
  },
  // Calculations
  {
    message: 'Addition',
    keys: ['2', 'plus', '5', 'equal'],
    result: '7'
  }, {
    message: 'Subtraction',
    keys: ['5', 'minus', '9', 'equal'],
    result: '-4'
  }, {
    message: 'Multiplication',
    keys: ['4', 'times', '8', 'equal'],
    result: '32'
  }, {
    message: 'Division',
    keys: ['5', 'divide', '1', '0', 'equal'],
    result: '0.5'
  },
  // Easy Edge Cases
  // Number keys first
  {
    message: 'Number Equal',
    keys: ['5', 'equal'],
    result: '5'
  }, {
    message: 'Number Decimal Equal',
    keys: ['2', 'decimal', '4', '5', 'equal'],
    result: '2.45'
  },
  // Decimal keys first
  {
    message: 'Decimal key',
    keys: ['decimal'],
    result: '0.'
  }, {
    message: 'Decimal Decimal',
    keys: ['2', 'decimal', 'decimal'],
    result: '2.'
  }, {
    message: 'Decimal Decimal',
    keys: ['2', 'decimal', '5', 'decimal', '5'],
    result: '2.55'
  }, {
    message: 'Decimal Equal',
    keys: ['2', 'decimal', 'equal'],
    result: '2'
  },
  // Equal key first
  {
    message: 'Equal',
    keys: ['equal'],
    result: '0'
  }, {
    message: 'Equal Number',
    keys: ['equal', '3'],
    result: '3'
  }, {
    message: 'Number Equal Number',
    keys: ['5', 'equal', '3'],
    result: '3'
  }, {
    message: 'Equal Decimal',
    keys: ['equal', 'decimal'],
    result: '0.'
  }, {
    message: 'Number Equal Decimal',
    keys: ['5', 'equal', 'decimal'],
    result: '0.'
  }, {
    message: 'Calculation + Operator',
    keys: ['1', 'plus', '1', 'equal', 'plus', '1', 'equal'],
    result: '3'
  },
  // Operator Keys first
  {
    message: 'Operator Decimal',
    keys: ['times', 'decimal'],
    result: '0.'
  }, {
    message: 'Number Operator Decimal',
    keys: ['5', 'times', 'decimal'],
    result: '0.'
  }, {
    message: 'Number Operator Equal',
    keys: ['7', 'divide', 'equal'],
    result: '1'
  }, {
    message: 'Number Operator Operator',
    keys: ['9', 'times', 'divide'],
    result: '9'
  },
  // Difficult edge cases
  // Operator calculation
  {
    message: 'Operator calculation',
    keys: ['9', 'plus', '5', 'plus'],
    result: '14'
  }, {
    message: 'Operator follow-up calculation',
    keys: ['1', 'plus', '2', 'plus', '3', 'plus', '4', 'plus', '5', 'plus'],
    result: '15'
  },
  // Equal followup calculation
  {
    message: 'Number Operator Equal Equal',
    keys: ['9', 'minus', 'equal', 'equal'],
    result: '-9'
  }, {
    message: 'Number Operator Number Equal Equal',
    keys: ['8', 'minus', '5', 'equal', 'equal'],
    result: '-2'
  }
]
Tests which contain Equal keys will not work (because we haven’t handled the Equal key yet). But other tests should pass. Here’s a list of tests that’ll fail at this point.
   
Handle Equal Keys 
Again, we will begin by uncommenting the part we use to handle equal keys.
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'equal': handleEqualKey(calculator); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
Here’s what we wrote to handle Equal previously.
function handleEqualKey (calculator) {
  const displayValue = getDisplayValue()
  const { firstValue, operator, modifierValue } = calculator.dataset
  const secondValue = modifierValue || displayValue
  if (firstValue && operator) {
    const result = calculate(firstValue, operator, secondValue)
    display.textContent = result
    calculator.dataset.firstValue = result
    calculator.dataset.modifierValue = secondValue
  } else {
    display.textContent = parseFloat(displayValue) * 1
  }
}
We’ll copy this code into Calculator as a method.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleEqualKey (calculator) {
      const displayValue = getDisplayValue()
      const { firstValue, operator, modifierValue } = calculator.dataset
      const secondValue = modifierValue || displayValue
      if (firstValue && operator) {
        const result = calculate(firstValue, operator, secondValue)
        display.textContent = result
        calculator.dataset.firstValue = result
        calculator.dataset.modifierValue = secondValue
      } else {
        display.textContent = parseFloat(displayValue) * 1
      }
    },
    // Other methods
    // Listeners
  }
  // Add event listeners
  // Return calculator
}
And we’ll make the usual changes:
Change calculator to calculatorElement 
Omit calculatorElement from parameters 
Use calculator.displayValue getters and setters 
Use calculator.calculate 
 
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleEqualKey () {
      const displayValue = calculator.displayValue
      const { firstValue, operator, modifierValue } = calculatorElement.dataset
      const secondValue = modifierValue || displayValue
      if (firstValue && operator) {
        const result = calculator.calculate(firstValue, operator, secondValue)
        calculator.displayValue = result
        calculatorElement.dataset.firstValue = result
        calculatorElement.dataset.modifierValue = secondValue
      } else {
        calculator.displayValue = parseFloat(displayValue) * 1
      }
    },
    // Other methods
    // Listeners
  }
  // Add event listeners
  // Return calculator
}
We use handleEqualKey like this:
export default function Calculator () {
  // Variables
  const calculator = {
    // Other methods
    handleClick (event) {
      // ...
      switch (buttonType) {
        // ...
        case 'equal': calculator.handleEqualKey(); break
      }
      // ...
    }
  }
  // Add Event Listeners
  // Return the calculator
}
All tests should pass. There should be no error left.
   
One final thing to do.
Adding Keyboard Functionality 
Here’s the code we used to add keyboard functionality:
calculator.addEventListener('keydown', event => {
  let key = event.key
  // Operator keys
  if (key === '+') key = 'plus'
  if (key === '-') key = 'minus'
  if (key === '*') key = 'times'
  if (key === '/') key = 'divide'
  // Special keys
  if (key === '.') key = 'decimal'
  if (key === 'Backspace') key = 'clear'
  if (key === 'Escape') key = 'clear'
  if (key === 'Enter') key = 'equal'
  if (key === '=') key = 'equal'
  const button = calculator.querySelector(`[data-key="${key}"]`)
  if (!button) return
  event.preventDefault()
  button.click()
})
We’ll start by creating a event listener inside Calculator.
export default function Calculator () {
  // ...
  calculatorElement.addEventListener('keydown', event => {/* ... */})
  // Return calculator
}
We’ll name the callback handleKeydown
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleKeydown (event) {
      // ...
    }
  }
  calculatorElement.addEventListener('keydown', calculator.handleKeydown)
  // Return calculator
}
We’ll copy-paste the code we’ve written into handleKeydown.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleKeydown (event) {
      let key = event.key
      // Operator keys
      if (key === '+') key = 'plus'
      if (key === '-') key = 'minus'
      if (key === '*') key = 'times'
      if (key === '/') key = 'divide'
      // Special keys
      if (key === '.') key = 'decimal'
      if (key === 'Backspace') key = 'clear'
      if (key === 'Escape') key = 'clear'
      if (key === 'Enter') key = 'equal'
      if (key === '=') key = 'equal'
      const button = calculator.querySelector(`[data-key="${key}"]`)
      if (!button) return
      event.preventDefault()
      button.click()
    }
  // Add event listeners
  // Return calculator
}
And we’ll change calculator to calculatorElement.
export default function Calculator () {
  // Variables
  const calculator = {
    // ...
    handleKeydown (event) {
      // ...
      const button = calculatorElement.querySelector(`[data-key="${key}"]`)
      // ...
    }
  // Add event listeners
  // Return calculator
}
You should be able use the calculator with the keyboard now.
That’s it!