mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
complete base implementation of todoapp
This commit is contained in:
@@ -2,6 +2,8 @@ import { TodoItem } from "./TodoItem.js";
|
||||
|
||||
const { StoreMixin, Component } = odoo.core;
|
||||
|
||||
const ENTER_KEY = 13;
|
||||
|
||||
export class TodoApp extends StoreMixin(Component) {
|
||||
template = "todoapp";
|
||||
widgets = { TodoItem };
|
||||
@@ -11,12 +13,23 @@ export class TodoApp extends StoreMixin(Component) {
|
||||
return this.env.store.state.todos;
|
||||
}
|
||||
|
||||
get visibleTodos() {
|
||||
let todos = this.todos;
|
||||
if (this.state.filter === "active") {
|
||||
todos = todos.filter(t => !t.completed);
|
||||
}
|
||||
if (this.state.filter === "completed") {
|
||||
todos = todos.filter(t => t.completed);
|
||||
}
|
||||
return todos;
|
||||
}
|
||||
|
||||
get allChecked() {
|
||||
return this.todos.every(todo => todo.done);
|
||||
return this.todos.every(todo => todo.completed);
|
||||
}
|
||||
|
||||
get remaining() {
|
||||
return this.todos.filter(todo => !todo.done).length;
|
||||
return this.todos.filter(todo => !todo.completed).length;
|
||||
}
|
||||
|
||||
get remainingText() {
|
||||
@@ -24,10 +37,10 @@ export class TodoApp extends StoreMixin(Component) {
|
||||
}
|
||||
|
||||
addTodo(ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
const text = ev.target.value;
|
||||
if (text.trim()) {
|
||||
this.env.store.dispatch("addTodo", text);
|
||||
if (ev.keyCode === ENTER_KEY) {
|
||||
const title = ev.target.value;
|
||||
if (title.trim()) {
|
||||
this.env.store.dispatch("addTodo", title);
|
||||
}
|
||||
ev.target.value = "";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
const ENTER_KEY = 13;
|
||||
const ESC_KEY = 27;
|
||||
|
||||
export class TodoItem extends odoo.core.Component {
|
||||
template = "todoitem";
|
||||
|
||||
state = { isEditing: false };
|
||||
|
||||
removeTodo() {
|
||||
this.env.store.dispatch("removeTodo", this.props.id);
|
||||
}
|
||||
@@ -8,4 +13,37 @@ export class TodoItem extends odoo.core.Component {
|
||||
toggleTodo() {
|
||||
this.env.store.dispatch("toggleTodo", this.props.id);
|
||||
}
|
||||
|
||||
async editTodo() {
|
||||
await this.updateState({ isEditing: true });
|
||||
this.refs.input.value = "";
|
||||
this.refs.input.focus();
|
||||
this.refs.input.value = this.props.title;
|
||||
}
|
||||
|
||||
handleKeyup(ev) {
|
||||
if (ev.keyCode === ENTER_KEY) {
|
||||
this.updateTitle(ev.target.value);
|
||||
}
|
||||
if (ev.keyCode === ESC_KEY) {
|
||||
ev.target.value = this.props.title;
|
||||
this.updateState({ isEditing: false });
|
||||
}
|
||||
}
|
||||
|
||||
handleBlur(ev) {
|
||||
this.updateTitle(ev.target.value);
|
||||
}
|
||||
updateTitle(title) {
|
||||
const value = title.trim();
|
||||
if (!value) {
|
||||
this.removeTodo(this.props.id);
|
||||
} else {
|
||||
this.env.store.dispatch("editTodo", {
|
||||
id: this.props.id,
|
||||
title: value
|
||||
});
|
||||
this.updateState({ isEditing: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-21
@@ -3,27 +3,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const actions = {
|
||||
addTodo({ commit }, text) {
|
||||
commit("addTodo", text);
|
||||
addTodo({ commit }, title) {
|
||||
commit("addTodo", title);
|
||||
},
|
||||
removeTodo({ commit }, id) {
|
||||
commit("removeTodo", id);
|
||||
},
|
||||
toggleTodo({ state, commit }, id) {
|
||||
const todo = state.todos.find(t => t.id === id);
|
||||
commit("editTodo", { id, done: !todo.done });
|
||||
commit("editTodo", { id, completed: !todo.completed });
|
||||
},
|
||||
clearCompleted({ state, commit }) {
|
||||
state.todos
|
||||
.filter(todo => todo.done)
|
||||
.filter(todo => todo.completed)
|
||||
.forEach(todo => {
|
||||
commit("removeTodo", todo.id);
|
||||
});
|
||||
},
|
||||
toggleAll({ state, commit }, done) {
|
||||
toggleAll({ state, commit }, completed) {
|
||||
state.todos.forEach(todo => {
|
||||
commit("editTodo", { id: todo.id, done });
|
||||
commit("editTodo", { id: todo.id, completed });
|
||||
});
|
||||
},
|
||||
editTodo({ commit }, { id, title }) {
|
||||
commit("editTodo", { id, title });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,35 +35,41 @@ const actions = {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const mutations = {
|
||||
addTodo(state, text) {
|
||||
addTodo(state, title) {
|
||||
const id = state.nextId++;
|
||||
const todo = { id, text, done: false };
|
||||
const todo = { id, title, completed: false };
|
||||
state.todos.push(todo);
|
||||
},
|
||||
removeTodo(state, id) {
|
||||
const index = state.todos.findIndex(t => t.id === id);
|
||||
state.todos.splice(index, 1);
|
||||
},
|
||||
editTodo(state, { id, text, done }) {
|
||||
editTodo(state, { id, title, completed }) {
|
||||
const todo = state.todos.find(t => t.id === id);
|
||||
if (text !== undefined) {
|
||||
todo.text = text;
|
||||
if (title !== undefined) {
|
||||
todo.title = title;
|
||||
}
|
||||
if (done !== undefined) {
|
||||
todo.done = done;
|
||||
if (completed !== undefined) {
|
||||
todo.completed = completed;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TodoStore extends odoo.core.Store {
|
||||
commit(...args) {
|
||||
super.commit(...args);
|
||||
window.localStorage.setItem("todos", JSON.stringify(this.state.todos));
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// STORE
|
||||
//------------------------------------------------------------------------------
|
||||
const LOCALSTORAGE_KEY = "todos-odoo";
|
||||
|
||||
export function makeStore() {
|
||||
const todos = JSON.parse(window.localStorage.getItem("todos") || "[]");
|
||||
const todos = JSON.parse(
|
||||
window.localStorage.getItem(LOCALSTORAGE_KEY) || "[]"
|
||||
);
|
||||
const nextId = Math.max(0, ...todos.map(t => t.id || 0)) + 1;
|
||||
const state = { todos, nextId };
|
||||
return new TodoStore({ state, actions, mutations });
|
||||
const store = new odoo.core.Store({ state, actions, mutations });
|
||||
store.on("update", null, () => {
|
||||
const state = JSON.stringify(store.state.todos);
|
||||
window.localStorage.setItem(LOCALSTORAGE_KEY, state);
|
||||
});
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<input class="toggle-all" id="toggle-all" type="checkbox" t-att-checked="allChecked" t-on-click="toggleAll"/>
|
||||
<label for="toggle-all"></label>
|
||||
<ul class="todo-list">
|
||||
<t t-foreach="todos" t-as="todo">
|
||||
<t t-foreach="visibleTodos" t-as="todo">
|
||||
<t t-widget="TodoItem" t-props="todo"/>
|
||||
</t>
|
||||
</ul>
|
||||
@@ -25,20 +25,32 @@
|
||||
</strong>
|
||||
<t t-esc="remainingText"/>
|
||||
</span>
|
||||
<ul class="filters">
|
||||
<li>
|
||||
<a href="#/all" t-on-click="updateState({filter:'all'})" t-att-class="state.filter === 'all' ? 'selected' : ''">All</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/active" t-on-click="updateState({filter:'active'})" t-att-class="state.filter === 'active' ? 'selected' : ''">Active</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#/completed" t-on-click="updateState({filter:'completed'})" t-att-class="state.filter === 'completed' ? 'selected' : ''">Completed</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button class="clear-completed" t-if="todos.length gt remaining" t-on-click="clearCompleted">
|
||||
Clear completed
|
||||
</button>
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
<li t-name="todoitem" class="todo">
|
||||
<li t-name="todoitem" class="todo" t-att-class="(props.completed ? 'completed ' : ' ') + (state.isEditing ? 'editing' : '')">
|
||||
<div class="view">
|
||||
<input class="toggle" type="checkbox" t-on-change="toggleTodo" t-att-checked="props.done"/>
|
||||
<label>
|
||||
<t t-esc="props.text"/>
|
||||
<input class="toggle" type="checkbox" t-on-change="toggleTodo" t-att-checked="props.completed"/>
|
||||
<label t-on-dblclick="editTodo">
|
||||
<t t-esc="props.title"/>
|
||||
</label>
|
||||
<button class="destroy" t-on-click="removeTodo"></button>
|
||||
</div>
|
||||
<input class="edit" t-ref="input" t-if="state.isEditing" t-att-value="props.title" t-on-keyup="handleKeyup" t-on-blur="handleBlur"/>
|
||||
</li>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -35,7 +35,6 @@ function updateAttrs(oldVnode: VNode, vnode: VNode): void {
|
||||
for (key in attrs) {
|
||||
const cur = attrs[key];
|
||||
const old = oldAttrs[key];
|
||||
debugger;
|
||||
if (old !== cur) {
|
||||
if (cur === true) {
|
||||
elm.setAttribute(key, "");
|
||||
|
||||
Reference in New Issue
Block a user