complete base implementation of todoapp

This commit is contained in:
Géry Debongnie
2019-03-20 13:36:37 +01:00
parent 9baf3ad4a7
commit c32f1d1e38
5 changed files with 104 additions and 33 deletions
+19 -6
View File
@@ -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 = "";
}
+38
View File
@@ -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
View File
@@ -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;
}
+17 -5
View File
@@ -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>
-1
View File
@@ -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, "");