Browse Source

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

Bernadette Elena Hammerle 2 năm trước cách đây
mục cha
commit
3f7a980238
1 tập tin đã thay đổi với 175 bổ sung37 xóa
  1. 175 37
      src/Subtraction.js

+ 175 - 37
src/Subtraction.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 Subtraction() {
   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(false); // 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 Subtraction() {
     if(calculationInput.current && calculationInput.current.value === ""){
       calculationInput.current.focus();
     }
-  },[])
+  }, []);
+
+  useEffect(()=>{
+    if(!autoMoveComma){
+      addNumbersToTable([]);
+    }
+  }, [numbers]);
 
   const handleInput = (e) => {
     setInput(e.target.value);
@@ -56,15 +63,15 @@ function Subtraction() {
       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();
         }
@@ -90,11 +97,73 @@ function Subtraction() {
       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);
+      }
+    }
+  }
 
-      setNumbersGrid(addNumbersToGrid(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();
+    }
+  }
+
+  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;
     }
   }
 
@@ -107,12 +176,17 @@ function Subtraction() {
     let firstDigit = 0;
     let digit = 0;
 
-    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){
@@ -123,17 +197,13 @@ function Subtraction() {
         nosLeft = nosLeft - 1;
       }
 
-      if(numbers.length>2){
-        labelText = "("
-      }
-
       // iterate numbers for this digit index
-      for (let n in numbers){
+      for(let n in numbers){
         if(parseInt(n)===0){
           firstDigit = numbers[parseInt(n)][imdtResIdx];
         }else{
           // 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 <></>
@@ -149,9 +219,6 @@ function Subtraction() {
             if(carryArr[0] !== undefined && carryArr[0] > 0){
               labelText += " + " + carryArr[0].toString();
             }
-            if(numbers.length>2){
-              labelText += ")";
-            }
           }else{
             labelText += " + ";
           }
@@ -194,7 +261,7 @@ function Subtraction() {
     }
   }
 
-  const addButtonsToImdtSteps = () => {
+  const addButtonsToImdtSteps = (carryArrCopy) => {
     // workaround to access DOM td after grid values are set
     setTimeout(() => {
       let table = document.getElementById("idmtResultSteps").getElementsByTagName("table")[0]
@@ -207,7 +274,7 @@ function Subtraction() {
           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);
         }
       }
@@ -236,7 +303,7 @@ function Subtraction() {
 
       let realDigitRes = 0;
       let firstDigit = 0;
-      for (let j=0; j<numbers.length; j++) {
+      for(let j=0; j<numbers.length; j++) {
         if(parseInt(j)===0){
           firstDigit = numbers[parseInt(j)][idxNumbers];
           if(firstDigit==="" | firstDigit==="&nbsp;"){
@@ -324,11 +391,10 @@ function Subtraction() {
     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;
@@ -388,6 +454,76 @@ function Subtraction() {
     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>
 
@@ -408,17 +544,19 @@ function Subtraction() {
       </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>