if(!dojo._hasResource["dojo.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojo.behavior"] = true; dojo.provide("dojo.behavior"); dojo.behavior = new function(){ function arrIn(obj, name){ if(!obj[name]){ obj[name] = []; } return obj[name]; } var _inc = 0; function forIn(obj, scope, func){ var tmpObj = {}; for(var x in obj){ if(typeof tmpObj[x] == "undefined"){ if(!func){ scope(obj[x], x); }else{ func.call(scope, obj[x], x); } } } } // FIXME: need a better test so we don't exclude nightly Safari's! this._behaviors = {}; this.add = function(behaviorObj){ // summary: // add the specified behavior to the list of behaviors which will // be applied the next time apply() is called. Calls to add() for // an already existing behavior do not replace the previous rules, // but are instead additive. New nodes which match the rule will // have all add()-ed behaviors applied to them when matched. // // description: // behavior objects are specified in the following format(s): // // { // "#id": { // "found": function(element){ // // ... // }, // // "onblah": {targetObj: foo, targetFunc: "bar"}, // // "onblarg": "/foo/bar/baz/blarg", // // "onevent": function(evt){ // }, // // "onotherevent: function(evt){ // // ... // } // }, // // "#id2": { // // ... // }, // // "#id3": function(element){ // // ... // }, // // // publish the match on a topic // "#id4": "/found/topic/name", // // // match all direct descendants // "#id4 > *": function(element){ // // ... // }, // // // match the first child node that's an element // "#id4 > :first-child": { ... }, // // // match the last child node that's an element // "#id4 > :last-child": { ... }, // // // all elements of type tagname // "tagname": { // // ... // }, // // "tagname1 tagname2 tagname3": { // // ... // }, // // ".classname": { // // ... // }, // // "tagname.classname": { // // ... // }, // } // // The "found" method is a generalized handler that's called as soon // as the node matches the selector. Rules for values that follow also // apply to the "found" key. // // The "on*" handlers are attached with dojo.connect(). // // If the value corresponding to the ID key is a function and not a // list, it's treated as though it was the value of "found". var tmpObj = {}; forIn(behaviorObj, this, function(behavior, name){ var tBehavior = arrIn(this._behaviors, name); if(typeof tBehavior["id"] != "number"){ tBehavior.id = _inc++; } var cversion = []; tBehavior.push(cversion); if((dojo.isString(behavior))||(dojo.isFunction(behavior))){ behavior = { found: behavior }; } forIn(behavior, function(rule, ruleName){ arrIn(cversion, ruleName).push(rule); }); }); } var _applyToNode = function(node, action, ruleSetName){ if(dojo.isString(action)){ if(ruleSetName == "found"){ dojo.publish(action, [ node ]); }else{ dojo.connect(node, ruleSetName, function(){ dojo.publish(action, arguments); }); } }else if(dojo.isFunction(action)){ if(ruleSetName == "found"){ action(node); }else{ dojo.connect(node, ruleSetName, action); } } } this.apply = function(){ // summary: // applies all currently registered behaviors to the document, // taking care to ensure that only incremental updates are made // since the last time add() or apply() were called. If new // matching nodes have been added, all rules in a behavior will be // applied to that node. For previously matched nodes, only // behaviors which have been added since the last call to apply() // will be added to the nodes. forIn(this._behaviors, function(tBehavior, id){ dojo.query(id).forEach( function(elem){ var runFrom = 0; var bid = "_dj_behavior_"+tBehavior.id; if(typeof elem[bid] == "number"){ runFrom = elem[bid]; // console.debug(bid, runFrom); if(runFrom == (tBehavior.length)){ return; } } // run through the versions, applying newer rules at each step for(var x=runFrom, tver; tver = tBehavior[x]; x++){ // console.debug(tver); forIn(tver, function(ruleSet, ruleSetName){ if(dojo.isArray(ruleSet)){ dojo.forEach(ruleSet, function(action){ _applyToNode(elem, action, ruleSetName); }); } }); } // ensure that re-application only adds new rules to the node elem[bid] = tBehavior.length; } ); }); } } dojo.addOnLoad(dojo.behavior, "apply"); }