Skip to content

Instantly share code, notes, and snippets.

@justinbmeyer
Created November 27, 2017 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save justinbmeyer/ecf98e0ff7bcc166493877438f5c3740 to your computer and use it in GitHub Desktop.
Save justinbmeyer/ecf98e0ff7bcc166493877438f5c3740 to your computer and use it in GitHub Desktop.
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