diff --git a/package-lock.json b/package-lock.json
index 90e9696..5d1f08a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -118,6 +118,12 @@
"webpack-sources": "1.4.3"
},
"dependencies": {
+ "tslib": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
+ "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
+ "dev": true
+ },
"typescript": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz",
@@ -195,9 +201,9 @@
}
},
"@angular/animations": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.1.tgz",
- "integrity": "sha512-IvKv8sV0ymbzDEX2ZLW+F6nOTQqDYallHexuzRVT9txvNE8TNHyySvLcyC5dTmX9fj9LA72NZ6nFyhxq0LFvtQ=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-9.1.12.tgz",
+ "integrity": "sha512-tphpf9QHnOPoL2Jl7KpR+R5aHNW3oifLEmRUTajJYJGvo1uzdUDE82+V9OGOinxJsYseCth9gYJhN24aYTB9NA=="
},
"@angular/cli": {
"version": "9.1.1",
@@ -242,14 +248,14 @@
}
},
"@angular/common": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.1.tgz",
- "integrity": "sha512-bS13veMs7//YqYjYJ+JI78ylaCyVcdFKZKikd5SZa6+r6fajcyvLnSKqrKypG3O1BeJ8vOG/Pq54P5gWhbR6eA=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/common/-/common-9.1.12.tgz",
+ "integrity": "sha512-XSIqkbM6VV1yixF9zuzeE5eqN1VsiXS517K2VU0XgCRSAzhVhLOeKsdYjeLf7PdSu/HgW/Tr81H+isi9A9I0YA=="
},
"@angular/compiler": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.1.tgz",
- "integrity": "sha512-u1IP6IzUgK6lIzrG1cxp96umXgtThyhuFn/KPoyVt7wPxZ6vVR0ZxjM7zycEcrMGzk0nf0nyOKaksJk9sTXTbg=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.1.12.tgz",
+ "integrity": "sha512-suefk0OFkaJpUUKnV+phbL4T8fmVGHvzkereY5eqybQlumOez8NPL1PJcygAylh/E6OIAYm8SWookYwM6ZY9dg=="
},
"@angular/compiler-cli": {
"version": "9.1.1",
@@ -455,14 +461,14 @@
}
},
"@angular/core": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.1.tgz",
- "integrity": "sha512-6lDlUlePafr/392hOvvTZZl6xPHT50U6658sHUAVIr0Un4mJ2MHNHKZtO45bpn3hM4gjFcYRQ7Rpd0umW74iTA=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.1.12.tgz",
+ "integrity": "sha512-WVA/eh3fzjx0apOzkKot4YRRUsGkHj50zFQWrAOMgivGaj1YVrvhf+m3hpglj5fn/BkLiFDl8RT0wAE8z9X+gQ=="
},
"@angular/forms": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.1.tgz",
- "integrity": "sha512-NX+LuK8JFisiq3uHCOK6YoN/yIb2R9Ye5mwiOPkuZA3lZLKCnUXqCHZbM8VHy/WdjIxxeUaFMJc38yV8RVoabg=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-9.1.12.tgz",
+ "integrity": "sha512-LhjnZlC4WEsEsAJfOZLte+Lks3WBAFVeRv2lzoQNFVr/IMzBNDVfjEaaSqKF1cei3cjY39Df2nYDMJM7HfqbJA=="
},
"@angular/language-service": {
"version": "9.1.1",
@@ -471,19 +477,19 @@
"dev": true
},
"@angular/platform-browser": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.1.tgz",
- "integrity": "sha512-tjALKhdAWPErj0euIIdvx/31AHEZ7is7ADsMu+nYn2NY2gcPUuiqq3RCUJVxBYJ2Cclq1nlF0i2rEDKh7TrBKg=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-9.1.12.tgz",
+ "integrity": "sha512-rPa/hJcLfdId6bYB0b6pFUo3QIgjZlvUlmtKMGdrLNLYR8XQxPa2Y/UdN/5YeZ12htGw6GXrX9U8U7nTbUSpkw=="
},
"@angular/platform-browser-dynamic": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.1.tgz",
- "integrity": "sha512-kEox5UOwkRLjGKXLh5o5SYopoAylpKgrXtRrKRKTCMmZTpYSe1bLlXMjpwMAMZ9ZFSTvWp9iX94aT5bJDpLrRQ=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-9.1.12.tgz",
+ "integrity": "sha512-NmwUZaQeMnA6f+vP9Fp9P+qjL72H8dKlxLS76ujlKHVf75pP5oahWS8wfl7KXel1tKW3FQWMMffmKf5/NHRiSw=="
},
"@angular/router": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.1.tgz",
- "integrity": "sha512-OQ5Ctd+swF7ZNlgUxrkGKk2B4yBFqJm0QCxkM86kFDCKQV/4OButZ+4HPy1HxeozBIAmm2pbQA+YjsAUs0VZcQ=="
+ "version": "9.1.12",
+ "resolved": "https://registry.npmjs.org/@angular/router/-/router-9.1.12.tgz",
+ "integrity": "sha512-+qCaXa9y0nsRhzjAYBqmGoQ2YkrdXgftZwuFDf6t4qEi30EXa0oS97KrlFq0M5GKdLIDGrbUm9PcdHSTOI+ZhA=="
},
"@babel/code-frame": {
"version": "7.8.3",
@@ -11511,9 +11517,9 @@
}
},
"tslib": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
- "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA=="
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
+ "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
},
"tslint": {
"version": "6.1.1",
diff --git a/src/app/app.component.html b/src/app/app.component.html
index f348a5a..c34ed49 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -4,27 +4,3 @@
-
-
-
-
-
-
-
- Valido {{profileForm.valid}}
-
-
- Touched {{profileForm.touched}}
-
-
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index b31f041..576314c 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,5 +1,4 @@
import { Component } from '@angular/core';
-import { FormGroup, FormControl, Form, Validators, AbstractControl } from '@angular/forms';
@Component({
selector: 'app-root',
@@ -8,25 +7,4 @@ import { FormGroup, FormControl, Form, Validators, AbstractControl } from '@angu
})
export class AppComponent {
title = 'Todo';
- profileForm = new FormGroup({
- firstName: new FormControl('', [Validators.required, Validators.maxLength(10)]),
- lastName: new FormControl('', [Validators.required, StartsWithAValidator]),
- })
- constructor () {
- this.profileForm.valueChanges.subscribe(value => console.log(value));
- }
-
- onSubmit() {
- console.log(this.profileForm.value);
- }
- initialize() {
- this.profileForm.reset()
- }
}
-
-export function StartsWithAValidator(control: AbstractControl) {
- if (!control.value.startsWith('A')) {
- return { startsWithA: true };
- }
- return null;
-}
\ No newline at end of file
diff --git a/src/app/model/todo-item.ts b/src/app/model/todo-item.ts
index bdb4f8b..1e2a408 100644
--- a/src/app/model/todo-item.ts
+++ b/src/app/model/todo-item.ts
@@ -2,6 +2,7 @@ export class TodoItem {
id: number;
description: string;
isCompleted: boolean = false;
+ url:string
toggleCompleted() {
this.isCompleted = !this.isCompleted;
diff --git a/src/app/stats/stats.component.html b/src/app/stats/stats.component.html
index b599e29..f3bb63c 100644
--- a/src/app/stats/stats.component.html
+++ b/src/app/stats/stats.component.html
@@ -1,6 +1,6 @@
-
-{{completedPercentage()}} %
-
+
+
+ {{completedPercentage()}}
+
+
\ No newline at end of file
diff --git a/src/app/stats/stats.component.scss b/src/app/stats/stats.component.scss
index 3543841..03942bb 100644
--- a/src/app/stats/stats.component.scss
+++ b/src/app/stats/stats.component.scss
@@ -3,4 +3,6 @@
height: 50px;
font-size: x-large;
transition: width 0.3s;
+
+
}
diff --git a/src/app/stats/stats.component.ts b/src/app/stats/stats.component.ts
index 1ec80aa..8300f35 100644
--- a/src/app/stats/stats.component.ts
+++ b/src/app/stats/stats.component.ts
@@ -15,6 +15,8 @@ export class StatsComponent implements OnInit {
ngOnInit(): void {
}
completedPercentage() {
- return Math.round(this.service.completedSize() / this.service.list.length * 100) || 0
+ let percentaje = Math.round(this.service.completedSize() / this.service.list.length * 100) || 0
+ return percentaje + '%'
}
+
}
diff --git a/src/app/todo-app/todo-app.component.html b/src/app/todo-app/todo-app.component.html
index 786cc57..cbc01f9 100644
--- a/src/app/todo-app/todo-app.component.html
+++ b/src/app/todo-app/todo-app.component.html
@@ -1,12 +1,16 @@
-
-
+
+
+
+ (itemEdited) = "onItemEditing($event)"
+ >
-
-
+
+
+
\ No newline at end of file
diff --git a/src/app/todo-app/todo-app.component.ts b/src/app/todo-app/todo-app.component.ts
index cc42271..9c407ce 100644
--- a/src/app/todo-app/todo-app.component.ts
+++ b/src/app/todo-app/todo-app.component.ts
@@ -1,5 +1,5 @@
-import { Component, OnInit } from '@angular/core';
-import {TodoItem} from '../model/todo-item';
+import { Component, OnInit, EventEmitter, Output } from '@angular/core';
+import { TodoItem } from '../model/todo-item';
import { element } from 'protractor';
import { TodoService } from '../todo.service';
/** */
@@ -8,11 +8,11 @@ import { TodoService } from '../todo.service';
templateUrl: './todo-app.component.html',
styleUrls: ['./todo-app.component.scss'],
})
-export class TodoAppComponent {
+export class TodoAppComponent {
+ editingTask = undefined;
+ isEditingTask = false;
- constructor(
- private service: TodoService
- ) {}
+ constructor(private service: TodoService) {}
getList() {
return this.service.list;
@@ -24,6 +24,14 @@ export class TodoAppComponent {
item.toggleCompleted();
}
onTodoItemCreated(task) {
- this.service.add(task)
+ this.service.add(task);
}
+ onItemEditing(task){
+ this.editingTask = task;
+ this.isEditingTask = true;
+ }
+ onCancelEditingTask(){
+ this.isEditingTask = false;
+ }
+
}
diff --git a/src/app/todo-form/todo-form.component.html b/src/app/todo-form/todo-form.component.html
index ec0ad47..4a23bc8 100644
--- a/src/app/todo-form/todo-form.component.html
+++ b/src/app/todo-form/todo-form.component.html
@@ -1,10 +1,22 @@
+
\ No newline at end of file
diff --git a/src/app/todo-form/todo-form.component.scss b/src/app/todo-form/todo-form.component.scss
index 213bb36..b1edf77 100644
--- a/src/app/todo-form/todo-form.component.scss
+++ b/src/app/todo-form/todo-form.component.scss
@@ -1,3 +1,35 @@
+.task-main-form {
+ background-color: rgb(70, 162, 255);
+ padding: 20px;
+ border-radius: 15px;
+}
+
.add-todo {
- width: 80%
+ width: 100%;
+}
+.main-row{
+ display: flex;
+ justify-content: stretch;
+}
+
+.optional-row{
+ display: flex;
+ justify-content: stretch;
+}
+
+.optional-row p{
+ display: inline-block;
+ padding: 0px 10px;
+}
+
+.optional-row .add-todo{
+ width: 100%;
+}
+
+input.ng-invalid{
+ border: 2px solid red;
}
+
+.btn{
+ margin: 0px 0px 0px 10px;
+}
\ No newline at end of file
diff --git a/src/app/todo-form/todo-form.component.ts b/src/app/todo-form/todo-form.component.ts
index 3366020..cc4ed02 100644
--- a/src/app/todo-form/todo-form.component.ts
+++ b/src/app/todo-form/todo-form.component.ts
@@ -1,24 +1,97 @@
-import { Component, OnInit, Output, EventEmitter} from '@angular/core';
+import {
+ Component,
+ Output,
+ EventEmitter,
+ Input,
+ OnChanges,
+ SimpleChange,
+} from '@angular/core';
import { TodoItem } from '../model/todo-item';
+import { FormGroup, FormControl, AbstractControl } from '@angular/forms';
+import { TodoService } from '../todo.service';
@Component({
selector: 'app-todo-form',
templateUrl: './todo-form.component.html',
- styleUrls: ['./todo-form.component.scss']
+ styleUrls: ['./todo-form.component.scss'],
})
export class TodoFormComponent {
-
@Output() add = new EventEmitter();
- save(description){
- if(!description.value || description.value === '') {
+ @Input() editingTask;
+ @Input() isEditingTask;
+ @Output() cancelEditing = new EventEmitter();
+
+ taskForm = new FormGroup({
+ taskName: new FormControl(''),
+ taskUrl: new FormControl('', [UrlValidator]),
+ });
+
+ constructor(private service: TodoService) {}
+
+ save() {
+ let description = this.taskForm.controls.taskName;
+
+ if (!description.value || description.value === '') {
return;
}
let task = new TodoItem();
task.description = description.value;
task.isCompleted = false;
+ task.url = this.taskForm.controls.taskUrl.value;
this.add.emit(task);
- description.value = '';
+
+ this.taskForm.reset();
+ }
+
+ ngOnChanges(changes: { [propertyName: string]: SimpleChange }) {
+ let isEditing = changes.isEditingTask;
+ if (isEditing !== undefined) {
+ if (isEditing.currentValue && !isEditing.previousValue) {
+ this.taskForm.patchValue({
+ taskName: this.editingTask.description,
+ taskUrl: this.editingTask.url,
+ });
+ }
+ }
}
+
+ edit() {
+ this.editingTask.description = this.taskForm.controls.taskName.value;
+ this.editingTask.url = this.taskForm.controls.taskUrl.value;
+
+ this.service.edit(this.editingTask);
+ this.cancelEdit()
+ }
+ cancelEdit() {
+ this.taskForm.reset();
+ this.isEditingTask = false;
+ this.cancelEditing.emit();
+ }
+
}
+export function UrlValidator(control: AbstractControl) {
+ // valid url and empty strings.
+ if (
+ validURL(control.value) ||
+ control.value == '' ||
+ control.value == undefined
+ ) {
+ return null;
+ }
+ return { error: true };
+}
+
+function validURL(str) {
+ var pattern = new RegExp(
+ '^(https?:\\/\\/)?' + // protocol
+ '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
+ '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
+ '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
+ '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
+ '(\\#[-a-z\\d_]*)?$',
+ 'i'
+ );
+ return pattern.test(str);
+}
diff --git a/src/app/todo-list/todo-list.component.html b/src/app/todo-list/todo-list.component.html
index 127ec76..3f09035 100644
--- a/src/app/todo-list/todo-list.component.html
+++ b/src/app/todo-list/todo-list.component.html
@@ -1,11 +1,28 @@
-
- -
+
+
+
\ No newline at end of file
diff --git a/src/app/todo-list/todo-list.component.scss b/src/app/todo-list/todo-list.component.scss
index 0096849..c37550b 100644
--- a/src/app/todo-list/todo-list.component.scss
+++ b/src/app/todo-list/todo-list.component.scss
@@ -1,5 +1,5 @@
.completed {
- background-color: greenyellow;
+ background-color: #4CED69
}
.list {
padding: 0;
@@ -8,8 +8,27 @@
margin: 0;
list-style-type: none;
font-size: 2rem;
- border-bottom: 1px solid lightgrey;
- width: 80%;
+ border-bottom: 1px solid rgb(172, 170, 170);
+ border-radius: 5px;
+ width: 100%;
+}
+.task-main {
+ padding: 0px 0px 0px 20px;
display: flex;
justify-content: space-between;
+
+}
+.buttons{
+ min-width: 170px;
+}
+
+.task-url{
+ font-size: medium;
+ padding-left: 20px;
}
+
+.task-list{
+ background-color: rgb(219, 219, 221);
+ padding: 0px;
+ border-radius: 5px;
+}
\ No newline at end of file
diff --git a/src/app/todo-list/todo-list.component.ts b/src/app/todo-list/todo-list.component.ts
index fc5d8f0..e9ecb28 100644
--- a/src/app/todo-list/todo-list.component.ts
+++ b/src/app/todo-list/todo-list.component.ts
@@ -1,26 +1,37 @@
-import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { TodoItem } from '../model/todo-item';
@Component({
selector: 'app-todo-list',
templateUrl: './todo-list.component.html',
- styleUrls: ['./todo-list.component.scss']
+ styleUrls: ['./todo-list.component.scss'],
})
export class TodoListComponent implements OnInit {
@Input() list: any[];
@Output() itemRemoved = new EventEmitter();
@Output() itemStateChanged = new EventEmitter();
- constructor() { }
+ @Output() itemEdited = new EventEmitter();
- ngOnInit() {
- }
+ constructor() {}
+ ngOnInit() {}
removeItem(id) {
this.itemRemoved.emit(id);
}
- completeTask(item:TodoItem) {
+ completeTask(item: TodoItem) {
this.itemStateChanged.emit(item);
+ }
+ editTask(item: TodoItem) {
+ this.itemEdited.emit(item);
}
+ CompleteUrl(url) {
+ if (url === null || url === undefined) return '';
-}
\ No newline at end of file
+ // completa la URL para que se pueda navegar por click.
+ if (!url.startsWith('http')) {
+ url = '//' + url;
+ }
+ return url;
+ }
+}
diff --git a/src/app/todo.service.ts b/src/app/todo.service.ts
index 9bba8cc..c41b6d6 100644
--- a/src/app/todo.service.ts
+++ b/src/app/todo.service.ts
@@ -2,15 +2,14 @@ import { Injectable } from '@angular/core';
import { LocalStorageService } from './local-storage.service';
@Injectable({
- providedIn: 'root'
+ providedIn: 'root',
})
export class TodoService {
-
list = [];
lastItemId = 0;
- constructor(private storage: LocalStorageService) { }
-
+ constructor(private storage: LocalStorageService) {}
+
add(task) {
const id = this.lastItemId;
task.id = id;
@@ -24,11 +23,14 @@ export class TodoService {
}
incompletedSize() {
- return this.list.filter(item => !item.isCompleted).length;
-
+ return this.list.filter((item) => !item.isCompleted).length;
}
completedSize() {
- return this.list.filter(item => item.isCompleted).length ;
+ return this.list.filter((item) => item.isCompleted).length;
+ }
+ edit(task) {
+ const index = this.list.findIndex((element) => element.id === task.id);
+ this.list[index] = task;
}
getName() {
diff --git a/src/index.html b/src/index.html
index 62a7817..9ace089 100644
--- a/src/index.html
+++ b/src/index.html
@@ -6,6 +6,10 @@
+
+
+
+