diff --git a/js/examples/todo/index.html b/js/examples/todo/index.html
index c3a8070..0d6251d 100644
--- a/js/examples/todo/index.html
+++ b/js/examples/todo/index.html
@@ -27,14 +27,14 @@
-
+
-
+
diff --git a/js/examples/todo/index.js b/js/examples/todo/index.js
index 7b49c33..9069600 100644
--- a/js/examples/todo/index.js
+++ b/js/examples/todo/index.js
@@ -1,30 +1,53 @@
-assertion type todo(id, task, completed);
+assertion type todo(id, title, completed);
message type deleteTodo(id);
assertion type show(completed);
assertion type currentLocationHash(hash);
+/*
+ To Do (ho ho ho)
+ spec is at: https://github.com/tastejs/todomvc/blob/master/app-spec.md
+
+ - file layout?
+ - README
+ - pattern the HTML more explicitly on the given template, keep changes to a minimum
+ - code style https://github.com/tastejs/todomvc/blob/master/contributing.md#code-style
+
+ - no todos: make sure #main and #footer are hidden
+ - mark all as complete/incomplete; make sure it is only ever checked when all the todos are checked
+ - count of active todos; pluralize correctly; format correctly
+ - hide "clear completed" button when no completed todos exist
+ - persist to localStorage; use correct keys and name.
+
+ - routing: spec requires that filtering be done "on a model level";
+ we, by using "hidden" class, are kind of partly doing it on a view
+ level. We could either continue to do this, or switch to a proper
+ model level approach, but then we'd lose stability of ordering!
+ */
+
+var ESCAPE_KEY_CODE = 27;
+var ENTER_KEY_CODE = 13;
+
var nextId = 0;
-function addTodo(task) {
+function addTodo(title) {
+ title = title.trim();
+ if (!title) return;
+
actor {
this.id = nextId++;
this.ui = new Syndicate.UI.Anchor();
- this.task = task;
+ this.title = title;
this.completed = false;
this.editing = false;
this.visible = false;
react {
- assert todo(this.id, this.task, this.completed);
+ assert todo(this.id, this.title, this.completed);
+
during show(this.completed) {
- do {
- this.visible = true;
- console.log('shown', this.id, this.task, this.visible);
- }
- finally {
- this.visible = false;
- console.log('hidden', this.id, this.task, this.visible);
- }
+ do { this.visible = true; }
+ finally { this.visible = false; }
}
+
assert this.ui.html('#todo-list',
Mustache.render($(this.editing
? '#todo-list-item-edit-template'
@@ -34,21 +57,44 @@ function addTodo(task) {
hidden_class: this.visible ? "" : "hidden",
id: this.id,
checked: this.completed ? "checked" : "",
- task: this.task
+ title: this.title
}));
+
on message this.ui.event('.toggle', 'change', $e) {
this.completed = e.target.checked;
}
+
on message this.ui.event('.destroy', 'click', _) {
- console.log('destroy clicked');
:: deleteTodo(this.id);
}
+
on message this.ui.event('label', 'dblclick', _) {
+ var self = this;
this.editing = true;
+ focusMe(); // TODO this is gross
+ function focusMe() {
+ setTimeout(function () {
+ var q = 'li[data-id="'+self.id+'"] input.edit';
+ var n = document.querySelector(q);
+ if (!n) { return focusMe(); }
+ n.focus();
+ n.setSelectionRange(n.value.length, n.value.length);
+ }, 0);
+ }
+ }
+
+ on message this.ui.event('input.edit', 'keyup', $e) {
+ if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
+ this.editing = false;
+ }
+ }
+ on message this.ui.event('input.edit', 'blur', $e) {
+ this.editing = false;
}
on message this.ui.event('input.edit', 'change', $e) {
- this.task = e.target.value;
+ this.title = e.target.value.trim();
this.editing = false;
+ if (!this.title) :: deleteTodo(this.id);
}
} until {
case message deleteTodo(this.id);
@@ -84,17 +130,22 @@ ground dataspace G {
actor {
react {
+ on asserted currentLocationHash($hash) {
+ // TODO this is a bit icky too
+ var ns = document.querySelectorAll('ul.filters > li > a');
+ for (var i = 0; i < ns.length; i++) { ns[i].className = ''; }
+ var n = document.querySelector('ul.filters > li > a[href="#'+hash+'"]');
+ n.className = 'selected';
+ }
+
during currentLocationHash('/') {
- do { console.log('set hash to /'); }
assert show(true);
assert show(false);
}
during currentLocationHash('/active') {
- do { console.log('set hash to /active'); }
assert show(false);
}
during currentLocationHash('/completed') {
- do { console.log('set hash to /completed'); }
assert show(true);
}
}