Commit add71117 authored by Alex Kit's avatar Alex Kit

Atma.js: update and refactor (closes GH-816)

parent 935aed05
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"todomvc-common": "~0.1.4", "todomvc-common": "~0.1.4",
"jquery": "~2.0.2" "jquery": "~2.0.2",
"maskjs": "~0.10.1",
"includejs": "~0.9.10",
"ruta": "~0.1.11",
"atma-class": "~1.0.68"
} }
} }
...@@ -6,9 +6,7 @@ ...@@ -6,9 +6,7 @@
<link rel="stylesheet" href="bower_components/todomvc-common/base.css"> <link rel="stylesheet" href="bower_components/todomvc-common/base.css">
</head> </head>
<body> <body>
<!--
<script type="mask/template" id="layout">
/*
TodoMVC Atma.js Application TodoMVC Atma.js Application
...@@ -18,10 +16,10 @@ ...@@ -18,10 +16,10 @@
The application structure guide: The application structure guide:
Controls Overview: - Controls
todo:input; todo:input;
Components Overview: - Components
:app\ :app\
:filter; :filter;
:todoList\ :todoList\
...@@ -39,55 +37,16 @@ ...@@ -39,55 +37,16 @@
app.js app.js
_If the controller loads a template, do not forget to review that._ _If the controller loads a template, do not forget to review that._
*/ -->
// Application Template
section #todoapp {
header #header {
h1 > 'todos'
todo:input #new-todo
autofocus
x-signal = 'enter: newTask'
placeholder = 'What needs to be done?'
;
}
section #main >
:todoList;
footer #footer xx-visible = 'status.count' {
span #todo-count {
strong > '~[bind: status.todoCount]'
span > ' item~[bind: status.todoCount != 1 ? "s"] left'
}
:filter;
button #clear-completed
xx-visible = 'status.completedCount > 0'
x-signal = 'click: removeAllCompleted' {
'Clear completed (~[bind:status.completedCount])'
}
}
}
footer #info {
p { 'Double-click to edit a todo' }
p { 'Created by ' a href='http://github.com/tenbits' > 'tenbits' }
p { 'Part of ' a href='http://todomvc.com' > 'TodoMVC' }
}
</script>
<script src="bower_components/todomvc-common/base.js"></script> <script src="bower_components/todomvc-common/base.js"></script>
<script src="bower_components/jquery/jquery.js"></script> <script src="bower_components/jquery/jquery.js"></script>
<script src="lib/atma-globals-dev.js"></script> <script src="bower_components/includejs/lib/include.js"></script>
<script src="bower_components/atma-class/lib/class.js"></script>
<script src="bower_components/maskjs/lib/mask.js"></script>
<script src="bower_components/ruta/lib/ruta.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
</body> </body>
......
/*jshint newcap:false */ /*jshint newcap:false */
/*global include, Compo */ /*global include, mask, Compo, ruta */
'use strict'; 'use strict';
...@@ -31,32 +31,41 @@ include ...@@ -31,32 +31,41 @@ include
compo: ['todoList', 'filter'] compo: ['todoList', 'filter']
}) })
.ready(function (resp) { .load('./app.mask::Template')
/* Initialize and load the model from the Store */ .ready(function (resp) {
var todos = resp.Todos.fetch();
var Application = Compo({ mask.registerHandler(':app', Compo({
template: '#layout', template: resp.load.Template,
model: resp.Todos.fetch(),
scope: {
action: ''
},
slots: { slots: {
newTask: function (event, title) { newTask: function (event, title) {
if (title) { if (title) {
this.model.create(title); this.model.create(title);
} }
}, },
removeAllCompleted: function () { removeAllCompleted: function () {
this.model.del(function (x) {
this
.model
.del(function (x) {
return x.completed === true; return x.completed === true;
}); });
} }
},
onRenderStart: function () {
// (RutaJS) Default router is the History API,
// but for this app spec enable hashes
ruta
.setRouterType('hash')
.add('/?:action', this.applyFilter.bind(this))
.notifyCurrent()
;
},
applyFilter: function (route, params) {
this.scope.action = params.action || '';
} }
}); }));
Compo.initialize(Application, todos, document.body); Compo.initialize(':app', document.body);
}); });
\ No newline at end of file
section #todoapp {
header #header {
h1 > 'todos'
todo:input #new-todo
autofocus
placeholder = 'What needs to be done?'
x-signal = 'enter: newTask'
;
}
+if (status.count) {
section #main >
:todoList;
footer #footer {
span #todo-count {
strong > '~[bind: status.todoCount]'
span > ' item~[bind: status.todoCount != 1 ? "s"] left'
}
:filter;
+if (status.completedCount > 0) {
button #clear-completed x-signal = 'click: removeAllCompleted' >
'Clear completed (~[bind:status.completedCount])'
}
}
}
}
footer #info {
p { 'Double-click to edit a todo' }
p { 'Created by ' a href='http://github.com/tenbits' > 'tenbits' }
p { 'Part of ' a href='http://todomvc.com' > 'TodoMVC' }
}
\ No newline at end of file
...@@ -48,24 +48,22 @@ ...@@ -48,24 +48,22 @@
}, },
'blur': 'save' 'blur': 'save'
}, },
focus: function focus() { focus: function () {
this.$.focus(); this.$.focus();
}, },
cancel: function cancel() { cancel: function () {
this.$.trigger('cancel'); this.$.trigger('cancel');
this.afterEdit(); this.afterEdit();
}, },
save: function save() { save: function () {
var value = this.$.val().trim(); var value = this.$.val().trim();
this.$.trigger('enter', value); this.$.trigger('enter', value);
this.afterEdit(); this.afterEdit();
}, },
afterEdit: function () { afterEdit: function () {
this.$.val(this.attr.preserve ? this.model.title : ''); this.$.val(this.attr.preserve ? this.model.title : '');
} }
......
...@@ -12,61 +12,7 @@ include ...@@ -12,61 +12,7 @@ include
.done(function (resp) { .done(function (resp) {
'use strict'; 'use strict';
// `Compo` function creates components constructor,
// but it doesnt have ClassJS features, like inhertince and
// others. With `Compo.createClass`(_if ClassJS is used_) we
// can use those features in components constructor
mask.registerHandler(':filter', Compo.createClass({ mask.registerHandler(':filter', Compo.createClass({
template: resp.load.Template, template: resp.load.Template
onRenderStart: function () {
ruta
// (RutaJS) Default router is the History API,
// but for this APP use hashes
.setRouterType('hash')
// Note: we do not bind to `this` compo instance,
// as applyFilter is already bound to it.
.add('/?:action', this.applyFilter)
;
// Define filters model
this.model = [{
title: 'All',
action: ''
}, {
title: 'Active',
action: 'active'
}, {
title: 'Completed',
action: 'completed'
}];
this.applyFilter(ruta.current());
},
Self: {
applyFilter: function (route) {
this.action = _setSelectedFilter(route.current, this.model);
// Emit a signal 'action' in a 'filter' pipe
Compo.pipe('filter').emit('action', this.action);
}
}
})); }));
function _setSelectedFilter(route, filters) {
var action = route.params.action || '';
// Update View via Binding
filters.forEach(function (filter) {
filter.selected = action === filter.action ? 'selected' : '';
});
return action;
}
}); });
var filters = {
'' : 'All',
'active': 'Active',
'completed': 'Completed'
};
ul #filters > ul #filters >
// take each filter item from the array model for ((key, val) in filters) {
% each = '.' > // compare with the scoped value `action`
li > li >
a.~[bind:selected] href = '#~[action]' > a .~[bind: action == key ? 'selected' ] href = '#~[key]' >
'~[title]' '~[val]'
\ No newline at end of file }
\ No newline at end of file
...@@ -6,52 +6,24 @@ ...@@ -6,52 +6,24 @@
* *
* Collection is passed as a model to this component * Collection is passed as a model to this component
*/ */
include include
.load('todoList.mask') .load('todoList.mask')
.js('todoTask/todoTask.js') .js('todoTask/todoTask.js')
.done(function (response) { .done(function (response) {
'use strict'; 'use strict';
mask.registerHandler(':todoList', Compo({ mask.registerHandler(':todoList', Compo({
template: response.load.todoList, template: response.load.todoList,
action: '',
pipes: {
// To manage the communication within hierarchical components
// (ancestors/descendants) you should use `slot-signal` pattern.
//
// To bind any components in an app use `piped_slot-signal` feature.
// Here we listen for signals in the `filter` pipe, which are
// emitted by `:filter` component
filter: {
action: function (action) {
this.action = action;
}
}
},
slots: { slots: {
// Component's slots for the signals, // Component's slots for the signals
// defined in the template and in a single tasks's template
toggleAll: function (event) { toggleAll: function (event) {
this var completed = event.currentTarget.checked;
.model this.model.toggleAll(completed);
.each(function (task) {
task.completed = event.currentTarget.checked;
})
.save();
}, },
taskChanged: function () { taskChanged: function () {
this.model.save(); this.model.save();
}, },
taskRemoved: function (event, task) { taskRemoved: function (event, task) {
this.model.del(task); this.model.del(task);
} }
......
input#toggle-all input #toggle-all
type = 'checkbox' type = checkbox
checked = '~[bind: status.todoCount == 0 ? "checked" ]' checked = '~[bind: status.todoCount == 0 ? "checked" ]'
x-signal = 'click: toggleAll' x-signal = 'click: toggleAll'
// bind and hide/show accordingly
xx-visible = 'status.count'
; ;
label for = 'toggle-all' >
'Mark all as complete' label for='toggle-all' > 'Mark all as complete'
ul#todo-list {
// binded todos array ul #todo-list {
%% each = '.' > // bind todos collection
:todoTask; +each (.) > :todoTask;
} }
\ No newline at end of file
...@@ -109,7 +109,7 @@ navigate to ``` http://localhost:5777/ ``` ...@@ -109,7 +109,7 @@ navigate to ``` http://localhost:5777/ ```
### Build ### Build
To build the application for release, run ``` $ atma ```. We provide also a compiled version in 'build/' directory, so you To build the application for release, run ``` $ atma build --file index.html --output release/```. We provide also a compiled version in 'build/' directory, so you
can see how the application looks like for production. can see how the application looks like for production.
......
...@@ -217,6 +217,9 @@ ...@@ -217,6 +217,9 @@
}, { }, {
"name": "Atma.js on GitHub", "name": "Atma.js on GitHub",
"url": "https://github.com/atmajs" "url": "https://github.com/atmajs"
}, {
"name": "Atma.js DevTool",
"url": "https://chrome.google.com/webstore/detail/atmajs-devtool/bpaepkmcmoablpdahclhdceapndfhdpo"
}] }]
}, { }, {
"heading": "Overview", "heading": "Overview",
......
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