A Pen by Jubin Ayoob N V on CodePen.
Created
April 1, 2018 07:51
-
-
Save Jubin369/36bfaea7ef9e450a7c21f135f1db77ca to your computer and use it in GitHub Desktop.
FCC: calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#app | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// PROJECTOR SELECTOR FOR EXTERNAL TEST SCRIPT: | |
const project_name = 'javascript-calculator'; | |
localStorage.setItem('example_project', 'Javascript Calculator'); | |
// VARS: | |
const isOperator = /[x/+‑]/, | |
endsWithOperator = /[x+‑/]$/, | |
clearStyle = {background: '#ac3939'}, | |
operatorStyle = {background: '#666666'}, | |
equalsStyle = { | |
background: '#004466', | |
position: 'absolute', | |
height: 130, | |
bottom: 5 | |
}; | |
// COMPONENTS: | |
class Calculator extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
currentVal: '0', | |
prevVal: '0', | |
formula: '', | |
currentSign: 'pos', | |
lastClicked: '' | |
} | |
this.maxDigitWarning = this.maxDigitWarning.bind(this); | |
this.handleOperators = this.handleOperators.bind(this); | |
this.handleEvaluate = this.handleEvaluate.bind(this); | |
this.initialize = this.initialize.bind(this); | |
this.handleDecimal = this.handleDecimal.bind(this); | |
this.handleNumbers = this.handleNumbers.bind(this); | |
} | |
maxDigitWarning() { | |
this.setState({ | |
currentVal: 'Digit Limit Met', | |
prevVal: this.state.currentVal | |
}); | |
setTimeout(() => this.setState({currentVal: this.state.prevVal}), 1000); | |
} | |
handleEvaluate() { | |
if (!this.state.currentVal.includes('Limit')) { | |
let expression = this.state.formula; | |
if (endsWithOperator.test(expression)) expression = expression.slice(0, -1); | |
expression = expression.replace(/x/g, "*").replace(/‑/g, "-"); | |
let answer = Math.round(1000000000000 * eval(expression)) / 1000000000000; | |
this.setState({ | |
currentVal: answer.toString(), | |
formula: expression.replace(/\*/g, '⋅').replace(/-/g, '‑') + '=' + answer, | |
prevVal: answer, | |
evaluated: true | |
}); | |
} | |
} | |
handleOperators(e) { | |
if (!this.state.currentVal.includes('Limit')) { | |
this.setState({currentVal: e.target.value,evaluated: false}); | |
if (this.state.formula.includes('=')) { | |
this.setState({formula: this.state.prevVal + e.target.value}); // comment 1 | |
} else { | |
this.setState({ // comment 2 | |
prevVal: !isOperator.test(this.state.currentVal) ? | |
this.state.formula : | |
this.state.prevVal, | |
formula: !isOperator.test(this.state.currentVal) ? | |
this.state.formula += e.target.value : | |
this.state.prevVal += e.target.value | |
}); | |
} | |
} | |
} | |
handleNumbers(e) { | |
if (!this.state.currentVal.includes('Limit')) { | |
this.setState({evaluated: false}) | |
if (this.state.currentVal.length > 21) { | |
this.maxDigitWarning(); | |
} else if (this.state.evaluated === true) { | |
this.setState({ | |
currentVal: e.target.value, | |
formula: e.target.value != '0' ? e.target.value : '', | |
}); | |
} else { | |
this.setState({ | |
currentVal: | |
this.state.currentVal == '0' || | |
isOperator.test(this.state.currentVal) ? | |
e.target.value : this.state.currentVal + e.target.value, | |
formula: | |
this.state.currentVal == '0' && e.target.value == '0' ? | |
this.state.formula : | |
/([^.0-9]0)$/.test(this.state.formula) ? | |
this.state.formula.slice(0, -1) + e.target.value : | |
this.state.formula + e.target.value, | |
}); | |
} | |
} | |
} | |
handleDecimal() { | |
if (this.state.evaluated === true) { | |
this.setState({ | |
currentVal: '0.', | |
formula: '0.', | |
evaluated: false}); | |
} else if (!this.state.currentVal.includes('.') && | |
!this.state.currentVal.includes('Limit')) { | |
this.setState({evaluated: false}) | |
if (this.state.currentVal.length > 21) { | |
this.maxDigitWarning(); | |
} else if (endsWithOperator.test(this.state.formula) || | |
this.state.currentVal == '0' && this.state.formula === '') { | |
this.setState({ | |
currentVal: '0.', | |
formula: this.state.formula + '0.' | |
}); | |
} else { | |
this.setState({ | |
currentVal: this.state.formula.match(/(-?\d+\.?\d*)$/)[0] + '.', | |
formula: this.state.formula + '.', | |
}); | |
} | |
} | |
} | |
initialize() { | |
this.setState({ | |
currentVal: '0', | |
prevVal: '0', | |
formula: '', | |
currentSign: 'pos', | |
lastClicked: '' | |
}); | |
} | |
render() { | |
return ( | |
<div> | |
<div className='calculator'> | |
<Formula formula={this.state.formula.replace(/x/g, '⋅')} /> | |
<Output currentValue={this.state.currentVal} /> | |
<Buttons evaluate={this.handleEvaluate} | |
operators={this.handleOperators} | |
initialize={this.initialize} | |
decimal={this.handleDecimal} | |
numbers={this.handleNumbers} /> | |
</div> | |
</div> | |
) | |
} | |
}; | |
class Buttons extends React.Component { | |
render() { | |
return ( | |
<div> | |
<button id="clear" value='AC' onClick={this.props.initialize} className='jumbo' style={clearStyle}>AC</button> | |
<button id="divide" value='/' onClick={this.props.operators} style={operatorStyle}>/</button> | |
<button id="multiply" value='x' onClick={this.props.operators} style={operatorStyle}>x</button> | |
<button id="seven" value='7' onClick={this.props.numbers} >7</button> | |
<button id="eight" value='8' onClick={this.props.numbers} >8</button> | |
<button id="nine" value='9' onClick={this.props.numbers} >9</button> | |
<button id="subtract" value='‑' onClick={this.props.operators} style={operatorStyle}>-</button> | |
<button id="four" value='4' onClick={this.props.numbers} >4</button> | |
<button id="five" value='5' onClick={this.props.numbers} >5</button> | |
<button id="six" value='6' onClick={this.props.numbers} >6</button> | |
<button id="add" value='+' onClick={this.props.operators} style={operatorStyle}>+</button> | |
<button id="one" value='1' onClick={this.props.numbers} >1</button> | |
<button id="two" value='2' onClick={this.props.numbers} >2</button> | |
<button id="three" value='3' onClick={this.props.numbers} >3</button> | |
<button id="zero" value='0' onClick={this.props.numbers} className='jumbo'>0</button> | |
<button id="decimal" value='.' onClick={this.props.decimal} >.</button> | |
<button id="equals" value='=' onClick={this.props.evaluate} style={equalsStyle}>=</button> | |
</div> | |
); | |
} | |
} | |
class Output extends React.Component { | |
render () { | |
return <div id="display" className="outputScreen">{this.props.currentValue}</div> | |
} | |
}; | |
class Formula extends React.Component { | |
render() { | |
return <div className="formulaScreen">{this.props.formula}</div> | |
} | |
}; | |
ReactDOM.render(<Calculator />, document.getElementById('app')); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://codepen.io/no_stack_dub_sack/pen/bwJxAw"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script> | |
<script src="https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$button: #4d4d4d; | |
@import 'https://fonts.googleapis.com/css?family=Share+Tech+Mono'; | |
@font-face { | |
font-family: "Digital"; | |
src: url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.eot"); | |
src: url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.eot?#iefix") format("embedded-opentype"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.woff2") format("woff2"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.woff") format("woff"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.ttf") format("truetype"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.svg#Digital-7") format("svg"); | |
} | |
#app { | |
height: 100vh; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
body { | |
background: #c2c2d6; | |
-webkit-touch-callout: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
-webkit-user-select: none; | |
user-select: none; | |
cursor: default; | |
} | |
.calculator { | |
border: 2px solid #47476b; | |
padding: 5px; | |
background: black; | |
width: 320px; | |
position: relative; | |
} | |
.formulaScreen { | |
min-height: 20px; | |
font-family: digital; | |
font-size: 20px; | |
color: orange; | |
text-align: right; | |
vertical-align: text-top; | |
line-height: 20px; | |
overflow-wrap: break-word; | |
word-wrap: break-word; | |
} | |
.outputScreen { | |
font-size: 29px; | |
font-family: digital; | |
color: white; | |
text-align: right; | |
line-height: 35px; | |
} | |
button { | |
position: relative; | |
height: 65px; | |
width: 80px; | |
color: white; | |
outline: 1px solid black; | |
border: none; | |
background: $button; | |
font-family: Share Tech Mono, monospace; | |
font-size: 20px; | |
cursor: default; | |
&:hover { | |
color: black; | |
outline: .05em solid grey; | |
z-index: 3; | |
} | |
} | |
.jumbo { | |
width: 160px; | |
} | |
.author { | |
text-align: center; | |
font-family: Share Tech Mono, sans; | |
margin-top: 15px; | |
a { | |
text-decoration: none; | |
color: #00264d; | |
line-height: 26px; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment