Skip to content

Instantly share code, notes, and snippets.

@seanr707
Last active August 26, 2015 16:16
Show Gist options
  • Save seanr707/e2421b04b654d9726688 to your computer and use it in GitHub Desktop.
Save seanr707/e2421b04b654d9726688 to your computer and use it in GitHub Desktop.
Calculator
<nav class="navbar navbar-default navbar-fixed-top header">
<div class="container text-center">
<h2>FreeCodeCamp Calculator</h2>
</div>
</nav>
<div class="space"></div>
<!-- Main section for setting up Angular -->
<div class="text-center" ng-app="calcApp" ng-controller="calcCtrl">
<div class="calc container">
<div class="display container text-center input-group">
<input class="form-control" value="{{ display }}" disabled>
<span class="input-group-addon" ng-show="mem[1]">{{ mem[1] }}</span>
</div>
<!-- Angular generates buttons in 3 sections -->
<div class="buttons">
<div class="row top">
<button class="norm btn btn-danger" ng-repeat="item in top" ng-click="item.func(item.val)">{{ item.disp }}</button>
</div>
<div class="row main">
<button class="norm col-md-1 btn btn-default text-right" ng-repeat="num in nums" ng-click="pressNum(num)" id="{{ num }}">{{ num }}</button>
<button class="bottom btn btn-default" ng-repeat="num in bottom" ng-click="pressNum(num)">{{ num }}</button>
</div>
<div class="side row">
<button class="norm btn btn-primary" ng-repeat="item in side" ng-click="item.func(item.val)" id="{{ item.id }}">{{ item.disp }}</button>
</div>
</div>
</div>
</div>
// Calculator Solution by Seanr707 for FreeCodeCamp
// Copying of this solution without credit and permission of author is not allowed
var calcApp = angular.module('calcApp', []);
calcApp.controller('calcCtrl', function($scope){
$scope.nums = [
7, 8, 9,
4, 5, 6,
1, 2, 3,
];
// Seperate these for CSS sizing purposes
$scope.bottom = [0, '.',];
// Where sum is stored
$scope.store = 0;
// Where ints turned to strings, conectated, eval()
// Always maxes at 3 items: [store, operand, current] -> [store, waitForOperand]
$scope.mem = [];
// Current entry we are entering
$scope.curr = 0;
// What displays in the view
$scope.display = 0;
var maxChar = 12;
// Changes what is displayed to users; rounds so it fits in textarea
$scope.update = function(type) {
// 'c' for current OR 's' for stored
if (type === 'c') {
$scope.display = $scope.curr;
} else {
$scope.display = $scope.store;
}
// Rounds if the number is too large
if ($scope.display.toString().length > maxChar) {
$scope.display = Math
.round($scope.display * Math.pow(10, maxChar)) / Math.pow(10, maxChar);
}
}
function opExec(mem, op) {
// If len < 3 then it is waiting to receive input
// Return first number to wait
if (mem.length < 3) {
return mem[0];
}
// Parse var's just in case
mem[0] = parseFloat(mem[0]);
mem[2] = parseFloat(mem[2]);
// Perform operation
switch(op) {
case '+':
return mem[0] + mem[2];
case '-':
return mem[0] - mem[2];
case '*':
return mem[0] * mem[2];
case '/':
return mem[0] / mem[2];
}
}
// Runs when any number or decimal is pressed
$scope.pressNum = function(num) {
// Prevents overflowing textarea
if ($scope.curr.length >= maxChar) {
return;
}
// Prevents multiple decimals
if (num === '.' && $scope.curr.toString().match(/[^0-9|-]/g)) {
return;
}
// Prevents displaying as '0892'
if ($scope.curr === 0) {
$scope.curr = '';
}
// Converts to string for easy number conectation (especially with decimal button)
$scope.curr = $scope.curr.toString() + num.toString();
$scope.update('c');
}
// Operand function
$scope.pressOp = function(op) {
// For changing operand in use instead of stacking them in mem
if ($scope.mem[1] && $scope.curr === 0) {
$scope.mem[1] = op;
return;
}
// NOTE: Used strings instead of numbers so eval can be used to
// parse operands unconditionally
// Push current entry in the memory
$scope.mem.push($scope.curr);
console.log($scope.mem);
// Empty the current entry
$scope.curr = 0;
// Evaluate our 3 (or 2 if first press) items in memory and move them
// to storage
$scope.store = opExec($scope.mem, $scope.mem[1]);
// Add stored sum and the operand to memory
$scope.mem = [$scope.store, op];
// Updates display to stored number, so '2+3+4' would display '5' when
// I press '+' the second time, until '4' is pressed
$scope.update('s');
console.log($scope.mem);
}
$scope.clear = function(type) {
if (type === 'ac') {
// Clears all memory
$scope.curr = 0;
$scope.store = 0;
$scope.update('c');
$scope.mem = [];
} else {
// Clears current entry
$scope.curr = 0;
$scope.update('c');
}
}
// NA is a null variable used to make ngRepeat usable on all entries in HTML
// Most functions pass a variable through, so some functions need null values
// So that the ngRepeat loop can be used unconditionally
$scope.equal = function(NA) {
// Pushes current to memory
$scope.mem.push($scope.curr);
// Eval's memory and moves to current, so it can be operated on
$scope.curr = opExec($scope.mem, $scope.mem[1]);
// Clears everything out
$scope.store = 0;
$scope.mem = [];
$scope.update('c');
}
// Changes pos/neg value of number in current
$scope.chgSign = function(NA) {
if ($scope.curr === 0) {
return;
}
$scope.curr *= -1;
$scope.update('c');
}
// NOTE: These objects were added last because they call on functions from above
// Operands on side in order
// IDs added so size could be changed on plus sign in CSS
$scope.side = {
multiply: {
id: 'mult',
disp: 'x',
val: '*',
func: $scope.pressOp,
},
divide: {
id: 'div',
disp: '÷',
val: '/',
func: $scope.pressOp,
},
minus: {
id: 'minus',
disp: '-',
val: '-',
func: $scope.pressOp,
},
plus: {
id: 'plus',
disp: '+',
val: '+',
func: $scope.pressOp,
},
};
// Operands on top in order
$scope.top = {
ac: {
disp: 'AC',
val: 'ac',
func: $scope.clear,
},
ce: {
disp: 'CE',
val: 'ce',
func: $scope.clear,
},
changeSign: {
disp: '±',
val: null,
func: $scope.chgSign,
},
/* Not enough room for this operand (least needed) yet
percent: {
disp: '%',
val: '%',
func: $scope.pressOp,
},
*/
equal: {
disp: '=',
val: null,
func: $scope.equal,
},
};
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.5.1/less.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
body {
background-image: url("http://www.publicdomainpictures.net/pictures/60000/velka/stripes-background-colorful-1376773871uk4.jpg");
background-size: cover;
width: 100%;
height: 100%;
color: black;
}
.space {
height: 100px;
}
.header {
padding-bottom: 1%;
border: solid 1px grey;
opacity: .99;
}
.calc {
width: 180px;
height: 250px;
padding: 5px;
padding-top: 10px;
margin: 1% auto 0 auto;
background: lightgrey;
color: black;
border: solid 1px grey;
border-radius: 5px;
box-shadow: 0 2px 4px grey;
}
.display {
width: 150px;
margin 1% auto 1% auto;
padding: 4px;
}
.buttons {
width: 170px;
margin: 0 auto 0 auto;
padding: 18px;
text-align: center
}
.btn {
border-radius: 0;
box-shadow: 0 1px 1px grey;
}
.top {
width: 133px;
margin: 0 auto 0 auto;
}
.norm {
margin: 1px;
width: 30px;
padding: 3px;
}
.main {
width: 96px;
margin: 0 0 0 auto;
display: inline-block;
}
.row {
margin: 0;
padding: 0;
}
.bottom {
width: 46px;
margin: 1px;
}
.side {
width: 34px;
margin: 0 auto 0 -4px;
display: inline-block;
}
.side-btn {
width: 30px;
}
#plus {
height: 34px;
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment