Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    
    <!--jQuery-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

    <!--Bootstrap-->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

    <title>FCC: Calculator</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

<script src="https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js" type="text/javascript"></script>

              
            
!

CSS

              
                body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  
}

#page-wrap{
  background: rgb(50, 60, 105);
  height: 100vh;
}

#main-content{
  font-family: 'Courier New', Courier, monospace;
  font-weight: bolder;
  min-height: 360px;
}

#calc-wrap{
  box-shadow: 0.1em 0.1em rgb(180, 177, 177);
  border-radius: 20px;
  height: 100%;
  border-style: inset;
  background: rgb(107, 87, 71);


  display: grid;
  grid-template-columns: 25% 25% 25% 25%;
  grid-template-rows: 5vh 15vh 12vh 2vh 7vh 7vh 7vh 7vh 7vh 2vh;
  grid-template-areas: 
    "title title title title"
    "display display display display"
    "tempDisplay tempDisplay tempDisplay tempDisplay"
    "line line line line"
    "clear clear divide multiply"
    "seven eight nine subtract"
    "four five six add"
    "one two three equals"
    "zero zero decimal equals"
    "bottom bottom bottom bottom";
}

#title {
  text-align: right;
  line-height: 5vh;
  font-size: 0.7em;
  color: silver;
  text-shadow: 0.3vh 0.3vh black;
}

.display {
  user-select: none;
  height: auto;
  background: black;
  color: white;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  text-align: right;
  word-wrap: break-word;
  padding: 5% 5% 10% 5%;
  border-radius: 10px;

  box-shadow: 0 0 0.5em rgb(196, 195, 224);
}

.buttons{
  user-select: none;
  outline: none;
  font-weight: bold;
  font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
  border-radius: 10px;
  margin: .1em;

  box-shadow: 0.1em 0.1em black;
  background: seashell;
}

.buttons:focus {
  outline: none;
}

.buttons:hover{
  background: rgb(153, 181, 184);
}

#clear {
  color: red;
  text-shadow: 0px 1px 0px rgba(255,255,255,.5);
}

#add, #divide, #subtract, #multiply {
  color: rgb(151, 138, 18);
  text-shadow: 0 0 2em 2em rgb(19, 29, 31);
}

#equals{
  font-size: 1.7em;
  color: rgb(166, 216, 48);
  text-shadow: 1em 1em 2em 2em rgb(19, 29, 31);
}

#decimal {
  font-size: 1.5em;
  line-height: 0.01em;
}
              
            
!

JS

              
                const DEFAULT_STATE = ""
const DEFAULT_STATE_ARR = ["0"]

const CALC_BTNS = [
    {value: "0", id: "zero"},
    {value: "1", id: "one"},
    {value: "2", id: "two"},
    {value: "3", id: "three"},
    {value: "4", id: "four"},
    {value: "5", id: "five"},
    {value: "6", id: "six"},
    {value: "7", id: "seven"},
    {value: "8", id: "eight"},
    {value: "9", id: "nine"},
    {value: "AC", id: "clear"},
    {value: ".", id: "decimal"},
    {value: "+", id: "add"},
    {value: "-", id: "subtract"},
    {value: "x", id: "multiply"},
    {value: "/", id: "divide"},
    {value: "=", id: "equals"}
]

//TODO: Calculation function
// console.log(parseFloat("+"))
// console.log(parseFloat("12.129230000021323"))

const calculate = (inputArr) => {
    let arr = [...inputArr]
    console.log(arr.length)
    if(arr.length <= 2){
        return arr[0]
    }
    //Loop control variables
    var timeOut = 500
    var iter = 0;
    var d = new Date()
    console.log(`Start Time: ${d.toTimeString()}`)

    while(arr.length > 1 && iter <= 50000000000){
        iter++
        //Break loop after 500ms
        var currentTime = new Date()
        if(currentTime.getTime() >= d.getTime() + timeOut){
            console.log(`Loop broken out \nExit time: ${currentTime.toTimeString()}`)
            break;
        }

        //Operation here
        //Check to see if array has * or /
        //If encounter * and /. Perform on i+1 and i-1
            //take out these 3, insert new value in position i-1
        let hasMultiplyOrDivide = false
        let hasMultiplyOrDivide_index = null
        for(let i = 0; i < arr.length; i++){
            if(arr[i] === "x" || arr[i] === "/"){
                hasMultiplyOrDivide = true;
                hasMultiplyOrDivide_index = i;
                break;
            }
        }

        if(hasMultiplyOrDivide){
            let j = hasMultiplyOrDivide_index
            switch(arr[hasMultiplyOrDivide_index]){
                case "x": 
                    arr.splice(j-1, 3, parseFloat(arr[j-1]) * parseFloat(arr[j+1]))
                    console.log(arr)
                    break
                case "/":
                    arr.splice(j-1, 3, parseFloat(arr[j-1]) / parseFloat(arr[j+1]))
                    console.log(arr)
                    break
                default: break;
            }
        }

        //Perform the + and - on the rest
        for(let i = 0; i < arr.length; i++){
            switch(arr[i]){
                case "+":
                    arr.splice(i-1,3,parseFloat(arr[i-1]) + parseFloat(arr[i+1]))
                    console.log(arr)
                break;
                case "-":
                    arr.splice(i-1,3,parseFloat(arr[i-1]) - parseFloat(arr[i+1]))
                    console.log(arr)
                break;
                default: break;
            }
            continue;
        }

        
    }

    console.log(`Current Iteration: ${iter}`)
    console.log(`Loop completed \nExit time: ${new Date().toTimeString()}`)
    console.log(`Time took: ${new Date() - d}ms`)

    return arr[0]
}

class App extends React.Component{
    constructor(props){
        super(props)
        this.state ={
            input: DEFAULT_STATE,
            inputArr: DEFAULT_STATE_ARR,
            currentArrPos: 0,
            hasDecimal: false,
            onOperation: false,
            currentResult: null
        }
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick(e){
        console.log(`Current Arr Pos: ${this.state.currentArrPos}`)
        switch (e.target.value){
            //Input
            case "0": case "1": case "2": case "3": case "4":
            case "5": case "6": case "7": case "8": case "9":

                if(this.state.currentResult !== null && !this.state.onOperation){
                    this.setState({
                        currentResult: null,
                    })
                }

                let newInput = this.state.input.concat(e.target.value)
                //Eliminate leading zeros
                while(newInput.startsWith(0) && newInput.length > 1){newInput = newInput.substr(1)}

                let newArr = [...this.state.inputArr]
                newArr[this.state.currentArrPos] = newInput

                this.setState({
                    input: newInput,
                    inputArr: newArr,
                    onOperation: false,
                })
            
            break;

            //Allow only one decimal dot
            case ".": 
                if(!this.state.hasDecimal){
                    this.setState({
                        input: this.state.input.concat(e.target.value),
                        hasDecimal: true,
                        onOperation: false
                    })
                }
                break;
                
            //Clear
            case "AC": this.setState({
                input: DEFAULT_STATE, 
                inputArr: DEFAULT_STATE_ARR,
                hasDecimal: false,
                onOperation: false,
                currentArrPos: 0,
                currentResult: null
            });
            console.log(`Cleared`)
            // TODO clear output value
            break;

            //Separate case -. if onOperation is true. concat - to current pos. if not, perform normally
            // case "-":
            //     if(this.state.onOperation){
                    
            //     }
            //     else{

            //     }
            // break;

            //Add all input into an array. the equals case will process the array
            case "+": case "x": case "/": case"-":
                //Handle case operation after equals
                //Use last result, clear inputArr
                if(this.state.currentResult !== null){
                    this.setState({
                        input: '',
                        inputArr: [this.state.currentResult, e.target.value],
                        currentResult: null,
                        currentArrPos: 2
                    })
                    break;
                }

                //Don't accept input if arrpos === 0 and no number has been entered
                if(this.state.currentArrPos === 0 && this.state.inputArr.length === 0){break;}

                 //Handle 3 or more operators
                 if(this.state.onOperation
                    && this.state.currentArrPos > 0 
                    && ["+","-","x","/"].includes(this.state.inputArr[this.state.currentArrPos])
                    && ["+","-","x","/"].includes(this.state.inputArr[this.state.currentArrPos-1])
                    ){
                        console.log("etst test")
                        let thisCase = [...this.state.inputArr]
                        thisCase[this.state.currentArrPos-1] = e.target.value
                        thisCase[this.state.currentArrPos] = ""
                        thisCase.pop()
                        console.log(thisCase)
                        this.setState({
                            inputArr: thisCase,
                            input:""
                        })
                        break;
                    }

                //Handle case *- or */
                if(this.state.onOperation && this.state.currentArrPos > 0
                    && 
                    (this.state.inputArr[this.state.currentArrPos-1] === "x" 
                    || this.state.inputArr[this.state.currentArrPos-1] === "/" || this.state.inputArr[this.state.currentArrPos-1] === "+") 
                    && (e.target.value === "-" || e.target.value === "+")
                    ){
                        let thisCase = [...this.state.inputArr]
                        thisCase[this.state.currentArrPos] = e.target.value
                        this.setState({
                            input: e.target.value,
                            inputArr: thisCase
                        })
                    break;
                }

                //Don't accept multile operations
                if(this.state.onOperation && this.state.currentArrPos > 0){
                    //Change operation if button clicked is different
                    if(e.target.value !== this.state.inputArr[this.state.currentArrPos-1]){
                        let changeOpArr = [...this.state.inputArr]
                        changeOpArr[this.state.currentArrPos -1] = e.target.value
                        this.setState({
                            inputArr: changeOpArr,
                            onOperation: true
                        })
                    }
                    break;
                }
                let newInputArrOp = [...this.state.inputArr]
                newInputArrOp.push(e.target.value)
                newInputArrOp.push("")

                this.setState({
                    input: DEFAULT_STATE,
                    inputArr: newInputArrOp,
                    onOperation: true,
                    currentArrPos: this.state.currentArrPos + 2,
                    hasDecimal: false
                })

            break;


            case "=":
            //TODO: Function to handle inputArr into result
                //TODO: After returning result. Empty input Array and add current result into position 0
                console.log(calculate(this.state.inputArr))

                let result = calculate(this.state.inputArr)

                console.log(typeof result)
                this.setState({
                    currentResult: result
                }, function(){
                    // let resultArr = [...this.state.inputArr]
                    // resultArr.push(`=${this.state.currentResult}`)
                    this.setState({
                        inputArr: [this.state.currentResult],
                        input: "",
                        currentArrPos: 0
                    })
                })
            
            break;
            default: break;
        }
    }

    render(){
        return(
            <div id="page-wrap" className="container-fluid align-content-center">
                {/* Top Padding */}
                <div className="row" style={{"height":"10%"}}></div>
                <div id="main-content" className="row" style={{"height":"auto"}}>
                    {/* Left Padding */}
                    <div className="col-sm-4"></div>

                    {/* Calculator Wrap */}
                    <div id="calc-wrap" className="col-sm-4">
                        {/* Use display grid for calculator */}
                        {/* Title */}
                        <div id="title" style={{"gridArea":"title"}}>FreeCodeCamp: Calculator <i class="fab fa-free-code-camp"></i></div>
                        {/* Display */}
                        <div className="display" style={{"gridArea":"display"}} id="display">
                            <p><span>{this.state.inputArr}</span></p>
                        </div>
                        <div className="display" style={{"gridArea":"tempDisplay"}}>{this.state.input}</div>
                        {CALC_BTNS.map((elem) => 
                            <button className="buttons" key={elem.value} id={elem.id} value={elem.value} onClick={this.handleClick} style={{"gridArea": elem.id}}>{elem.value}</button>
                        )}
                    </div>
                </div>
                {/* Bottom Padding */}
                <div className="row" style={{"height":"10%"}}></div>
            </div>
        )
    }
}
ReactDOM.render(<App />, document.getElementById('root'));
              
            
!
999px

Console