tildefriends/apps/todo/script.js

212 lines
4.6 KiB
JavaScript

import {LitElement, html} from './lit-core.min.js';
import * as tfrpc from '/static/tfrpc.js';
class TodosElement extends LitElement {
static get properties() {
return {
lists: {type: Array},
};
}
constructor() {
super();
this.lists = [];
let self = this;
tfrpc.rpc
.todo_get_all()
.then(function (lists) {
self.lists = lists;
})
.catch(function (error) {
console.log(error);
});
}
async new_list() {
await tfrpc.rpc.todo_add('new list');
await this.refresh();
}
async refresh() {
this.lists = await tfrpc.rpc.todo_get_all();
}
render() {
return html`
<div>
<div style="display: flex">
${this.lists.map(
(x) => html`
<tf-todo-list
name=${x.name}
.items=${x.items}
@change=${this.refresh}
></tf-todo-list>
`
)}
</div>
<input type="button" @click=${this.new_list} value="+ List"></input>
</div>`;
}
}
class TodoListElement extends LitElement {
static get properties() {
return {
name: {type: String},
items: {type: Array},
editing: {type: Number},
editing_name: {type: Boolean},
};
}
constructor() {
super();
this.items = [];
}
save() {
let self = this;
console.log('saving', self.name, self.items);
tfrpc.rpc
.todo_set(self.name, self.items)
.then(function () {
console.log('saved', self.name, self.items);
})
.catch(function (error) {
console.log(error);
});
}
remove_item(item) {
let index = this.items.indexOf(item);
this.items = [].concat(
this.items.slice(0, index),
this.items.slice(index + 1)
);
this.save();
}
handle_check(event, item) {
item.x = event.srcElement.checked;
this.save();
}
input_blur(item) {
this.save();
this.editing = undefined;
}
input_change(event, item) {
item.text = event.srcElement.value;
}
input_keydown(event, item) {
if (event.key === 'Enter' || event.key === 'Escape') {
item.text = event.srcElement.value;
this.editing = undefined;
this.save();
}
}
updated() {
let edit = this.renderRoot.getElementById('edit');
if (edit) {
edit.select();
}
}
render_item(item) {
let index = this.items.indexOf(item);
let self = this;
if (index === this.editing) {
return html`
<div><input type="checkbox" ?checked=${item.x} @change=${(x) => self.handle_check(x, item)}></input>
<input
id="edit"
type="text"
value=${item.text}
@change=${(event) => self.input_change(event, item)}
@keydown=${(event) => self.input_keydown(event, item)}
@blur=${(x) => self.input_blur(item)}></input>
<span @click=${(x) => self.remove_item(item)} style="cursor: pointer">❎</span></div>
`;
} else {
return html`
<div><input type="checkbox" ?checked=${item.x} @change=${(x) => self.handle_check(x, item)}></input>
<span @click=${(x) => (self.editing = index)}>${item.text || '(empty)'}</span>
`;
}
}
add_item() {
this.items = [].concat(this.items || [], [{text: 'new item'}]);
this.editing = this.items.length - 1;
this.save();
}
async remove_list() {
if (confirm(`Are you sure you want to remove "${this.name}"?`)) {
await tfrpc.rpc.todo_remove(this.name);
this.dispatchEvent(new Event('change'));
}
}
rename(new_name) {
let self = this;
return tfrpc.rpc
.todo_rename(this.name, new_name)
.then(function () {
self.dispatchEvent(new Event('change'));
self.editing_name = false;
})
.catch(function (error) {
console.log(error);
alert(error.message);
self.editing_name = false;
});
}
name_blur(new_name) {
this.rename(new_name);
}
name_keydown(event, item) {
let self = this;
if (event.key == 'Enter' || event.key === 'Escape') {
let new_name = event.srcElement.value;
this.rename(new_name);
}
}
render() {
let self = this;
let name = this.editing_name
? html`<input
type="text"
id="edit"
@keydown=${(event) => self.name_keydown(event)}
@blur=${(event) => self.name_blur(event.srcElement.value)}
value=${this.name}></input>`
: html`<h2 @click=${(x) => (this.editing_name = true)}>${this.name}</h2>`;
return html`
<div
style="border: 3px solid black; padding: 8px; margin: 8px; border-radius: 8px; background-color: #444"
>
${name}
${(this.items || [])
.filter((item) => !item.x)
.map((x) => self.render_item(x))}
${(this.items || [])
.filter((item) => item.x)
.map((x) => self.render_item(x))}
<button @click=${self.add_item}>+ Item</button>
<button @click=${self.remove_list}>- List</button>
</div>
`;
}
}
customElements.define('tf-todo-list', TodoListElement);
customElements.define('tf-todos', TodosElement);