]> git.pond.sub.org Git - eow/blob - static/dojo-release-1.1.1/dojo/_base/NodeList.js
add Dojo 1.1.1
[eow] / static / dojo-release-1.1.1 / dojo / _base / NodeList.js
1 if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojo._base.NodeList"] = true;
3 dojo.provide("dojo._base.NodeList");
4 dojo.require("dojo._base.lang");
5 dojo.require("dojo._base.array");
6
7 (function(){
8
9         var d = dojo;
10
11         var tnl = function(arr){
12                 // decorate an array to make it look like a NodeList
13                 arr.constructor = dojo.NodeList;
14                 dojo._mixin(arr, dojo.NodeList.prototype);
15                 return arr;
16         }
17
18         var _mapIntoDojo = function(func, alwaysThis){
19                 // returns a function which, when executed in the scope of its caller,
20                 // applies the passed arguments to a particular dojo.* function (named
21                 // in func) and aggregates the returns. if alwaysThis is true, it
22                 // always returns the scope object and not the collected returns from
23                 // the Dojo method
24                 return function(){
25                         var _a = arguments;
26                         var aa = d._toArray(_a, 0, [null]);
27                         var s = this.map(function(i){
28                                 aa[0] = i;
29                                 return d[func].apply(d, aa);
30                         });
31                         return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
32                 }
33         };
34
35         dojo.NodeList = function(){
36                 //      summary:
37                 //              dojo.NodeList is as subclass of Array which adds syntactic 
38                 //              sugar for chaining, common iteration operations, animation, 
39                 //              and node manipulation. NodeLists are most often returned as
40                 //              the result of dojo.query() calls.
41                 //      example:
42                 //              create a node list from a node
43                 //              |       new dojo.NodeList(dojo.byId("foo"));
44
45                 return tnl(Array.apply(null, arguments));
46         }
47
48         dojo.NodeList._wrap = tnl;
49
50         dojo.extend(dojo.NodeList, {
51                 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
52
53                 // FIXME: handle return values for #3244
54                 //              http://trac.dojotoolkit.org/ticket/3244
55                 
56                 // FIXME:
57                 //              need to wrap or implement:
58                 //                      join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
59                 //                      reduce
60                 //                      reduceRight
61
62                 slice: function(/*===== begin, end =====*/){
63                         // summary:
64                         //              Returns a new NodeList, maintaining this one in place
65                         // description:
66                         //              This method behaves exactly like the Array.slice method
67                         //              with the caveat that it returns a dojo.NodeList and not a
68                         //              raw Array. For more details, see:
69                         //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
70                         // begin: Integer
71                         //              Can be a positive or negative integer, with positive
72                         //              integers noting the offset to begin at, and negative
73                         //              integers denoting an offset from the end (i.e., to the left
74                         //              of the end)
75                         // end: Integer?
76                         //              Optional parameter to describe what position relative to
77                         //              the NodeList's zero index to end the slice at. Like begin,
78                         //              can be positive or negative.
79                         var a = dojo._toArray(arguments);
80                         return tnl(a.slice.apply(this, a));
81                 },
82
83                 splice: function(/*===== index, howmany, item =====*/){
84                         // summary:
85                         //              Returns a new NodeList, manipulating this NodeList based on
86                         //              the arguments passed, potentially splicing in new elements
87                         //              at an offset, optionally deleting elements
88                         // description:
89                         //              This method behaves exactly like the Array.splice method
90                         //              with the caveat that it returns a dojo.NodeList and not a
91                         //              raw Array. For more details, see:
92                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
93                         // index: Integer
94                         //              begin can be a positive or negative integer, with positive
95                         //              integers noting the offset to begin at, and negative
96                         //              integers denoting an offset from the end (i.e., to the left
97                         //              of the end)
98                         // howmany: Integer?
99                         //              Optional parameter to describe what position relative to
100                         //              the NodeList's zero index to end the slice at. Like begin,
101                         //              can be positive or negative.
102                         // item: Object...?
103                         //              Any number of optional parameters may be passed in to be
104                         //              spliced into the NodeList
105                         // returns:
106                         //              dojo.NodeList
107                         var a = dojo._toArray(arguments);
108                         return tnl(a.splice.apply(this, a));
109                 },
110
111                 concat: function(/*===== item =====*/){
112                         // summary:
113                         //              Returns a new NodeList comprised of items in this NodeList
114                         //              as well as items passed in as parameters
115                         // description:
116                         //              This method behaves exactly like the Array.concat method
117                         //              with the caveat that it returns a dojo.NodeList and not a
118                         //              raw Array. For more details, see:
119                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
120                         // item: Object...?
121                         //              Any number of optional parameters may be passed in to be
122                         //              spliced into the NodeList
123                         // returns:
124                         //              dojo.NodeList
125                         var a = dojo._toArray(arguments, 0, [this]);
126                         return tnl(a.concat.apply([], a));
127                 },
128                 
129                 indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
130                         //      summary:
131                         //              see dojo.indexOf(). The primary difference is that the acted-on 
132                         //              array is implicitly this NodeList
133                         // value:
134                         //              The value to search for.
135                         // fromIndex:
136                         //              The loction to start searching from. Optional. Defaults to 0.
137                         //      description:
138                         //              For more details on the behavior of indexOf, see:
139                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
140                         //      returns:
141                         //              Positive Integer or 0 for a match, -1 of not found.
142                         return d.indexOf(this, value, fromIndex); // Integer
143                 },
144
145                 lastIndexOf: function(/*===== value, fromIndex =====*/){
146                         // summary:
147                         //              see dojo.lastIndexOf(). The primary difference is that the
148                         //              acted-on array is implicitly this NodeList
149                         //      description:
150                         //              For more details on the behavior of lastIndexOf, see:
151                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
152                         // value: Object
153                         //              The value to search for.
154                         // fromIndex: Integer?
155                         //              The loction to start searching from. Optional. Defaults to 0.
156                         // returns:
157                         //              Positive Integer or 0 for a match, -1 of not found.
158                         return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
159                 },
160
161                 every: function(/*Function*/callback, /*Object?*/thisObject){
162                         //      summary:
163                         //              see `dojo.every()` and:
164                         //                      <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
165                         //              Takes the same structure of arguments and returns as
166                         //              dojo.every() with the caveat that the passed array is
167                         //              implicitly this NodeList
168                         return d.every(this, callback, thisObject); // Boolean
169                 },
170
171                 some: function(/*Function*/callback, /*Object?*/thisObject){
172                         //      summary:
173                         //              see dojo.some() and:
174                         //                      http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
175                         //              Takes the same structure of arguments and returns as
176                         //              dojo.some() with the caveat that the passed array is
177                         //              implicitly this NodeList
178                         return d.some(this, callback, thisObject); // Boolean
179                 },
180
181                 map: function(/*Function*/ func, /*Function?*/ obj){
182                         //      summary:
183                         //              see dojo.map(). The primary difference is that the acted-on
184                         //              array is implicitly this NodeList and the return is a
185                         //              dojo.NodeList (a subclass of Array)
186
187                         return d.map(this, func, obj, d.NodeList); // dojo.NodeList
188                 },
189
190                 forEach: function(callback, thisObj){
191                         //      summary:
192                         //              see dojo.forEach(). The primary difference is that the acted-on 
193                         //              array is implicitly this NodeList
194
195                         d.forEach(this, callback, thisObj);
196                         // non-standard return to allow easier chaining
197                         return this; // dojo.NodeList 
198                 },
199
200                 // custom methods
201                 
202                 coords: function(){
203                         //      summary:
204                         //              Returns the box objects all elements in a node list as
205                         //              an Array (*not* a NodeList)
206                         
207                         return d.map(this, d.coords); // Array
208                 },
209
210                 /*=====
211                 attr: function(property, value){
212                         //      summary:
213                         //              gets or sets the DOM attribute for every element in the
214                         //              NodeList
215                         //      property: String
216                         //              the attribute to get/set
217                         //      value: String?
218                         //              optional. The value to set the property to
219                         //      return:
220                         //              if no value is passed, the result is an array of attribute values
221                         //              If a value is passed, the return is this NodeList
222                 },
223
224                 style: function(property, value){
225                         //      summary:
226                         //              gets or sets the CSS property for every element in the NodeList
227                         //      property: String
228                         //              the CSS property to get/set, in JavaScript notation
229                         //              ("lineHieght" instead of "line-height") 
230                         //      value: String?
231                         //              optional. The value to set the property to
232                         //      return:
233                         //              if no value is passed, the result is an array of strings.
234                         //              If a value is passed, the return is this NodeList
235                 },
236
237                 addClass: function(className){
238                         //      summary:
239                         //              adds the specified class to every node in the list
240                         //      className: String
241                         //              the CSS class to add
242                         //      return:
243                         //              dojo.NodeList, this list
244                 },
245
246                 removeClass: function(className){
247                         //      summary:
248                         //              removes the specified class from every node in the list
249                         //      className: String
250                         //              the CSS class to add
251                         //      return:
252                         //              dojo.NodeList, this list
253                 },
254
255                 toggleClass: function(className, condition){
256                         //      summary:
257                         //              Adds a class to node if not present, or removes if present.
258                         //              Pass a boolean condition if you want to explicitly add or remove.
259                         //      condition: Boolean?
260                         //              If passed, true means to add the class, false means to remove.
261                         //      className: String
262                         //              the CSS class to add
263                         //      return: dojo.NodeList
264                         //              this list
265                 },
266
267                 connect: function(methodName, objOrFunc, funcName){
268                         //      summary:
269                         //              attach event handlers to every item of the NodeList. Uses dojo.connect()
270                         //              so event properties are normalized
271                         //      methodName: String
272                         //              the name of the method to attach to. For DOM events, this should be
273                         //              the lower-case name of the event
274                         //      objOrFunc: Object|Function|String
275                         //              if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
276                         //              reference a function or be the name of the function in the global
277                         //              namespace to attach. If 3 arguments are provided
278                         //              (methodName, objOrFunc, funcName), objOrFunc must be the scope to 
279                         //              locate the bound function in
280                         //      funcName: String?
281                         //              optional. A string naming the function in objOrFunc to bind to the
282                         //              event. May also be a function reference.
283                         //      example:
284                         //              add an onclick handler to every button on the page
285                         //              |       dojo.query("div:nth-child(odd)").connect("onclick", function(e){
286                         //              |               console.debug("clicked!");
287                         //              |       });
288                         // example:
289                         //              attach foo.bar() to every odd div's onmouseover
290                         //              |       dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
291                 },
292                 =====*/
293                 attr: _mapIntoDojo("attr"),
294                 style: _mapIntoDojo("style"),
295                 addClass: _mapIntoDojo("addClass", true),
296                 removeClass: _mapIntoDojo("removeClass", true),
297                 toggleClass: _mapIntoDojo("toggleClass", true),
298                 connect: _mapIntoDojo("connect", true),
299
300                 // FIXME: connectPublisher()? connectRunOnce()?
301
302                 place: function(/*String||Node*/ queryOrNode, /*String*/ position){
303                         //      summary:
304                         //              places elements of this node list relative to the first element matched
305                         //              by queryOrNode. Returns the original NodeList.
306                         //      queryOrNode:
307                         //              may be a string representing any valid CSS3 selector or a DOM node.
308                         //              In the selector case, only the first matching element will be used 
309                         //              for relative positioning.
310                         //      position:
311                         //              can be one of:
312                         //                      * "last"||"end" (default)
313                         //                      * "first||"start"
314                         //                      * "before"
315                         //                      * "after"
316                         //              or an offset in the childNodes property
317                         var item = d.query(queryOrNode)[0];
318                         return this.forEach(function(i){ d.place(i, item, (position||"last")); }); // dojo.NodeList
319                 },
320
321                 orphan: function(/*String?*/ simpleFilter){
322                         //      summary:
323                         //              removes elements in this list that match the simple
324                         //              filter from their parents and returns them as a new
325                         //              NodeList.
326                         //      simpleFilter:
327                         //              single-expression CSS filter
328                         //      return:
329                         //              `dojo.NodeList` the orpahned elements 
330                         var orphans = simpleFilter ? d._filterQueryResult(this, simpleFilter) : this;
331                         orphans.forEach(function(item){
332                                 if(item.parentNode){
333                                         item.parentNode.removeChild(item);
334                                 }
335                         });
336                         return orphans; // dojo.NodeList
337                 },
338
339                 adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
340                         //      summary:
341                         //              places any/all elements in queryOrListOrNode at a
342                         //              position relative to the first element in this list.
343                         //              Returns a dojo.NodeList of the adopted elements.
344                         //      queryOrListOrNode:
345                         //              a DOM node or a query string or a query result.
346                         //              Represents the nodes to be adopted relative to the
347                         //              first element of this NodeList.
348                         //      position:
349                         //              can be one of:
350                         //                      * "last"||"end" (default)
351                         //                      * "first||"start"
352                         //                      * "before"
353                         //                      * "after"
354                         //              or an offset in the childNodes property
355                         var item = this[0];
356                         return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, position || "last"); }); // dojo.NodeList
357                 },
358
359                 // FIXME: do we need this?
360                 query: function(/*String*/ queryStr){
361                         //      summary:
362                         //              Returns a new, flattened NodeList. Elements of the new list
363                         //              satisfy the passed query but use elements of the
364                         //              current NodeList as query roots.
365
366                         if(!queryStr){ return this; }
367
368                         // FIXME: probably slow
369                         // FIXME: use map?
370                         var ret = d.NodeList();
371                         this.forEach(function(item){
372                                 d.query(queryStr, item).forEach(function(subItem){
373                                         if(subItem !== undefined){
374                                                 ret.push(subItem);
375                                         }
376                                 });
377                         });
378                         return ret; // dojo.NodeList
379                 },
380
381                 filter: function(/*String*/ simpleQuery){
382                         //      summary:
383                         //              "masks" the built-in javascript filter() method to support
384                         //              passing a simple string filter in addition to supporting
385                         //              filtering function objects.
386                         //      example:
387                         //              "regular" JS filter syntax as exposed in dojo.filter:
388                         //              |       dojo.query("*").filter(function(item){
389                         //              |               // highlight every paragraph
390                         //              |               return (item.nodeName == "p");
391                         //              |       }).styles("backgroundColor", "yellow");
392                         // example:
393                         //              the same filtering using a CSS selector
394                         //              |       dojo.query("*").filter("p").styles("backgroundColor", "yellow");
395
396                         var items = this;
397                         var _a = arguments;
398                         var r = d.NodeList();
399                         var rp = function(t){ 
400                                 if(t !== undefined){
401                                         r.push(t); 
402                                 }
403                         }
404                         if(d.isString(simpleQuery)){
405                                 items = d._filterQueryResult(this, _a[0]);
406                                 if(_a.length == 1){
407                                         // if we only got a string query, pass back the filtered results
408                                         return items; // dojo.NodeList
409                                 }
410                                 // if we got a callback, run it over the filtered items
411                                 _a.shift();
412                         }
413                         // handle the (callback, [thisObject]) case
414                         d.forEach(d.filter(items, _a[0], _a[1]), rp);
415                         return r; // dojo.NodeList
416                 },
417                 
418                 /*
419                 // FIXME: should this be "copyTo" and include parenting info?
420                 clone: function(){
421                         // summary:
422                         //              creates node clones of each element of this list
423                         //              and returns a new list containing the clones
424                 },
425                 */
426
427                 addContent: function(/*String*/ content, /*String||Integer?*/ position){
428                         //      summary:
429                         //              add a node or some HTML as a string to every item in the list. 
430                         //              Returns the original list.
431                         //      description:
432                         //              a copy of the HTML content is added to each item in the
433                         //              list, with an optional position argument. If no position
434                         //              argument is provided, the content is appended to the end of
435                         //              each item.
436                         //      content:
437                         //              the HTML in string format to add at position to every item
438                         //      position:
439                         //              can be one of:
440                         //                      * "last"||"end" (default)
441                         //                      * "first||"start"
442                         //                      * "before"
443                         //                      * "after"
444                         //              or an offset in the childNodes property
445                         //      example:
446                         //              appends content to the end if the position is ommitted
447                         //      |       dojo.query("h3 > p").addContent("hey there!");
448                         //      example:
449                         //              add something to the front of each element that has a "thinger" property:
450                         //      |       dojo.query("[thinger]").addContent("...", "first");
451                         //      example:
452                         //              adds a header before each element of the list
453                         //      |       dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
454                         var ta = d.doc.createElement("span");
455                         if(d.isString(content)){
456                                 ta.innerHTML = content;
457                         }else{
458                                 ta.appendChild(content);
459                         }
460                         if(position === undefined){
461                                 position = "last";
462                         }
463                         var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
464                         this.forEach(function(item){
465                                 var tn = ta.cloneNode(true);
466                                 while(tn[ct]){
467                                         d.place(tn[ct], item, position);
468                                 }
469                         });
470                         return this; // dojo.NodeList
471                 },
472
473                 empty: function(){
474                         //      summary:
475                         //              clears all content from each node in the list
476                         return this.forEach("item.innerHTML='';"); // dojo.NodeList
477
478                         // FIXME: should we be checking for and/or disposing of widgets below these nodes?
479                 },
480                 
481                 instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
482                         //      summary:
483                         //              Create a new instance of a specified class, using the
484                         //              specified properties and each node in the nodeList as a
485                         //              srcNodeRef
486                         //
487                         var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
488                         return this.forEach(function(i){
489                                 new c(properties||{},i);
490                         }) // dojo.NodeList
491                 }
492
493         });
494
495         // syntactic sugar for DOM events
496         d.forEach([
497                 "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
498                 "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
499                 "mouseup"
500                 ], function(evt){
501                         var _oe = "on"+evt;
502                         dojo.NodeList.prototype[_oe] = function(a, b){
503                                 return this.connect(_oe, a, b);
504                         }
505                                 // FIXME: should these events trigger publishes?
506                                 /*
507                                 return (a ? this.connect(_oe, a, b) : 
508                                                         this.forEach(function(n){  
509                                                                 // FIXME:
510                                                                 //              listeners get buried by
511                                                                 //              addEventListener and can't be dug back
512                                                                 //              out to be triggered externally.
513                                                                 // see:
514                                                                 //              http://developer.mozilla.org/en/docs/DOM:element
515
516                                                                 console.debug(n, evt, _oe);
517
518                                                                 // FIXME: need synthetic event support!
519                                                                 var _e = { target: n, faux: true, type: evt };
520                                                                 // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
521                                                                 try{ n[evt](_e); }catch(e){ console.debug(e); }
522                                                                 try{ n[_oe](_e); }catch(e){ console.debug(e); }
523                                                         })
524                                 );
525                         }
526                         */
527                 }
528         );
529
530 })();
531
532 }