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");
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);
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
26 var aa = d._toArray(_a, 0, [null]);
27 var s = this.map(function(i){
29 return d[func].apply(d, aa);
31 return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
35 dojo.NodeList = function(){
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.
42 // create a node list from a node
43 // | new dojo.NodeList(dojo.byId("foo"));
45 return tnl(Array.apply(null, arguments));
48 dojo.NodeList._wrap = tnl;
50 dojo.extend(dojo.NodeList, {
51 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
53 // FIXME: handle return values for #3244
54 // http://trac.dojotoolkit.org/ticket/3244
57 // need to wrap or implement:
58 // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
62 slice: function(/*===== begin, end =====*/){
64 // Returns a new NodeList, maintaining this one in place
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
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
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));
83 splice: function(/*===== index, howmany, item =====*/){
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
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>
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
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.
103 // Any number of optional parameters may be passed in to be
104 // spliced into the NodeList
107 var a = dojo._toArray(arguments);
108 return tnl(a.splice.apply(this, a));
111 concat: function(/*===== item =====*/){
113 // Returns a new NodeList comprised of items in this NodeList
114 // as well as items passed in as parameters
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>
121 // Any number of optional parameters may be passed in to be
122 // spliced into the NodeList
125 var a = dojo._toArray(arguments, 0, [this]);
126 return tnl(a.concat.apply([], a));
129 indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
131 // see dojo.indexOf(). The primary difference is that the acted-on
132 // array is implicitly this NodeList
134 // The value to search for.
136 // The loction to start searching from. Optional. Defaults to 0.
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>
141 // Positive Integer or 0 for a match, -1 of not found.
142 return d.indexOf(this, value, fromIndex); // Integer
145 lastIndexOf: function(/*===== value, fromIndex =====*/){
147 // see dojo.lastIndexOf(). The primary difference is that the
148 // acted-on array is implicitly this NodeList
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>
153 // The value to search for.
154 // fromIndex: Integer?
155 // The loction to start searching from. Optional. Defaults to 0.
157 // Positive Integer or 0 for a match, -1 of not found.
158 return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
161 every: function(/*Function*/callback, /*Object?*/thisObject){
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
171 some: function(/*Function*/callback, /*Object?*/thisObject){
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
181 map: function(/*Function*/ func, /*Function?*/ obj){
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)
187 return d.map(this, func, obj, d.NodeList); // dojo.NodeList
190 forEach: function(callback, thisObj){
192 // see dojo.forEach(). The primary difference is that the acted-on
193 // array is implicitly this NodeList
195 d.forEach(this, callback, thisObj);
196 // non-standard return to allow easier chaining
197 return this; // dojo.NodeList
204 // Returns the box objects all elements in a node list as
205 // an Array (*not* a NodeList)
207 return d.map(this, d.coords); // Array
211 attr: function(property, value){
213 // gets or sets the DOM attribute for every element in the
216 // the attribute to get/set
218 // optional. The value to set the property to
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
224 style: function(property, value){
226 // gets or sets the CSS property for every element in the NodeList
228 // the CSS property to get/set, in JavaScript notation
229 // ("lineHieght" instead of "line-height")
231 // optional. The value to set the property to
233 // if no value is passed, the result is an array of strings.
234 // If a value is passed, the return is this NodeList
237 addClass: function(className){
239 // adds the specified class to every node in the list
241 // the CSS class to add
243 // dojo.NodeList, this list
246 removeClass: function(className){
248 // removes the specified class from every node in the list
250 // the CSS class to add
252 // dojo.NodeList, this list
255 toggleClass: function(className, condition){
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.
262 // the CSS class to add
263 // return: dojo.NodeList
267 connect: function(methodName, objOrFunc, funcName){
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
281 // optional. A string naming the function in objOrFunc to bind to the
282 // event. May also be a function reference.
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!");
289 // attach foo.bar() to every odd div's onmouseover
290 // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
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),
300 // FIXME: connectPublisher()? connectRunOnce()?
302 place: function(/*String||Node*/ queryOrNode, /*String*/ position){
304 // places elements of this node list relative to the first element matched
305 // by queryOrNode. Returns the original NodeList.
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.
312 // * "last"||"end" (default)
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
321 orphan: function(/*String?*/ simpleFilter){
323 // removes elements in this list that match the simple
324 // filter from their parents and returns them as a new
327 // single-expression CSS filter
329 // `dojo.NodeList` the orpahned elements
330 var orphans = simpleFilter ? d._filterQueryResult(this, simpleFilter) : this;
331 orphans.forEach(function(item){
333 item.parentNode.removeChild(item);
336 return orphans; // dojo.NodeList
339 adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
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.
350 // * "last"||"end" (default)
354 // or an offset in the childNodes property
356 return d.query(queryOrListOrNode).forEach(function(ai){ d.place(ai, item, position || "last"); }); // dojo.NodeList
359 // FIXME: do we need this?
360 query: function(/*String*/ queryStr){
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.
366 if(!queryStr){ return this; }
368 // FIXME: probably slow
370 var ret = d.NodeList();
371 this.forEach(function(item){
372 d.query(queryStr, item).forEach(function(subItem){
373 if(subItem !== undefined){
378 return ret; // dojo.NodeList
381 filter: function(/*String*/ simpleQuery){
383 // "masks" the built-in javascript filter() method to support
384 // passing a simple string filter in addition to supporting
385 // filtering function objects.
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");
393 // the same filtering using a CSS selector
394 // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
398 var r = d.NodeList();
399 var rp = function(t){
404 if(d.isString(simpleQuery)){
405 items = d._filterQueryResult(this, _a[0]);
407 // if we only got a string query, pass back the filtered results
408 return items; // dojo.NodeList
410 // if we got a callback, run it over the filtered items
413 // handle the (callback, [thisObject]) case
414 d.forEach(d.filter(items, _a[0], _a[1]), rp);
415 return r; // dojo.NodeList
419 // FIXME: should this be "copyTo" and include parenting info?
422 // creates node clones of each element of this list
423 // and returns a new list containing the clones
427 addContent: function(/*String*/ content, /*String||Integer?*/ position){
429 // add a node or some HTML as a string to every item in the list.
430 // Returns the original list.
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
437 // the HTML in string format to add at position to every item
440 // * "last"||"end" (default)
444 // or an offset in the childNodes property
446 // appends content to the end if the position is ommitted
447 // | dojo.query("h3 > p").addContent("hey there!");
449 // add something to the front of each element that has a "thinger" property:
450 // | dojo.query("[thinger]").addContent("...", "first");
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;
458 ta.appendChild(content);
460 if(position === undefined){
463 var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
464 this.forEach(function(item){
465 var tn = ta.cloneNode(true);
467 d.place(tn[ct], item, position);
470 return this; // dojo.NodeList
475 // clears all content from each node in the list
476 return this.forEach("item.innerHTML='';"); // dojo.NodeList
478 // FIXME: should we be checking for and/or disposing of widgets below these nodes?
481 instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
483 // Create a new instance of a specified class, using the
484 // specified properties and each node in the nodeList as a
487 var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
488 return this.forEach(function(i){
489 new c(properties||{},i);
495 // syntactic sugar for DOM events
497 "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
498 "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
502 dojo.NodeList.prototype[_oe] = function(a, b){
503 return this.connect(_oe, a, b);
505 // FIXME: should these events trigger publishes?
507 return (a ? this.connect(_oe, a, b) :
508 this.forEach(function(n){
510 // listeners get buried by
511 // addEventListener and can't be dug back
512 // out to be triggered externally.
514 // http://developer.mozilla.org/en/docs/DOM:element
516 console.debug(n, evt, _oe);
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); }