SemanticScuttle/includes/js/dojo/behavior.js

185 lines
4.8 KiB
JavaScript

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");
}