]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/behavior.js.uncompressed.js
upgrade dojo to 1.8.3 (refs #570)
[tt-rss.git] / lib / dojo / behavior.js.uncompressed.js
1 define("dojo/behavior", ["./_base/kernel", "./_base/lang", "./_base/array", "./_base/connect", "./query", "./ready"],
2 function(dojo, lang, darray, connect, query, ready){
3
4 // module:
5 // dojo/behavior
6
7 dojo.deprecated("dojo.behavior", "Use dojo/on with event delegation (on.selector())");
8
9 var 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
244 dojo.behavior = new Behavior();
245
246 ready(dojo.behavior, "apply"); // FIXME: should this use a priority? before/after parser priority?
247
248 return dojo.behavior;
249 });