diff --git a/.gitignore b/.gitignore
index a1066ba..19b4ef7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -249,7 +249,6 @@ typings/
# Nuxt.js build / generate output
.nuxt
-dist
# Gatsby files
.cache/
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..b58b603
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..03d9549
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/javascript-calculator.iml b/.idea/javascript-calculator.iml
new file mode 100644
index 0000000..0c8867d
--- /dev/null
+++ b/.idea/javascript-calculator.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ba07bc0
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cypress.json b/cypress.json
new file mode 100644
index 0000000..3d8d2be
--- /dev/null
+++ b/cypress.json
@@ -0,0 +1,7 @@
+{
+ "baseUrl": "http://localhost:5050",
+ "env": {
+ "TOTAL": "#total",
+ "MODIFIER": ".modifier"
+ }
+}
diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json
new file mode 100644
index 0000000..02e4254
--- /dev/null
+++ b/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+ "name": "Using fixtures to represent data",
+ "email": "hello@cypress.io",
+ "body": "Fixtures are a great way to mock data for responses to routes"
+}
diff --git a/cypress/integration/sample_spec.ts b/cypress/integration/sample_spec.ts
new file mode 100644
index 0000000..8c12617
--- /dev/null
+++ b/cypress/integration/sample_spec.ts
@@ -0,0 +1,43 @@
+describe("Reg form", () => {
+ const clickButtons = (values: string): void => {
+ const charFromValues = values.split("");
+ charFromValues.forEach((char) => {
+ cy.get("button").contains(char).click();
+ })
+ };
+
+ const calculate = (expression: string, expectedResult: string): void => {
+ clickButtons(expression);
+ cy.get(Cypress.env("TOTAL")).should('have.text', expectedResult);
+ cy.get(Cypress.env("MODIFIER")).click();
+ }
+ it("input numbers must be in range 0 ~ 999", () => {
+ cy.visit("/");
+ clickButtons("123111");
+ cy.get(Cypress.env("TOTAL")).should("have.text", "123");
+ })
+ it("clear board", () => {
+ cy.get(Cypress.env("MODIFIER")).click();
+ cy.get(Cypress.env("TOTAL")).should("have.text", "0");
+ })
+ it("add numbers", () => {
+ calculate("123+123=","246");
+ calculate("123+123+","246");
+ calculate("123+123+123=","369");
+ })
+ it("multiply numbers", () => {
+ calculate("123X123=","15129");
+ calculate("123X123X","15129");
+ calculate("123X123X123=","1860867");
+ })
+ it("divide numbers", () => {
+ calculate("123/123=","1");
+ calculate("123/123/","1");
+ calculate("123/123/123=","0");
+ })
+ it("subtract numbers", () => {
+ calculate("123-123=","0");
+ calculate("123-123-","0");
+ calculate("123-123-123=","-123");
+ })
+})
\ No newline at end of file
diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js
new file mode 100644
index 0000000..63fa4f5
--- /dev/null
+++ b/cypress/plugins/index.js
@@ -0,0 +1,22 @@
+///
+// ***********************************************************
+// This example plugins/index.tsfile can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+/**
+ * @type {Cypress.PluginConfig}
+ */
+// eslint-disable-next-line no-unused-vars
+module.exports = (on, config) => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+}
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 0000000..3d8b9b6
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,25 @@
+// ***********************************************
+// This example commands.tsfile shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
diff --git a/cypress/support/index.js b/cypress/support/index.js
new file mode 100644
index 0000000..265454b
--- /dev/null
+++ b/cypress/support/index.js
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.tsfile is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.tsfile using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/cypress/videos/sample_spec.ts.mp4 b/cypress/videos/sample_spec.ts.mp4
new file mode 100644
index 0000000..3678cf5
Binary files /dev/null and b/cypress/videos/sample_spec.ts.mp4 differ
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..aa62084
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,2 @@
+import Calculator from "./tsfile/component/calculator.js";
+new Calculator(document.querySelector('.calculator'));
diff --git a/dist/tsfile/component/board.js b/dist/tsfile/component/board.js
new file mode 100644
index 0000000..290cecf
--- /dev/null
+++ b/dist/tsfile/component/board.js
@@ -0,0 +1,23 @@
+import { isClear, isOperator } from "../../utils/utils.js";
+class BoardImpl {
+ constructor({ $element, onClick }) {
+ this.addEvent = () => {
+ this.$element.addEventListener('click', ({ target }) => {
+ if (!(target instanceof HTMLButtonElement))
+ return;
+ const value = target.textContent;
+ if (isOperator(value)) {
+ return this.onClick({ type: 'Operator', value });
+ }
+ if (isClear(value)) {
+ return this.onClick({ type: 'Clear', value });
+ }
+ return this.onClick({ type: 'Number', value });
+ });
+ };
+ this.$element = $element;
+ this.onClick = onClick;
+ this.addEvent();
+ }
+}
+export default BoardImpl;
diff --git a/dist/tsfile/component/calculator.js b/dist/tsfile/component/calculator.js
new file mode 100644
index 0000000..5a04f8c
--- /dev/null
+++ b/dist/tsfile/component/calculator.js
@@ -0,0 +1,65 @@
+import ScreenImpl from "./screen.js";
+import BoardImpl from "./board.js";
+import { calc } from "../../utils/utils.js";
+class Calculator {
+ constructor($element) {
+ this.$element = $element;
+ this.clear = () => {
+ this.value = '';
+ this.oper = '';
+ this.prev = '';
+ };
+ this.setState = (value) => {
+ this.value = value;
+ this.screen.setState(value);
+ };
+ this.onClick = ({ type, value }) => {
+ switch (type) {
+ case 'Operator':
+ if (this.operatorPressed)
+ return;
+ this.operatorPressed = true;
+ this.prev = calc(this.prev, this.oper, this.value);
+ this.oper = value;
+ this.screen.setState(this.prev);
+ if (value === '=') {
+ this.operatorPressed = false;
+ }
+ this.value = '0';
+ break;
+ case 'Clear':
+ this.clear();
+ this.setState('0');
+ break;
+ case 'Number':
+ if (this.oper === '=')
+ this.clear();
+ if (this.value.length === 3)
+ break;
+ let newValue = this.value === '0' ? value : this.value + value;
+ if (!this.operatorPressed) {
+ this.setState(newValue);
+ break;
+ }
+ this.operatorPressed = false;
+ this.setState(value);
+ break;
+ default:
+ throw new Error('Operation fail');
+ }
+ };
+ this.value = '0';
+ this.prev = '';
+ this.oper = '';
+ this.operatorPressed = false;
+ this.screen = new ScreenImpl({
+ $element: this.$element.querySelector('#total'),
+ value: this.value
+ });
+ new BoardImpl({
+ $element: this.$element,
+ onClick: this.onClick
+ });
+ }
+}
+export default Calculator;
diff --git a/dist/tsfile/component/screen.js b/dist/tsfile/component/screen.js
new file mode 100644
index 0000000..5719282
--- /dev/null
+++ b/dist/tsfile/component/screen.js
@@ -0,0 +1,14 @@
+class ScreenImpl {
+ constructor({ $element, value }) {
+ this.setState = (value) => {
+ this.value = value;
+ this.render();
+ };
+ this.render = () => {
+ this.$element.textContent = `${this.value}`;
+ };
+ this.$element = $element;
+ this.value = value;
+ }
+}
+export default ScreenImpl;
diff --git a/dist/types/types.js b/dist/types/types.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/dist/types/types.js
@@ -0,0 +1 @@
+export {};
diff --git a/dist/utils/utils.js b/dist/utils/utils.js
new file mode 100644
index 0000000..29de25b
--- /dev/null
+++ b/dist/utils/utils.js
@@ -0,0 +1,30 @@
+const isOperator = (value) => {
+ const allowedKey = ['+', '-', '/', 'X', '='];
+ return allowedKey.indexOf(value) !== -1;
+};
+const isClear = (value) => {
+ const allowedKey = 'AC';
+ return allowedKey === value;
+};
+const operate = (prev, oper, value) => {
+ const num_prev = +prev;
+ const num_value = +value;
+ switch (oper) {
+ case '+':
+ return String(num_prev + num_value);
+ case '-':
+ return String(num_prev - num_value);
+ case 'X':
+ return String(num_prev * num_value);
+ case '/':
+ return String(Math.floor(num_prev / num_value));
+ default:
+ return prev;
+ }
+};
+const calc = (prev, oper, value) => {
+ if (prev === '' || oper === '')
+ return value;
+ return operate(prev, oper, value);
+};
+export { isOperator, isClear, calc };
diff --git a/index.html b/index.html
index 8bf48ab..58e3603 100644
--- a/index.html
+++ b/index.html
@@ -1,38 +1,39 @@
-
-
-
- Calculator
-
-
-
-
-
-
0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
Calculator
+
+
+
+
+
+
0
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+