1 if(!dojo._hasResource["dojo.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojo.behavior"] = true;
3 dojo.provide("dojo.behavior");
5 dojo.behavior = new function(){
6 function arrIn(obj, name){
7 if(!obj[name]){ obj[name] = []; }
13 function forIn(obj, scope, func){
16 if(typeof tmpObj[x] == "undefined"){
20 func.call(scope, obj[x], x);
26 // FIXME: need a better test so we don't exclude nightly Safari's!
28 this.add = function(behaviorObj){
30 // add the specified behavior to the list of behaviors which will
31 // be applied the next time apply() is called. Calls to add() for
32 // an already existing behavior do not replace the previous rules,
33 // but are instead additive. New nodes which match the rule will
34 // have all add()-ed behaviors applied to them when matched.
37 // behavior objects are specified in the following format(s):
41 // "found": function(element){
45 // "onblah": {targetObj: foo, targetFunc: "bar"},
47 // "onblarg": "/foo/bar/baz/blarg",
49 // "onevent": function(evt){
52 // "onotherevent: function(evt){
61 // "#id3": function(element){
65 // // publish the match on a topic
66 // "#id4": "/found/topic/name",
68 // // match all direct descendants
69 // "#id4 > *": function(element){
73 // // match the first child node that's an element
74 // "#id4 > :first-child": { ... },
76 // // match the last child node that's an element
77 // "#id4 > :last-child": { ... },
79 // // all elements of type tagname
84 // "tagname1 tagname2 tagname3": {
92 // "tagname.classname": {
97 // The "found" method is a generalized handler that's called as soon
98 // as the node matches the selector. Rules for values that follow also
99 // apply to the "found" key.
101 // The "on*" handlers are attached with dojo.connect().
103 // If the value corresponding to the ID key is a function and not a
104 // list, it's treated as though it was the value of "found".
107 forIn(behaviorObj, this, function(behavior, name){
108 var tBehavior = arrIn(this._behaviors, name);
109 if(typeof tBehavior["id"] != "number"){
110 tBehavior.id = _inc++;
113 tBehavior.push(cversion);
114 if((dojo.isString(behavior))||(dojo.isFunction(behavior))){
115 behavior = { found: behavior };
117 forIn(behavior, function(rule, ruleName){
118 arrIn(cversion, ruleName).push(rule);
123 var _applyToNode = function(node, action, ruleSetName){
124 if(dojo.isString(action)){
125 if(ruleSetName == "found"){
126 dojo.publish(action, [ node ]);
128 dojo.connect(node, ruleSetName, function(){
129 dojo.publish(action, arguments);
132 }else if(dojo.isFunction(action)){
133 if(ruleSetName == "found"){
136 dojo.connect(node, ruleSetName, action);
141 this.apply = function(){
143 // applies all currently registered behaviors to the document,
144 // taking care to ensure that only incremental updates are made
145 // since the last time add() or apply() were called. If new
146 // matching nodes have been added, all rules in a behavior will be
147 // applied to that node. For previously matched nodes, only
148 // behaviors which have been added since the last call to apply()
149 // will be added to the nodes.
150 forIn(this._behaviors, function(tBehavior, id){
151 dojo.query(id).forEach(
154 var bid = "_dj_behavior_"+tBehavior.id;
155 if(typeof elem[bid] == "number"){
157 // console.debug(bid, runFrom);
158 if(runFrom == (tBehavior.length)){
162 // run through the versions, applying newer rules at each step
164 for(var x=runFrom, tver; tver = tBehavior[x]; x++){
165 // console.debug(tver);
166 forIn(tver, function(ruleSet, ruleSetName){
167 if(dojo.isArray(ruleSet)){
168 dojo.forEach(ruleSet, function(action){
169 _applyToNode(elem, action, ruleSetName);
175 // ensure that re-application only adds new rules to the node
176 elem[bid] = tBehavior.length;
183 dojo.addOnLoad(dojo.behavior, "apply");