Ver Fonte

addition: let user move comma, check comma input, replaced numbers grid with table; clean up; fix small bugs

Bernadette Elena Hammerle há 2 anos atrás
pai
commit
7cb1827c98
2 ficheiros alterados com 185 adições e 32 exclusões
  1. 176 31
      src/Addition.js
  2. 9 1
      src/App.css

+ 176 - 31
src/Addition.js

@@ -1,24 +1,25 @@
 import React, { useState, useEffect, useRef } from "react";
 import DataGrid, {Column} from "devextreme-react/data-grid";
-import {addNumbersToGrid, numbersToArrOfArr, afterCommaLen, handleKeyDown} from "./helpers.js";
+import {numbersToArrOfArr, afterCommaLen, handleKeyDown} from "./helpers.js";
 import "./App.css";
 
 let imdtRes;
 let imdtResIdx;
 let resArr = [];
 let noOfDigits = 0;
+let commaIsSet = false;
 
 function Addition() {
   const [input, setInput] = useState(""); // initial user input like 34+56.7
   const [realResult, setRealResult] = useState(0); // real result of calculation
   const [carryArr, setCarryArr] = useState([]); // array of carries ["1","0"]
-  const [commaIdx, setCommaIdx] = useState(0); // int: comma position
+  const [commaIdx, setCommaIdx] = useState(-1); // int: comma position
   const [numbers, setNumbers] = useState(0); // array of arrays with input numbers
-  const [numbersGrid, setNumbersGrid] = useState([{id: 1, number: ""}]);
-  const [resultsGrid, setResultsGrid] = useState([{id: 1, number: ""}]);
-  const [stepsGrid, setStepsGrid] = useState([{id: 1, step: ""}]);
+  const [resultsGrid, setResultsGrid] = useState([{id: 1, number: ""}]); // calculated result
+  const [stepsGrid, setStepsGrid] = useState([{id: 1, step: ""}]); // one step for every digit
 
-  const [showSteps, setShowSteps] = useState(true);
+  const [autoMoveComma, setAutoMoveComma] = useState(true); // move the comma automatically
+  const [allowStartOver, setAllowStartOver] = useState(true); // show steps and allow restart
 
   // focus the input field
   let calculationInput = useRef(null);
@@ -26,7 +27,13 @@ function Addition() {
     if(calculationInput.current && calculationInput.current.value === ""){
       calculationInput.current.focus();
     }
-  },[])
+  }, []);
+
+  useEffect(()=>{
+    if(!autoMoveComma){
+      addNumbersToTable([]);
+    }
+  }, [numbers]);
 
   const handleInput = (e) => {
     setInput(e.target.value);
@@ -57,15 +64,15 @@ function Addition() {
       let noCarry = carryArrCopy[0] === "" || carryArrCopy[0] === "0" || carryArrCopy[0] === undefined
       if((nosLeft === 1 && noCarry) ||
          // if stop after first iteration, numbers left is undefined at first
-         (nosLeft !== nosLeft && realResult.toString().length === 1 && noCarry)){
+         (isNaN(nosLeft) && realResult.toString().length === 1 && noCarry)){
         nosLeft = 0;
         handleResChange(" ")
       }
 
       if(nosLeft === 0){
-        if(showSteps){
+        if(allowStartOver){
           showIdmtResults(carryArrCopy);
-          addButtonsToImdtSteps();
+          addButtonsToImdtSteps(carryArrCopy);
         }else{
           finishCalculation();
         }
@@ -87,11 +94,73 @@ function Addition() {
       setRealResult(realRes);
       console.log("real result:", realRes);
 
-      let [numbersArr, commaIdx] = numbersToArrOfArr(numbers);
-      setNumbers(numbersArr);
-      setCommaIdx(commaIdx);
+      let numbersArr, commaIdx;
+      if(!autoMoveComma){
+        numbersArr = numbers.map(x => x.toString().split(""));
+        setNumbers(numbersArr);
+        addNumbersToTable([]);
+        startCommaMove();
+
+      }else{
+        commaIsSet = true;
+        [numbersArr, commaIdx] = numbersToArrOfArr(numbers);
+        setNumbers(numbersArr);
+        setCommaIdx(commaIdx);
+        addNumbersToTable(numbersArr);
+      }
+    }
+  }
+
+  const handleKeyMoveComma = (e) => {
+    let pressedKey = e.keyCode;
+    let tdId = e.target.id;
+    let noId = tdId.split("numbersTd")[1];
+    let numbersCopy = [...numbers];
+
+    if(pressedKey === 37){ // left arrow
+      numbersCopy[noId].push(" ");
+      setNumbers(numbersCopy);
+      setTimeout(() => {
+        document.getElementById(tdId).focus();
+      }, 100);
+
+    }else if(pressedKey === 39 && // right arrow
+             numbersCopy[noId][numbersCopy[noId].length-1] === " "){
+      numbersCopy[noId].pop();
+      setNumbers(numbersCopy);
+      setTimeout(() => {
+        document.getElementById(tdId).focus();
+      }, 100);
+
+    }else if(pressedKey === 38){ // up
+      let nextFocusId = Math.max(noId-1, 0);
+      document.getElementById("numbersTd" + nextFocusId).focus();
+
+    }else if(pressedKey === 40){ // down
+      let nextFocusId = Math.min(noId+1, numbers.length-1);
+      document.getElementById("numbersTd" + nextFocusId).focus();
+    }
+  }
 
-      setNumbersGrid(addNumbersToGrid(numbersArr, "+"));
+  const addNumbersToTable = (numbersArr) => {
+    let nos;
+    if(numbersArr.length > 0){
+      nos = numbersArr;
+    }else{
+      nos = numbers;
+    }
+    let table = document.getElementById("numbersGrid");
+    table.innerHTML = "";
+    for(let noIdx in nos){
+      let row = table.insertRow();
+      let cell = row.insertCell();
+      let cellText = nos[noIdx].join("");
+      if(noIdx == nos.length-1){
+        cellText = "+ " + cellText;
+      }
+      cell.innerHTML = cellText;
+      cell.tabIndex = "0";
+      cell.id = "numbersTd" + noIdx;
     }
   }
 
@@ -102,12 +171,17 @@ function Addition() {
     let nosLeft = imdtResIdx + 1;
     let carryText = "Übertrag = ";
 
-    if(typeof numbers === "object" && imdtResIdx !== -1){
+    if(commaIsSet && typeof numbers === "object" && imdtResIdx !== -1){
+      document.getElementById("commaWarning").innerHTML = "";
+
       // set the digit index, start with the last digit
       if(typeof imdtResIdx === "undefined" || imdtResIdx === null){
         noOfDigits = Math.min(...numbers.map(n => n.length));
         imdtResIdx = noOfDigits - 1;
       }
+      if(typeof nosLeft === "undefined" ){
+        nosLeft = imdtResIdx + 1;
+      }
 
       // skip over comma
       if(imdtResIdx === commaIdx){
@@ -119,9 +193,9 @@ function Addition() {
       }
 
       // iterate numbers for this digit index
-      for (let n in numbers){
+      for(let n in numbers){
         // skip last empty number if no carry
-        if(nosLeft === 1 && carryArr[0] === "0"){
+        if(nosLeft === 1 && (carryArr[0] === "0" || carryArr[0] === "")){
           nosLeft = 0;
           imdtResIdx = -1;
           return <></>
@@ -176,7 +250,7 @@ function Addition() {
     }
   }
 
-  const addButtonsToImdtSteps = () => {
+  const addButtonsToImdtSteps = (carryArrCopy) => {
     // workaround to access DOM td after grid values are set
     setTimeout(() => {
       let table = document.getElementById("idmtResultSteps").getElementsByTagName("table")[0]
@@ -189,7 +263,7 @@ function Addition() {
           btn.innerHTML = "hier starten";
           btn.classList = "btn btn-secondary btn-sm";
           btn.id = "btn-" + trIdx;
-          btn.addEventListener("click", () => startOver(trIdx));
+          btn.addEventListener("click", () => startOver(trIdx, carryArrCopy));
           td.appendChild(btn);
         }
       }
@@ -210,13 +284,13 @@ function Addition() {
 
     let foundComma = false;
     let stepsGridCopy = [];
-    for (let i=0; i<resArr.length; i++) {
+    for(let i=0; i<resArr.length; i++) {
       let text = "";
       let trueNumbers = false;
       let idxNumbers = resArr.length - i - 1;
       let idxCarry = carries.length - i - 1;
       let realSum = 0;
-      for (let j=0; j<numbers.length; j++) {
+      for(let j=0; j<numbers.length; j++) {
         let no = numbers[j][idxNumbers];
         if (no!=="." && no!=="&nbsp;"){
           trueNumbers = true;
@@ -284,11 +358,10 @@ function Addition() {
     document.getElementById("idmtResultSteps").focus();
   }
 
-  const startOver = (idx) => {
+  const startOver = (idx, carryArrCopy) => {
     let invertedIdx = numbers[0].length - idx - 1;
     imdtResIdx = invertedIdx;
 
-    let carryArrCopy = [...carryArr];
     let slicer = invertedIdx;
     if(resArr[0] !== "&nbsp;" && !resArr.includes(".")){
       slicer += 1;
@@ -331,6 +404,76 @@ function Addition() {
     document.getElementById("finishCalculation").focus();
   }
 
+  const startCommaMove = () => {
+    document.getElementById("commaSubmit").style.display = "inline-block";
+    setTimeout(() => {
+      document.getElementById("numbersTd0").focus();
+    }, 300)
+  }
+
+  const submitCommaMove = () => {
+    let numbersCopy = [...numbers];
+    let commaPositions = [];
+
+    // reset numbers to calculate new length after error
+    for(let noIdx in numbersCopy){
+      while(numbersCopy[noIdx][0] === "&nbsp;"){
+        numbersCopy[noIdx].shift();
+      }
+    }
+
+    // get all numbers up to the same length
+    let numbersLen = Math.max(...numbers.map(n => n.length));
+    for(let noIdx in numbersCopy){
+      while(numbersCopy[noIdx].length <= numbersLen){
+        numbersCopy[noIdx].unshift("&nbsp;");
+      }
+      commaPositions.push(numbersCopy[noIdx].indexOf("."));
+    }
+    setNumbers(numbersCopy);
+
+    let commaCorrect = false;
+    commaPositions = [...new Set(commaPositions.filter(c => c >= 0))];
+
+    // if no commas in numbers
+    if(commaPositions.length === 0){
+      setCommaIdx(-1);
+      // check if no number was moved
+      commaCorrect = !numbersCopy.map(n => n[numbersLen] !== "&nbsp;").includes(false)
+
+    // correct comma positions
+    }else if(commaPositions.length === 1){
+      setCommaIdx(commaPositions[0]);
+      commaCorrect = true;
+
+      // check if numbers without comma are correct too
+      for(let no of numbersCopy){
+        if(!no.includes(".")){
+          // digit before comma is a number, no space
+          if(no[commaPositions[0]-1] === "&nbsp;"){
+            commaCorrect = false;
+          }
+          // only spaces from comma to end
+          for(let digit=commaPositions[0]; digit<=numbersLen; digit++){
+            if(no[digit] !== "&nbsp;"){
+              commaCorrect = false;
+            }
+          }
+        }
+      }
+    }
+
+    if(commaCorrect){
+      document.getElementById("commaSubmit").style.display = "none";
+      commaIsSet = true;
+    }else{
+      let paragraph = document.getElementById("commaWarning");
+      paragraph.innerHTML = "das ist leider falsch, versuche es noch einmal:";
+      paragraph.tabIndex = "0";
+      paragraph.focus();
+    }
+  }
+
   return (
     <main>
 
@@ -351,17 +494,19 @@ function Addition() {
       </form>
 
       <div id="finishCalculation"></div>
+      <div id="commaWarning"></div>
 
       <div id="overview">
-        <DataGrid
-          dataSource={numbersGrid}
-          keyExpr="id"
-          focusedRowEnabled={true}
-          showBorders={true}
-          showColumnHeaders={false}
+        <table
+          id="numbersGrid"
+          onKeyDown={handleKeyMoveComma}
         >
-          <Column dataField="number" />
-        </DataGrid>
+        </table>
+
+        <input type="submit"
+          value="Komma best&auml;tigen"
+          id="commaSubmit"
+          onClick={() => submitCommaMove()}/>
 
         <hr></hr>
 

+ 9 - 1
src/App.css

@@ -51,8 +51,16 @@ hr{
   margin: 0.2em 1em;
 }
 
+#commaSubmit{
+  display: none;
+}
+
 #idmtResultSteps{
-  display: inline-block;
+  display: none;
+}
+
+#stepsParagraph{
+  margin-top: 10px;
 }
 
 footer{