├── 01 ├── docs │ ├── docco.css │ └── script.html ├── index.html ├── script.coffee └── script.js ├── 02 ├── docs │ ├── docco.css │ └── script.html ├── index.html ├── script.coffee └── script.js ├── 03 ├── docs │ ├── docco.css │ └── script.html ├── index.html ├── script.coffee └── script.js ├── 04 ├── docs │ ├── docco.css │ └── script.html ├── index.html ├── script.coffee └── script.js ├── 05 ├── docs │ ├── docco.css │ └── script.html ├── index.html ├── script.coffee └── script.js ├── README.md ├── index.html └── style.css /01/docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /01/docs/script.html: -------------------------------------------------------------------------------- 1 | script.coffee
Jump To … 2 |
3 | 10 |
11 |

script.coffee

Extending Backbone.View

First, we'll extend 12 | Backbone.View to create a 13 | very minimal unordered list view. Take a look at the implementation 14 | of this step so you'll know what we're building.

The jQuery wrapper isn't necessary since we know this script is called 15 | after jQuery has been included, but it explicitly shows our dependence 16 | on jQuery. Clarity is a good thing.

jQuery ->
17 |   

Our main application view.

  class ListView extends Backbone.View
18 |     

We'll be using the body element for our view in all our examples. All 19 | views have a DOM element at all times. 20 | el is our view's 21 | connetion to the DOM.

    el: $ 'body'
22 |     

initialize() 23 | is automatically called upon instantiation.

    initialize: ->

We're using Underscore.js's bindAll method 24 | to bind all the view's methods to this instance of our view.

      _.bindAll @
25 |       @render()
26 |     

render() renders the view in @el. It must be called by the us; 27 | we called it at the end of our initialize() function.

    render: ->
28 |       $(@el).append '<ul><li>Hello, Backbone!</li></ul>'
29 |   
30 |   

Lastly, we instantiate our main app view.

  list_view = new ListView

Onward to Part 2.

-------------------------------------------------------------------------------- /01/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, meet Backbone.js: Part 1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

CoffeeScript, meet Backbone.js: Part 1

16 |

Looking for the documentation?

17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /01/script.coffee: -------------------------------------------------------------------------------- 1 | # ##Extending Backbone.View 2 | 3 | # First, we'll extend 4 | # [Backbone.View](http://documentcloud.github.com/backbone/#View) to create a 5 | # very minimal unordered list view. Take a look at [the implementation](../) 6 | # of this step so you'll know what we're building. 7 | 8 | # The `jQuery` wrapper isn't necessary since we know this script is called 9 | # after jQuery has been included, but it explicitly shows our dependence 10 | # on jQuery. Clarity is a good thing. 11 | jQuery -> 12 | 13 | # Our main application view. 14 | class ListView extends Backbone.View 15 | 16 | # We'll be using the `body` element for our view in all our examples. All 17 | # views have a DOM element at all times. 18 | # [`el`](http://documentcloud.github.com/backbone/#View-el) is our view's 19 | # connetion to the DOM. 20 | el: $ 'body' 21 | 22 | # [`initialize()`](http://documentcloud.github.com/backbone/#View-constructor) 23 | # is automatically called upon instantiation. 24 | initialize: -> 25 | # We're using [Underscore.js's bindAll method](http://documentcloud.github.com/underscore/#bindAll) 26 | # to bind all the view's methods to this instance of our view. 27 | _.bindAll @ 28 | @render() 29 | 30 | # `render()` renders the view in `@el`. It must be called by the us; 31 | # we called it at the end of our `initialize()` function. 32 | render: -> 33 | $(@el).append '' 34 | 35 | 36 | # Lastly, we instantiate our main app view. 37 | list_view = new ListView 38 | 39 | # Onward to [Part 2](/02/docs/script.html). 40 | -------------------------------------------------------------------------------- /01/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 4 | function ctor() { this.constructor = child; } 5 | ctor.prototype = parent.prototype; 6 | child.prototype = new ctor; 7 | child.__super__ = parent.prototype; 8 | return child; 9 | }; 10 | jQuery(function() { 11 | var ListView, list_view; 12 | ListView = (function() { 13 | __extends(ListView, Backbone.View); 14 | function ListView() { 15 | ListView.__super__.constructor.apply(this, arguments); 16 | } 17 | ListView.prototype.el = $('body'); 18 | ListView.prototype.initialize = function() { 19 | _.bindAll(this); 20 | return this.render(); 21 | }; 22 | ListView.prototype.render = function() { 23 | return $(this.el).append(''); 24 | }; 25 | return ListView; 26 | })(); 27 | return list_view = new ListView; 28 | }); 29 | }).call(this); 30 | -------------------------------------------------------------------------------- /02/docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /02/docs/script.html: -------------------------------------------------------------------------------- 1 | script.coffee
Jump To … 2 |
3 | 10 |
11 |

script.coffee

Binding DOM Events to View Methods

So, part one was pretty boring. Let's spice it up by 12 | binding DOM events to our view's methods. The implementation of this 13 | step is slighlty more exciting than the last.

jQuery ->
14 |   
15 |   class ListView extends Backbone.View
16 |     
17 |     el: $ 'body'
18 |     
19 |     initialize: ->
20 |       _.bindAll @
21 |       @counter = 0
22 |       @render()
23 |     

We'll add a button and an empty list to our view.

    render: ->
24 |       $(@el).append '<button>Add List Item</button>'
25 |       $(@el).append '<ul></ul>'
26 |     

addItem() will be called via the click event on the button we added 27 | in our render method.

    addItem: ->
28 |       @counter++
29 |       $('ul').append "<li>Hello, Backbone #{@counter}!</li>"
30 |     

events 31 | is a JSON object where DOM events are bound to view methods. Backbone 32 | doesn't have a separate controller to handle event bindings; it all 33 | happens in a view.

    events: 'click button': 'addItem'
34 |   
35 |   
36 |   list_view = new ListView

Onward to Part 3.

-------------------------------------------------------------------------------- /02/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, meet Backbone.js: Part 2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

CoffeeScript, meet Backbone.js: Part 2

16 |

Looking for the documentation?

17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /02/script.coffee: -------------------------------------------------------------------------------- 1 | # ##Binding DOM Events to View Methods 2 | 3 | # So, [part one](/01/docs/script.html) was pretty boring. Let's spice it up by 4 | # binding DOM events to our view's methods. [The implementation](../) of this 5 | # step is slighlty more exciting than the last. 6 | 7 | # 8 | jQuery -> 9 | 10 | class ListView extends Backbone.View 11 | 12 | el: $ 'body' 13 | 14 | initialize: -> 15 | _.bindAll @ 16 | @counter = 0 17 | @render() 18 | 19 | # We'll add a button and an empty list to our view. 20 | render: -> 21 | $(@el).append '' 22 | $(@el).append '' 23 | 24 | # `addItem()` will be called via the `click` event on the button we added 25 | # in our `render` method. 26 | addItem: -> 27 | @counter++ 28 | $('ul').append "
  • Hello, Backbone #{@counter}!
  • " 29 | 30 | # [`events`](http://documentcloud.github.com/backbone/#View-delegateEvents) 31 | # is a JSON object where DOM events are bound to view methods. Backbone 32 | # doesn't have a separate controller to handle event bindings; it all 33 | # happens in a view. 34 | events: 'click button': 'addItem' 35 | 36 | 37 | list_view = new ListView 38 | 39 | # Onward to [Part 3](/03/docs/script.html). 40 | -------------------------------------------------------------------------------- /02/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 4 | function ctor() { this.constructor = child; } 5 | ctor.prototype = parent.prototype; 6 | child.prototype = new ctor; 7 | child.__super__ = parent.prototype; 8 | return child; 9 | }; 10 | jQuery(function() { 11 | var ListView, list_view; 12 | ListView = (function() { 13 | __extends(ListView, Backbone.View); 14 | function ListView() { 15 | ListView.__super__.constructor.apply(this, arguments); 16 | } 17 | ListView.prototype.el = $('body'); 18 | ListView.prototype.initialize = function() { 19 | _.bindAll(this); 20 | this.counter = 0; 21 | return this.render(); 22 | }; 23 | ListView.prototype.render = function() { 24 | $(this.el).append(''); 25 | return $(this.el).append(''); 26 | }; 27 | ListView.prototype.addItem = function() { 28 | this.counter++; 29 | return $('ul').append("
  • Hello, Backbone " + this.counter + "!
  • "); 30 | }; 31 | ListView.prototype.events = { 32 | 'click button': 'addItem' 33 | }; 34 | return ListView; 35 | })(); 36 | return list_view = new ListView; 37 | }); 38 | }).call(this); 39 | -------------------------------------------------------------------------------- /03/docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /03/docs/script.html: -------------------------------------------------------------------------------- 1 | script.coffee
    Jump To … 2 |
    3 | 10 |
    11 |

    script.coffee

    Using a Collection of Models

    So far we've used the view as our view and model. We'll extend 12 | Backbone.Model and Backbone.Collection to separate our model from our view.

    You might want to view the implementation of this step before 13 | diving in.

    jQuery ->
    14 |   

    The model is the heart 15 | of any application. We have a very small heart in this example.

      class Item extends Backbone.Model
    16 |     

    defaults 17 | is a JSON object used to specify the default attributes for our model.

        defaults:
    18 |       part1: 'Hello'
    19 |       part2: 'Backbone'
    20 |   
    21 |   

    Our collection is 22 | an ordered set of the previously defined Items.

      class List extends Backbone.Collection
    23 |     
    24 |     model: Item
    25 |   
    26 |   
    27 |   class ListView extends Backbone.View
    28 |     
    29 |     el: $ 'body'
    30 |     

    initialize() now instantiates a collection and binds the 31 | add event 32 | to the appendItem() method.

        initialize: ->
    33 |       _.bindAll @
    34 |       
    35 |       @collection = new List
    36 |       @collection.bind 'add', @appendItem
    37 |       
    38 |       @counter = 0
    39 |       @render()
    40 |     
    41 |     render: ->
    42 |       $(@el).append '<button>Add List Item</button>'
    43 |       $(@el).append '<ul></ul>'
    44 |     

    addItem() now deals solely with models/collections. View updates are 45 | delegated to the add event bound to appendItem() when we 46 | initializeed our list_view.

        addItem: ->
    47 |       @counter++
    48 |       

    Instantiate a new Item,

          item = new Item

    and modify its second part.

          item.set part2: "#{item.get 'part2'} #{@counter}"

    Then, add it to our collection.

          @collection.add item
    49 |     

    appendItem() is triggered by the collection event add and handles 50 | updates to the interface.

        appendItem: (item) ->
    51 |       $('ul').append "<li>#{item.get 'part1'} #{item.get 'part2'}!</li>"
    52 |     
    53 |     events: 'click button': 'addItem'
    54 |   
    55 |   
    56 |   list_view = new ListView

    Onward to Part 4

    -------------------------------------------------------------------------------- /03/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, meet Backbone.js: Part 3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |

    CoffeeScript, meet Backbone.js: Part 3

    16 |

    Looking for the documentation?

    17 |
    18 | 19 | 20 | -------------------------------------------------------------------------------- /03/script.coffee: -------------------------------------------------------------------------------- 1 | # ##Using a Collection of Models 2 | 3 | # So far we've used the view as our view and model. We'll extend 4 | # Backbone.Model and Backbone.Collection to separate our model from our view. 5 | 6 | # You might want to [view the implementation](../) of this step before 7 | # diving in. 8 | 9 | # 10 | jQuery -> 11 | 12 | # The [model](http://documentcloud.github.com/backbone/#Model) is the heart 13 | # of any application. We have a very small heart in this example. 14 | class Item extends Backbone.Model 15 | 16 | # [`defaults`](http://documentcloud.github.com/backbone/#Model-defaults) 17 | # is a JSON object used to specify the default attributes for our model. 18 | defaults: 19 | part1: 'Hello' 20 | part2: 'Backbone' 21 | 22 | 23 | # Our [collection](http://documentcloud.github.com/backbone/#Collection) is 24 | # an ordered set of the previously defined `Item`s. 25 | class List extends Backbone.Collection 26 | 27 | model: Item 28 | 29 | 30 | class ListView extends Backbone.View 31 | 32 | el: $ 'body' 33 | 34 | # `initialize()` now instantiates a collection and binds the 35 | # [`add`](http://documentcloud.github.com/backbone/#Collection-add) event 36 | # to the `appendItem()` method. 37 | initialize: -> 38 | _.bindAll @ 39 | 40 | @collection = new List 41 | @collection.bind 'add', @appendItem 42 | 43 | @counter = 0 44 | @render() 45 | 46 | render: -> 47 | $(@el).append '' 48 | $(@el).append '' 49 | 50 | # `addItem()` now deals solely with models/collections. View updates are 51 | # delegated to the `add` event bound to `appendItem()` when we 52 | # `initialize`ed our list_view. 53 | addItem: -> 54 | @counter++ 55 | 56 | # Instantiate a new Item, 57 | item = new Item 58 | # and modify its second part. 59 | item.set part2: "#{item.get 'part2'} #{@counter}" 60 | # Then, add it to our collection. 61 | @collection.add item 62 | 63 | # `appendItem()` is triggered by the collection event `add` and handles 64 | # updates to the interface. 65 | appendItem: (item) -> 66 | $('ul').append "
  • #{item.get 'part1'} #{item.get 'part2'}!
  • " 67 | 68 | events: 'click button': 'addItem' 69 | 70 | 71 | list_view = new ListView 72 | 73 | # Onward to [Part 4](/04/docs/script.html) 74 | -------------------------------------------------------------------------------- /03/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 4 | function ctor() { this.constructor = child; } 5 | ctor.prototype = parent.prototype; 6 | child.prototype = new ctor; 7 | child.__super__ = parent.prototype; 8 | return child; 9 | }; 10 | jQuery(function() { 11 | var Item, List, ListView, list_view; 12 | Item = (function() { 13 | __extends(Item, Backbone.Model); 14 | function Item() { 15 | Item.__super__.constructor.apply(this, arguments); 16 | } 17 | Item.prototype.defaults = { 18 | part1: 'Hello', 19 | part2: 'Backbone' 20 | }; 21 | return Item; 22 | })(); 23 | List = (function() { 24 | __extends(List, Backbone.Collection); 25 | function List() { 26 | List.__super__.constructor.apply(this, arguments); 27 | } 28 | List.prototype.model = Item; 29 | return List; 30 | })(); 31 | ListView = (function() { 32 | __extends(ListView, Backbone.View); 33 | function ListView() { 34 | ListView.__super__.constructor.apply(this, arguments); 35 | } 36 | ListView.prototype.el = $('body'); 37 | ListView.prototype.initialize = function() { 38 | _.bindAll(this); 39 | this.collection = new List; 40 | this.collection.bind('add', this.appendItem); 41 | this.counter = 0; 42 | return this.render(); 43 | }; 44 | ListView.prototype.render = function() { 45 | $(this.el).append(''); 46 | return $(this.el).append(''); 47 | }; 48 | ListView.prototype.addItem = function() { 49 | var item; 50 | this.counter++; 51 | item = new Item; 52 | item.set({ 53 | part2: "" + (item.get('part2')) + " " + this.counter 54 | }); 55 | return this.collection.add(item); 56 | }; 57 | ListView.prototype.appendItem = function(item) { 58 | return $('ul').append("
  • " + (item.get('part1')) + " " + (item.get('part2')) + "!
  • "); 59 | }; 60 | ListView.prototype.events = { 61 | 'click button': 'addItem' 62 | }; 63 | return ListView; 64 | })(); 65 | return list_view = new ListView; 66 | }); 67 | }).call(this); 68 | -------------------------------------------------------------------------------- /04/docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /04/docs/script.html: -------------------------------------------------------------------------------- 1 | script.coffee
    Jump To … 2 |
    3 | 10 |
    11 |

    script.coffee

    Using a Dedicated View for a Model

    We added a model and collection in the 12 | previous example, but our main application view 13 | still held the structure for our model. We'll add a dedicated view, 14 | ItemView, for our Item model. The implementation for this part 15 | looks exactly the same as the implementation of Part 3.

    jQuery ->
    16 |   
    17 |   class Item extends Backbone.Model
    18 |     
    19 |     defaults:
    20 |       part1: 'Hello'
    21 |       part2: 'Backbone'
    22 |   
    23 |   
    24 |   class List extends Backbone.Collection
    25 |     
    26 |     model: Item
    27 |   
    28 |   

    The ItemView is now responsible for rendering each Item.

      class ItemView extends Backbone.View
    29 |     

    tagName is used to create our 30 | @el. You can also 31 | add className and id properties, but tagName is enough for this 32 | simple example.

        tagName: 'li'
    33 |     
    34 |     initialize: ->
    35 |       _.bindAll @
    36 |     
    37 |     render: ->
    38 |       $(@el).html "<span>#{@model.get 'part1'} #{@model.get 'part2'}!</span>"

    Returning @ is considered a good practice. It let's us chain method 39 | calls (i.e., item_view.render().el).

          @
    40 |   
    41 |   
    42 |   class ListView extends Backbone.View
    43 |     
    44 |     el: $ 'body'
    45 |     
    46 |     initialize: ->
    47 |       _.bindAll @
    48 |       
    49 |       @collection = new List
    50 |       @collection.bind 'add', @appendItem
    51 |       
    52 |       @counter = 0
    53 |       @render()
    54 |     
    55 |     render: ->
    56 |       $(@el).append '<button>Add List Item</button>'
    57 |       $(@el).append '<ul></ul>'
    58 |     
    59 |     addItem: ->
    60 |       @counter++
    61 |       item = new Item
    62 |       item.set part2: "#{item.get 'part2'} #{@counter}"
    63 |       @collection.add item
    64 |     

    appendItem() no longer renders an individual Item. Rendering is 65 | delegated to the render() method of each ItemView instance.

        appendItem: (item) ->

    Instantiate a new ItemView using item as the model.

          item_view = new ItemView model: item
    66 |       $('ul').append item_view.render().el
    67 |     
    68 |     events: 'click button': 'addItem'
    69 |   
    70 |   
    71 |   list_view = new ListView

    Onward to Part 5

    -------------------------------------------------------------------------------- /04/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, meet Backbone.js: Part 4 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |

    CoffeeScript, meet Backbone.js: Part 4

    16 |

    Looking for the documentation?

    17 |
    18 | 19 | 20 | -------------------------------------------------------------------------------- /04/script.coffee: -------------------------------------------------------------------------------- 1 | # ##Using a Dedicated View for a Model 2 | 3 | # We added a model and collection in the 4 | # [previous example](/03/docs/script.html), but our main application view 5 | # still held the structure for our model. We'll add a dedicated view, 6 | # `ItemView`, for our `Item` model. [The implementation](../) for this part 7 | # looks exactly the same as the [implementation of Part 3](/03/). 8 | 9 | # 10 | jQuery -> 11 | 12 | class Item extends Backbone.Model 13 | 14 | defaults: 15 | part1: 'Hello' 16 | part2: 'Backbone' 17 | 18 | 19 | class List extends Backbone.Collection 20 | 21 | model: Item 22 | 23 | 24 | # The `ItemView` is now responsible for rendering each `Item`. 25 | class ItemView extends Backbone.View 26 | 27 | # `tagName` is used to create our 28 | # [`@el`](http://documentcloud.github.com/backbone/#View-el). You can also 29 | # add `className` and `id` properties, but `tagName` is enough for this 30 | # simple example. 31 | tagName: 'li' 32 | 33 | initialize: -> 34 | _.bindAll @ 35 | 36 | render: -> 37 | $(@el).html "#{@model.get 'part1'} #{@model.get 'part2'}!" 38 | # Returning `@` is considered a good practice. It let's us chain method 39 | # calls (i.e., `item_view.render().el`). 40 | @ 41 | 42 | 43 | class ListView extends Backbone.View 44 | 45 | el: $ 'body' 46 | 47 | initialize: -> 48 | _.bindAll @ 49 | 50 | @collection = new List 51 | @collection.bind 'add', @appendItem 52 | 53 | @counter = 0 54 | @render() 55 | 56 | render: -> 57 | $(@el).append '' 58 | $(@el).append '' 59 | 60 | addItem: -> 61 | @counter++ 62 | item = new Item 63 | item.set part2: "#{item.get 'part2'} #{@counter}" 64 | @collection.add item 65 | 66 | # `appendItem()` no longer renders an individual `Item`. Rendering is 67 | # delegated to the `render()` method of each `ItemView` instance. 68 | appendItem: (item) -> 69 | # Instantiate a new `ItemView` using `item` as the `model`. 70 | item_view = new ItemView model: item 71 | $('ul').append item_view.render().el 72 | 73 | events: 'click button': 'addItem' 74 | 75 | 76 | list_view = new ListView 77 | 78 | # Onward to [Part 5](/05/docs/script.html) 79 | -------------------------------------------------------------------------------- /04/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 4 | function ctor() { this.constructor = child; } 5 | ctor.prototype = parent.prototype; 6 | child.prototype = new ctor; 7 | child.__super__ = parent.prototype; 8 | return child; 9 | }; 10 | jQuery(function() { 11 | var Item, ItemView, List, ListView, list_view; 12 | Item = (function() { 13 | __extends(Item, Backbone.Model); 14 | function Item() { 15 | Item.__super__.constructor.apply(this, arguments); 16 | } 17 | Item.prototype.defaults = { 18 | part1: 'Hello', 19 | part2: 'Backbone' 20 | }; 21 | return Item; 22 | })(); 23 | List = (function() { 24 | __extends(List, Backbone.Collection); 25 | function List() { 26 | List.__super__.constructor.apply(this, arguments); 27 | } 28 | List.prototype.model = Item; 29 | return List; 30 | })(); 31 | ItemView = (function() { 32 | __extends(ItemView, Backbone.View); 33 | function ItemView() { 34 | ItemView.__super__.constructor.apply(this, arguments); 35 | } 36 | ItemView.prototype.tagName = 'li'; 37 | ItemView.prototype.initialize = function() { 38 | return _.bindAll(this); 39 | }; 40 | ItemView.prototype.render = function() { 41 | $(this.el).html("" + (this.model.get('part1')) + " " + (this.model.get('part2')) + "!"); 42 | return this; 43 | }; 44 | return ItemView; 45 | })(); 46 | ListView = (function() { 47 | __extends(ListView, Backbone.View); 48 | function ListView() { 49 | ListView.__super__.constructor.apply(this, arguments); 50 | } 51 | ListView.prototype.el = $('body'); 52 | ListView.prototype.initialize = function() { 53 | _.bindAll(this); 54 | this.collection = new List; 55 | this.collection.bind('add', this.appendItem); 56 | this.counter = 0; 57 | return this.render(); 58 | }; 59 | ListView.prototype.render = function() { 60 | $(this.el).append(''); 61 | return $(this.el).append(''); 62 | }; 63 | ListView.prototype.addItem = function() { 64 | var item; 65 | this.counter++; 66 | item = new Item; 67 | item.set({ 68 | part2: "" + (item.get('part2')) + " " + this.counter 69 | }); 70 | return this.collection.add(item); 71 | }; 72 | ListView.prototype.appendItem = function(item) { 73 | var item_view; 74 | item_view = new ItemView({ 75 | model: item 76 | }); 77 | return $('ul').append(item_view.render().el); 78 | }; 79 | ListView.prototype.events = { 80 | 'click button': 'addItem' 81 | }; 82 | return ListView; 83 | })(); 84 | return list_view = new ListView; 85 | }); 86 | }).call(this); 87 | -------------------------------------------------------------------------------- /05/docs/docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 15px; 5 | line-height: 22px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 0px 0 15px 0; 20 | } 21 | h1 { 22 | margin-top: 40px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 525px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 450px; 76 | min-width: 450px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | overflow-x: hidden; 80 | vertical-align: top; 81 | text-align: left; 82 | } 83 | .docs pre { 84 | margin: 15px 0 15px; 85 | padding-left: 15px; 86 | } 87 | .docs p tt, .docs p code { 88 | background: #f8f8ff; 89 | border: 1px solid #dedede; 90 | font-size: 12px; 91 | padding: 0 0.2em; 92 | } 93 | .pilwrap { 94 | position: relative; 95 | } 96 | .pilcrow { 97 | font: 12px Arial; 98 | text-decoration: none; 99 | color: #454545; 100 | position: absolute; 101 | top: 3px; left: -20px; 102 | padding: 1px 2px; 103 | opacity: 0; 104 | -webkit-transition: opacity 0.2s linear; 105 | } 106 | td.docs:hover .pilcrow { 107 | opacity: 1; 108 | } 109 | td.code, th.code { 110 | padding: 14px 15px 16px 25px; 111 | width: 100%; 112 | vertical-align: top; 113 | background: #f5f5ff; 114 | border-left: 1px solid #e5e5ee; 115 | } 116 | pre, tt, code { 117 | font-size: 12px; line-height: 18px; 118 | font-family: Monaco, Consolas, "Lucida Console", monospace; 119 | margin: 0; padding: 0; 120 | } 121 | 122 | 123 | /*---------------------- Syntax Highlighting -----------------------------*/ 124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 126 | body .hll { background-color: #ffffcc } 127 | body .c { color: #408080; font-style: italic } /* Comment */ 128 | body .err { border: 1px solid #FF0000 } /* Error */ 129 | body .k { color: #954121 } /* Keyword */ 130 | body .o { color: #666666 } /* Operator */ 131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 132 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 135 | body .gd { color: #A00000 } /* Generic.Deleted */ 136 | body .ge { font-style: italic } /* Generic.Emph */ 137 | body .gr { color: #FF0000 } /* Generic.Error */ 138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 139 | body .gi { color: #00A000 } /* Generic.Inserted */ 140 | body .go { color: #808080 } /* Generic.Output */ 141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 142 | body .gs { font-weight: bold } /* Generic.Strong */ 143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 144 | body .gt { color: #0040D0 } /* Generic.Traceback */ 145 | body .kc { color: #954121 } /* Keyword.Constant */ 146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 148 | body .kp { color: #954121 } /* Keyword.Pseudo */ 149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 150 | body .kt { color: #B00040 } /* Keyword.Type */ 151 | body .m { color: #666666 } /* Literal.Number */ 152 | body .s { color: #219161 } /* Literal.String */ 153 | body .na { color: #7D9029 } /* Name.Attribute */ 154 | body .nb { color: #954121 } /* Name.Builtin */ 155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 156 | body .no { color: #880000 } /* Name.Constant */ 157 | body .nd { color: #AA22FF } /* Name.Decorator */ 158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 160 | body .nf { color: #0000FF } /* Name.Function */ 161 | body .nl { color: #A0A000 } /* Name.Label */ 162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 164 | body .nv { color: #19469D } /* Name.Variable */ 165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 166 | body .w { color: #bbbbbb } /* Text.Whitespace */ 167 | body .mf { color: #666666 } /* Literal.Number.Float */ 168 | body .mh { color: #666666 } /* Literal.Number.Hex */ 169 | body .mi { color: #666666 } /* Literal.Number.Integer */ 170 | body .mo { color: #666666 } /* Literal.Number.Oct */ 171 | body .sb { color: #219161 } /* Literal.String.Backtick */ 172 | body .sc { color: #219161 } /* Literal.String.Char */ 173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 174 | body .s2 { color: #219161 } /* Literal.String.Double */ 175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 176 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 178 | body .sx { color: #954121 } /* Literal.String.Other */ 179 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 180 | body .s1 { color: #219161 } /* Literal.String.Single */ 181 | body .ss { color: #19469D } /* Literal.String.Symbol */ 182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 183 | body .vc { color: #19469D } /* Name.Variable.Class */ 184 | body .vg { color: #19469D } /* Name.Variable.Global */ 185 | body .vi { color: #19469D } /* Name.Variable.Instance */ 186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /05/docs/script.html: -------------------------------------------------------------------------------- 1 | script.coffee
    Jump To … 2 |
    3 | 10 |
    11 |

    script.coffee

    Adding Actions to a View

    12 | 13 |

    Our models have been pretty lifeless so far. We'll attach some actions to 14 | our Items for some dynamic goodness. Take a look at 15 | the implementation before getting started.

    jQuery ->
     16 |   
     17 |   class Item extends Backbone.Model
     18 |     
     19 |     defaults:
     20 |       part1: 'Hello'
     21 |       part2: 'Backbone'
     22 |   
     23 |   
     24 |   class List extends Backbone.Collection
     25 |     
     26 |     model: Item
     27 |   
     28 |   
     29 |   class ItemView extends Backbone.View
     30 |     
     31 |     tagName: 'li'
     32 |     

    initialize() 33 | binds change 34 | and remove 35 | to @render and @unrender, respectively.

        initialize: ->
     36 |       _.bindAll @
     37 |       
     38 |       @model.bind 'change', @render
     39 |       @model.bind 'remove', @unrender
     40 |     

    render() now includes two extra spans for swapping and deleting 41 | an item.

        render: =>
     42 |       $(@el).html """
     43 |         <span>#{@model.get 'part1'} #{@model.get 'part2'}!</span>
     44 |         <span class="swap">swap</span>
     45 |         <span class="delete">delete</span>
     46 |       """
     47 |       @
     48 |     

    unrender() removes the calling list item from the DOM. This uses 49 | jQuery's remove() method.

        unrender: =>
     50 |       $(@el).remove()
     51 |     

    swap() interchanges an Item's attributes. The set() model 52 | function triggers 53 | the change event.

        swap: ->
     54 |       @model.set
     55 |         part1: @model.get 'part2'
     56 |         part2: @model.get 'part1'
     57 |     
     58 |     

    remove() calls the model's 59 | destroy() 60 | method, removing the model from its collection. destroy() would 61 | normally delete the record from its persistent storage, but we'll 62 | override this in Backbone.sync below.

        remove: -> @model.destroy()
     63 |     

    ItemViews now respond to two click actions for each Item.

        events:
     64 |       'click .swap': 'swap'
     65 |       'click .delete': 'remove'
     66 |   
     67 |   

    We no longer need to modify the ListView because swap and delete are 68 | called on each Item.

      class ListView extends Backbone.View
     69 |     
     70 |     el: $ 'body'
     71 |     
     72 |     initialize: ->
     73 |       _.bindAll @
     74 |       
     75 |       @collection = new List
     76 |       @collection.bind 'add', @appendItem
     77 |       
     78 |       @counter = 0
     79 |       @render()
     80 |     
     81 |     render: ->
     82 |       $(@el).append '<button>Add Item List</button>'
     83 |       $(@el).append '<ul></ul>'
     84 |     
     85 |     addItem: ->
     86 |       @counter++
     87 |       item = new Item
     88 |       item.set part2: "#{item.get 'part2'} #{@counter}"
     89 |       @collection.add item
     90 |     
     91 |     appendItem: (item) ->
     92 |       item_view = new ItemView model: item
     93 |       $('ul').append item_view.render().el
     94 |     
     95 |     events: 'click button': 'addItem'
     96 |   
     97 |   

    We'll override 98 | Backbone.sync since 99 | we're not making any calls to the server when we change our model.

      Backbone.sync = (method, model, success, error) ->
    100 |     

    Perform a NOOP when we successfully change our model. In our example, 101 | this will happen when we remove each Item view.

        success()
    102 |   
    103 |   
    104 |   list_view = new ListView
    105 | 
    106 | 
    -------------------------------------------------------------------------------- /05/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, meet Backbone.js: Part 5 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 |

    CoffeeScript, Meet Backbone.js: Part 5

    16 |

    Looking for the documentation?

    17 |
    18 | 19 | 20 | -------------------------------------------------------------------------------- /05/script.coffee: -------------------------------------------------------------------------------- 1 | # ##Adding Actions to a View 2 | # 3 | # Our models have been pretty lifeless so far. We'll attach some actions to 4 | # our `Item`s for some dynamic goodness. Take a look at 5 | # [the implementation](../) before getting started. 6 | 7 | # 8 | jQuery -> 9 | 10 | class Item extends Backbone.Model 11 | 12 | defaults: 13 | part1: 'Hello' 14 | part2: 'Backbone' 15 | 16 | 17 | class List extends Backbone.Collection 18 | 19 | model: Item 20 | 21 | 22 | class ItemView extends Backbone.View 23 | 24 | tagName: 'li' 25 | 26 | # `initialize()` 27 | # binds [`change`](http://documentcloud.github.com/backbone/#Model-change) 28 | # and [`remove`](http://documentcloud.github.com/backbone/#Collection-remove) 29 | # to `@render` and `@unrender`, respectively. 30 | initialize: -> 31 | _.bindAll @ 32 | 33 | @model.bind 'change', @render 34 | @model.bind 'remove', @unrender 35 | 36 | # `render()` now includes two extra `span`s for swapping and deleting 37 | # an item. 38 | render: => 39 | $(@el).html """ 40 | #{@model.get 'part1'} #{@model.get 'part2'}! 41 | swap 42 | delete 43 | """ 44 | @ 45 | 46 | # `unrender()` removes the calling list item from the DOM. This uses 47 | # [jQuery's `remove()` method](http://api.jquery.com/remove/). 48 | unrender: => 49 | $(@el).remove() 50 | 51 | # `swap()` interchanges an `Item`'s attributes. The [`set()` model 52 | # function](http://documentcloud.github.com/backbone/#Model-set) triggers 53 | # the `change` event. 54 | swap: -> 55 | @model.set 56 | part1: @model.get 'part2' 57 | part2: @model.get 'part1' 58 | 59 | 60 | # `remove()` calls the model's 61 | # [`destroy()`](http://documentcloud.github.com/backbone/#Model-destroy) 62 | # method, removing the model from its collection. `destroy()` would 63 | # normally delete the record from its persistent storage, but we'll 64 | # override this in `Backbone.sync` below. 65 | remove: -> @model.destroy() 66 | 67 | # `ItemView`s now respond to two click actions for each `Item`. 68 | events: 69 | 'click .swap': 'swap' 70 | 'click .delete': 'remove' 71 | 72 | 73 | # We no longer need to modify the `ListView` because `swap` and `delete` are 74 | # called on each `Item`. 75 | class ListView extends Backbone.View 76 | 77 | el: $ 'body' 78 | 79 | initialize: -> 80 | _.bindAll @ 81 | 82 | @collection = new List 83 | @collection.bind 'add', @appendItem 84 | 85 | @counter = 0 86 | @render() 87 | 88 | render: -> 89 | $(@el).append '' 90 | $(@el).append '' 91 | 92 | addItem: -> 93 | @counter++ 94 | item = new Item 95 | item.set part2: "#{item.get 'part2'} #{@counter}" 96 | @collection.add item 97 | 98 | appendItem: (item) -> 99 | item_view = new ItemView model: item 100 | $('ul').append item_view.render().el 101 | 102 | events: 'click button': 'addItem' 103 | 104 | 105 | # We'll override 106 | # [`Backbone.sync`](http://documentcloud.github.com/backbone/#Sync) since 107 | # we're not making any calls to the server when we change our model. 108 | Backbone.sync = (method, model, success, error) -> 109 | 110 | # Perform a NOOP when we successfully change our model. In our example, 111 | # this will happen when we remove each Item view. 112 | success() 113 | 114 | 115 | list_view = new ListView 116 | -------------------------------------------------------------------------------- /05/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { 3 | for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } 4 | function ctor() { this.constructor = child; } 5 | ctor.prototype = parent.prototype; 6 | child.prototype = new ctor; 7 | child.__super__ = parent.prototype; 8 | return child; 9 | }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 10 | jQuery(function() { 11 | var Item, ItemView, List, ListView, list_view; 12 | Item = (function() { 13 | __extends(Item, Backbone.Model); 14 | function Item() { 15 | Item.__super__.constructor.apply(this, arguments); 16 | } 17 | Item.prototype.defaults = { 18 | part1: 'Hello', 19 | part2: 'Backbone' 20 | }; 21 | return Item; 22 | })(); 23 | List = (function() { 24 | __extends(List, Backbone.Collection); 25 | function List() { 26 | List.__super__.constructor.apply(this, arguments); 27 | } 28 | List.prototype.model = Item; 29 | return List; 30 | })(); 31 | ItemView = (function() { 32 | __extends(ItemView, Backbone.View); 33 | function ItemView() { 34 | this.unrender = __bind(this.unrender, this); 35 | this.render = __bind(this.render, this); 36 | ItemView.__super__.constructor.apply(this, arguments); 37 | } 38 | ItemView.prototype.tagName = 'li'; 39 | ItemView.prototype.initialize = function() { 40 | _.bindAll(this); 41 | this.model.bind('change', this.render); 42 | return this.model.bind('remove', this.unrender); 43 | }; 44 | ItemView.prototype.render = function() { 45 | $(this.el).html("" + (this.model.get('part1')) + " " + (this.model.get('part2')) + "!\nswap\ndelete"); 46 | return this; 47 | }; 48 | ItemView.prototype.unrender = function() { 49 | return $(this.el).remove(); 50 | }; 51 | ItemView.prototype.swap = function() { 52 | return this.model.set({ 53 | part1: this.model.get('part2'), 54 | part2: this.model.get('part1') 55 | }); 56 | }; 57 | ItemView.prototype.remove = function() { 58 | return this.model.destroy(); 59 | }; 60 | ItemView.prototype.events = { 61 | 'click .swap': 'swap', 62 | 'click .delete': 'remove' 63 | }; 64 | return ItemView; 65 | })(); 66 | ListView = (function() { 67 | __extends(ListView, Backbone.View); 68 | function ListView() { 69 | ListView.__super__.constructor.apply(this, arguments); 70 | } 71 | ListView.prototype.el = $('body'); 72 | ListView.prototype.initialize = function() { 73 | _.bindAll(this); 74 | this.collection = new List; 75 | this.collection.bind('add', this.appendItem); 76 | this.counter = 0; 77 | return this.render(); 78 | }; 79 | ListView.prototype.render = function() { 80 | $(this.el).append(''); 81 | return $(this.el).append(''); 82 | }; 83 | ListView.prototype.addItem = function() { 84 | var item; 85 | this.counter++; 86 | item = new Item; 87 | item.set({ 88 | part2: "" + (item.get('part2')) + " " + this.counter 89 | }); 90 | return this.collection.add(item); 91 | }; 92 | ListView.prototype.appendItem = function(item) { 93 | var item_view; 94 | item_view = new ItemView({ 95 | model: item 96 | }); 97 | return $('ul').append(item_view.render().el); 98 | }; 99 | ListView.prototype.events = { 100 | 'click button': 'addItem' 101 | }; 102 | return ListView; 103 | })(); 104 | Backbone.sync = function(method, model, success, error) { 105 | return success(); 106 | }; 107 | return list_view = new ListView; 108 | }); 109 | }).call(this); 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoffeeScript, Meet Backbone.js 2 | 3 | **CoffeeScript, Meet BackBone.js** is a simple [Backbone.js](http://documentcloud.github.com/backbone) tutorial written in [CoffeeScript](http://coffeescript.org/) comprised of self-explanatory "hello world" examples of increasing complexity. It was designed to provide a smoother transition from zero to the popular [Todos example](http://documentcloud.github.com/backbone/docs/todos.html). The bulk of this tutorial is a rewrite of the original [hello-backbonejs](http://arturadib.github.com/hello-backbonejs/) tutorial. 4 | 5 | See it in action: http://adamjspooner.github.com/coffeescript-meet-backbonejs/ 6 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoffeeScript, Meet Backbone.js: A Tutorial 6 | 7 | 21 | 22 | 23 |
    24 |
    25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 41 | 65 | 66 | 67 |

    CoffeeScript, Meet Backbone.js

    35 |

    CoffeeScript, Meet Backbone.js is a simple Backbone.js tutorial written in CoffeeScript comprised of self-explanatory "hello world" examples of increasing complexity. It was designed to provide a smoother transition from zero to the popular Todos example The bulk of this tutorial is a rewrite of the original hello-backbonejs tutorial.

    36 |

    Backbone.js offers a lean MVC framework for organizing your Javascript application. It leads to more maintainable code by untangling the "spaghetti" of callbacks tied to different parts of the DOM and the backend server that often arises in rich client-side applications.

    37 |

    The tutorial starts with a minimalist View object, and progressively introduces event binding/handling, Models, and Collections.

    38 |

    Once in the tutorial, use the navigation menu in the top-right corner to view other examples. Example numbers are in order of increasing complexity.

    39 |

    Start the Tutorial

    40 |
    42 |

    The only non-Javascript part of the examples is the following HTML template (with some minimal styling):

    43 |
    44 | <!doctype html>
    45 | <html lang="en">
    46 | <head>
    47 |   <meta charset="utf-8">
    48 |   <title>CoffeeScript, Meet Backbone.js: Part N</title>
    49 |   <link rel="stylesheet" href="/style.css">
    50 |   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    51 |   <script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
    52 |   <script src="http://ajax.cdnjs.com/ajax/libs/underscore.js/1.1.6/underscore-min.js"></script>
    53 |   <script src="http://ajax.cdnjs.com/ajax/libs/backbone.js/0.3.3/backbone-min.js"></script>
    54 |   <script src="script.js"></script>
    55 | </head>
    56 | <body>
    57 |   <header>
    58 |     <h1>CoffeeScript, Meet Backbone.js: Part N</h1>
    59 |     <p>Looking for <a href="docs/script.html">the documentation</a>?</p>
    60 |   </header>
    61 | </body>
    62 | </html>
    63 |               
    64 |
    68 |
    69 | 70 | 71 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | a { color: #2929FF; } 2 | a:visited { color: #777; } 3 | a:hover { 4 | color: #8F8FFF; 5 | text-decoration: none; 6 | } 7 | body, button { font: 100%/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; } 8 | body { 9 | background: #FFF; 10 | color: #444; 11 | padding: 25px 50px; 12 | } 13 | button, .delete, .swap { 14 | border: 0; 15 | border-radius: 5px; 16 | color: #FFF; 17 | cursor: pointer; 18 | font-weight: bold; 19 | line-height: 1; 20 | text-align: center; 21 | text-transform: uppercase; 22 | } 23 | button:hover, .delete:hover, .swap:hover { opacity: 1; } 24 | button { 25 | background: #2929FF; 26 | font-size: 0.75em; 27 | padding: 7px 12px; 28 | opacity: .75; 29 | } 30 | h1 { 31 | font-size: 1.25em; 32 | letter-spacing: -0.5px; 33 | } 34 | p { 35 | color: #777; 36 | font: italic 0.75em/1.2 "Georgia", Palatino, "Times New Roman", Times, serif; 37 | } 38 | span { 39 | display: inline-block; 40 | margin-right: 10px; 41 | } 42 | ul { padding-left: 0; } 43 | .delete, .swap { 44 | font-size: 0.625em; 45 | opacity: .25; 46 | padding: 3px 10px; 47 | position: relative; 48 | top: -3px; 49 | } 50 | .delete { background: #FF29D0; } 51 | .swap { background: #FF6529; } 52 | --------------------------------------------------------------------------------