forked from cory/tildefriends
		
	
		
			
				
	
	
		
			212 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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);
 |