1 /* ***** BEGIN LICENSE BLOCK *****
  2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3  *
  4  * The contents of this file are subject to the Mozilla Public License Version
  5  * 1.1 (the "License"); you may not use this file except in compliance with
  6  * the License. You may obtain a copy of the License at
  7  * http://www.mozilla.org/MPL/
  8  *
  9  * Software distributed under the License is distributed on an "AS IS" basis,
 10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11  * for the specific language governing rights and limitations under the
 12  * License.
 13  *
 14  * The Original Code is MozMill Test code.
 15  *
 16  * The Initial Developer of the Original Code is the Mozilla Foundation.
 17  * Portions created by the Initial Developer are Copyright (C) 2010
 18  * the Initial Developer. All Rights Reserved.
 19  *
 20  * Contributor(s):
 21  *   Henrik Skupin <hskupin@mozilla.com>
 22  *
 23  * Alternatively, the contents of this file may be used under the terms of
 24  * either the GNU General Public License Version 2 or later (the "GPL"), or
 25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 26  * in which case the provisions of the GPL or the LGPL are applicable instead
 27  * of those above. If you wish to allow use of your version of this file only
 28  * under the terms of either the GPL or the LGPL, and not to allow others to
 29  * use your version of this file under the terms of the MPL, indicate your
 30  * decision by deleting the provisions above and replace them with the notice
 31  * and other provisions required by the GPL or the LGPL. If you do not delete
 32  * the provisions above, a recipient may use your version of this file under
 33  * the terms of any one of the MPL, the GPL or the LGPL.
 34  *
 35  * ***** END LICENSE BLOCK ***** */
 36 
 37 /**
 38  * Default constructor
 39  *
 40  * @param {object} aRoot
 41  *        Root node in the DOM to use as parent
 42  */
 43 function nodeCollector(aRoot) {
 44   this._root = aRoot.wrappedJSObject ? aRoot.wrappedJSObject : aRoot;
 45   this._document = this._root.ownerDocument ? this._root.ownerDocument : this._root;
 46   this._nodes = [ ];
 47 }
 48 
 49 /**
 50  * Node collector class
 51  */
 52 nodeCollector.prototype = {
 53   /**
 54    * Converts current nodes to elements
 55    *
 56    * @returns List of elements
 57    * @type {array of ElemBase}
 58    */
 59   get elements() {
 60     var elements = [ ];
 61 
 62     Array.forEach(this._nodes, function(element) {
 63       elements.push(new elementslib.Elem(element));
 64     });
 65 
 66     return elements;
 67   },
 68 
 69   /**
 70    * Get the current list of DOM nodes
 71    *
 72    * @returns List of nodes
 73    * @type {array of object}
 74    */
 75   get nodes() {
 76     return this._nodes;
 77   },
 78 
 79   /**
 80    * Sets current nodes to entries from the node list
 81    * 
 82    * @param {array of objects} aNodeList
 83    *        List of DOM nodes to set
 84    */
 85   set nodes(aNodeList) {
 86     if (aNodeList) {
 87       this._nodes = [ ];
 88 
 89       Array.forEach(aNodeList, function(node) {
 90         this._nodes.push(node);
 91       }, this);
 92     }
 93   },
 94 
 95   /**
 96    * Get the root node used as parent for a node collection
 97    *
 98    * @returns Current root node
 99    * @type {object}
100    */
101   get root() {
102     return this._root;
103   },
104 
105   /**
106    * Sets root node to the specified DOM node
107    * 
108    * @param {object} aRoot
109    *        DOM node to use as root for node collection
110    */
111   set root(aRoot) {
112     if (aRoot) {
113       this._root = aRoot;
114       this._nodes = [ ];
115     }
116   },
117 
118   /**
119    * Filter nodes given by the specified callback function
120    *
121    * @param {function} aCallback
122    *        Function to test each element of the array.
123    *        Elements: node, index (optional) , array (optional)
124    * @param {object} aThisObject
125    *        Object to use as 'this' when executing callback.
126    *        [optional - default: function scope]
127    *
128    * @returns The class instance
129    * @type {object}
130    */
131   filter : function nodeCollector_filter(aCallback, aThisObject) {
132     if (!aCallback)
133       throw new Error(arguments.callee.name + ": No callback specified");
134 
135     this.nodes = Array.filter(this.nodes, aCallback, aThisObject);
136 
137     return this;
138   },
139 
140   /**
141    * Filter nodes by DOM property and its value
142    *
143    * @param {string} aProperty
144    *        Property to filter for
145    * @param {string} aValue
146    *        Expected value of the DOM property
147    *        [optional - default: n/a]
148    *
149    * @returns The class instance
150    * @type {object}
151    */
152   filterByDOMProperty : function nodeCollector_filterByDOMProperty(aProperty, aValue) {
153     return this.filter(function(node) {
154       if (aProperty && aValue)
155         return node.getAttribute(aProperty) == aValue;
156       else if (aProperty)
157         return node.hasAttribute(aProperty);
158       else
159         return true;
160     });
161   },
162 
163   /**
164    * Filter nodes by JS property and its value
165    *
166    * @param {string} aProperty
167    *        Property to filter for
168    * @param {string} aValue
169    *        Expected value of the JS property
170    *        [optional - default: n/a]
171    *
172    * @returns The class instance
173    * @type {object}
174    */
175   filterByJSProperty : function nodeCollector_filterByJSProperty(aProperty, aValue) {
176     return this.filter(function(node) {
177       if (aProperty && aValue)
178         return node.aProperty == aValue;
179       else if (aProperty)
180         return node.aProperty !== undefined;
181       else
182         return true;
183     });
184   },
185 
186   /**
187    * Find anonymouse nodes with the specified attribute and value
188    *
189    * @param {string} aAttribute
190    *        DOM attribute of the wanted node
191    * @param {string} aValue
192    *        Value of the DOM attribute
193    *
194    * @returns The class instance
195    * @type {object}
196    */
197   queryAnonymousNodes : function nodeCollector_queryAnonymousNodes(aAttribute, aValue) {
198     var node = this._document.getAnonymousElementByAttribute(this._root,
199                                                              aAttribute,
200                                                              aValue);
201     this.nodes = node ? [node] : [ ];
202 
203     return this;
204   },
205 
206   /**
207    * Find nodes with the specified selector
208    *
209    * @param {string} aSelector
210    *        jQuery like element selector string
211    *
212    * @returns The class instance
213    * @type {object}
214    */
215   queryNodes : function nodeCollector_queryNodes(aSelector) {
216     this.nodes = this._root.querySelectorAll(aSelector);
217 
218     return this;
219   }
220 }
221 
222 exports.nodeCollector = nodeCollector;
223