]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/behavior.js
2 Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
8 if(!dojo
._hasResource
["dojo.behavior"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
9 dojo
._hasResource
["dojo.behavior"] = true;
10 dojo
.provide("dojo.behavior");
13 dojo
.behavior
= new function(){
15 // Utility for unobtrusive/progressive event binding, DOM traversal,
20 // A very simple, lightweight mechanism for applying code to
21 // existing documents, based around `dojo.query` (CSS3 selectors) for node selection,
22 // and a simple two-command API: `dojo.behavior.add()` and `dojo.behavior.apply()`;
24 // Behaviors apply to a given page, and are registered following the syntax
25 // options described by `dojo.behavior.add` to match nodes to actions, or "behaviors".
27 // Added behaviors are applied to the current DOM when .apply() is called,
28 // matching only new nodes found since .apply() was last called.
30 function arrIn(obj
, name
){
31 if(!obj
[name
]){ obj
[name
] = []; }
37 function forIn(obj
, scope
, func
){
40 if(typeof tmpObj
[x
] == "undefined"){
44 func
.call(scope
, obj
[x
], x
);
50 // FIXME: need a better test so we don't exclude nightly Safari's!
52 this.add = function(/* Object */behaviorObj
){
54 // Add the specified behavior to the list of behaviors, ignoring existing
58 // Add the specified behavior to the list of behaviors which will
59 // be applied the next time apply() is called. Calls to add() for
60 // an already existing behavior do not replace the previous rules,
61 // but are instead additive. New nodes which match the rule will
62 // have all add()-ed behaviors applied to them when matched.
64 // The "found" method is a generalized handler that's called as soon
65 // as the node matches the selector. Rules for values that follow also
66 // apply to the "found" key.
68 // The "on*" handlers are attached with `dojo.connect()`, using the
71 // If the value corresponding to the ID key is a function and not a
72 // list, it's treated as though it was the value of "found".
74 // dojo.behavior.add() can be called any number of times before
75 // the DOM is ready. `dojo.behavior.apply()` is called automatically
76 // by `dojo.addOnLoad`, though can be called to re-apply previously added
77 // behaviors anytime the DOM changes.
79 // There are a variety of formats permitted in the behaviorObject
82 // Simple list of properties. "found" is special. "Found" is assumed if
83 // no property object for a given selector, and property is a function.
85 // | dojo.behavior.add({
87 // | "found": function(element){
88 // | // node match found
90 // | "onclick": function(evt){
91 // | // register onclick handler for found node
94 // | "#otherid": function(element){
95 // | // assumes "found" with this syntax
100 // If property is a string, a dojo.publish will be issued on the channel:
102 // | dojo.behavior.add({
103 // | // dojo.publish() whenever class="noclick" found on anchors
104 // | "a.noclick": "/got/newAnchor",
105 // | "div.wrapper": {
106 // | "onclick": "/node/wasClicked"
109 // | dojo.subscribe("/got/newAnchor", function(node){
110 // | // handle node finding when dojo.behavior.apply() is called,
111 // | // provided a newly matched node is found.
115 // Scoping can be accomplished by passing an object as a property to
116 // a connection handle (on*):
118 // | dojo.behavior.add({
120 // | // like calling dojo.hitch(foo,"bar"). execute foo.bar() in scope of foo
121 // | "onmouseenter": { targetObj: foo, targetFunc: "bar" },
122 // | "onmouseleave": { targetObj: foo, targetFunc: "baz" }
127 // Bahaviors match on CSS3 Selectors, powered by dojo.query. Example selectors:
129 // | dojo.behavior.add({
130 // | // match all direct descendants
131 // | "#id4 > *": function(element){
135 // | // match the first child node that's an element
136 // | "#id4 > :first-child": { ... },
138 // | // match the last child node that's an element
139 // | "#id4 > :last-child": { ... },
141 // | // all elements of type tagname
146 // | "tagname1 tagname2 tagname3": {
154 // | "tagname.classname": {
161 forIn(behaviorObj
, this, function(behavior
, name
){
162 var tBehavior
= arrIn(this._behaviors
, name
);
163 if(typeof tBehavior
["id"] != "number"){
164 tBehavior
.id
= _inc
++;
167 tBehavior
.push(cversion
);
168 if((dojo
.isString(behavior
))||(dojo
.isFunction(behavior
))){
169 behavior
= { found
: behavior
};
171 forIn(behavior
, function(rule
, ruleName
){
172 arrIn(cversion
, ruleName
).push(rule
);
177 var _applyToNode = function(node
, action
, ruleSetName
){
178 if(dojo
.isString(action
)){
179 if(ruleSetName
== "found"){
180 dojo
.publish(action
, [ node
]);
182 dojo
.connect(node
, ruleSetName
, function(){
183 dojo
.publish(action
, arguments
);
186 }else if(dojo
.isFunction(action
)){
187 if(ruleSetName
== "found"){
190 dojo
.connect(node
, ruleSetName
, action
);
195 this.apply = function(){
197 // Applies all currently registered behaviors to the document.
200 // Applies all currently registered behaviors to the document,
201 // taking care to ensure that only incremental updates are made
202 // since the last time add() or apply() were called.
204 // If new matching nodes have been added, all rules in a behavior will be
205 // applied to that node. For previously matched nodes, only
206 // behaviors which have been added since the last call to apply()
207 // will be added to the nodes.
209 // apply() is called once automatically by `dojo.addOnLoad`, so
210 // registering behaviors with `dojo.behavior.add` before the DOM is
211 // ready is acceptable, provided the dojo.behavior module is ready.
213 // Calling appy() manually after manipulating the DOM is required
214 // to rescan the DOM and apply newly .add()ed behaviors, or to match
215 // nodes that match existing behaviors when those nodes are added to
218 forIn(this._behaviors
, function(tBehavior
, id
){
219 dojo
.query(id
).forEach(
222 var bid
= "_dj_behavior_"+tBehavior
.id
;
223 if(typeof elem
[bid
] == "number"){
225 if(runFrom
== (tBehavior
.length
)){
229 // run through the versions, applying newer rules at each step
231 for(var x
=runFrom
, tver
; tver
= tBehavior
[x
]; x
++){
232 forIn(tver
, function(ruleSet
, ruleSetName
){
233 if(dojo
.isArray(ruleSet
)){
234 dojo
.forEach(ruleSet
, function(action
){
235 _applyToNode(elem
, action
, ruleSetName
);
241 // ensure that re-application only adds new rules to the node
242 elem
[bid
] = tBehavior
.length
;
249 dojo
.addOnLoad(dojo
.behavior
, "apply");