001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.dom.query;
021 
022 import js.ArrayObject;
023 import js.ArrayLike;
024 import js.Disposable;
025 import js.Js;
026 import js.user.JsElement;
027 import js.user.JsNode;
028 
029 /**
030  * <p>An abstract base class that defines selectors to select nodes when paths perform 
031  * queries.</p>
032  * 
033  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
034  */
035 public abstract class Selector extends Disposable
036 {
037     /**
038      * <p>Default constructor doing nothing.</p>
039      * @since 1.0
040      */
041     protected Selector() {}
042 
043     /**
044      * <p>Resets the selector and returns the new one.</p>
045      * <p>This method simply returns the current selector without doing anything else. 
046      * Overriding methods can do more as needed.</p>
047      * @return The new selector reset from the current one.
048      * @since 1.0
049      */
050     public Selector reset() { return this;}
051 
052     /**
053      * <p>Determines if the specified node meets the criteria of this selector.</p>
054      * @param node A node to select.
055      * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
056      * @since 1.0
057      */
058     public abstract boolean select(JsNode node);
059 
060     /**
061      * <p>The singleton seletor that selects any nodes.</p>
062      * @since 1.0
063      */
064     public static final Selector ANY = new Any();
065 
066     /**
067      * <p>Creates a logical-NOT selector based on the current one.</p>
068      * @return The newly created selector.
069      * @since 1.0
070      */
071     public final Not not() {
072         return new Not(this);
073     }
074 
075     /**
076      * <p>Creates a logical-AND selector based on the current one and the specified one.</p>
077      * @return The newly created selector.
078      * @since 1.0
079      */
080     public final And and(Selector s) {
081         return new And(this, s);
082     }
083 
084     /**
085      * <p>Creates a logical-OR selector based on the current one and the specified one.</p>
086      * @return The newly created selector.
087      * @since 1.0
088      */
089     public final Or or(Selector s) {
090         return new Or(this, s);
091     }
092 
093     /**
094      * <p>Selects on a list of nodes.</p>
095      * @param nodes A list of nodes to be selected by this selector.
096      * @return A list of nodes selected by this selector.
097      * @since 1.0
098      */
099     public final ArrayLike<JsNode> select(ArrayObject<JsNode> nodes) {
100         final ArrayLike<JsNode> ret = Js.array();
101         if (Js.not(nodes)) {
102             return ret;
103         }
104         for (int i = 0, len = nodes.length(); i < len; i++) {
105             JsNode n = nodes.get(i);
106             if (Js.be(n) && select(n)) {
107                 ret.push(n);
108             }
109         }
110         return ret;
111     }
112 
113     /**
114      * <p>Defines selectors which select any nodes provided.</p>
115      * <p>A selector of this type does nothing except returns <tt>true</tt> from the 
116      * {@link Any#select(ArrayObject)} method.</p>
117      * 
118      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
119      */
120     public final static class Any extends Selector
121     {
122         /**
123          * <p>Constructs a selector of this type.</p>
124          * @since 1.0
125          */
126         public Any() {}
127 
128         /**
129          * <p>Determines if the specified node meets the criteria of this selector.</p>
130          * @param node A node to select.
131          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
132          * @since 1.0
133          */
134         @Override
135         public boolean select(JsNode node) {
136             return true;
137         }
138     }
139 
140     /**
141      * <p>Defines logical-NOT selectors based on other selectors.</p>
142      * <p>A selector of this type only selects the nodes the base selector would not.</p>
143      * 
144      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
145      */
146     public final static class Not extends Selector
147     {
148         private final Selector s;
149 
150         /**
151          * <p>Constructs a selector of this type.</p>
152          * @param s The base selector.
153          * @since 1.0
154          */
155         public Not(Selector s) {
156             this.s = s;
157         }
158 
159         /**
160          * <p>Determines if the specified node meets the criteria of this selector.</p>
161          * @param node A node to select.
162          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
163          * @since 1.0
164          */
165         @Override
166         public boolean select(JsNode node) {
167             return !s.select(node);
168         }
169     }
170 
171     /**
172      * <p>Defines logical-AND selectors based on other selectors.</p>
173      * <p>A selector of this type only selects the nodes both base selectors would.</p>
174      * 
175      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
176      */
177     public final static class And extends Selector
178     {
179         private final Selector s1, s2;
180 
181         /**
182          * <p>Constructs a selector of this type.</p>
183          * @param s1 A base selector.
184          * @param s2 A base selector.
185          * @since 1.0
186          */
187         public And(Selector s1, Selector s2) {
188             this.s1 = s1;
189             this.s2 = s2;
190         }
191 
192         /**
193          * <p>Determines if the specified node meets the criteria of this selector.</p>
194          * @param node A node to select.
195          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
196          * @since 1.0
197          */
198         @Override
199         public boolean select(JsNode node) {
200             return s1.select(node) && s2.select(node);
201         }
202     }
203 
204     /**
205      * <p>Defines logical-OR selectors based on other selectors.</p>
206      * <p>A selector of this type only selects the nodes either base selectors would.</p>
207      * 
208      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
209      */
210     public final static class Or extends Selector
211     {
212         private final Selector s1, s2;
213 
214         /**
215          * <p>Constructs a selector of this type.</p>
216          * @param s1 A base selector.
217          * @param s2 A base selector.
218          * @since 1.0
219          */
220         public Or(Selector s1, Selector s2) {
221             this.s1 = s1;
222             this.s2 = s2;
223         }
224 
225         /**
226          * <p>Determines if the specified node meets the criteria of this selector.</p>
227          * @param node A node to select.
228          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
229          * @since 1.0
230          */
231         @Override
232         public boolean select(JsNode node) {
233             return s1.select(node) || s2.select(node);
234         }
235     }
236 
237     /**
238      * <p>Defines tag name selectors.</p>
239      * <p>A selector of this type only selects the nodes that have the specific tag name.</p>
240      * 
241      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
242      */
243     public final static class Tag extends Selector
244     {
245         private final String utag;
246 
247         /**
248          * <p>Constructs a selector of this type.</p>
249          * @param name The tag name a node must have to be selected by this selector.
250          * @since 1.0
251          */
252         public Tag(String name) {
253             this.utag = name.toUpperCase();
254         }
255 
256         /**
257          * <p>Determines if the specified node meets the criteria of this selector.</p>
258          * @param node A node to select.
259          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
260          * @since 1.0
261          */
262         @Override
263         public boolean select(JsNode node) {
264             return Js.be(node) && Js.eq(utag, JsElement.tagName.with(node));
265         }
266     }
267 
268     /**
269      * <p>Defines selectors that only select the nodes that have the specific indices.</p>
270      * 
271      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
272      */
273     public final static class Nth extends Selector
274     {
275         private final int index;
276         private int i;
277 
278         /**
279          * <p>Constructs a selector of this type.</p>
280          * @param index The index of the node this selector selects.
281          * @since 1.0
282          */
283         public Nth(int index) {
284             this.index = index;
285         }
286 
287         /**
288          * <p>Resets the selector and returns the new one.</p>
289          * @return The new selector reset from the current one.
290          * @since 1.0
291          */
292         @Override
293         public Nth reset() {
294             i = 0;
295             return this;
296         }
297 
298         /**
299          * <p>Determines if the specified node meets the criteria of this selector.</p>
300          * @param node A node to select.
301          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
302          * @since 1.0
303          */
304         @Override
305         public boolean select(JsNode node) {
306             return index == i++;
307         }
308     }
309 
310     /**
311      * <p>Defines selectors that only select the nodes that have even indices.</p>
312      * 
313      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
314      */
315     public final static class Even extends Selector
316     {
317         private int index;
318 
319         /**
320          * <p>Constructs a selector of this type.</p>
321          * @since 1.0
322          */
323         public Even() {}
324 
325         /**
326          * <p>Resets the selector and returns the new one.</p>
327          * @return The new selector reset from the current one.
328          * @since 1.0
329          */
330         @Override
331         public Even reset() {
332             index = 0;
333             return this;
334         }
335 
336         /**
337          * <p>Determines if the specified node meets the criteria of this selector.</p>
338          * @param node A node to select.
339          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
340          * @since 1.0
341          */
342         @Override
343         public boolean select(JsNode node) {
344             return index++ % 2 == 0;
345         }
346     }
347 
348     /**
349      * <p>Defines selectors that only select the nodes that have odd indices.</p>
350      * 
351      * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
352      */
353     public final class Odd extends Selector
354     {
355         private int index;
356 
357         /**
358          * <p>Constructs a selector of this type.</p>
359          * @since 1.0
360          */
361         public Odd() {}
362 
363         /**
364          * <p>Resets the selector and returns the new one.</p>
365          * @return The new selector reset from the current one.
366          * @since 1.0
367          */
368         @Override
369         public Odd reset() {
370             index = 0;
371             return this;
372         }
373 
374         /**
375          * <p>Determines if the specified node meets the criteria of this selector.</p>
376          * @param node A node to select.
377          * @return <tt>true</tt> if the node is to be selected; <tt>false</tt>, otherwise.
378          * @since 1.0
379          */
380         @Override
381         public boolean select(JsNode node) {
382             return index++ % 2 != 0;
383         }
384     }
385 }