Save 37% off PRO during our Black Friday Sale! »

Spine

Baf018e2cc4616e4776d323215c7136c?s=47 Alex MacCaw
October 04, 2011

 Spine

JavaScript MVC Framework

Baf018e2cc4616e4776d323215c7136c?s=128

Alex MacCaw

October 04, 2011
Tweet

Transcript

  1. Spine JavaScript MVC Framework

  2. None
  3. createBox(t, s): function{ return ['<div class="x-box-blue">', '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',

    '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>', '</div>'].join(''); }, emailMultiple : function(){ " " if(!Aireo.multipleSelect()){ " " " return " " } " " var nodes = assetView.getSelectedNodes() " " var query_string = [] " " for(var i=0; i < nodes.length; i ++){ " " " var data = Aireo.lookup[nodes[i].id]; " " " if(data.is_folder){ " " " query_string.push('folders[]=' + data.id) " " " " } else { " " " query_string.push('assets[]=' + data.id) " " " } " " } " " Email.init(lc.multiple_file_folders, query_string.join('&'), '',true); " " }, " " emailSelected : function(e){ " " if(!Aireo.currentlySelectedObject){ " " " return; " " } " " if(Aireo.multipleSelect()){ " " " Aireo.emailMultiple() " " } else { " " if(Aireo.currentlySelectedObject){ " " " var data = Aireo.currentlySelectedObject; " " if(Aireo.currentlySelectedObject.type == 'folder'){ " " Email.init(data.name,data.id,'folders',false);" " " } " " else if(Aireo.currentlySelectedObject.type == 'asset') {" " " Email.init(data.name,data.id,'assets',false);" " " } " " }
  4. The Problem with JavaScript • No structure • No namespacing

    • No dependency management • No conventions • Poor JS implementations • Misunderstanding and ignorance
  5. Hope

  6. Namespacing

  7. The Good Parts

  8. MVC

  9. None
  10. None
  11. None
  12. ?

  13. Spine

  14. MVC

  15. Don’t block

  16. Simplicity

  17. None
  18. 1.0

  19. Features • CoffeeScript (although not required) • MVC and ORM

    • Ajax and Local Storage • HTML5 History integration • Simple API • Excellent documentation
  20. Models

  21. class Task extends Spine.Model @configure "Task", "name", "done" @extend Spine.Model.Local

    @active: -> @select (item) -> !item.done @done: -> @select (item) -> !!item.done @destroyDone: -> rec.destroy() for rec in @done()
  22. class Task extends Spine.Model @configure "Task", "name", "done" @extend Spine.Model.Local

    @active: -> @select (item) -> !item.done @done: -> @select (item) -> !!item.done @destroyDone: -> rec.destroy() for rec in @done()
  23. class Task extends Spine.Model @configure "Task", "name", "done" @extend Spine.Model.Local

    @active: -> @select (item) -> !item.done @done: -> @select (item) -> !!item.done @destroyDone: -> rec.destroy() for rec in @done()
  24. Controllers

  25. @el

  26. class Tasks extends Spine.Controller constructor: -> Task.bind('refresh change', @render) render:

    => tasks = Task.all() @html require('views/tasks')(tasks)
  27. class Tasks extends Spine.Controller constructor: -> Task.bind('refresh change', @render) render:

    => tasks = Task.all() @html require('views/tasks')(tasks)
  28. class Tasks extends Spine.Controller constructor: -> Task.bind('refresh change', @render) render:

    => tasks = Task.all() @html require('views/tasks')(tasks)
  29. class Tasks extends Spine.Controller constructor: -> Task.bind('refresh change', @render) render:

    => tasks = Task.all() @html require('views/tasks')(tasks)
  30. Views

  31. <div class="item"> <input type="checkbox" <%- if @done: %>checked="checked"<% end %>>

    <span> <%= @name %> <a class="destroy"></a> </span> </div>
  32. <div class="item"> <input type="checkbox" <%- if @done: %>checked="checked"<% end %>>

    <span> <%= @name %> <a class="destroy"></a> </span> </div>
  33. <div class="item"> <input type="checkbox" <%- if @done: %>checked="checked"<% end %>>

    <span> <%= @name %> <a class="destroy"></a> </span> </div>
  34. <div class="item"> <input type="checkbox" <%- if @done: %>checked="checked"<% end %>>

    <span> <%= @name %> <a class="destroy"></a> </span> </div>
  35. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy()
  36. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy()
  37. Binding

  38. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy()
  39. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy() 1. record is destroyed
  40. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy() 1. record is destroyed 2. change callback is triggered
  41. class Tasks extends Spine.Controller events: 'click .item .destroy': 'destroy' constructor:

    -> Task.bind('refresh change', @render) render: => tasks = Task.all() @html require('views/tasks')(tasks) destroy: (e) -> task = $(e).item() task.destroy() 1. record is destroyed 2. change callback is triggered 3. tasks are re-rendered
  42. More? •Classes & Modules •Routing •Ajax •Dependency Manager (Hem)

  43. Spine Mobile

  44. UX

  45. None
  46. None
  47. ? Stage Panel Transitions

  48. class ContactsCreate extends Panel # ... class ContactsList extends Panel

    constructor: -> super @addButton('Add Contact', @add) add: -> @navigate('/contacts/create', trans: 'right') class Contacts extends Spine.Controller constructor: -> super @list = new ContactsList @create = new ContactsCreate @routes '/contacts': (params) -> @list.active(params) '/contacts/create': (params) -> @create.active(params)
  49. class ContactsCreate extends Panel # ... class ContactsList extends Panel

    constructor: -> super @addButton('Add Contact', @add) add: -> @navigate('/contacts/create', trans: 'right') class Contacts extends Spine.Controller constructor: -> super @list = new ContactsList @create = new ContactsCreate @routes '/contacts': (params) -> @list.active(params) '/contacts/create': (params) -> @create.active(params)
  50. class ContactsCreate extends Panel # ... class ContactsList extends Panel

    constructor: -> super @addButton('Add Contact', @add) add: -> @navigate('/contacts/create', trans: 'right') class Contacts extends Spine.Controller constructor: -> super @list = new ContactsList @create = new ContactsCreate @routes '/contacts': (params) -> @list.active(params) '/contacts/create': (params) -> @create.active(params)
  51. class ContactsCreate extends Panel # ... class ContactsList extends Panel

    constructor: -> super @addButton('Add Contact', @add) add: -> @navigate('/contacts/create', trans: 'right') class Contacts extends Spine.Controller constructor: -> super @list = new ContactsList @create = new ContactsCreate @routes '/contacts': (params) -> @list.active(params) '/contacts/create': (params) -> @create.active(params)
  52. None
  53. None
  54. Full Featured

  55. None
  56. None
  57. @maccman http://alexmaccaw.co.uk