~clinton-collins/familyproject/trunk

« back to all changes in this revision

Viewing changes to ZendFramework/externals/dojo/dojo/behavior.js

  • Committer: Clinton Collins
  • Date: 2009-06-26 19:54:58 UTC
  • Revision ID: clinton.collins@gmail.com-20090626195458-5ebba0qcvo15xlpy
Initial Import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
dojo.provide("dojo.behavior");
 
2
 
 
3
dojo.behavior = new function(){
 
4
        // summary: 
 
5
        //              Utility for unobtrusive/progressive event binding, DOM traversal,
 
6
        //              and manipulation.
 
7
        //
 
8
        // description:
 
9
        //              
 
10
        //              A very simple, lightweight mechanism for applying code to 
 
11
        //              existing documents, based around `dojo.query` (CSS3 selectors) for node selection, 
 
12
        //              and a simple two-command API: `dojo.behavior.add()` and `dojo.behavior.apply()`;
 
13
        //      
 
14
        //              Behaviors apply to a given page, and are registered following the syntax 
 
15
        //              options described by `dojo.behavior.add` to match nodes to actions, or "behaviors".
 
16
        //              
 
17
        //              Added behaviors are applied to the current DOM when .apply() is called,
 
18
        //              matching only new nodes found since .apply() was last called. 
 
19
        //              
 
20
        function arrIn(obj, name){
 
21
                if(!obj[name]){ obj[name] = []; }
 
22
                return obj[name];
 
23
        }
 
24
 
 
25
        var _inc = 0;
 
26
 
 
27
        function forIn(obj, scope, func){
 
28
                var tmpObj = {};
 
29
                for(var x in obj){
 
30
                        if(typeof tmpObj[x] == "undefined"){
 
31
                                if(!func){
 
32
                                        scope(obj[x], x);
 
33
                                }else{
 
34
                                        func.call(scope, obj[x], x);
 
35
                                }
 
36
                        }
 
37
                }
 
38
        }
 
39
 
 
40
        // FIXME: need a better test so we don't exclude nightly Safari's!
 
41
        this._behaviors = {};
 
42
        this.add = function(/* Object */behaviorObj){
 
43
                //      summary:
 
44
                //              Add the specified behavior to the list of behaviors, ignoring existing
 
45
                //              matches. 
 
46
                //
 
47
                //      description:
 
48
                //              Add the specified behavior to the list of behaviors which will
 
49
                //              be applied the next time apply() is called. Calls to add() for
 
50
                //              an already existing behavior do not replace the previous rules,
 
51
                //              but are instead additive. New nodes which match the rule will
 
52
                //              have all add()-ed behaviors applied to them when matched.
 
53
                //              
 
54
                //              The "found" method is a generalized handler that's called as soon
 
55
                //              as the node matches the selector. Rules for values that follow also
 
56
                //              apply to the "found" key.
 
57
                //              
 
58
                //              The "on*" handlers are attached with `dojo.connect()`, using the 
 
59
                //              matching node
 
60
                //              
 
61
                //              If the value corresponding to the ID key is a function and not a
 
62
                //              list, it's treated as though it was the value of "found".
 
63
                //
 
64
                //              dojo.behavior.add() can be called any number of times before 
 
65
                //              the DOM is ready. `dojo.behavior.apply()` is called automatically
 
66
                //              by `dojo.addOnLoad`, though can be called to re-apply previously added
 
67
                //              behaviors anytime the DOM changes.
 
68
                //
 
69
                //              There are a variety of formats permitted in the behaviorObject
 
70
                //      
 
71
                //      example:
 
72
                //              Simple list of properties. "found" is special. "Found" is assumed if 
 
73
                //              no property object for a given selector, and property is a function.
 
74
                //
 
75
                //      |       dojo.behavior.add({
 
76
                //      |               "#id": {
 
77
                //      |                       "found": function(element){
 
78
                //      |                               // node match found
 
79
                //      |                       },
 
80
                //      |                       "onclick": function(evt){
 
81
                //      |                               // register onclick handler for found node
 
82
                //      |                       }
 
83
                //      |               },
 
84
                //      |               "#otherid": function(element){
 
85
                //      |                       // assumes "found" with this syntax
 
86
                //      |               }
 
87
                //      |       });
 
88
                //
 
89
                //      example: 
 
90
                //               If property is a string, a dojo.publish will be issued on the channel:
 
91
                //
 
92
                //      |       dojo.behavior.add({
 
93
                //      |               // dojo.publish() whenever class="noclick" found on anchors
 
94
                //      |               "a.noclick": "/got/newAnchor",
 
95
                //      |               "div.wrapper": {
 
96
                //      |                       "onclick": "/node/wasClicked"
 
97
                //      |               }
 
98
                //      |       });
 
99
                //      |       dojo.subscribe("/got/newAnchor", function(node){
 
100
                //      |               // handle node finding when dojo.behavior.apply() is called, 
 
101
                //      |               // provided a newly matched node is found.
 
102
                //      |       });
 
103
                //
 
104
                //      example:
 
105
                //              Scoping can be accomplished by passing an object as a property to 
 
106
                //              a connection handle (on*):
 
107
                //      
 
108
                //      |       dojo.behavior.add({ 
 
109
                //      |                       "#id": {
 
110
                //      |                               // like calling dojo.hitch(foo,"bar"). execute foo.bar() in scope of foo
 
111
                //      |                               "onmouseenter": { targetObj: foo, targetFunc: "bar" },
 
112
                //      |                               "onmouseleave": { targetObj: foo, targetFunc: "baz" }
 
113
                //      |                       }
 
114
                //      |       });
 
115
                //
 
116
                //      example: 
 
117
                //              Bahaviors match on CSS3 Selectors, powered by dojo.query. Example selectors:
 
118
                //
 
119
                //      |       dojo.behavior.add({
 
120
                //      |               // match all direct descendants
 
121
                //      |               "#id4 > *": function(element){
 
122
                //      |                       // ...
 
123
                //      |               },
 
124
                //      |               
 
125
                //      |               // match the first child node that's an element
 
126
                //      |               "#id4 > :first-child": { ... },
 
127
                //      |               
 
128
                //      |               // match the last child node that's an element
 
129
                //      |               "#id4 > :last-child":  { ... },
 
130
                //      |               
 
131
                //      |               // all elements of type tagname
 
132
                //      |               "tagname": {
 
133
                //      |                       // ...
 
134
                //      |               },
 
135
                //      |               
 
136
                //      |               "tagname1 tagname2 tagname3": {
 
137
                //      |                       // ...
 
138
                //      |               },
 
139
                //      |               
 
140
                //      |               ".classname": {
 
141
                //      |                       // ...
 
142
                //      |               },
 
143
                //      |               
 
144
                //      |               "tagname.classname": {
 
145
                //      |                       // ...
 
146
                //      |               }
 
147
                //      |       });
 
148
                //   
 
149
 
 
150
                var tmpObj = {};
 
151
                forIn(behaviorObj, this, function(behavior, name){
 
152
                        var tBehavior = arrIn(this._behaviors, name);
 
153
                        if(typeof tBehavior["id"] != "number"){
 
154
                                tBehavior.id = _inc++;
 
155
                        }
 
156
                        var cversion = [];
 
157
                        tBehavior.push(cversion);
 
158
                        if((dojo.isString(behavior))||(dojo.isFunction(behavior))){
 
159
                                behavior = { found: behavior };
 
160
                        }
 
161
                        forIn(behavior, function(rule, ruleName){
 
162
                                arrIn(cversion, ruleName).push(rule);
 
163
                        });
 
164
                });
 
165
        }
 
166
 
 
167
        var _applyToNode = function(node, action, ruleSetName){
 
168
                if(dojo.isString(action)){
 
169
                        if(ruleSetName == "found"){
 
170
                                dojo.publish(action, [ node ]);
 
171
                        }else{
 
172
                                dojo.connect(node, ruleSetName, function(){
 
173
                                        dojo.publish(action, arguments);
 
174
                                });
 
175
                        }
 
176
                }else if(dojo.isFunction(action)){
 
177
                        if(ruleSetName == "found"){
 
178
                                action(node);
 
179
                        }else{
 
180
                                dojo.connect(node, ruleSetName, action);
 
181
                        }
 
182
                }
 
183
        }
 
184
 
 
185
        this.apply = function(){
 
186
                // summary:
 
187
                //              Applies all currently registered behaviors to the document.
 
188
                // 
 
189
                // description:
 
190
                //              Applies all currently registered behaviors to the document,
 
191
                //              taking care to ensure that only incremental updates are made
 
192
                //              since the last time add() or apply() were called. 
 
193
                //      
 
194
                //              If new matching nodes have been added, all rules in a behavior will be
 
195
                //              applied to that node. For previously matched nodes, only
 
196
                //              behaviors which have been added since the last call to apply()
 
197
                //              will be added to the nodes.
 
198
                //
 
199
                //              apply() is called once automatically by `dojo.addOnLoad`, so 
 
200
                //              registering behaviors with `dojo.behavior.add` before the DOM is
 
201
                //              ready is acceptable, provided the dojo.behavior module is ready.
 
202
                //              
 
203
                //              Calling appy() manually after manipulating the DOM is required 
 
204
                //              to rescan the DOM and apply newly .add()ed behaviors, or to match
 
205
                //              nodes that match existing behaviors when those nodes are added to 
 
206
                //              the DOM.
 
207
                //              
 
208
                forIn(this._behaviors, function(tBehavior, id){
 
209
                        dojo.query(id).forEach( 
 
210
                                function(elem){
 
211
                                        var runFrom = 0;
 
212
                                        var bid = "_dj_behavior_"+tBehavior.id;
 
213
                                        if(typeof elem[bid] == "number"){
 
214
                                                runFrom = elem[bid];
 
215
                                                if(runFrom == (tBehavior.length)){
 
216
                                                        return;
 
217
                                                }
 
218
                                        }
 
219
                                        // run through the versions, applying newer rules at each step
 
220
 
 
221
                                        for(var x=runFrom, tver; tver = tBehavior[x]; x++){
 
222
                                                forIn(tver, function(ruleSet, ruleSetName){
 
223
                                                        if(dojo.isArray(ruleSet)){
 
224
                                                                dojo.forEach(ruleSet, function(action){
 
225
                                                                        _applyToNode(elem, action, ruleSetName);
 
226
                                                                });
 
227
                                                        }
 
228
                                                });
 
229
                                        }
 
230
 
 
231
                                        // ensure that re-application only adds new rules to the node
 
232
                                        elem[bid] = tBehavior.length;
 
233
                                }
 
234
                        );
 
235
                });
 
236
        }
 
237
}
 
238
 
 
239
dojo.addOnLoad(dojo.behavior, "apply");