getting started with mulberry
DESCRIPTION
TRANSCRIPT
A Mobile App Development ToolkitRebecca Murphey & Dan Imal
Boston Front End Developer Meetup
January 2012
Tuesday, January 24, 12
Rebecca MurpheyLead JavaScript Developer@rmurphey
Dan ImalSenior User Experience Developer@mrdanimal
Tuesday, January 24, 12
Tuesday, January 24, 12
linkage
mulberry.toura.com
bit.ly/toura-mulberry
bit.ly/toura-mulberry-demos
Tuesday, January 24, 12
Tuesday, January 24, 12
Tuesday, January 24, 12
command line tools scaffold your app and generate skeleton "les for the pieces you’ll need
application code harness a powerful CSS and JavaScript framework to develop rich interfaces
app builder generates production-ready builds for Android, iOS (mobile web is on the way)
Tuesday, January 24, 12
CallbackCordova
Tuesday, January 24, 12
$ mulberry scaffold recipes
Tuesday, January 24, 12
Tuesday, January 24, 12
Tuesday, January 24, 12
$ mulberry generate
Tuesday, January 24, 12
dramatic pause.
Tuesday, January 24, 12
Tuesday, January 24, 12
create content with yaml, markdown & html
Tuesday, January 24, 12
create functionality with javascript
Tuesday, January 24, 12
create styles with css & sass
Tuesday, January 24, 12
Tuesday, January 24, 12
$ mulberry serve
Tuesday, January 24, 12
ohai sane development tools.
Tuesday, January 24, 12
$ mulberry test
Tuesday, January 24, 12
Tuesday, January 24, 12
Tuesday, January 24, 12
$ mulberry deploy
Tuesday, January 24, 12
it’s just javascript.
(ok, and some haml, yaml, & sass.)
Tuesday, January 24, 12
todos: capabilities: - name: PageTodos screens: - name: index regions: - components: - custom.TodoForm - className: list scrollable: true components: - custom.TodoList - components: - custom.TodoTools
NB: You can define this with JavaScript, too, using toura.pageDef(‘todos’, { ... }).
Tuesday, January 24, 12
mulberry.page('/todos', { name : 'Todos', pageDef : 'todos'}, true);
mulberry.page('/completed', { name : 'Completed', pageDef : 'completed'});
$YOURAPP/javascript/routes.js
#/todos #/completed
Tuesday, January 24, 12
mulberry.component('TodoForm', { componentTemplate : dojo.cache('client.components', 'TodoForm/TodoForm.haml'),
init : function() { this.connect(this.domNode, 'submit', function(e) { e.preventDefault();
var description = dojo.trim(this.descriptionInput.value), item;
if (!description) { return; }
item = { description : description }; this.domNode.reset(); this.onAdd(item); }); },
onAdd : function(item) { }});
$YOURAPP/javascript/components/TodoForm.js
Tuesday, January 24, 12
%form.component.todo-form %input{ placeholder : 'New todo', dojoAttachPoint : 'descriptionInput' } %button{ dojoAttachPoint : 'saveButton' } Add
$YOURAPP/javascript/components/TodoForm/TodoForm.haml
Tuesday, January 24, 12
mulberry.store('todos', { model : 'Todo',
finish : function(id) { this.invoke(id, 'finish'); },
unfinish : function(id) { this.invoke(id, 'unfinish'); }});
$YOURAPP/javascript/stores/todos.js
Tuesday, January 24, 12
mulberry.model('Todo', { complete : false,
finish : function() { this.set('complete', true); },
unfinish : function() { this.set('complete', false); }});
$YOURAPP/javascript/models/Todo.js
Tuesday, January 24, 12
@touradev @rmurphey @mrdanimal
mulberry.toura.com
bit.ly/toura-mulberry
bit.ly/toura-mulberry-demos
Tuesday, January 24, 12
Tuesday, January 24, 12
routes manage high-level application state
components receive and render data, and react to user input
capabilities provide data to components, and broker communications between them
page de!nitions reusable groupings of components and capabilities
stores persist data on the device, make that data query-able, and return model instances
Tuesday, January 24, 12
routes manage high-level application state
Tuesday, January 24, 12
mulberry.page('/todos', { name : 'Todos', pageDef : 'todos'}, true);
mulberry.page('/completed', { name : 'Completed', pageDef : 'completed'});
$YOURAPP/javascript/routes.js
#/todos #/completed
Tuesday, January 24, 12
stores persist data on the device, make that data query-able, and return model instances
Tuesday, January 24, 12
mulberry.store('todos', { model : 'Todo',
finish : function(id) { this.invoke(id, 'finish'); },
unfinish : function(id) { this.invoke(id, 'unfinish'); }});
$YOURAPP/javascript/stores/todos.js
Tuesday, January 24, 12
page de!nitions reusable groupings of components and capabilities
Tuesday, January 24, 12
todos: capabilities: - name: PageTodos screens: - name: index regions: - components: - custom.TodoForm - className: list scrollable: true components: - custom.TodoList - components: - custom.TodoTools
NB: You can define this with JavaScript, too, using toura.pageDef(‘todos’, { ... }).
Tuesday, January 24, 12
components receive and render data, and react to user input
Tuesday, January 24, 12
mulberry.component('TodoForm', { componentTemplate : dojo.cache('client.components', 'TodoForm/TodoForm.haml'),
init : function() { this.connect(this.domNode, 'submit', function(e) { e.preventDefault();
var description = dojo.trim(this.descriptionInput.value), item;
if (!description) { return; }
item = { description : description }; this.domNode.reset(); this.onAdd(item); }); },
onAdd : function(item) { }});
$YOURAPP/javascript/components/TodoForm.js
Tuesday, January 24, 12
%form.component.todo-form %input{ placeholder : 'New todo', dojoAttachPoint : 'descriptionInput' } %button{ dojoAttachPoint : 'saveButton' } Add
$YOURAPP/javascript/components/TodoForm/TodoForm.haml
Tuesday, January 24, 12
mulberry.component('TodoForm', { componentTemplate : dojo.cache('client.components', 'TodoForm/TodoForm.haml'),
init : function() { this.connect(this.domNode, 'submit', function(e) { e.preventDefault();
var description = dojo.trim(this.descriptionInput.value), item;
if (!description) { return; }
item = { description : description }; this.domNode.reset(); this.onAdd(item); }); },
onAdd : function(item) { }});
$YOURAPP/javascript/components/TodoForm.js
Tuesday, January 24, 12
capabilities provide data to components, and broker communications between them
Tuesday, January 24, 12
todos: capabilities: - name: PageTodos screens: - name: index regions: - components: - custom.TodoForm - className: list scrollable: true components: - custom.TodoList - components: - custom.TodoTools
mulberry.capability('PageTodos', { requirements : { todoList : 'custom.TodoList', todoForm : 'custom.TodoForm', todoTools : 'custom.TodoTools' },
connects : [ [ 'todoForm', 'onAdd', '_add' ], [ 'todoList', 'onComplete', '_complete' ], [ 'todoList', 'onDelete', '_delete' ], [ 'todoTools', 'onCompleteAll', '_completeAll' ] ],
init : function() { this.todos = client.stores.todos; this._updateList(); },
_add : function(item) { this.todos.add(item); this._updateList(); },
_delete : function(id) { this.todos.remove(id); this._updateList(); },
_complete : function(id) { this.todos.finish(id); this._updateList(); },
_updateList : function() { var items = this.todos.query(function(item) { return !item.complete; });
this.todoList.set('todos', items); },
_completeAll : function() { this.todos.query(function(item) { return !item.complete; }).forEach(dojo.hitch(this, function(t) { t.finish(); this.todos.put(t); }));
this._updateList(); }});
Tuesday, January 24, 12
todos: capabilities: - name: PageTodos screens: - name: index regions: - components: - custom.TodoForm - className: list scrollable: true components: - custom.TodoList - components: - custom.TodoTools
mulberry.capability('PageTodos', { requirements : { todoList : 'custom.TodoList', todoForm : 'custom.TodoForm', todoTools : 'custom.TodoTools' },
connects : [ [ 'todoForm', 'onAdd', '_add' ], [ 'todoList', 'onComplete', '_complete' ], [ 'todoList', 'onDelete', '_delete' ], [ 'todoTools', 'onCompleteAll', '_completeAll' ] ],
init : function() { this.todos = client.stores.todos; this._updateList(); },
_add : function(item) { this.todos.add(item); this._updateList(); },
_delete : function(id) { this.todos.remove(id); this._updateList(); },
_complete : function(id) { this.todos.finish(id); this._updateList(); },
_updateList : function() { var items = this.todos.query(function(item) { return !item.complete; });
this.todoList.set('todos', items); },
_completeAll : function() { this.todos.query(function(item) { return !item.complete; }).forEach(dojo.hitch(this, function(t) { t.finish(); this.todos.put(t); }));
this._updateList(); }});
Tuesday, January 24, 12
todos: capabilities: - name: PageTodos screens: - name: index regions: - components: - custom.TodoForm - className: list scrollable: true components: - custom.TodoList - components: - custom.TodoTools
mulberry.capability('PageTodos', { requirements : { todoList : 'custom.TodoList', todoForm : 'custom.TodoForm', todoTools : 'custom.TodoTools' },
connects : [ [ 'todoForm', 'onAdd', '_add' ], [ 'todoList', 'onComplete', '_complete' ], [ 'todoList', 'onDelete', '_delete' ], [ 'todoTools', 'onCompleteAll', '_completeAll' ] ],
init : function() { this.todos = client.stores.todos; this._updateList(); },
_add : function(item) { this.todos.add(item); this._updateList(); },
_delete : function(id) { this.todos.remove(id); this._updateList(); },
_complete : function(id) { this.todos.finish(id); this._updateList(); },
_updateList : function() { var items = this.todos.query(function(item) { return !item.complete; });
this.todoList.set('todos', items); },
_completeAll : function() { this.todos.query(function(item) { return !item.complete; }).forEach(dojo.hitch(this, function(t) { t.finish(); this.todos.put(t); }));
this._updateList(); }});
Tuesday, January 24, 12