SPINE JS
var Messenger = function(message){
  defaultGreeting = "hello ";
  this.message = message;
}

Messenger.prototype.sayHi = function(){
  alert(defaultGreeting + this.message);
}

var hiDosug = new Messenger("DOSUG");
hiDosug.sayHi();
tr    var Messenger = function(message){
                                              ("id",
            listParent.children("ul").at
"list" + uniqueListId);                          defaultGreeting = "hello ";

              self.listName = "list" +
                                    listParent = $  this.message = message;
uniqueLi stId;         ('#categoryList').pare
                                                nt();
                                                  }
                                                 " +
              li stParent.attr("id", "wrapper            var
                                    listParent.children("u ViewBuilder = functi
                                                             l").attr("id",       on(type){
uniqueListId);         "list" + uniqueListId); Messenger.prototype.sayHi = functionunction(){
                                                           defaultSomething = "grid"
              se lf.wrapperName = self pper" +
                                     "wra                                             ;
                                         .listName alert(defaultGreeting + this.message);
                                                    = "list" +
uniqueLi stId;         uniqueListId;                       this.type = type;
                   this.message = message;
                                               , } ue);
                                                  tr
               self.updateView(inlistPa tion
                                    Transi
                                           rent.attr("id",this.buildView();
                                                             "wrapper" +
                }     uniqueListId);      listParent = $
                                                  var hiDosug = new Messenger("DOSUG");
           })               ('#categoryList').parent(); }
                Messenger.prototype.sayHi = function(){
                                   self.wrapperName = "wra
                                                  hiDosug.sayHi(); +
                                                              pper"
       );             uniqueListId;       listParent.children("ul").attr("id",
                                                        Messen
                   alert(defaultGreeting + this.message); ger.prototype.buildView = function(
                            "list" + uniqueListId);
 }switch(this.viewType){           self.updateView(inTran target.loa
                                                          $( tion, true 'templates
                }                                           si          d();        /category.html'
                                          self.listName = "list" +
      case "grid":          uniqueListId;
                               })
                var hiDosug = new Messenger("DOSUG");             function() {
        templatePath = "templates/ listParent.attr("id", "wrapper" +
                            );
  categoryGridElement.html";
                hiDosug.sayHi();                                     listParent = $
                            uniqueListId);             ('#categoryList').parent
                     }                                                           ();
        break;                            self.wrapperName = "wrapper" +
                                                                     listParent.children("ul"
                            uniqueListId;              "list" + uniqueListId);                ).att
      default:
                                          self.updateView(inTransition, true);
        templatePath = "templates/                                  self.listName = "list" +
                                                       uniqueListId;
  categoryListElement.html";          })

    }                                                            listParent.attr("id", "w
                                                                                          rapper
What’s Needed


Framework for consistency

Core UI and Data Modeling

Easy to get up to speed

Minimal dependencies
What’s Out There
SPINE JS HISTORY
MAY 2011
OCTOBER 2011
CURRENT V1.0.4 5
JAVASCRIPT OR
COFFESCRIPT
CoffeeScript


You’re not forced into using it

SpineJS is written in CoffeeScript

It’s not just a cool new trend...
CoffeeScript Benefits


Helps avoid erroneously global vars and pollution

Leads to more readable code

Provides appearance of classical inheritance
WHAT’S IN IT FOR ME?
Benefits


Lightweight Framework

Single Library Dependency

Straightforward Use
More reasons...


Flexible UI rendering with no pre-determined templating

Built in LocalStorage and RESTful support

Write once with near-ready-to-deploy mobile code
Minimal Dependencies
Compatibility


No Plans for Archaic Browser Support

HTML5-Centric with LocalStorage

json2.js Dependency for IE7 Support
ON THE HORIZON
Spine Mobile


Strengthens reason to build around core framework

Extend core components to be mobile ready

Requires minimal additional implementation
Spine Mobile


No Re-Writing, Extend Existing Controllers

Transition Effects

Tap & Orientation Events
IMPLEMENTATION
& CODE EXAMPLES
SPINE CLASS
Module (a.k.a. Spine Class)


Spine’s extension of core CoffeeScript class

Provides class and instance property support

All Spine internals inherit from Spine.Module
Spine Module
   (a.k.a. Extended CoffeeScript Class)


class MyClass extends Spine.Module
  @extend MyOtherClass
  @include myInstanceProperty
MODEL
Model


Inherits from Spine.Module

Establishes Controller and UI Agnostic Data Model

One and Only component for storing and retrieving data
(local or remote)
class UsrGrp extends Spine.model
   @configure "UsrGrp",
   ↳"groupName", "description"


   @extend Spine.Model.Ajax
   @extend Spine.Model.Local
class UsrGrp extends Spine.model
   @configure "UsrGrp",
   ↳"groupName", "description"


   @extend Spine.Model.Ajax
   @extend Spine.Model.Local


   validate: ->
      unless @groupName.length > 0
      "Group Name field missing"
@extend Spine.Model.Ajax
@extend Spine.Model.Local


validate: ->
   unless @groupName.length > 0
   "Group Name field missing"
CONTROLLER
Controller


Brings it all together

Glues the HTML, DOM manipulation and Model together

Handles all event and UI interaction binding

Extends Spine.Events, allows custom event triggering
class UsrGrpsApp extends
   ↳Spine.Controller
   constructor: ->
      super
      UsrGrp.bind("create",
      ↳@addOne)


   #Bind event handling
UsrGrp.bind("create",
   ↳@addOne)


#Bind event handling
#to DOM elements
events:
   "submit form": "create"
   "click .deleteAll": "delete"


#DOM Element references
elements:
events:
   "submit form": "create"
   "click .deleteAll": "delete"


#DOM Element references
elements:
  "form input": "input"
  ".list": "list"


#New up a model & render
create: (event) ->
"form input": "input"
  ".list": "list"


#New up a model & render
create: (event) ->
   #Prevent form submit
   #page load from propagating
   event.preventDefault()


   #New up a model instance
#Prevent form submit
#page load from propagating
event.preventDefault()


#New up a model instance
user = new UserGrp(
↳groupName: @input.val())


#Persist or catch
#validation error
unless user.save()
user = new UserGrp(
  ↳groupName: @input.val())


   #Persist or catch
   #validation error
   unless user.save()
      #Very basic notification
      alert user.validate()


#Add new element to DOM
#Add new element to DOM
#Triggered on create() of Model
addOne: (userGroup) =>
   group = new UsrGrps(
  ↳item: userGroup)
   @list.append(
  ↳$("#listTemplate")
  ↳.tmpl(userGroup))
GETTING IT STARTED
$ = jQuery
$ ->
  new UsrGrpsApp(el: $("#groups"))
CONTROLLER MANAGER
Controller Manager


Simple state machine for Controller Instances

One additional script to include in HTML

Manipulates DOM with class flag
<script src="lib/spine/manager.js"
↳type="text/javascript"></script>
class UsrGrpsApp extends
↳Spine.Controller
class OtherController extends
↳Spine.Controller


ugApp = new UsrGrpsApp
other = new OtherController
class UsrGrpsApp extends
↳Spine.Controller
class OtherController extends
↳Spine.Controller


ugApp = new UsrGrpsApp
other = new OtherController


new Spine.Manager(ugApp, other)
class OtherController extends
↳Spine.Controller


ugApp = new UsrGrpsApp
other = new OtherController


new Spine.Manager(ugApp, other)
ugApp.active()
Ques
    tions
         ?
Contact Me

Jordan McCullough
Twitter: @ambientphoto
Email: jordanm@ambientideas.com
Web: ambientideas.com
Links & Resources

SpineJS: http://www.SpineJS.com

jQuery: http://www.jQuery.com

Zepto: http://www.ZeptoJS.com

CoffeeScript: http://jashkenas.github.com/coffee-script/

Little Book of CoffeeScript:
http://arcturo.github.com/library/coffeescript/
Links & Resources


JavaScriptMVC: http://javascriptmvc.com

Backbone JS: http://documentcloud.github.com/backbone/

SproutCore: http://www.sproutcore.com

Knockout: http://knockoutjs.com
Photo Credit



Ambient Ideas Photography
http://www.AmbientIdeasPhotography.com

Spine JS

  • 1.
  • 2.
    var Messenger =function(message){ defaultGreeting = "hello "; this.message = message; } Messenger.prototype.sayHi = function(){ alert(defaultGreeting + this.message); } var hiDosug = new Messenger("DOSUG"); hiDosug.sayHi();
  • 3.
    tr var Messenger = function(message){ ("id", listParent.children("ul").at "list" + uniqueListId); defaultGreeting = "hello "; self.listName = "list" + listParent = $ this.message = message; uniqueLi stId; ('#categoryList').pare nt(); } " + li stParent.attr("id", "wrapper var listParent.children("u ViewBuilder = functi l").attr("id", on(type){ uniqueListId); "list" + uniqueListId); Messenger.prototype.sayHi = functionunction(){ defaultSomething = "grid" se lf.wrapperName = self pper" + "wra ; .listName alert(defaultGreeting + this.message); = "list" + uniqueLi stId; uniqueListId; this.type = type; this.message = message; , } ue); tr self.updateView(inlistPa tion Transi rent.attr("id",this.buildView(); "wrapper" + } uniqueListId); listParent = $ var hiDosug = new Messenger("DOSUG"); }) ('#categoryList').parent(); } Messenger.prototype.sayHi = function(){ self.wrapperName = "wra hiDosug.sayHi(); + pper" ); uniqueListId; listParent.children("ul").attr("id", Messen alert(defaultGreeting + this.message); ger.prototype.buildView = function( "list" + uniqueListId); }switch(this.viewType){ self.updateView(inTran target.loa $( tion, true 'templates } si d(); /category.html' self.listName = "list" + case "grid": uniqueListId; }) var hiDosug = new Messenger("DOSUG"); function() { templatePath = "templates/ listParent.attr("id", "wrapper" + ); categoryGridElement.html"; hiDosug.sayHi(); listParent = $ uniqueListId); ('#categoryList').parent } (); break; self.wrapperName = "wrapper" + listParent.children("ul" uniqueListId; "list" + uniqueListId); ).att default: self.updateView(inTransition, true); templatePath = "templates/ self.listName = "list" + uniqueListId; categoryListElement.html"; }) } listParent.attr("id", "w rapper
  • 4.
    What’s Needed Framework forconsistency Core UI and Data Modeling Easy to get up to speed Minimal dependencies
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
    CoffeeScript You’re not forcedinto using it SpineJS is written in CoffeeScript It’s not just a cool new trend...
  • 12.
    CoffeeScript Benefits Helps avoiderroneously global vars and pollution Leads to more readable code Provides appearance of classical inheritance
  • 13.
  • 14.
    Benefits Lightweight Framework Single LibraryDependency Straightforward Use
  • 15.
    More reasons... Flexible UIrendering with no pre-determined templating Built in LocalStorage and RESTful support Write once with near-ready-to-deploy mobile code
  • 16.
  • 17.
    Compatibility No Plans forArchaic Browser Support HTML5-Centric with LocalStorage json2.js Dependency for IE7 Support
  • 18.
  • 19.
    Spine Mobile Strengthens reasonto build around core framework Extend core components to be mobile ready Requires minimal additional implementation
  • 20.
    Spine Mobile No Re-Writing,Extend Existing Controllers Transition Effects Tap & Orientation Events
  • 21.
  • 22.
  • 23.
    Module (a.k.a. SpineClass) Spine’s extension of core CoffeeScript class Provides class and instance property support All Spine internals inherit from Spine.Module
  • 24.
    Spine Module (a.k.a. Extended CoffeeScript Class) class MyClass extends Spine.Module @extend MyOtherClass @include myInstanceProperty
  • 25.
  • 26.
    Model Inherits from Spine.Module EstablishesController and UI Agnostic Data Model One and Only component for storing and retrieving data (local or remote)
  • 27.
    class UsrGrp extendsSpine.model @configure "UsrGrp", ↳"groupName", "description" @extend Spine.Model.Ajax @extend Spine.Model.Local
  • 28.
    class UsrGrp extendsSpine.model @configure "UsrGrp", ↳"groupName", "description" @extend Spine.Model.Ajax @extend Spine.Model.Local validate: -> unless @groupName.length > 0 "Group Name field missing"
  • 29.
    @extend Spine.Model.Ajax @extend Spine.Model.Local validate:-> unless @groupName.length > 0 "Group Name field missing"
  • 30.
  • 31.
    Controller Brings it alltogether Glues the HTML, DOM manipulation and Model together Handles all event and UI interaction binding Extends Spine.Events, allows custom event triggering
  • 32.
    class UsrGrpsApp extends ↳Spine.Controller constructor: -> super UsrGrp.bind("create", ↳@addOne) #Bind event handling
  • 33.
    UsrGrp.bind("create", ↳@addOne) #Bind event handling #to DOM elements events: "submit form": "create" "click .deleteAll": "delete" #DOM Element references elements:
  • 34.
    events: "submit form": "create" "click .deleteAll": "delete" #DOM Element references elements: "form input": "input" ".list": "list" #New up a model & render create: (event) ->
  • 35.
    "form input": "input" ".list": "list" #New up a model & render create: (event) -> #Prevent form submit #page load from propagating event.preventDefault() #New up a model instance
  • 36.
    #Prevent form submit #pageload from propagating event.preventDefault() #New up a model instance user = new UserGrp( ↳groupName: @input.val()) #Persist or catch #validation error unless user.save()
  • 37.
    user = newUserGrp( ↳groupName: @input.val()) #Persist or catch #validation error unless user.save() #Very basic notification alert user.validate() #Add new element to DOM
  • 38.
    #Add new elementto DOM #Triggered on create() of Model addOne: (userGroup) => group = new UsrGrps( ↳item: userGroup) @list.append( ↳$("#listTemplate") ↳.tmpl(userGroup))
  • 39.
  • 40.
    $ = jQuery $-> new UsrGrpsApp(el: $("#groups"))
  • 41.
  • 42.
    Controller Manager Simple statemachine for Controller Instances One additional script to include in HTML Manipulates DOM with class flag
  • 43.
  • 44.
    class UsrGrpsApp extends ↳Spine.Controller classOtherController extends ↳Spine.Controller ugApp = new UsrGrpsApp other = new OtherController
  • 45.
    class UsrGrpsApp extends ↳Spine.Controller classOtherController extends ↳Spine.Controller ugApp = new UsrGrpsApp other = new OtherController new Spine.Manager(ugApp, other)
  • 46.
    class OtherController extends ↳Spine.Controller ugApp= new UsrGrpsApp other = new OtherController new Spine.Manager(ugApp, other)
  • 47.
  • 48.
    Ques tions ?
  • 49.
    Contact Me Jordan McCullough Twitter:@ambientphoto Email: jordanm@ambientideas.com Web: ambientideas.com
  • 50.
    Links & Resources SpineJS:http://www.SpineJS.com jQuery: http://www.jQuery.com Zepto: http://www.ZeptoJS.com CoffeeScript: http://jashkenas.github.com/coffee-script/ Little Book of CoffeeScript: http://arcturo.github.com/library/coffeescript/
  • 51.
    Links & Resources JavaScriptMVC:http://javascriptmvc.com Backbone JS: http://documentcloud.github.com/backbone/ SproutCore: http://www.sproutcore.com Knockout: http://knockoutjs.com
  • 52.
    Photo Credit Ambient IdeasPhotography http://www.AmbientIdeasPhotography.com