if (!dojo._hasResource["dojo._base.NodeList"]) { // _hasResource checks added // by build. Do not use // _hasResource directly in // your code. dojo._hasResource["dojo._base.NodeList"] = true; dojo.provide("dojo._base.NodeList"); dojo.require("dojo._base.lang"); dojo.require("dojo._base.array"); (function() { var d = dojo; var tnl = function(arr) { arr.constructor = dojo.NodeList; dojo._mixin(arr, dojo.NodeList.prototype); return arr; } dojo.NodeList = function() { // summary: // dojo.NodeList is as subclass of Array which adds syntactic // sugar for chaining, common iteration operations, animation, // and node manipulation. NodeLists are most often returned as // the result of dojo.query() calls. // example: // create a node list from a node // | new dojo.NodeList(dojo.byId("foo")); return tnl(Array.apply(null, arguments)); } dojo.NodeList._wrap = tnl; dojo.extend(dojo.NodeList, { // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods // FIXME: handle return values for #3244 // http://trac.dojotoolkit.org/ticket/3244 // FIXME: // need to wrap or implement: // join (perhaps w/ innerHTML/outerHTML overload for toString() of // items?) // reduce // reduceRight slice : function(/* ===== begin, end ===== */) { // summary: // Returns a new NodeList, maintaining this one in place // description: // This method behaves exactly like the Array.slice method // with the caveat that it returns a dojo.NodeList and not a // raw Array. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice // begin: Integer // Can be a positive or negative integer, with positive // integers noting the offset to begin at, and negative // integers denoting an offset from the end (i.e., to the left // of the end) // end: Integer? // Optional parameter to describe what position relative to // the NodeList's zero index to end the slice at. Like begin, // can be positive or negative. var a = dojo._toArray(arguments); return tnl(a.slice.apply(this, a)); }, splice : function(/* ===== index, howmany, item ===== */) { // summary: // Returns a new NodeList, manipulating this NodeList based on // the arguments passed, potentially splicing in new elements // at an offset, optionally deleting elements // description: // This method behaves exactly like the Array.splice method // with the caveat that it returns a dojo.NodeList and not a // raw Array. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice // index: Integer // begin can be a positive or negative integer, with positive // integers noting the offset to begin at, and negative // integers denoting an offset from the end (i.e., to the left // of the end) // howmany: Integer? // Optional parameter to describe what position relative to // the NodeList's zero index to end the slice at. Like begin, // can be positive or negative. // item: Object...? // Any number of optional parameters may be passed in to be // spliced into the NodeList // returns: // dojo.NodeList var a = dojo._toArray(arguments); return tnl(a.splice.apply(this, a)); }, concat : function(/* ===== item ===== */) { // summary: // Returns a new NodeList comprised of items in this NodeList // as well as items passed in as parameters // description: // This method behaves exactly like the Array.concat method // with the caveat that it returns a dojo.NodeList and not a // raw Array. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat // item: Object...? // Any number of optional parameters may be passed in to be // spliced into the NodeList // returns: // dojo.NodeList var a = dojo._toArray(arguments, 0, [this]); return tnl(a.concat.apply([], a)); }, indexOf : function(/* Object */value, /* Integer? */fromIndex) { // summary: // see dojo.indexOf(). The primary difference is that the // acted-on // array is implicitly this NodeList // value: // The value to search for. // fromIndex: // The loction to start searching from. Optional. Defaults to 0. // description: // For more details on the behavior of indexOf, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf // returns: // Positive Integer or 0 for a match, -1 of not found. return d.indexOf(this, value, fromIndex); // Integer }, lastIndexOf : function(/* ===== value, fromIndex ===== */) { // summary: // see dojo.lastIndexOf(). The primary difference is that the // acted-on array is implicitly this NodeList // description: // For more details on the behavior of lastIndexOf, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf // value: Object // The value to search for. // fromIndex: Integer? // The loction to start searching from. Optional. Defaults to 0. // returns: // Positive Integer or 0 for a match, -1 of not found. return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer }, every : function(/* Function */callback, /* Object? */thisObject) { // summary: // see dojo.every() and: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every // Takes the same structure of arguments and returns as // dojo.every() with the caveat that the passed array is // implicitly this NodeList return d.every(this, callback, thisObject); // Boolean }, some : function(/* Function */callback, /* Object? */thisObject) { // summary: // see dojo.some() and: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some // Takes the same structure of arguments and returns as // dojo.some() with the caveat that the passed array is // implicitly this NodeList return d.some(this, callback, thisObject); // Boolean }, map : function(/* Function */func, /* Function? */obj) { // summary: // see dojo.map(). The primary difference is that the acted-on // array is implicitly this NodeList and the return is a // dojo.NodeList (a subclass of Array) return d.map(this, func, obj, d.NodeList); // dojo.NodeList }, forEach : function(callback, thisObj) { // summary: // see dojo.forEach(). The primary difference is that the // acted-on // array is implicitly this NodeList d.forEach(this, callback, thisObj); return this; // dojo.NodeList non-standard return to allow // easier chaining }, // custom methods coords : function() { // summary: // Returns the box objects all elements in a node list as // an Array (*not* a NodeList) return d.map(this, d.coords); }, style : function(/* ===== property, value ===== */) { // summary: // gets or sets the CSS property for every element in the // NodeList // property: String // the CSS property to get/set, in JavaScript notation // ("lineHieght" instead of "line-height") // value: String? // optional. The value to set the property to // return: // if no value is passed, the result is an array of strings. // If a value is passed, the return is this NodeList var aa = d._toArray(arguments, 0, [null]); var s = this.map(function(i) { aa[0] = i; return d.style.apply(d, aa); }); return (arguments.length > 1) ? this : s; // String||dojo.NodeList }, styles : function(/* ===== property, value ===== */) { // summary: // Deprecated. Use NodeList.style instead. Will be removed in // Dojo 1.1. Gets or sets the CSS property for every element // in the NodeList // property: String // the CSS property to get/set, in JavaScript notation // ("lineHieght" instead of "line-height") // value: String? // optional. The value to set the property to // return: // if no value is passed, the result is an array of strings. // If a value is passed, the return is this NodeList d.deprecated("NodeList.styles", "use NodeList.style instead", "1.1"); return this.style.apply(this, arguments); }, addClass : function(/* String */className) { // summary: // adds the specified class to every node in the list // this.forEach(function(i) { d.addClass(i, className); }); return this; }, removeClass : function(/* String */className) { this.forEach(function(i) { d.removeClass(i, className); }); return this; }, // FIXME: toggleClass()? connectPublisher()? connectRunOnce()? place : function(/* String||Node */queryOrNode, /* String */position) { // summary: // places elements of this node list relative to the first // element matched // by queryOrNode. Returns the original NodeList. // queryOrNode: // may be a string representing any valid CSS3 selector or a DOM // node. // In the selector case, only the first matching element will be // used // for relative positioning. // position: // can be one of: // "last"||"end" (default) // "first||"start" // "before" // "after" // or an offset in the childNodes property var item = d.query(queryOrNode)[0]; position = position || "last"; for (var x = 0; x < this.length; x++) { d.place(this[x], item, position); } return this; // dojo.NodeList }, connect : function(/* String */methodName, /* Object||Function||String */ objOrFunc, /* String? */funcName) { // summary: // attach event handlers to every item of the NodeList. Uses // dojo.connect() // so event properties are normalized // methodName: // the name of the method to attach to. For DOM events, this // should be // the lower-case name of the event // objOrFunc: // if 2 arguments are passed (methodName, objOrFunc), objOrFunc // should // reference a function or be the name of the function in the // global // namespace to attach. If 3 arguments are provided // (methodName, objOrFunc, funcName), objOrFunc must be the // scope to // locate the bound function in // funcName: // optional. A string naming the function in objOrFunc to bind // to the // event. May also be a function reference. // example: // add an onclick handler to every button on the page // | dojo.query("onclick", function(e){ // | console.debug("clicked!"); // | }); // example: // attach foo.bar() to every odd div's onmouseover // | dojo.query("div:nth-child(odd)").onclick("onmouseover", // foo, "bar"); this.forEach(function(item) { d.connect(item, methodName, objOrFunc, funcName); }); return this; // dojo.NodeList }, orphan : function(/* String? */simpleFilter) { // summary: // removes elements in this list that match the simple // filter from their parents and returns them as a new // NodeList. // simpleFilter: single-expression CSS filter // return: a dojo.NodeList of all of the elements orpahned var orphans = (simpleFilter) ? d._filterQueryResult(this, simpleFilter) : this; orphans.forEach(function(item) { if (item["parentNode"]) { item.parentNode.removeChild(item); } }); return orphans; // dojo.NodeList }, adopt : function(/* String||Array||DomNode */queryOrListOrNode, /* String? */ position) { // summary: // places any/all elements in queryOrListOrNode at a // position relative to the first element in this list. // Returns a dojo.NodeList of the adopted elements. // queryOrListOrNode: // a DOM node or a query string or a query result. // Represents the nodes to be adopted relative to the // first element of this NodeList. // position: // optional. One of: // "last"||"end" (default) // "first||"start" // "before" // "after" // or an offset in the childNodes property var item = this[0]; return d.query(queryOrListOrNode).forEach(function(ai) { d.place(ai, item, (position || "last")); }); // dojo.NodeList }, // FIXME: do we need this? query : function(/* String */queryStr) { // summary: // Returns a new, flattened NodeList. Elements of the new list // satisfy the passed query but use elements of the // current NodeList as query roots. queryStr = queryStr || ""; // FIXME: probably slow var ret = d.NodeList(); this.forEach(function(item) { d.query(queryStr, item).forEach(function(subItem) { if (typeof subItem != "undefined") { ret.push(subItem); } }); }); return ret; // dojo.NodeList }, filter : function(/* String */simpleQuery) { // summary: // "masks" the built-in javascript filter() method to support // passing a simple string filter in addition to supporting // filtering function objects. // example: // "regular" JS filter syntax as exposed in dojo.filter: // | dojo.query("*").filter(function(item){ // | // highlight every paragraph // | return (item.nodeName == "p"); // | }).styles("backgroundColor", "yellow"); // example: // the same filtering using a CSS selector // | dojo.query("*").filter("p").styles("backgroundColor", // "yellow"); var items = this; var _a = arguments; var r = d.NodeList(); var rp = function(t) { if (typeof t != "undefined") { r.push(t); } } if (d.isString(simpleQuery)) { items = d._filterQueryResult(this, _a[0]); if (_a.length == 1) { // if we only got a string query, pass back the filtered // results return items; // dojo.NodeList } // if we got a callback, run it over the filtered items d.forEach(d.filter(items, _a[1], _a[2]), rp); return r; // dojo.NodeList } // handle the (callback, [thisObject]) case d.forEach(d.filter(items, _a[0], _a[1]), rp); return r; // dojo.NodeList }, /* * // FIXME: should this be "copyTo" and include parenting info? * clone: function(){ // summary: // creates node clones of each * element of this list // and returns a new list containing the * clones }, */ addContent : function(/* String */content, /* String||Integer? */ position) { // summary: // add a node or some HTML as a string to every item in the // list. // Returns the original list. // content: // the HTML in string format to add at position to every item // position: // One of: // "last"||"end" (default) // "first||"start" // "before" // "after" // or an integer offset in the childNodes property var ta = d.doc.createElement("span"); if (d.isString(content)) { ta.innerHTML = content; } else { ta.appendChild(content); } var ct = ((position == "first") || (position == "after")) ? "lastChild" : "firstChild"; this.forEach(function(item) { var tn = ta.cloneNode(true); while (tn[ct]) { d.place(tn[ct], item, position); } }); return this; // dojo.NodeList } }); // syntactic sugar for DOM events d.forEach(["blur", "click", "keydown", "keypress", "keyup", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup"], function(evt) { var _oe = "on" + evt; dojo.NodeList.prototype[_oe] = function(a, b) { return this.connect(_oe, a, b); } // FIXME: should these events trigger publishes? /* * return (a ? this.connect(_oe, a, b) : * this.forEach(function(n){ // FIXME: // listeners get buried * by // addEventListener and can't be dug back // out to be * triggered externally. // see: // * http://developer.mozilla.org/en/docs/DOM:element * * console.debug(n, evt, _oe); * // FIXME: need synthetic event support! var _e = { target: * n, faux: true, type: evt }; // * dojo._event_listener._synthesizeEvent({}, { target: n, faux: * true, type: evt }); try{ n[evt](_e); }catch(e){ * console.debug(e); } try{ n[_oe](_e); }catch(e){ * console.debug(e); } }) ); } */ }); })(); }