can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
181 lines (152 loc) • 4.72 kB
HTML
<html>
<head>
<style>
label {
width: 200px;
display: inline-block;
}
li {
border: solid 1px white;
}
.selected {
background-color: #d1ecf1;
border-color: #bee5eb;
}
</style>
</head>
<body>
<todo-app></todo-app>
<script src="../../node_modules/steal/steal.js" dev-bundle></script>
<script type="steal-module" id="demo-source">
import {
fixture,
ObservableArray,
ObservableObject,
restModel,
StacheElement,
type,
} from "can";
class Todo extends ObservableObject {
static props = {
id: { type: type.maybeConvert(Number), identity: true },
complete: { type: type.maybeConvert(Boolean), default: false },
dueDate: {
type: type.maybeConvert(Date),
get default() {
return new Date();
}
},
name: type.maybeConvert(String)
};
preventSave() {
return !this.name || this.isSaving();
}
}
class TodoListModel extends ObservableArray {
static items = type.maybeConvert(Todo);
}
const todoConnection = restModel({
Map: Todo,
List: TodoListModel,
url: "/api/todos/{id}"
});
let terms = ["can you","please","","","",""],
verbs = ["clean","walk","do","vaccum","organize","fold","wash","dust","pay","cook","get","take out"],
subjects = ["dog","laundry","diapers","clothes","car","windows","carpet","taxes","food","gas","trash"];
let dayInMS = 24*60*60*1000;
let lastWeek = new Date() - (7*dayInMS);
let fourWeeks = new Date().getTime() + (4*7*dayInMS);
let todoStore = fixture.store(10, function(){
return {
complete: fixture.rand([true, false],1)[0],
dueDate: new Date( fixture.rand(lastWeek, fourWeeks) ).toString(),
name: (fixture.rand(terms,1)[0]+" "+fixture.rand(verbs,1)[0]+" "+fixture.rand(subjects,1)[0]).trim()
}
}, Todo);
fixture("/api/todos/{id}", todoStore);
fixture.delay = 1000;
class TodoUpdate extends StacheElement {
static view = `
{{# if(todo) }}
<h3>Update Todo</h3>
<form on:submit="updateTodo(scope.element, scope.event)">
<p>
<label>Name</label>
<input name="name" value:from='todo.name' />
</p>
<p>
<label>Complete</label>
<input type='checkbox' name='complete'
checked:from='todo.complete'/>
</p>
<p>
<label>Date</label>
<input type='date'
name='dueDate' valueAsDate:from='todo.dueDate'/>
</p>
<button disabled:from="todo.preventSave()">
{{# if(todo.isSaving()) }}Updating{{ else }}Update{{/ if }}Todo
</button>
<button disabled:from="todo.preventSave()"
on:click="cancelEdit()">Cancel</button>
</form>
{{ else }}
<i>Click a todo above to edit it here.</i>
{{/ if }}
`;
static props = {
todo: type.maybeConvert(Todo)
};
updateTodo(form, event) {
event.preventDefault();
this.todo.assign({
name: form.name.value,
complete: form.complete.checked,
dueDate: form.dueDate.valueAsDate
}).save().then(this.cancelEdit.bind(this))
}
cancelEdit() {
this.todo = null;
}
}
customElements.define("todo-update", TodoUpdate);
class TodoList extends StacheElement {
static view = `
<ul>
{{# if(this.todosPromise.isResolved) }}
{{# for(todo of this.todosPromise.value) }}
<li on:click="this.select(todo)"
class="{{# eq(todo, this.selected) }}selected{{/ eq }}">
<input type='checkbox' checked:bind='todo.complete' disabled/>
<label>{{ todo.name }}</label>
</li>
{{/ for }}
{{/ if }}
{{# if(this.todosPromise.isPending) }}
<li>Loading</li>
{{/ if }}
</ul>
`;
static props = {
todosPromise: {
get default() {
return Todo.getList({});
}
},
selected: type.maybeConvert(Todo)
};
select(todo) {
this.selected = todo;
}
}
customElements.define("todo-list", TodoList);
class TodoApp extends StacheElement {
static view = `
<todo-list selected:bind="scope.vars.selected"></todo-list>
<todo-update todo:bind="scope.vars.selected"></todo-update>
`;
}
customElements.define("todo-app", TodoApp);
</script>
</body>
</html>