todomvc web-components, change title, id & completed attributes on item component (#314)
This commit is contained in:
parent
4316b5fb14
commit
44c809305d
4 changed files with 74 additions and 62 deletions
|
|
@ -7,15 +7,18 @@ import itemStyles from "../../styles/todo-item.constructable.js";
|
|||
|
||||
class TodoItem extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ["id", "title", "completed"];
|
||||
return ["itemid", "itemtitle", "itemcompleted"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.id = "";
|
||||
this.title = "Todo Item";
|
||||
this.completed = "false";
|
||||
// Renamed this.id to this.itemid and this.title to this.itemtitle.
|
||||
// When the component assigns to this.id or this.title, this causes the browser's implementation of the existing setters to run, which convert these property sets into internal setAttribute calls. This can have surprising consequences.
|
||||
// [Issue]: https://github.com/WebKit/Speedometer/issues/313
|
||||
this.itemid = "";
|
||||
this.itemtitle = "Todo Item";
|
||||
this.itemcompleted = "false";
|
||||
|
||||
const node = document.importNode(template.content, true);
|
||||
this.item = node.querySelector(".todo-item");
|
||||
|
|
@ -51,18 +54,18 @@ class TodoItem extends HTMLElement {
|
|||
update(...args) {
|
||||
args.forEach((argument) => {
|
||||
switch (argument) {
|
||||
case "id":
|
||||
if (this.id !== undefined)
|
||||
this.item.id = `todo-item-${this.id}`;
|
||||
case "itemid":
|
||||
if (this.itemid !== undefined)
|
||||
this.item.id = `todo-item-${this.itemid}`;
|
||||
break;
|
||||
case "title":
|
||||
if (this.title !== undefined) {
|
||||
this.todoText.textContent = this.title;
|
||||
this.editInput.value = this.title;
|
||||
case "itemtitle":
|
||||
if (this.itemtitle !== undefined) {
|
||||
this.todoText.textContent = this.itemtitle;
|
||||
this.editInput.value = this.itemtitle;
|
||||
}
|
||||
break;
|
||||
case "completed":
|
||||
this.toggleInput.checked = this.completed === "true" ? true : false;
|
||||
case "itemcompleted":
|
||||
this.toggleInput.checked = this.itemcompleted === "true" ? true : false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
@ -70,7 +73,7 @@ class TodoItem extends HTMLElement {
|
|||
|
||||
startEdit() {
|
||||
this.item.classList.add("editing");
|
||||
this.editInput.value = this.title;
|
||||
this.editInput.value = this.itemtitle;
|
||||
this.editInput.focus();
|
||||
}
|
||||
|
||||
|
|
@ -85,11 +88,11 @@ class TodoItem extends HTMLElement {
|
|||
toggleItem() {
|
||||
// The todo-list checks the "completed" attribute to filter based on route
|
||||
// (therefore the completed state needs to already be updated before the check)
|
||||
this.setAttribute("completed", this.toggleInput.checked);
|
||||
this.setAttribute("itemcompleted", this.toggleInput.checked);
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("toggle-item", {
|
||||
detail: { id: this.id, completed: this.toggleInput.checked },
|
||||
detail: { id: this.itemid, completed: this.toggleInput.checked },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -100,7 +103,7 @@ class TodoItem extends HTMLElement {
|
|||
// (therefore the removal has to happen after the list is updated)
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("remove-item", {
|
||||
detail: { id: this.id },
|
||||
detail: { id: this.itemid },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -108,14 +111,14 @@ class TodoItem extends HTMLElement {
|
|||
}
|
||||
|
||||
updateItem(event) {
|
||||
if (event.target.value !== this.title) {
|
||||
if (event.target.value !== this.itemtitle) {
|
||||
if (!event.target.value.length) {
|
||||
this.removeItem();
|
||||
} else {
|
||||
this.setAttribute("title", event.target.value);
|
||||
this.setAttribute("itemtitle", event.target.value);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("update-item", {
|
||||
detail: { id: this.id, title: event.target.value },
|
||||
detail: { id: this.itemid, title: event.target.value },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -153,7 +156,7 @@ class TodoItem extends HTMLElement {
|
|||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.update("id", "title", "completed");
|
||||
this.update("itemid", "itemtitle", "itemcompleted");
|
||||
|
||||
this.keysListeners.push(
|
||||
useKeyListener({
|
||||
|
|
|
|||
|
|
@ -33,8 +33,12 @@ class TodoList extends HTMLElement {
|
|||
}
|
||||
|
||||
addItem(entry) {
|
||||
const { id, title, completed } = entry;
|
||||
const element = new TodoItem();
|
||||
Object.keys(entry).forEach((key) => element.setAttribute(key, entry[key]));
|
||||
|
||||
element.setAttribute("itemid", id);
|
||||
element.setAttribute("itemtitle", title);
|
||||
element.setAttribute("itemcompleted", completed);
|
||||
|
||||
const elementIndex = this.#elements.length;
|
||||
this.#elements.push(element);
|
||||
|
|
@ -48,18 +52,18 @@ class TodoList extends HTMLElement {
|
|||
|
||||
removeCompletedItems() {
|
||||
this.#elements = this.#elements.filter((element) => {
|
||||
if (element.completed === "true")
|
||||
if (element.itemcompleted === "true")
|
||||
element.removeItem();
|
||||
|
||||
return element.completed === "false";
|
||||
return element.itemcompleted === "false";
|
||||
});
|
||||
}
|
||||
|
||||
toggleItems(completed) {
|
||||
this.#elements.forEach((element) => {
|
||||
if (completed && element.completed === "false")
|
||||
if (completed && element.itemcompleted === "false")
|
||||
element.toggleInput.click();
|
||||
else if (!completed && element.completed === "true")
|
||||
else if (!completed && element.itemcompleted === "true")
|
||||
element.toggleInput.click();
|
||||
});
|
||||
}
|
||||
|
|
@ -74,10 +78,10 @@ class TodoList extends HTMLElement {
|
|||
updateView(element) {
|
||||
switch (this.#route) {
|
||||
case "completed":
|
||||
element.style.display = element.completed === "true" ? "block" : "none";
|
||||
element.style.display = element.itemcompleted === "true" ? "block" : "none";
|
||||
break;
|
||||
case "active":
|
||||
element.style.display = element.completed === "true" ? "none" : "block";
|
||||
element.style.display = element.itemcompleted === "true" ? "none" : "block";
|
||||
break;
|
||||
default:
|
||||
element.style.display = "block";
|
||||
|
|
@ -92,13 +96,12 @@ class TodoList extends HTMLElement {
|
|||
case "toggle-item":
|
||||
case "add-item":
|
||||
this.#elements.forEach((element) => {
|
||||
if (element.id === id)
|
||||
if (element.itemid === id)
|
||||
this.updateView(element);
|
||||
});
|
||||
break;
|
||||
case "remove-item":
|
||||
this.#elements = this.#elements.filter((element) => element.id !== id);
|
||||
|
||||
this.#elements = this.#elements.filter((element) => element.itemid !== id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,18 @@ import itemStyles from "../../../node_modules/todomvc-css/dist/todo-item.constru
|
|||
|
||||
class TodoItem extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ["id", "title", "completed"];
|
||||
return ["itemid", "itemtitle", "itemcompleted"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.id = "";
|
||||
this.title = "Todo Item";
|
||||
this.completed = "false";
|
||||
// Renamed this.id to this.itemid and this.title to this.itemtitle.
|
||||
// When the component assigns to this.id or this.title, this causes the browser's implementation of the existing setters to run, which convert these property sets into internal setAttribute calls. This can have surprising consequences.
|
||||
// [Issue]: https://github.com/WebKit/Speedometer/issues/313
|
||||
this.itemid = "";
|
||||
this.itemtitle = "Todo Item";
|
||||
this.itemcompleted = "false";
|
||||
|
||||
const node = document.importNode(template.content, true);
|
||||
this.item = node.querySelector(".todo-item");
|
||||
|
|
@ -51,18 +54,18 @@ class TodoItem extends HTMLElement {
|
|||
update(...args) {
|
||||
args.forEach((argument) => {
|
||||
switch (argument) {
|
||||
case "id":
|
||||
if (this.id !== undefined)
|
||||
this.item.id = `todo-item-${this.id}`;
|
||||
case "itemid":
|
||||
if (this.itemid !== undefined)
|
||||
this.item.id = `todo-item-${this.itemid}`;
|
||||
break;
|
||||
case "title":
|
||||
if (this.title !== undefined) {
|
||||
this.todoText.textContent = this.title;
|
||||
this.editInput.value = this.title;
|
||||
case "itemtitle":
|
||||
if (this.itemtitle !== undefined) {
|
||||
this.todoText.textContent = this.itemtitle;
|
||||
this.editInput.value = this.itemtitle;
|
||||
}
|
||||
break;
|
||||
case "completed":
|
||||
this.toggleInput.checked = this.completed === "true" ? true : false;
|
||||
case "itemcompleted":
|
||||
this.toggleInput.checked = this.itemcompleted === "true" ? true : false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
@ -70,7 +73,7 @@ class TodoItem extends HTMLElement {
|
|||
|
||||
startEdit() {
|
||||
this.item.classList.add("editing");
|
||||
this.editInput.value = this.title;
|
||||
this.editInput.value = this.itemtitle;
|
||||
this.editInput.focus();
|
||||
}
|
||||
|
||||
|
|
@ -85,11 +88,11 @@ class TodoItem extends HTMLElement {
|
|||
toggleItem() {
|
||||
// The todo-list checks the "completed" attribute to filter based on route
|
||||
// (therefore the completed state needs to already be updated before the check)
|
||||
this.setAttribute("completed", this.toggleInput.checked);
|
||||
this.setAttribute("itemcompleted", this.toggleInput.checked);
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("toggle-item", {
|
||||
detail: { id: this.id, completed: this.toggleInput.checked },
|
||||
detail: { id: this.itemid, completed: this.toggleInput.checked },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -100,7 +103,7 @@ class TodoItem extends HTMLElement {
|
|||
// (therefore the removal has to happen after the list is updated)
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("remove-item", {
|
||||
detail: { id: this.id },
|
||||
detail: { id: this.itemid },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -108,14 +111,14 @@ class TodoItem extends HTMLElement {
|
|||
}
|
||||
|
||||
updateItem(event) {
|
||||
if (event.target.value !== this.title) {
|
||||
if (event.target.value !== this.itemtitle) {
|
||||
if (!event.target.value.length) {
|
||||
this.removeItem();
|
||||
} else {
|
||||
this.setAttribute("title", event.target.value);
|
||||
this.setAttribute("itemtitle", event.target.value);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("update-item", {
|
||||
detail: { id: this.id, title: event.target.value },
|
||||
detail: { id: this.itemid, title: event.target.value },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
|
|
@ -153,7 +156,7 @@ class TodoItem extends HTMLElement {
|
|||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.update("id", "title", "completed");
|
||||
this.update("itemid", "itemtitle", "itemcompleted");
|
||||
|
||||
this.keysListeners.push(
|
||||
useKeyListener({
|
||||
|
|
|
|||
|
|
@ -33,8 +33,12 @@ class TodoList extends HTMLElement {
|
|||
}
|
||||
|
||||
addItem(entry) {
|
||||
const { id, title, completed } = entry;
|
||||
const element = new TodoItem();
|
||||
Object.keys(entry).forEach((key) => element.setAttribute(key, entry[key]));
|
||||
|
||||
element.setAttribute("itemid", id);
|
||||
element.setAttribute("itemtitle", title);
|
||||
element.setAttribute("itemcompleted", completed);
|
||||
|
||||
const elementIndex = this.#elements.length;
|
||||
this.#elements.push(element);
|
||||
|
|
@ -48,18 +52,18 @@ class TodoList extends HTMLElement {
|
|||
|
||||
removeCompletedItems() {
|
||||
this.#elements = this.#elements.filter((element) => {
|
||||
if (element.completed === "true")
|
||||
if (element.itemcompleted === "true")
|
||||
element.removeItem();
|
||||
|
||||
return element.completed === "false";
|
||||
return element.itemcompleted === "false";
|
||||
});
|
||||
}
|
||||
|
||||
toggleItems(completed) {
|
||||
this.#elements.forEach((element) => {
|
||||
if (completed && element.completed === "false")
|
||||
if (completed && element.itemcompleted === "false")
|
||||
element.toggleInput.click();
|
||||
else if (!completed && element.completed === "true")
|
||||
else if (!completed && element.itemcompleted === "true")
|
||||
element.toggleInput.click();
|
||||
});
|
||||
}
|
||||
|
|
@ -74,10 +78,10 @@ class TodoList extends HTMLElement {
|
|||
updateView(element) {
|
||||
switch (this.#route) {
|
||||
case "completed":
|
||||
element.style.display = element.completed === "true" ? "block" : "none";
|
||||
element.style.display = element.itemcompleted === "true" ? "block" : "none";
|
||||
break;
|
||||
case "active":
|
||||
element.style.display = element.completed === "true" ? "none" : "block";
|
||||
element.style.display = element.itemcompleted === "true" ? "none" : "block";
|
||||
break;
|
||||
default:
|
||||
element.style.display = "block";
|
||||
|
|
@ -92,13 +96,12 @@ class TodoList extends HTMLElement {
|
|||
case "toggle-item":
|
||||
case "add-item":
|
||||
this.#elements.forEach((element) => {
|
||||
if (element.id === id)
|
||||
if (element.itemid === id)
|
||||
this.updateView(element);
|
||||
});
|
||||
break;
|
||||
case "remove-item":
|
||||
this.#elements = this.#elements.filter((element) => element.id !== id);
|
||||
|
||||
this.#elements = this.#elements.filter((element) => element.itemid !== id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue