├── LICENSE ├── README.md ├── index.html ├── main.js ├── screenshot.png └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ayo Isaiah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Calculator 2 | 3 | This is the 7th project for freeCodeCamp's Front-End Development certificate. 4 | 5 | Completed On: 28 January 2016 6 | Last Updated: 30 March 2017 7 | 8 | ## Objectives 9 | 10 | Build an app that is functionally similar to this: https://codepen.io/FreeCodeCamp/full/rLJZrA/. 11 | 12 | **Rule #1**: Don't look at the example project's code. Figure it out for yourself. 13 | 14 | **Rule #2**: Fulfill the below user stories. Use whichever libraries or APIs you need. Give it your own personal style. 15 | 16 | ## User Stories 17 | 18 | - I can add, subtract, multiply and divide two numbers. 19 | - I can clear the input field with a clear button. 20 | - I can keep chaining mathematical operations together until I hit the equal button, and the calculator will tell me the correct output. 21 | 22 | ## My Work 23 | 24 | ![JavaScript calculator](https://cdn.rawgit.com/ayoisaiah/javascript-calculator/012d4c5f/screenshot.png) 25 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | JavaScript Calculator 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 | deg 17 |
18 |
19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 |
27 | 28 |
29 | 7 30 | 4 31 | 1 32 | . 33 |
34 | 35 |
36 | 8 37 | 5 38 | 2 39 | 0 40 |
41 | 42 |
43 | 9 44 | 6 45 | 3 46 | = 47 |
48 |
49 | 50 |
51 | del 52 | ÷ 53 | x 54 | - 55 | + 56 |
57 | 58 |
59 | 60 |
61 | 62 | View on Github 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const input = document.querySelector(".input"); 4 | const result = document.querySelector(".result"); 5 | const deleteBtn = document.querySelector(".delete"); 6 | const keys = document.querySelectorAll(".bottom span"); 7 | 8 | let operation = ""; 9 | let answer; 10 | let decimalAdded = false; 11 | 12 | const operators = ["+", "-", "x", "÷"]; 13 | 14 | function handleKeyPress (e) { 15 | const key = e.target.dataset.key; 16 | const lastChar = operation[operation.length - 1]; 17 | 18 | if (key === "=") { 19 | return; 20 | } 21 | 22 | if (key === "." && decimalAdded) { 23 | return; 24 | } 25 | 26 | if (operators.indexOf(key) !== -1) { 27 | decimalAdded = false; 28 | } 29 | 30 | if (operation.length === 0 && key === "-") { 31 | operation += key; 32 | input.innerHTML = operation; 33 | return; 34 | } 35 | 36 | if (operation.length === 0 && operators.indexOf(key) !== -1) { 37 | input.innerHTML = operation; 38 | return; 39 | } 40 | 41 | if (operators.indexOf(lastChar) !== -1 && operators.indexOf(key) !== -1) { 42 | operation = operation.replace(/.$/, key); 43 | input.innerHTML = operation; 44 | return; 45 | } 46 | 47 | if (key) { 48 | if (key === ".") decimalAdded = true; 49 | operation += key; 50 | input.innerHTML = operation; 51 | return; 52 | } 53 | 54 | } 55 | 56 | function evaluate(e) { 57 | const key = e.target.dataset.key; 58 | const lastChar = operation[operation.length - 1]; 59 | 60 | if (key === "=" && operators.indexOf(lastChar) !== -1) { 61 | operation = operation.slice(0, -1); 62 | } 63 | 64 | if (operation.length === 0) { 65 | answer = ""; 66 | result.innerHTML = answer; 67 | return; 68 | } 69 | 70 | try { 71 | 72 | if (operation[0] === "0" && operation[1] !== "." && operation.length > 1) { 73 | operation = operation.slice(1); 74 | } 75 | 76 | const final = operation.replace(/x/g, "*").replace(/÷/g, "/"); 77 | answer = +(eval(final)).toFixed(5); 78 | 79 | if (key === "=") { 80 | decimalAdded = false; 81 | operation = `${answer}`; 82 | answer = ""; 83 | input.innerHTML = operation; 84 | result.innerHTML = answer; 85 | return; 86 | } 87 | 88 | result.innerHTML = answer; 89 | 90 | } catch (e) { 91 | if (key === "=") { 92 | decimalAdded = false; 93 | input.innerHTML = `${operation}`; 94 | result.innerHTML = `Bad Expression`; 95 | } 96 | console.log(e); 97 | } 98 | 99 | } 100 | 101 | function clearInput (e) { 102 | 103 | if (e.ctrlKey) { 104 | operation = ""; 105 | answer = ""; 106 | input.innerHTML = operation; 107 | result.innerHTML = answer; 108 | return; 109 | } 110 | 111 | operation = operation.slice(0, -1); 112 | input.innerHTML = operation; 113 | 114 | } 115 | 116 | deleteBtn.addEventListener("click", clearInput); 117 | keys.forEach(key => { 118 | key.addEventListener("click", handleKeyPress); 119 | key.addEventListener("click", evaluate); 120 | }); 121 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ayoisaiah/javascript-calculator/2c514df83d9990b7e576ec9b2c6be78bd0f73a53/screenshot.png -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-family: "Roboto", "Noto Sans", "Helvetica", sans-serif; 9 | font-size: 14px; 10 | background-color: #3498DB; 11 | height: 100%; 12 | } 13 | 14 | .calculator { 15 | width: 350px; 16 | height: auto; 17 | margin: 70px auto 0; 18 | overflow: hidden; 19 | box-shadow: 4px 4px rgba(0, 0, 0, 0.2); 20 | } 21 | 22 | .calculator span { 23 | -moz-user-select: none; 24 | user-select: none; 25 | } 26 | 27 | .top { 28 | position: relative; 29 | height: 150px; 30 | background-color: white; 31 | } 32 | 33 | .top .unit { 34 | text-transform: uppercase; 35 | position: absolute; 36 | top: 10px; 37 | left: 10px; 38 | font-weight: 700; 39 | color: #757575; 40 | } 41 | 42 | .top .screen { 43 | position: relative; 44 | width: 100%; 45 | top: 20%; 46 | height: 80%; 47 | } 48 | 49 | .screen > div { 50 | display: flex; 51 | align-items: center; 52 | justify-content: flex-end; 53 | width: 100%; 54 | padding: 5px; 55 | text-align: right; 56 | } 57 | 58 | .screen .input { 59 | color: #757575; 60 | height: 60%; 61 | font-size: 35px; 62 | } 63 | 64 | .screen .result { 65 | color: #9e9e9e; 66 | font-size: 20px; 67 | height: 40%; 68 | } 69 | 70 | .bottom { 71 | background-color: #2D2D2D; 72 | height: 300px; 73 | color: #fff; 74 | cursor: pointer; 75 | } 76 | 77 | .bottom section { 78 | position: relative; 79 | height: 100%; 80 | float: left; 81 | display: flex; 82 | } 83 | 84 | .keys { 85 | width: 80%; 86 | } 87 | 88 | 89 | .keys .column { 90 | display: flex; 91 | flex-grow: 1; 92 | } 93 | 94 | .keys .column, .operators { 95 | flex-direction: column; 96 | justify-content: center; 97 | align-items: center; 98 | } 99 | 100 | .keys .column span, .operators span { 101 | position: relative; 102 | overflow: hidden; 103 | flex-grow: 1; 104 | width: 100%; 105 | line-height: 1; 106 | padding: 10px; 107 | display: flex; 108 | justify-content: center; 109 | align-items: center; 110 | transition: background-color 0.5s; 111 | } 112 | 113 | .keys .column span { 114 | font-size: 25px; 115 | } 116 | 117 | .keys .column span:hover, .operators span:hover { 118 | background-color: rgba(0, 0, 0, 0.2); 119 | } 120 | 121 | .operators { 122 | width: 20%; 123 | font-size: 18px; 124 | background-color: #434343; 125 | } 126 | 127 | .delete { 128 | font-size: 16px; 129 | text-transform: uppercase; 130 | } 131 | 132 | .credit { 133 | display: block; 134 | text-align: center; 135 | width: 100%; 136 | position: absolute; 137 | bottom: 20px; 138 | margin: 0 auto; 139 | } 140 | 141 | .credit a, .error { 142 | color: #C2185B; 143 | } 144 | --------------------------------------------------------------------------------