Created
November 27, 2017 21:19
-
-
Save justinbmeyer/ecf98e0ff7bcc166493877438f5c3740 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var todoAlgebra = new can.set.Algebra( | |
set.props.boolean("complete"), | |
set.props.id("id"), | |
set.props.sort("sort") | |
); | |
var todoStore = can.fixture.store([{ | |
name: "mow lawn", | |
complete: false, | |
id: 5 | |
}, | |
{ | |
name: "dishes", | |
complete: true, | |
id: 6 | |
}, | |
{ | |
name: "learn canjs", | |
complete: false, | |
id: 7 | |
} | |
], todoAlgebra); | |
can.fixture("/api/todos", todoStore); | |
can.fixture.delay = 1000; | |
class Todo extends can.Object { | |
constructor(props) { | |
super(props); | |
if (!this.hasOwnProperty("complete")) { | |
this.complete = false; | |
} | |
} | |
} | |
class TodoList extends can.Array { | |
get active() { | |
return this.filter(function(todo) { | |
return todo.complete === false; | |
}); | |
} | |
get complete() { | |
return this.filter(function(todo) { | |
return todo.complete === true; | |
}); | |
} | |
get allComplete() { | |
return this.length === this.complete.length; | |
} | |
get saving() { | |
return this.filter(function(todo) { | |
return todo.isSaving(); | |
}); | |
} | |
updateCompleteTo(value) { | |
this.forEach(function(todo) { | |
todo.complete = value; | |
todo.save(); | |
}); | |
} | |
destroyComplete() { | |
this.complete.forEach(function(todo) { | |
todo.destroy(); | |
}); | |
} | |
} | |
can.connect.baseMap({ | |
url: "/api/todos", | |
Map: Todo, | |
List: TodoList, | |
name: "todo", | |
algebra: todoAlgebra | |
}); | |
class TodoCreateVM extends can.Object { | |
constructor(props) { | |
super(props); | |
this.todo = new Todo(); | |
} | |
createTodo() { | |
this.todo.save().then(() => { | |
this.todo = new Todo(); | |
}); | |
} | |
} | |
can.tag("todo-create", TodoCreateVM, ` | |
<input id="new-todo" | |
placeholder="What needs to be done?" | |
value:bind="todo.name" | |
on:enter="createTodo()"/> | |
`); | |
class TodoListVM extends observe.Object { | |
isEditing(todo) { | |
return todo === this.editing; | |
} | |
edit(todo) { | |
this.backupName = todo.name; | |
this.editing = todo; | |
} | |
cancelEdit() { | |
if (this.editing) { | |
this.editing.name = this.backupName; | |
} | |
this.editing = null; | |
} | |
updateName() { | |
this.editing.save(); | |
this.editing = null; | |
} | |
} | |
can.tag("todo-list", TodoListVM, ` | |
<ul id="todo-list"> | |
{{#each(todos)}} | |
<li class="todo {{#if(./complete)}}completed{{/if}} | |
{{#if( isDestroying() )}}destroying{{/if}} | |
{{#if(../isEditing(this))}}editing{{/if}}"> | |
<div class="view"> | |
<input class="toggle" type="checkbox" checked:bind="complete"> | |
<label on:dblclick="../edit(this)">{{name}}</label> | |
<button class="destroy" on:click="destroy()"></button> | |
</div> | |
<input class="edit" type="text" | |
value:bind="name" | |
on:enter="../updateName()" | |
focused:from="../isEditing(this)" | |
on:blur="../cancelEdit()"/> | |
</li> | |
{{/each}} | |
</ul> | |
`) | |
class AppVM extends observe.Object { | |
constructor(props) { | |
super(props); | |
// needs to not be enumerable | |
Object.defineProperty(this, "todosList", { | |
enumerable: false, | |
value: null, | |
configurable: true, | |
writable: true | |
}); | |
} | |
connectedCallback() { | |
this.listenTo("todosPromise", (promise) => { | |
promise.then((todos) => { | |
this.todosList = todos; | |
}); | |
}); | |
this.todosPromise.then((todos) => { | |
console.log(JSON.stringify(todos)); | |
this.todosList = todos; | |
}); | |
return this.stopListening.bind(this); | |
} | |
get todosPromise() { | |
console.log("todosPromise"); | |
if (!this.filter) { | |
return Todo.getList({}); | |
} else { | |
return Todo.getList({ | |
complete: this.filter === "complete" | |
}); | |
} | |
} | |
get allChecked() { | |
return this.todosList && this.todosList.allComplete; | |
} | |
set allChecked(newVal) { | |
this.todosList && this.todosList.updateCompleteTo(newVal); | |
} | |
} | |
route.data = new AppVM(); | |
route("{filter}"); | |
route.start(); | |
can.tag("todo-mvc", route.data, ` | |
<section id="todoapp"> | |
<header id="header"> | |
<h1>todos</h1> | |
<todo-create/> | |
</header> | |
<section id="main" class=""> | |
<input id="toggle-all" type="checkbox" | |
checked:bind="allChecked" | |
disabled:from="todosList.saving.length"/> | |
<label for="toggle-all">Mark all as complete</label> | |
<todo-list todos:from="todosPromise.value"/> | |
</section> | |
<footer id="footer" class=""> | |
<span id="todo-count"> | |
<strong>{{todosPromise.value.active.length}}</strong> items left | |
</span> | |
<ul id="filters"> | |
<li> | |
<a href="{{routeUrl(filter=undefined)}}" | |
{{#routeCurrent(filter=undefined)}}class='selected'{{/routeCurrent}}>All</a> | |
</li> | |
<li> | |
<a href="{{routeUrl(filter='active')}}" | |
{{#routeCurrent(filter='active')}}class='selected'{{/routeCurrent}}>Active</a> | |
</li> | |
<li> | |
<a href="{{routeUrl(filter='complete')}}" | |
{{#routeCurrent(filter='complete')}}class='selected'{{/routeCurrent}}>Completed</a> | |
</li> | |
</ul> | |
<button id="clear-completed" | |
on:click="todosList.destroyComplete()"> | |
Clear completed ({{todosPromise.value.complete.length}}) | |
</button> | |
</footer> | |
</section> | |
`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment