Commit f92ad001 authored by Braden Shepherdson's avatar Braden Shepherdson

Update the FOAM example to the new UI, and also to latest FOAM

parent f2c2be74
{
"name": "todomvc-foam",
"version": "0.0.0",
"dependencies": {
"foam": "0.3.1",
"todomvc-app-css": "~1.0.1",
"todomvc-common": "~1.0.1"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -2,11 +2,10 @@ ...@@ -2,11 +2,10 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>FOAM • TodoMVC</title> <title>FOAM • TodoMVC</title>
<link rel="stylesheet" href="bower_components/todomvc-common/base.css"> <link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="bower_components/todomvc-app-css/index.css"> <link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
<script src="bower_components/foam/build/foam.js"></script> <script src="node_modules/todomvc-common/base.js"></script>
<script src="bower_components/todomvc-common/base.js"></script> <script src="build/foam.js"></script>
<script src="Todo.js"></script>
</head> </head>
<body><foam id="todo" model="Controller" showActions="false"></foam></body> <body><foam id="todo" model="com.todomvc.Controller" showActions="false"></foam></body>
</html> </html>
...@@ -3,94 +3,52 @@ ...@@ -3,94 +3,52 @@
// Necessary JSHint options. CLASS is not a constructor, just a global function. // Necessary JSHint options. CLASS is not a constructor, just a global function.
/* jshint newcap: false */ /* jshint newcap: false */
// These are provided by FOAM (up through EasyDAO) or defined in this file. // These are provided by FOAM (up through EasyDAO) or defined in this file.
/* global CLASS, TRUE, SET, NOT, GROUP_BY, COUNT, EasyDAO, Todo, TodoDAO */ /* global CLASS, TRUE, SET, GROUP_BY, COUNT */
CLASS({
name: 'TodoDAO',
extendsModel: 'ProxyDAO',
methods: {
put: function (issue, s) {
// If the user tried to put an empty text, remove the entry instead.
if (!issue.text) {
this.remove(issue.id, { remove: s && s.put });
} else {
this.SUPER(issue, s);
}
}
}
});
CLASS({
name: 'Todo',
properties: [
'id',
{ name: 'completed', model_: 'BooleanProperty' },
{ name: 'text', preSet: function (_, text) { return text.trim(); } }
],
templates: [function toDetailHTML() {/*
<li id="%%id">
<div class="view">
$$completed{className: 'toggle'}
$$text{mode: 'read-only', tagName: 'label'}
<button class="destroy" id="<%= this.on('click', function () { this.parent.dao.remove(this.data); }) %>"></button>
</div>
$$text{className: 'edit'}
</li>
<%
var toEdit = function () { DOM.setClass(this.$, 'editing'); this.textView.focus(); }.bind(this);
var toDisplay = function () { DOM.setClass(this.$, 'editing', false); }.bind(this);
this.on('dblclick', toEdit, this.id);
this.on('blur', toDisplay, this.textView.id);
this.textView.subscribe(this.textView.ESCAPE, toDisplay);
this.setClass('completed', function () { return this.data.completed; }.bind(this), this.id);
%> */}]
});
// Needed to massage the HTML to fit TodoMVC spec; it works without this.
CLASS({
name: 'TodoFilterView',
extendsModel: 'ChoiceListView',
methods: {
choiceToHTML: function (id, choice) {
var self = this;
this.setClass('selected', function () { return self.label === choice[1]; }, id);
return '<li><a id="' + id + '" class="choice" href="javascript:;">' + choice[1] + '</a></li>';
}
}
});
CLASS({ CLASS({
package: 'com.todomvc',
name: 'Controller', name: 'Controller',
traits: ['foam.ui.CSSLoaderTrait'],
requires: ['foam.ui.TextFieldView', 'foam.ui.DAOListView', 'foam.dao.EasyDAO', 'foam.memento.WindowHashValue',
'com.todomvc.Todo', 'com.todomvc.TodoDAO', 'com.todomvc.TodoFilterView'],
properties: [ properties: [
{ {
name: 'input', name: 'input',
setter: function (text) { setter: function (text) {
// This is a fake property that adds the todo when its value gets saved. // This is a fake property that adds the todo when its value gets saved.
if (!text) { return; } if (text) {
this.dao.put(Todo.create({text: text})); this.dao.put(this.Todo.create({text: text}));
this.propertyChange('input', text, ''); this.propertyChange('input', text, '');
}
}, },
view: { factory_: 'TextFieldView', placeholder: 'What needs to be done?' } view: { factory_: 'foam.ui.TextFieldView', placeholder: 'What needs to be done?' }
}, },
{ name: 'dao' }, { name: 'dao' },
{ name: 'filteredDAO', model_: 'DAOProperty', view: 'DAOListView' }, { name: 'filteredDAO', model_: 'foam.core.types.DAOProperty', view: 'foam.ui.DAOListView' },
{ name: 'completedCount', model_: 'IntProperty' }, { name: 'completedCount', model_: 'IntProperty' },
{ name: 'activeCount', model_: 'IntProperty', postSet: function (_, c) { this.toggle = !c; }}, { name: 'activeCount', model_: 'IntProperty', postSet: function (_, c) { this.toggle = !c; }},
{ name: 'toggle', model_: 'BooleanProperty', postSet: function (_, n) { { name: 'toggle', model_: 'BooleanProperty', postSet: function (_, n) {
if (n === (this.activeCount > 0)) { this.dao.update(SET(Todo.COMPLETED, n)); } if (n === this.activeCount > 0) {
this.dao.update(SET(this.Todo.COMPLETED, n));
}
}}, }},
{ {
name: 'query', name: 'query',
postSet: function (_, q) { this.filteredDAO = this.dao.where(q); }, postSet: function (_, q) { this.filteredDAO = this.dao.where(q); },
defaultValue: TRUE, defaultValue: TRUE,
view: { factory_: 'TodoFilterView', choices: [[TRUE, 'All'], [NOT(Todo.COMPLETED), 'Active'], [Todo.COMPLETED, 'Completed']] } view: 'com.todomvc.TodoFilterView'
},
{
name: 'memento',
factory: function () { return this.WindowHashValue.create(); }
} }
], ],
actions: [ actions: [
{ {
name: 'clear', name: 'clear',
labelFn: function () { return 'Clear completed (' + this.completedCount + ')'; }, label: 'Clear completed',
isEnabled: function () { return this.completedCount; }, isEnabled: function () { return this.completedCount; },
action: function () { this.dao.where(Todo.COMPLETED).removeAll(); } action: function () { this.dao.where(this.Todo.COMPLETED).removeAll(); }
} }
], ],
listeners: [ listeners: [
...@@ -98,7 +56,7 @@ ...@@ -98,7 +56,7 @@
name: 'onDAOUpdate', name: 'onDAOUpdate',
isFramed: true, isFramed: true,
code: function () { code: function () {
this.dao.select(GROUP_BY(Todo.COMPLETED, COUNT()))(function (q) { this.dao.select(GROUP_BY(this.Todo.COMPLETED, COUNT()))(function (q) {
this.completedCount = q.groups[true]; this.completedCount = q.groups[true];
this.activeCount = q.groups[false]; this.activeCount = q.groups[false];
}.bind(this)); }.bind(this));
...@@ -108,8 +66,8 @@ ...@@ -108,8 +66,8 @@
methods: { methods: {
init: function () { init: function () {
this.SUPER(); this.SUPER();
this.filteredDAO = this.dao = TodoDAO.create({ this.filteredDAO = this.dao = this.TodoDAO.create({
delegate: EasyDAO.create({model: Todo, seqNo: true, daoType: 'StorageDAO', name: 'todos-foam'}) }); delegate: this.EasyDAO.create({model: this.Todo, seqNo: true, daoType: 'LOCAL', name: 'todos-foam'}) });
this.dao.listen(this.onDAOUpdate); this.dao.listen(this.onDAOUpdate);
this.onDAOUpdate(); this.onDAOUpdate();
} }
...@@ -144,15 +102,15 @@ ...@@ -144,15 +102,15 @@
var f = function () { return this.completedCount + this.activeCount == 0; }.bind(this.data); var f = function () { return this.completedCount + this.activeCount == 0; }.bind(this.data);
this.setClass('hidden', f, 'main'); this.setClass('hidden', f, 'main');
this.setClass('hidden', f, 'footer'); this.setClass('hidden', f, 'footer');
Events.relate(this.X.memento, this.queryView.label$, Events.relate(this.data.memento, this.queryView.text$,
function (memento) { function (memento) {
var s = memento && memento.substring(1); var s = memento && memento.substring(1);
var t = s ? s.capitalize() : 'All'; var t = s ? s.capitalize() : 'All';
return t; return t;
}, },
function (label) { var s = '/' + label.toLowerCase(); console.log('label->memento', label, s); return s; }); function (label) { return '/' + label.toLowerCase(); });
this.addInitializer(function () { this.addInitializer(function () {
$('new-todo').focus(); X.$('new-todo').focus();
}); });
%> %>
*/} */}
......
(function () {
/* global CLASS */
'use strict';
CLASS({
package: 'com.todomvc',
name: 'Todo',
properties: [
'id',
{ name: 'completed', model_: 'BooleanProperty' },
{ name: 'text', preSet: function (_, text) { return text.trim(); } }
],
templates: [
function toDetailHTML() {/*
<li id="%%id">
<div class="view">
$$completed{className: 'toggle'}
$$text{mode: 'read-only', tagName: 'label'}
<button class="destroy" id="<%= this.on('click', function () { this.parent.dao.remove(this.data); }) %>"></button>
</div>
$$text{className: 'edit'}
</li>
<%
var toEdit = function () { DOM.setClass(this.$, 'editing'); this.textView.focus(); }.bind(this);
var toDisplay = function () { DOM.setClass(this.$, 'editing', false); }.bind(this);
this.on('dblclick', toEdit, this.id);
this.on('blur', toDisplay, this.textView.id);
this.textView.subscribe(this.textView.ESCAPE, toDisplay);
this.setClass('completed', function () { return this.data.completed; }.bind(this), this.id);
%>
*/}
]
});
})();
(function () {
/* global CLASS */
'use strict';
CLASS({
package: 'com.todomvc',
name: 'TodoDAO',
extendsModel: 'foam.dao.ProxyDAO',
methods: [
function put(issue, s) {
// If the user tried to put an empty text, remove the entry instead.
if (!issue.text) {
this.remove(issue.id, { remove: s && s.put });
} else {
this.SUPER(issue, s);
}
}
]
});
})();
(function () {
/* global CLASS, TRUE, NOT */
'use strict';
// Needed to massage the HTML to fit TodoMVC spec; it works without this.
CLASS({
package: 'com.todomvc',
name: 'TodoFilterView',
extendsModel: 'foam.ui.ChoiceListView',
requires: ['com.todomvc.Todo'],
properties: [
{
name: 'choices',
factory: function () {
return [[TRUE, 'All'], [NOT(this.Todo.COMPLETED), 'Active'], [this.Todo.COMPLETED, 'Completed']];
}
}
],
methods: [
function choiceToHTML(id, choice) {
var self = this;
this.setClass('selected', function () { return self.text === choice[1]; }, id);
return '<li><a id="' + id + '" class="choice">' + choice[1] + '</a></li>';
}
]
});
})();
...@@ -15,11 +15,9 @@ button { ...@@ -15,11 +15,9 @@ button {
font-weight: inherit; font-weight: inherit;
color: inherit; color: inherit;
-webkit-appearance: none; -webkit-appearance: none;
-ms-appearance: none;
appearance: none; appearance: none;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased; font-smoothing: antialiased;
} }
...@@ -33,7 +31,6 @@ body { ...@@ -33,7 +31,6 @@ body {
margin: 0 auto; margin: 0 auto;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased; font-smoothing: antialiased;
font-weight: 300; font-weight: 300;
} }
...@@ -83,7 +80,6 @@ input[type="checkbox"] { ...@@ -83,7 +80,6 @@ input[type="checkbox"] {
color: rgba(175, 47, 47, 0.15); color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility; -webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility; -moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
...@@ -102,11 +98,9 @@ input[type="checkbox"] { ...@@ -102,11 +98,9 @@ input[type="checkbox"] {
padding: 6px; padding: 6px;
border: 1px solid #999; border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-ms-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased; -moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased; font-smoothing: antialiased;
} }
...@@ -191,7 +185,6 @@ label[for='toggle-all'] { ...@@ -191,7 +185,6 @@ label[for='toggle-all'] {
margin: auto 0; margin: auto 0;
border: none; /* Mobile Safari */ border: none; /* Mobile Safari */
-webkit-appearance: none; -webkit-appearance: none;
-ms-appearance: none;
appearance: none; appearance: none;
} }
...@@ -323,19 +316,10 @@ html #clear-completed:active { ...@@ -323,19 +316,10 @@ html #clear-completed:active {
line-height: 20px; line-height: 20px;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
visibility: hidden;
position: relative; position: relative;
} }
#clear-completed::after { #clear-completed:hover {
visibility: visible;
content: 'Clear completed';
position: absolute;
right: 0;
white-space: nowrap;
}
#clear-completed:hover::after {
text-decoration: underline; text-decoration: underline;
} }
......
...@@ -114,7 +114,12 @@ ...@@ -114,7 +114,12 @@
})({}); })({});
if (location.hostname === 'todomvc.com') { if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-31081062-1', 'auto');
ga('send', 'pageview');
} }
/* jshint ignore:end */ /* jshint ignore:end */
...@@ -228,7 +233,7 @@ ...@@ -228,7 +233,7 @@
xhr.onload = function (e) { xhr.onload = function (e) {
var parsedResponse = JSON.parse(e.target.responseText); var parsedResponse = JSON.parse(e.target.responseText);
if (parsedResponse instanceof Array) { if (parsedResponse instanceof Array) {
var count = parsedResponse.length var count = parsedResponse.length;
if (count !== 0) { if (count !== 0) {
issueLink.innerHTML = 'This app has ' + count + ' open issues'; issueLink.innerHTML = 'This app has ' + count + ' open issues';
document.getElementById('issue-count').style.display = 'inline'; document.getElementById('issue-count').style.display = 'inline';
......
{
"private": true,
"dependencies": {
"todomvc-common": "^1.0.0",
"todomvc-app-css": "^1.0.1"
},
"devDependencies": {
"foam-framework": "0.4.2"
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment