diff --git a/todo-list-agung-hidayat/index.html b/todo-list-agung-hidayat/index.html
new file mode 100644
index 0000000..36674fc
--- /dev/null
+++ b/todo-list-agung-hidayat/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+ Todo List — Agung Hidayat
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/todo-list-agung-hidayat/index.js b/todo-list-agung-hidayat/index.js
new file mode 100644
index 0000000..9d98488
--- /dev/null
+++ b/todo-list-agung-hidayat/index.js
@@ -0,0 +1,115 @@
+"use strict";
+// Models
+class Todo {
+ constructor() {
+ this.title = "";
+ this.status = false;
+ this.id = String(Math.floor(Math.random() * (9000 + 1)));
+ }
+ set setTodo(title) {
+ this.title = title;
+ this.id = String(Math.floor(Math.random() * (9000 + 1)));
+ }
+ get getTodo() {
+ return { id: this.id, title: this.title, status: this.status };
+ }
+}
+class Todos extends Todo {
+ constructor() {
+ super();
+ this.todo = [];
+ }
+ get myTodos() {
+ return this.todo;
+ }
+ set addTodo(todo) {
+ this.todo.push(todo);
+ }
+ set toggleStatus(id) {
+ console.log(id);
+ this.todo = this.todo.map((item) => {
+ if (item.id === id) {
+ item.status = !item.status;
+ }
+ return item;
+ });
+ }
+ set deleteTodo(id) {
+ this.todo = this.todo.filter((item) => item.id !== id);
+ }
+}
+// Controller
+class Controller extends Todos {
+ constructor() {
+ super();
+ this.elementParent = document.querySelector("ul");
+ this.close = document.getElementsByClassName("close");
+ this.addButton = document.querySelector(".addBtn");
+ this.list = document.querySelector("ul");
+ this.init();
+ this.initEventListener();
+ }
+ init() {
+ this.initElement();
+ this.initCloseButton();
+ }
+ newElement() {
+ var li = document.createElement("li");
+ var input = document.getElementById("myInput");
+ var inputValue = input.value;
+ if (inputValue === "") {
+ alert("You must write something!");
+ }
+ else {
+ this.setTodo = inputValue;
+ this.addTodo = this.getTodo;
+ input.value = "";
+ this.init();
+ }
+ }
+ initElement() {
+ while (this.elementParent.firstChild) {
+ this.elementParent.removeChild(this.elementParent.firstChild);
+ }
+ for (let i = 0; i < this.myTodos.length; i++) {
+ const todo = this.myTodos[i].title;
+ const status = this.myTodos[i].status ? "checked" : "";
+ var li = document.createElement("li");
+ this.title = document.createTextNode(todo);
+ li.className = status;
+ li.setAttribute('data-id', String(this.myTodos[i].id));
+ li.appendChild(this.title);
+ var span = document.createElement("SPAN");
+ this.txt = document.createTextNode("\u00D7");
+ span.className = "close";
+ span.setAttribute('data-id', String(this.myTodos[i].id));
+ span.appendChild(this.txt);
+ li.appendChild(span);
+ this.elementParent.appendChild(li);
+ }
+ }
+ initCloseButton() {
+ for (let i = 0; i < this.close.length; i++) {
+ this.close[i].addEventListener("click", (ev) => {
+ this.deleteTodo = ev.target.getAttribute('data-id');
+ this.init();
+ });
+ }
+ }
+ initEventListener() {
+ this.list.addEventListener("click", (event) => {
+ this.toggleStatus = event.target.getAttribute('data-id');
+ this.init();
+ });
+ this.addButton.addEventListener("click", () => {
+ this.newElement();
+ });
+ var input = document.getElementById("myInput");
+ input.addEventListener("keyup", (event) => {
+ if (event.keyCode === 13) {
+ this.newElement();
+ }
+ });
+ }
+}
+const controller = new Controller();
diff --git a/todo-list-agung-hidayat/index.ts b/todo-list-agung-hidayat/index.ts
new file mode 100644
index 0000000..ea6e665
--- /dev/null
+++ b/todo-list-agung-hidayat/index.ts
@@ -0,0 +1,163 @@
+// Types
+interface ITodo {
+ id: string,
+ title: string,
+ status: boolean,
+}
+
+interface ITodos {
+ todo: ITodo[]
+}
+
+
+// Models
+class Todo implements ITodo {
+ id: string
+ title: string
+ status: boolean
+
+ constructor(){
+ this.title = ""
+ this.status = false
+ this.id = String(Math.floor(Math.random() * (9000 + 1)))
+ }
+
+ set setTodo(title: string){
+ this.title = title
+ this.id = String(Math.floor(Math.random() * (9000 + 1)))
+ }
+
+ get getTodo(){
+ return {id: this.id, title: this.title, status: this.status}
+ }
+}
+
+class Todos extends Todo implements ITodos {
+ todo: ITodo[]
+
+ constructor(){
+ super()
+ this.todo = []
+ }
+
+ get myTodos(){
+ return this.todo
+ }
+
+ set addTodo(todo: ITodo){
+ this.todo.push(todo)
+ }
+
+ set toggleStatus(id: any){
+ console.log(id)
+ this.todo = this.todo.map((item) => {
+ if(item.id === id){
+ item.status = !item.status
+ }
+
+ return item
+ })
+ }
+
+ set deleteTodo(id: string){
+ this.todo = this.todo.filter((item) => item.id !== id)
+ }
+}
+
+// Controller
+class Controller extends Todos {
+ elementParent: HTMLUListElement
+ title: any
+ txt: any
+
+ close: any
+ addButton: HTMLButtonElement
+ list: HTMLUListElement
+
+ constructor() {
+ super()
+ this.elementParent = document.querySelector("ul") as HTMLUListElement;
+ this.close = document.getElementsByClassName("close");
+ this.addButton = document.querySelector(".addBtn") as HTMLButtonElement;
+ this.list = document.querySelector("ul") as HTMLUListElement;
+
+ this.init()
+ this.initEventListener()
+ }
+
+ init(){
+ this.initElement()
+ this.initCloseButton()
+ }
+
+ newElement() {
+ var li = document.createElement("li");
+ var input: HTMLInputElement = document.getElementById("myInput") as HTMLInputElement;
+ var inputValue: string = input.value;
+ if (inputValue === "") {
+ alert("You must write something!");
+ }
+ else {
+ this.setTodo = inputValue
+ this.addTodo = this.getTodo
+ input.value = ""
+ this.init()
+ }
+ }
+
+ initElement(){
+ while (this.elementParent.firstChild) {
+ this.elementParent.removeChild(this.elementParent.firstChild);
+ }
+
+ for (let i = 0; i < this.myTodos.length; i++) {
+ const todo: string = this.myTodos[i].title;
+ const status: string = this.myTodos[i].status ? "checked" : "";
+
+ var li: HTMLLIElement = document.createElement("li");
+ this.title = document.createTextNode(todo);
+ li.className = status;
+ li.setAttribute('data-id', String(this.myTodos[i].id));
+ li.appendChild(this.title);
+
+ var span = document.createElement("SPAN");
+ this.txt = document.createTextNode("\u00D7");
+ span.className = "close";
+ span.setAttribute('data-id', String(this.myTodos[i].id));
+ span.appendChild(this.txt);
+ li.appendChild(span);
+
+ this.elementParent.appendChild(li);
+ }
+ }
+
+ initCloseButton(){
+ for (let i = 0; i < this.close.length; i++) {
+ this.close[i].addEventListener("click", (ev: any ): void => {
+ this.deleteTodo = ev.target.getAttribute('data-id')
+ this.init()
+ })
+ }
+ }
+
+ initEventListener(){
+ this.list.addEventListener("click", (event: any) : void => {
+ this.toggleStatus = event.target.getAttribute('data-id')
+ this.init()
+ });
+
+ this.addButton.addEventListener("click", (): void => {
+ this.newElement()
+ })
+
+ var input: HTMLInputElement = document.getElementById("myInput") as HTMLInputElement;
+ input.addEventListener("keyup", (event: { keyCode: number}): void => {
+
+ if(event.keyCode === 13){
+ this.newElement()
+ }
+ })
+ }
+}
+
+const controller = new Controller()
\ No newline at end of file
diff --git a/todo-list-agung-hidayat/style.css b/todo-list-agung-hidayat/style.css
new file mode 100644
index 0000000..3c9a52e
--- /dev/null
+++ b/todo-list-agung-hidayat/style.css
@@ -0,0 +1,155 @@
+body {
+ margin: 0;
+ min-width: 250px;
+}
+
+/* Include the padding and border in an element's total width and height */
+* {
+ box-sizing: border-box;
+}
+
+.container {
+ max-width: 700px;
+ margin: 3% auto;
+ padding: 2%;
+ border-radius: 18px;
+ box-shadow: 0px 0px 7px 1px rgba(0, 0, 0, 0.37);
+ -webkit-box-shadow: 0px 0px 7px 1px rgba(0, 0, 0, 0.37);
+ -moz-box-shadow: 0px 0px 7px 1px rgba(0, 0, 0, 0.37);
+}
+
+/* Remove margins and padding from the list */
+ul {
+ margin: 0;
+ padding: 0;
+}
+
+/* Style the list items */
+ul li {
+ cursor: pointer;
+ position: relative;
+ padding: 12px 8px 12px 40px;
+ list-style-type: none;
+ background: rgb(238, 238, 238);
+ color: black;
+ font-size: 18px;
+ transition: 0.2s;
+ text-decoration: none;
+
+ /* make the list items unselectable */
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#myUL {
+ padding: 20px;
+}
+
+#myUL > li {
+ border-radius: 11px;
+ margin: 8px 0;
+}
+
+#myUL > li {
+ border-radius: 15px;
+}
+
+/* Set all odd list items to a different color (zebra-stripes) */
+/* ul li:nth-child(odd) {
+ background: #f9f9f9;
+} */
+
+/* Darker background-color on hover */
+ul li:hover {
+ background: rgb(168, 168, 168);
+}
+
+/* When clicked on, add a background color and strike out text */
+ul li.checked {
+ background: #888;
+ color: #fff;
+ text-decoration: line-through;
+}
+
+/* Add a "checked" mark when clicked on */
+ul li.checked::before {
+ content: "";
+ position: absolute;
+ border-color: #fff;
+ border-style: solid;
+ border-width: 0 2px 2px 0;
+ top: 10px;
+ left: 16px;
+ transform: rotate(45deg);
+ height: 15px;
+ width: 7px;
+}
+
+/* Style the close button */
+.close {
+ position: absolute;
+ right: 0;
+ top: 0;
+ margin: 4px;
+ padding: 8px 12px 8px 12px;
+ border-radius: 11px;
+}
+
+.close:hover {
+ background-color: #f44336;
+ color: white;
+}
+
+/* Style the header */
+.header {
+ /* background-color: #f44336; */
+ padding: 30px 18px;
+ /* color: white; */
+ text-align: center;
+}
+
+/* Clear floats after the header */
+.header:after {
+ content: "";
+ display: table;
+ clear: both;
+}
+
+/* Style the input */
+input {
+ margin: 0;
+ border: none;
+ border-radius: 0;
+ width: 73%;
+ padding: 11px;
+ float: left;
+ font-size: 16px;
+ background: rgb(235, 235, 235);
+ border-radius: 5px;
+ margin-right: 1%;
+ transition: 0.2s;
+}
+
+input:focus-visible {
+ outline-color: rgb(126, 126, 126);
+}
+
+/* Style the "Add" button */
+.addBtn {
+ padding: 10px;
+ width: 25%;
+ background: #cccccc;
+ color: #555;
+ float: left;
+ text-align: center;
+ font-size: 16px;
+ cursor: pointer;
+ transition: 0.3s;
+ border-radius: 2px;
+}
+
+.addBtn:hover {
+ background-color: rgb(161, 161, 161);
+}
diff --git a/todo-list-agung-hidayat/tsconfig.json b/todo-list-agung-hidayat/tsconfig.json
new file mode 100644
index 0000000..5679481
--- /dev/null
+++ b/todo-list-agung-hidayat/tsconfig.json
@@ -0,0 +1,101 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Projects */
+ // "incremental": true, /* Enable incremental compilation */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+
+ /* Language and Environment */
+ "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
+ // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "resolveJsonModule": true, /* Enable importing .json files */
+ // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
+
+ /* JavaScript Support */
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
+
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
+ // "outDir": "./", /* Specify an output folder for all emitted files. */
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
+ // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
+ // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}