From 19b10f7c1dad52c4cd21855886f77704ac5bd2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 10 Oct 2019 17:17:42 +0200 Subject: [PATCH] [IMP] playground: update todoapp sample --- tools/playground/samples.js | 178 +++++++++++++++++------------------- 1 file changed, 86 insertions(+), 92 deletions(-) diff --git a/tools/playground/samples.js b/tools/playground/samples.js index d777ecb8..52b27b6c 100644 --- a/tools/playground/samples.js +++ b/tools/playground/samples.js @@ -385,99 +385,94 @@ const TODO_APP_STORE = `// This example is an implementation of the TodoList app // In this implementation, we use the owl Store class to manage the state. It // is very similar to the VueX store. const { Component, useState } = owl; -const { useRef } = owl.hooks; +const { useRef, useStore, useDispatch, onPatched, onMounted } = owl.hooks; +//------------------------------------------------------------------------------ +// Constants, helpers +//------------------------------------------------------------------------------ const ENTER_KEY = 13; const ESC_KEY = 27; const LOCALSTORAGE_KEY = "todomvc"; +function useAutofocus(name) { + let ref = useRef(name); + let isInDom = false; + function updateFocus() { + if (!isInDom && ref.el) { + isInDom = true; + const current = ref.el.value; + ref.el.value = ""; + ref.el.focus(); + ref.el.value = current; + } else if (isInDom && !ref.el) { + isInDom = false; + } + } + onPatched(updateFocus); + onMounted(updateFocus); +} + //------------------------------------------------------------------------------ -// Store Definition +// Store //------------------------------------------------------------------------------ +const initialState = { todos: [], nextId: 1}; + const actions = { addTodo({ state }, title) { - state.todos.push({ + const todo = { id: state.nextId++, title, completed: false - }); + } + state.todos.push(todo); }, removeTodo({ state }, id) { const index = state.todos.findIndex(t => t.id === id); state.todos.splice(index, 1); }, - toggleTodo({ state, dispatch }, id) { + updateTodo({state, dispatch}, {id, title}) { + const value = title.trim(); + if (!value) { + dispatch('removeTodo', id); + } else { + const todo = state.todos.find(t => t.id === id); + todo.title = value; + } + }, + toggleTodo({ state }, id) { const todo = state.todos.find(t => t.id === id); - dispatch("editTodo", { id, completed: !todo.completed }); + todo.completed = !todo.completed; }, clearCompleted({ state, dispatch }) { - state.todos - .filter(todo => todo.completed) - .forEach(todo => { + for (let todo of state.todos) { + if (todo.completed) { dispatch("removeTodo", todo.id); - }); + } + } }, toggleAll({ state, dispatch }, completed) { - state.todos.forEach(todo => { - dispatch("editTodo", { - id: todo.id, - completed - }); - }); - }, - editTodo({ state }, { id, title, completed }) { - const todo = state.todos.find(t => t.id === id); - if (title !== undefined) { - todo.title = title; - } - if (completed !== undefined) { + for (let todo of state.todos) { todo.completed = completed; } - } + }, }; -function saveState(state) { - const str = JSON.stringify(state); - window.localStorage.setItem(LOCALSTORAGE_KEY, str); -} - -function loadState() { - const localState = window.localStorage.getItem(LOCALSTORAGE_KEY); - return localState ? JSON.parse(localState) : { todos: [], nextId: 1}; -} - -function makeStore() { - const state = loadState(); - const store = new owl.store.Store({ state, actions }); - store.on("update", null, () => saveState(store.state)); - return store; -} - //------------------------------------------------------------------------------ // TodoItem //------------------------------------------------------------------------------ class TodoItem extends Component { state = useState({ isEditing: false }); - inputRef = useRef("input"); + dispatch = useDispatch(); - removeTodo() { - this.env.store.dispatch("removeTodo", this.props.id); + constructor(...args) { + super(...args); + useAutofocus("input"); } - toggleTodo() { - this.env.store.dispatch("toggleTodo", this.props.id); - } - - async editTodo() { + editTodo() { this.state.isEditing = true; } - focusInput() { - this.inputRef.el.value = ""; - this.inputRef.el.focus(); - this.inputRef.el.value = this.props.title; - } - handleKeyup(ev) { if (ev.keyCode === ENTER_KEY) { this.updateTitle(ev.target.value); @@ -493,48 +488,34 @@ class TodoItem extends Component { } 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.state.isEditing = false; - } + this.dispatch("updateTodo", {title, id: this.props.id}); + this.state.isEditing = false; } } //------------------------------------------------------------------------------ // TodoApp //------------------------------------------------------------------------------ -class TodoApp extends owl.store.ConnectedComponent { +class TodoApp extends Component { static components = { TodoItem }; state = useState({ filter: "all" }); + todos = useStore(state => state.todos); + dispatch = useDispatch(); - static mapStoreToProps(state) { - return { - todos: state.todos - }; - } get visibleTodos() { - let todos = this.storeProps.todos; - if (this.state.filter === "active") { - todos = todos.filter(t => !t.completed); + switch (this.state.filter) { + case "active": return this.todos.filter(t => !t.completed); + case "completed": return this.todos.filter(t => t.completed); + case "all": return this.todos; } - if (this.state.filter === "completed") { - todos = todos.filter(t => t.completed); - } - return todos; } get allChecked() { - return this.storeProps.todos.every(todo => todo.completed); + return this.todos.every(todo => todo.completed); } get remaining() { - return this.storeProps.todos.filter(todo => !todo.completed).length; + return this.todos.filter(todo => !todo.completed).length; } get remainingText() { @@ -560,12 +541,25 @@ class TodoApp extends owl.store.ConnectedComponent { //------------------------------------------------------------------------------ // App Initialization //------------------------------------------------------------------------------ -const store = makeStore(); -const qweb = new owl.QWeb(TEMPLATES); -const env = { - qweb, - store, -}; +function saveState(state) { + const str = JSON.stringify(state); + window.localStorage.setItem(LOCALSTORAGE_KEY, str); +} + +function loadState() { + const localState = window.localStorage.getItem(LOCALSTORAGE_KEY); + return localState ? JSON.parse(localState) : initialState; +} + +function makeEnv() { + const state = loadState(); + const store = new owl.Store({ state, actions }); + store.on("update", null, () => saveState(store.state)); + const qweb = new owl.QWeb(TEMPLATES); + return { qweb, store }; +} + +const env = makeEnv(); const app = new TodoApp(env); app.mount(document.body); `; @@ -576,7 +570,7 @@ const TODO_APP_STORE_XML = `

todos

-
+
    @@ -585,7 +579,7 @@ const TODO_APP_STORE_XML = `
-