source: Dev/trunk/src/client/dojo/behavior.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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