Skip to content
This repository
Newer
Older
100644 354 lines (245 sloc) 12.026 kb
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
1 h1. Entwine - Support for Concrete UI style programming in jQuery
679b3dd8 »
2009-08-13 Adding documentation
2
29fd0bda »
2009-10-12 Update README
3 By Hamish Friedlander, with thanks to "SilverStripe":http://www.silverstripe.com/
4
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
5 Entwine tries to provide a new model of code organisation - a replacement for Object Oriented programming that is focused on adding functions to groups of DOM elements based on the structure and contents of those DOM elements. It's a merging of the model and view layer that initially seems weird, but can give very powerful results.
29fd0bda »
2009-10-12 Update README
6
7 We're standing on the shoulders of giants here - combining ideas from Prototype's behaviour & lowpro and jQuery's effen & livequery (who themselves stole ideals from Self's Morphic UI and others), but extending & combining the concepts presented in those tools to provide a complete alternative to traditional OO concepts - self-aware methods, inheritance, polymorphisim and namespacing without a single class definition.
8
9 h2. Getting Started
10
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
11 * Walk through the "Tutorial":http://hafriedlander.github.com/jquery.entwine/tutorial/
7c2a032b »
2009-10-12 Update README
12 * Watch the "Screencast":http://www.vimeo.com/6353390 (shot during a introductory developer meeting at SilverStripe)
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
13 * Join the "Google Group":http://groups.google.com/group/jquery-entwine and let us know what you think, or what other features you'd like to see
679b3dd8 »
2009-08-13 Adding documentation
14
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
15 h2. Name change
92000686 »
2009-11-02 Update README with some information about pending name change
16
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
17 jQuery Entwine used to be called jQuery Concrete. The name was changed to avoid confusion with another product. The concrete function remains as an alias, but all new code should use entwine
92000686 »
2009-11-02 Update README with some information about pending name change
18
679b3dd8 »
2009-08-13 Adding documentation
19 h2. Basic use
20
21 h4. First intro
22
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
23 To attach methods to DOM nodes, call the `entwine` function on a jQuery selector object, passing a hash listing the method names and bodys
679b3dd8 »
2009-08-13 Adding documentation
24
25 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
26 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
27 foo: function(..){..},
28 bar: function(..){..}
29 });
30 </code></pre>
31
32 You can then call those methods on any jQuery object.
33
34 <pre><code>
35 $('#a').foo();
36 </code></pre>
37
38 Any elements in the jQuery selection that match the selector used during definition ('div' in this example) will have foo called with that element
39 set as this. Any other objects are skipped. The return value will be the return value of foo() for the last matched DOM object in the set
40
41 h4. A proper example
42
43 Given this DOM structure:
44
45 <pre><code>
46 <body>
47 <div class="internal_text">Internal text</div>
48 <div class="attribute_text" rel="Attribute text"></div>
49 <div>Nonsense</div>
50 </body>
51 </code></pre>
52
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
53 And this entwine definition
679b3dd8 »
2009-08-13 Adding documentation
54
55 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
56 $('.internal_text').entwine({
679b3dd8 »
2009-08-13 Adding documentation
57 foo: function(){ console.log(this.text()); }
58 });
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
59 $('.attribute_text').entwine({
679b3dd8 »
2009-08-13 Adding documentation
60 foo: function(){ console.log(this.attr('rel')); }
61 });
62 </code></pre>
63
64 Then this call
65
66 <pre><code>
67 $('div').foo();
68 </code></pre>
69
70 Will log this to the console
71
72 <pre><code>
73 Internal text
74 Attribute text
75 </code></pre>
76
77 h4. Limitations
78
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
79 When defining methods, the jQuery object that entwine is called on must be a plain selector, without context. These examples will not work
679b3dd8 »
2009-08-13 Adding documentation
80
81 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
82 $('div', el).entwine(...)
83 $([ela, elb, elc]).entwine(...)
84 $('<div id="a"></div>').entwine(...)
679b3dd8 »
2009-08-13 Adding documentation
85 </code></pre>
86
87 h2. Live
88
89 The definitions you provide are not bound to the elements that match at definition time. You can declare behaviour prior to the DOM existing in any
90 form (i.e. prior to DOMReady) and later calls will function correctly.
91
92 h2. Selector specifity
93
94 When there are two definitions for a particular method on a particular DOM node, the function with the most _specific_ selector is used.
95 _Specifity_ is calculated as defined by the CSS 2/3 spec. This can be seen as _subclassing_ applied to behaviour.
96
97 Another example. Given this DOM structure
98
99 <pre><code>
100 <body>
101 <div>Internal text</div>
102 <div class="attribute_text" rel="Attribute text"></div>
103 <div>Nonsense</div>
104 </body>
105 </code></pre>
106
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
107 And this entwine definition
679b3dd8 »
2009-08-13 Adding documentation
108
109 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
110 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
111 foo: function(){ console.log(this.text()); }
112 });
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
113 $('.attribute_text').entwine({
679b3dd8 »
2009-08-13 Adding documentation
114 foo: function(){ console.log(this.attr('rel')); }
115 });
116 </code></pre>
117
118 Then this call
119
120 <pre><code>
121 $('div').foo();
122 </code></pre>
123
124 Will log this to the console
125
126 <pre><code>
127 Internal text
128 Attribute text
129 Nonsense
130 </code></pre>
131
132 h2. Events
133
134 If you declare a function with a name starting with 'on', then instead of defining that function, it will be bound to an event of that
135 name. Just like other functions this binding will be live, and only the most specific definition will be used
136
137 <pre><code>
138 <head>
139 <script type='text/javascript'>
140 /* No need for onready wrapper. Events are bound as needed */
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
141 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
142 onclick: function(){ this.css({backgroundColor: 'blue'}); }
143 });
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
144 $('.green').entwine({
679b3dd8 »
2009-08-13 Adding documentation
145 onclick: function(){ this.css({color: 'green'}); }
146 });
147 </script>
148 <body>
149 <div>Background will turn blue when clicked on</div>
150 <div>Will also have blue background when clicked on</div>
151 <div class='green'>Will have green text when clicked on. Background color will not change</div>
152 </body>
153 </code></pre>
154
155 h2. Constructors / Destructors
156
157 Declaring a function with the name `onmatch` will create a behavior that is called on each object when it matches. Likewise, `onunmatch` will
158 be called when an object that did match this selector stops matching it (because it is removed, or because you've changed its properties).
159
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
160 Note that an onunmatch block must be paired with an onmatch block - an onunmatch without an onmatch _in the same entwine definition block_ is illegal
679b3dd8 »
2009-08-13 Adding documentation
161
162 Like other functions, only the most specific definition will be used. However, because property changes are not atomic, this may not work as you
163 expect.
164
165 h2. Namespaces
166
167 To avoid name clashes, to allow multiple bindings to the same event, and to generally seperate a set of functions from other code you can use namespaces
168
169 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
170 $.entwine('foo.bar', function($){
171 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
172 baz: function(){}
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
173 });
174 });
679b3dd8 »
2009-08-13 Adding documentation
175 </code></pre>
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
176
679b3dd8 »
2009-08-13 Adding documentation
177 You can then call these functions like this:
178
179 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
180 $('div').entwine('foo.bar').baz()
679b3dd8 »
2009-08-13 Adding documentation
181 </code></pre>
182
183 Namespaced functions work just like regular functions (`this` is still set to a matching DOM Node). However, specifity is calculated per namespace.
184 This is particularly useful for events, because given this:
185
186 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
187 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
188 onclick: function(){ this.css({backgroundColor: 'blue'}); }
189 });
190
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
191 $.entwine('foo', function($){
192 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
193 onclick: function(){ this.css({color: 'green'}); }
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
194 });
195 });
679b3dd8 »
2009-08-13 Adding documentation
196 </code></pre>
197
198 Clicking on a div will change the background **and** foreground color.
199
200 This is particularly important when writing reusable code, since otherwise you can't know before hand whether your event handler will be called or not
201
202 Although a namespace can be any string, best practise is to name them with dotted-identifier notation.
203
204 h4. Namespaces and scope (or What the hell's up with that ugly function closure)
205
206 Inside a namespace definition, functions remember the namespace they are in, and calls to other functions will be looked up inside that namespace first.
207 Where they don't exist, they will be looked up in the base namespace
208
209 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
210 $.entwine('foo', function($){
211 $('div').entwine({
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
212 bar: function() { this.baz(); this.qux(); }
213 baz: function() { console.log('baz'); }
214 })
679b3dd8 »
2009-08-13 Adding documentation
215 })
216
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
217 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
218 qux: function() { console.log('qux'); }
219 })
220 </code></pre>
221
222 Will print baz, qux to the console
223
224 Note that 'exists' means that a function is declared in this namespace for _any_ selector, not just a matching one. Given the dom
225
226 <pre><code>
227 <div>Internal text</div>
228 </code></pre>
229
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
230 And the entwine definitions
679b3dd8 »
2009-08-13 Adding documentation
231
232 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
233 $.entwine('foo', function($){
234 $('div').entwine({
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
235 bar: function() { this.baz(); }
236 });
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
237 $('span').entwine({
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
238 baz: function() { console.log('a'); }
239 });
679b3dd8 »
2009-08-13 Adding documentation
240 })
241
242
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
243 $('div').entwine({
679b3dd8 »
2009-08-13 Adding documentation
244 baz: function() { console.log('b'); }
245 })
246 </code></pre>
247
248 Then doing $('div').bar(); will _not_ display b. Even though the span rule could never match a div, because baz is defined for some rule in the foo namespace, the base namespace will never be checked
249
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
250 h4. Nesting namespace blocks
bde0327c »
2009-08-14 Add method of specifying namespace blocks separate from the internal …
251
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
252 You can also nest declarations. In this next example, we're defining the functions $().entwine('zap').bar() and $().entwine('zap.pow').baz()
bde0327c »
2009-08-14 Add method of specifying namespace blocks separate from the internal …
253
254 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
255 $.entwine('zap', function($){
256 $('div').entwine({
bde0327c »
2009-08-14 Add method of specifying namespace blocks separate from the internal …
257 bar: function() { .. }
258 })
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
259 $.entwine('pow', function($){
260 $('div').entwine({
bde0327c »
2009-08-14 Add method of specifying namespace blocks separate from the internal …
261 baz: function() { .. }
262 })
263 })
264 })
265 </code></pre>
266
267 h4. Calling to another namespace (and forcing base)
268
269 Inside a namespace, namespace lookups are by default relative to the current namespace.
270
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
271 In some situations (such as the last example) you may want to force using the base namespace. In this case you can call entwine with the first argument being the base namespace code '.'. For example, if the first definition in the previous example was
679b3dd8 »
2009-08-13 Adding documentation
272
273 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
274 $.entwine('foo', function($){
275 $('div').entwine({
276 bar: function() { this.entwine('.').baz(); }
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
277 })
679b3dd8 »
2009-08-13 Adding documentation
278 })
279 </code></pre>
280
bde0327c »
2009-08-14 Add method of specifying namespace blocks separate from the internal …
281 Then b _would_ be output to the console.
679b3dd8 »
2009-08-13 Adding documentation
282
283 h4. Using
284
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
285 Sometimes a block outside of a namespace will need to refer to that namespace repeatedly. By passing a function to the entwine function, you can change the looked-up namespace
679b3dd8 »
2009-08-13 Adding documentation
286
287 <pre><code>
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
288 $.entwine('foo', function($){
289 $('div').entwine({
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
290 bar: function() { console.log('a'); }
291 })
679b3dd8 »
2009-08-13 Adding documentation
292 })
293
7bf2d391 »
2009-12-01 Rename concrete to entwine (and concreteData to entwineData, etc.), a…
294 $('div').entwine('foo', function(){
679b3dd8 »
2009-08-13 Adding documentation
295 this.bar();
bae4684b »
2009-10-16 Update README to only use recommended namespace structure
296 this.bar();
297 this.bar();
679b3dd8 »
2009-08-13 Adding documentation
298 });
299 </code></pre>
300
29fd0bda »
2009-10-12 Update README
301 This equivalent to /with/ in javascript, and just like /with/, care should be taken to only use this construct in situations that merit it.
302
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
303 h2. Tests
b42d578a »
2009-10-22 add notes on how to run specs to the readme.
304
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
305 Specs are written using the awesome "JSpec":http://github.com/visionmedia/jspec library. You can run them in two ways
b42d578a »
2009-10-22 add notes on how to run specs to the readme.
306
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
307 h4. Ad-hoc
308
309 Open the file `spec/spec.html` in any modern browser
310
311 h4. Continuous testing
312
313 JSpec has a command line client which can be used for continuous testing. Make sure ruby is installed and enabled the "Gemcutter":http://gemcutter.org/ gem hosting service, like so:
b42d578a »
2009-10-22 add notes on how to run specs to the readme.
314
315 <pre><code>
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
316 sudo gem install gemcutter
317 sudo gem tumble
b42d578a »
2009-10-22 add notes on how to run specs to the readme.
318 </code></pre>
319
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
320 Then install the jspec binary:
b42d578a »
2009-10-22 add notes on how to run specs to the readme.
321
322 <pre><code>
323 sudo gem install jspec
324 </code></pre>
325
25ff759c »
2009-11-02 Update README to be a bit clearer on how to get JSpec running
326 The JSpec command line tool should now be installed. This command will re-run the specs whenever you edit a file:
327
328 <pre><code>
329 jspec spec/spec.html -p src,spec
330 </code></pre>
331
332
29fd0bda »
2009-10-12 Update README
333 h2. License
334
7c2a032b »
2009-10-12 Update README
335 Copyright (C) 2009 Hamish Friedlander (hamish@silverstripe.com) and SilverStripe Limited (www.silverstripe.com). All rights reserved.
29fd0bda »
2009-10-12 Update README
336
337 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
338
339 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
340 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
341 * Neither the name of Hamish Friedlander nor SilverStripe nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
679b3dd8 »
2009-08-13 Adding documentation
342
29fd0bda »
2009-10-12 Update README
343 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
679b3dd8 »
2009-08-13 Adding documentation
344
345
346
347
348
349
350
351
352
353
354
Something went wrong with that request. Please try again.