├── 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 | |
---|---|
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 ->
17 | |
Our main application view. | class ListView extends Backbone.View
18 | |
We'll be using the | el: $ 'body'
22 | |
| 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: ->
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. | |
Looking for the documentation?
17 | 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: ->
28 | @counter++
29 | $('ul').append "<li>Hello, Backbone #{@counter}!</li>"
30 | |
| events: 'click button': 'addItem'
34 |
35 |
36 | list_view = new ListView |
Onward to Part 3. | |
Looking for the documentation?
17 | 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:
18 | part1: 'Hello'
19 | part2: 'Backbone'
20 |
21 | |
Our collection is
22 | an ordered set of the previously defined | class List extends Backbone.Collection
23 |
24 | model: Item
25 |
26 |
27 | class ListView extends Backbone.View
28 |
29 | el: $ 'body'
30 | |
| 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: ->
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: (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 | |
Looking for the documentation?
17 | 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 | | |
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 | class ItemView extends Backbone.View
29 | |
| tagName: 'li'
33 |
34 | initialize: ->
35 | _.bindAll @
36 |
37 | render: ->
38 | $(@el).html "<span>#{@model.get 'part1'} #{@model.get 'part2'}!</span>" |
Returning | @
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: (item) -> |
Instantiate a new | 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 | |
Looking for the documentation?
17 | script.coffee | |
---|---|
Adding Actions to a View12 | 13 |Our models have been pretty lifeless so far. We'll attach some actions to
14 | our | |
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: ->
36 | _.bindAll @
37 |
38 | @model.bind 'change', @render
39 | @model.bind 'remove', @unrender
40 | |
| 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: =>
50 | $(@el).remove()
51 | |
| swap: ->
54 | @model.set
55 | part1: @model.get 'part2'
56 | part2: @model.get 'part1'
57 |
58 | |
| remove: -> @model.destroy()
63 | |
| events:
64 | 'click .swap': 'swap'
65 | 'click .delete': 'remove'
66 |
67 | |
We no longer need to modify the | 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 = (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 | |
Looking for the documentation?
17 |CoffeeScript, Meet Backbone.js |
29 | 30 | |
---|---|
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 | 40 | |
41 |
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 | |
65 |