mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
9b1c270501
Just fix a little bug when clicked on "Clear Completed" Also removed unusefull method.
179 lines
4.9 KiB
JavaScript
179 lines
4.9 KiB
JavaScript
// This example is an implementation of the TodoList application, from the
|
|
// www.todomvc.com project. This is a non trivial application with some
|
|
// interesting user interactions. It uses the local storage for persistence.
|
|
//
|
|
// In this implementation, we use the owl reactivity mechanism.
|
|
import { Component, useState, mount, useRef, reactive, useEnv, useEffect } from "@odoo/owl";
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Constants, helpers
|
|
//------------------------------------------------------------------------------
|
|
const ENTER_KEY = 13;
|
|
const ESC_KEY = 27;
|
|
|
|
function useAutofocus(name) {
|
|
let ref = useRef(name);
|
|
useEffect(el => el && el.focus(), () => [ref.el]);
|
|
}
|
|
|
|
function useStore() {
|
|
const env = useEnv();
|
|
return useState(env.store);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Task store
|
|
//------------------------------------------------------------------------------
|
|
class TaskList {
|
|
constructor(tasks) {
|
|
this.tasks = tasks || [];
|
|
const taskIds = this.tasks.map((t) => t.id);
|
|
this.nextId = taskIds.length ? Math.max(...taskIds) + 1 : 1;
|
|
}
|
|
|
|
addTask(text) {
|
|
text = text.trim();
|
|
if (text) {
|
|
const task = {
|
|
id: this.nextId++,
|
|
text: text,
|
|
isCompleted: false,
|
|
};
|
|
this.tasks.push(task);
|
|
}
|
|
}
|
|
|
|
toggleTask(id) {
|
|
const task = this.tasks.find(t => t.id === id);
|
|
task.isCompleted = !task.isCompleted;
|
|
}
|
|
|
|
toggleAll(value) {
|
|
for (let task of this.tasks) {
|
|
task.isCompleted = value;
|
|
}
|
|
}
|
|
|
|
clearCompleted() {
|
|
const tasks = this.tasks.filter(t => t.isCompleted);
|
|
for (let task of tasks) {
|
|
this.deleteTask(task.id);
|
|
}
|
|
}
|
|
|
|
deleteTask(id) {
|
|
const index = this.tasks.findIndex((t) => t.id === id);
|
|
this.tasks.splice(index, 1);
|
|
}
|
|
|
|
updateTask(id, text) {
|
|
const value = text.trim();
|
|
if (!value) {
|
|
this.deleteTask(id);
|
|
} else {
|
|
const task = this.tasks.find(t => t.id === id);
|
|
task.text = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
function createTaskStore() {
|
|
const saveTasks = () => localStorage.setItem("todoapp", JSON.stringify(taskStore.tasks));
|
|
const initialTasks = JSON.parse(localStorage.getItem("todoapp") || "[]");
|
|
const taskStore = reactive(new TaskList(initialTasks), saveTasks);
|
|
saveTasks();
|
|
return taskStore;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Todo
|
|
//------------------------------------------------------------------------------
|
|
class Todo extends Component {
|
|
static template = "Todo";
|
|
|
|
setup() {
|
|
useAutofocus("input");
|
|
this.store = useStore();
|
|
this.state = useState({
|
|
isEditing: false
|
|
});
|
|
}
|
|
|
|
handleKeyup(ev) {
|
|
if (ev.keyCode === ENTER_KEY) {
|
|
this.updateText(ev.target.value);
|
|
}
|
|
if (ev.keyCode === ESC_KEY) {
|
|
ev.target.value = this.props.text;
|
|
this.state.isEditing = false;
|
|
}
|
|
}
|
|
|
|
handleBlur(ev) {
|
|
this.updateText(ev.target.value);
|
|
}
|
|
|
|
updateText(text) {
|
|
this.store.updateTask(this.props.id, text);
|
|
this.state.isEditing = false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// TodoList
|
|
//------------------------------------------------------------------------------
|
|
class TodoList extends Component {
|
|
static template = "TodoList";
|
|
static components = { Todo };
|
|
|
|
setup() {
|
|
this.store = useStore();
|
|
this.state = useState({ filter: "all" });
|
|
}
|
|
|
|
get displayedTasks() {
|
|
const tasks = this.store.tasks;
|
|
switch (this.state.filter) {
|
|
case "active":
|
|
return tasks.filter((t) => !t.isCompleted);
|
|
case "completed":
|
|
return tasks.filter((t) => t.isCompleted);
|
|
case "all":
|
|
return tasks;
|
|
}
|
|
}
|
|
|
|
get allChecked() {
|
|
return this.store.tasks.every(todo => todo.isCompleted);
|
|
}
|
|
|
|
get remaining() {
|
|
return this.store.tasks.filter(todo => !todo.isCompleted).length;
|
|
}
|
|
|
|
get remainingText() {
|
|
const items = this.remaining < 2 ? "item" : "items";
|
|
return ` ${items} left`;
|
|
}
|
|
|
|
addTodo(ev) {
|
|
if (ev.keyCode === ENTER_KEY) {
|
|
const text = ev.target.value;
|
|
if (text.trim()) {
|
|
this.store.addTask(text);
|
|
}
|
|
ev.target.value = "";
|
|
}
|
|
}
|
|
|
|
setFilter(filter) {
|
|
this.state.filter = filter;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// App Initialization
|
|
//------------------------------------------------------------------------------
|
|
const env = { store: createTaskStore() };
|
|
mount(TodoList, document.body, { env, templates: TEMPLATES, dev: true });
|