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.*;
023 import js.core.*;
024 import js.user.*;
025 import jsx.client.Browser;
026 import jsx.client.Win;
027 import jsx.dom.query.Selector;
028 
029 /**
030  * <p>A utility class supporting DOM query with its static methods.</p>
031  * 
032  * @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>
033  */
034 public final class Query extends Disposable
035 {
036     private Query() {}
037 
038     /**
039      * <p>Returns an array of all {@link JsElement} nodes in the current document that have the
040      * specified tag name by traversing all descendants of this element and are selected against
041      * the given {@link Selector} object.</p>
042      * @param ctx The current element.
043      * @param name The tag name of the desired elements.
044      * @param sel A {@link Selector} object.
045      * @return An array of result nodes.
046      * @see #getElementsByTagName(String)
047      * @see #getElementsByTagName(JsElement, String)
048      * @see #getElementsByTagName(String, Selector)
049      * @see jsx.dom.Nodes#getElementsByTagName(JsNode, String)
050      * @since 1.0
051      */
052     public static final ArrayLike<JsNode> getElementsByTagName(JsElement ctx, String name, Selector sel) {
053         return sel.reset().select(ctx.getElementsByTagName(name));
054     }
055 
056     /**
057      * <p>Returns an array of all {@link JsElement} nodes in the current document that have the
058      * specified tag name by traversing all descendants of this element.</p>
059      * @param ctx The current element.
060      * @param name The tag name of the desired elements.
061      * @return An array of result nodes.
062      * @see #getElementsByTagName(String)
063      * @see #getElementsByTagName(String, Selector)
064      * @see #getElementsByTagName(JsElement, String, Selector)
065      * @see jsx.dom.Nodes#getElementsByTagName(JsNode, String)
066      * @since 1.0
067      */
068     public static final ArrayLike<JsNode> getElementsByTagName(JsElement ctx, String name) {
069         return getElementsByTagName(ctx, name, Selector.ANY);
070     }
071 
072     /**
073      * <p>Returns an array of all {@link JsElement} nodes in the current document that have the
074      * specified tag name by traversing all descendants of the current document and are selected against
075      * the given {@link Selector} object.</p>
076      * @param name The tag name of the desired elements.
077      * @param sel A {@link Selector} object.
078      * @return An array of result nodes.
079      * @see #getElementsByTagName(String)
080      * @see #getElementsByTagName(JsElement, String)
081      * @see #getElementsByTagName(JsElement, String, Selector)
082      * @see jsx.dom.Nodes#getElementsByTagName(JsNode, String)
083      * @since 1.0
084      */
085     public static final ArrayLike<JsNode> getElementsByTagName(String name, Selector sel) {
086         return sel.reset().select(Win.document.var().getElementsByTagName(name));
087     }
088 
089     /**
090      * <p>Returns an array of all {@link JsElement} nodes in the current document that have the
091      * specified tag name by traversing all descendants of the current document.</p>
092      * @param name The tag name of the desired elements.
093      * @return An array of result nodes.
094      * @see #getElementsByTagName(JsElement, String)
095      * @see #getElementsByTagName(String, Selector)
096      * @see #getElementsByTagName(JsElement, String, Selector)
097      * @see jsx.dom.Nodes#getElementsByTagName(JsNode, String)
098      * @since 1.0
099      */
100     public static final ArrayLike<JsNode> getElementsByTagName(String name) {
101         return getElementsByTagName(name, Selector.ANY);
102     }
103 
104     /**
105      * <p>Returns an array of all the child nodes of the current node that are selected against
106      * the given {@link Selector} object.</p>
107      * @param ctx The current node.
108      * @param sel A {@link Selector} object.
109      * @return An array of result nodes.
110      * @since 1.0
111      */
112     public static final ArrayLike<JsNode> getChildren(JsNode ctx, Selector sel) {
113         return sel.reset().select(JsNode.childNodes.with(ctx));
114     }
115 
116     private final static Var<JsFunction<String>> namespaceURLMapper = new Static<JsFunction<String>>(
117             new Var<JsFunction<String>>() {
118                 @Override
119                 public JsFunction<String> var() {
120                     return new Function<String>() {
121                         @Override
122                         protected String function(Object jsthis, Call<String> callee) {
123                             return "";
124 
125                         }
126                     }.var();
127                 }
128             }
129     );
130 
131     /**
132      * <p>Creates a new XPath expression object that represents a compiled <tt>XPath</tt> query.</p>
133      * <p>This method tries to eliminate browser dependencies.</p>
134      * @param xpath The string representing the XPath expression to compile.
135      * @return A newly created XPath expression object. 
136      * @see JsDocument#createExpression(String)
137      * @see #selectNodes(JsObject, JsNode)
138      * @see #selectNodes(JsObject)
139      * @since 1.0
140      */
141     public static final JsObject createExpression(String xpath) {
142         if (Browser.isIE) {
143             return Js.function(
144                     "cn",
145                     "x=new ActiveXObject('Microsoft.XMLDOM');" +
146                     "x.async=false;" +
147                     "x.load(cn.innerHTML);" +
148                     "x.setProperty('SelectionLanguage', 'XPath');" +
149                     "return x.selectNodes('" + xpath + "');"
150             );
151         } else {
152             return Win.document.var().createExpression(xpath, namespaceURLMapper.var());
153         }
154     }
155 
156     /**
157      * <p>Performs an XPath query using the current document as the root and returns the result as
158      * an array of nodes.</p>
159      * <p>This method tries to eliminate browser dependencies.</p>
160      * @param expr A compiled XPath expression object.
161      * @return The query result as an array of nodes.
162      * @see #selectNodes(JsObject, JsNode)
163      * @see #createExpression(String)
164      * @see JsNode#selectNodes(String)
165      * @since 1.0
166      */
167     public static final ArrayLike<JsNode> selectNodes(JsObject expr) {
168         return selectNodes(expr, Win.document.var());
169     }
170 
171     /**
172      * <p>Performs an XPath query using the given node as the root and returns the result as
173      * an array of nodes.</p>
174      * <p>This method tries to eliminate browser dependencies.</p>
175      * @param expr A compiled XPath expression object.
176      * @param ctx The root node.
177      * @return The query result as an array of nodes.
178      * @see #selectNodes(JsObject)
179      * @see #createExpression(String)
180      * @see JsNode#selectNodes(String)
181      * @since 1.0
182      */
183     public static final ArrayLike<JsNode> selectNodes(JsObject expr, JsNode ctx) {
184         ArrayLike<JsNode> ret = Js.array();
185         if (Browser.isIE) {
186             JsNodeList<?> rs = new JsFunction<JsNodeList<?>>(expr).invoke(ctx);
187             if (Js.be(rs)) {
188                 for (int i = 0, len = rs.length(); i < len; i++) {
189                     ret.push(rs.get(i));
190                 }
191             }
192         } else {
193             JsXPathResult rs = new JsXPathExpression(expr).evaluate(ctx, JsClient.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE.with());
194             Js.win().alert(rs);
195             if (Js.be(rs)) {
196                 int len = JsXPathResult.snapshotLength.with(rs).intValue();
197                 Js.win().alert(len);
198                 for (int i = 0; i < len; i++) {
199                     ret.push(rs.snapshotItem(i));
200                 }
201             }
202         }
203         return ret;
204     }
205 }