Package com.google.gwt.query.client.impl

Source Code of com.google.gwt.query.client.impl.SelectorEngine

/*
* Copyright 2011, The gwtquery team.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.query.client.impl;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.query.client.Predicate;
import com.google.gwt.query.client.js.JsMap;
import com.google.gwt.query.client.js.JsNodeArray;
import com.google.gwt.query.client.js.JsUtils;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;

/**
* Core Selector engine functions, and native JS utility functions.
*/
public class SelectorEngine implements HasSelector {

  private static DocumentStyleImpl styleImpl;

  public static native NodeList<Element> getElementsByClassName(String clazz,
      Node ctx) /*-{
        return ctx.getElementsByClassName(clazz);
  }-*/;

  public static native Node getNextSibling(Node n) /*-{
       return n.nextSibling || null;
  }-*/;

  public static native Node getPreviousSibling(Node n) /*-{
       return n.previousSibling || null;
  }-*/;

  public NodeList<Element> querySelectorAll(String selector, Node ctx) {
    if (!hasQuerySelector) {
      return impl.select(selector, ctx);
    }
    try {
      return querySelectorAllImpl(selector, ctx);
    } catch (Exception e) {
      return impl.select(selector, ctx);
    }
  }

  public static native NodeList<Element> querySelectorAllImpl(String selector,
      Node ctx) /*-{
      return ctx.querySelectorAll(selector);
  }-*/;

  public static native NodeList<Element> elementsByTagName(String selector,
      Node ctx) /*-{
      return ctx.getElementsByTagName(selector);
  }-*/;

  public static native NodeList<Element> elementsByClassName(String selector,
      Node ctx) /*-{
      return ctx.getElementsByClassName(selector);
  }-*/;

  public static NodeList<Element> veryQuickId(String id, Node ctx) {
    Document d = ctx.getNodeType() == Node.DOCUMENT_NODE
        ? ctx.<Document> cast() : ctx.getOwnerDocument();
    return JsNodeArray.create(d.getElementById(id));
  }

  public static NodeList<Element> xpathEvaluate(String selector, Node ctx) {
    return xpathEvaluate(selector, ctx, JsNodeArray.create());
  }

  public static native NodeList<Element> xpathEvaluate(String selector,
      Node ctx, JsNodeArray r) /*-{
      var node;
      var ownerDoc = ctx && (ctx.ownerDocument || ctx );
      var evalDoc = ownerDoc ? ownerDoc : $doc;
      var result = evalDoc.evaluate(selector, ctx, null, 0, null);
      while ((node = result.iterateNext())) {
          r.push(node);
      }
      return r;
  }-*/;

  public final SelectorEngineImpl impl;

  protected Node root = Document.get();

  public static final boolean hasQuerySelector = hasQuerySelectorAll();

  public static JsMap<String, Predicate> filters;

  static {
    filters = JsMap.create();
    filters.put("visible", new Predicate(){
      public boolean f(Element e, int index) {
        return (e.getOffsetWidth() + e.getOffsetHeight()) > 0 && styleImpl.isVisible(e);
      }
    });
    filters.put("hidden", new Predicate() {
      public boolean f(Element e, int index) {
        return !filters.get("visible").f(e, index);
      }
    });
    filters.put("selected", new Predicate() {
      public boolean f(Element e, int index) {
        return e.getPropertyBoolean("selected");
      }
    });
    filters.put("input", new Predicate(){
      public boolean f(Element e, int index) {
        return e.getNodeName().toLowerCase().matches("input|select|textarea|button");
      }
    });
    filters.put("header", new Predicate(){
      public boolean f(Element e, int index) {
        return e.getNodeName().toLowerCase().matches("h\\d");
      }
    });
  }

  public SelectorEngine() {
    impl = (SelectorEngineImpl) GWT.create(SelectorEngineImpl.class);
    GWT.log("GQuery - Created SelectorEngineImpl: " + impl.getClass().getName());
    styleImpl = GWT.create(DocumentStyleImpl.class);
    GWT.log("GQuery - Created DocumentStyleImpl: " + styleImpl.getClass().getName());
  }

  public Node getRoot() {
    return root;
  }

  public NodeList<Element> filter(NodeList<Element> nodes, Predicate p) {
    JsNodeArray res = JsNodeArray.create();
    for (int i = 0, l = nodes.getLength(), j = 0; i < l; i++) {
      Element e = nodes.getItem(i);
      if (p.f(e, i)) {
        res.addNode(e, j++);
      }
    }
    return res;
  }

  // pseudo selectors which are computed by gquery in runtime
  RegExp gQueryPseudo = RegExp.compile("(.*):((visible|hidden|selected|input|header)|((button|checkbox|file|hidden|image|password|radio|reset|submit|text)\\s*(,|$)))(.*)", "i");
  // pseudo selectors which work in engine
  RegExp nativePseudo = RegExp.compile("(.*):([\\w]+):(disabled|checked|enabled|empty|focus)\\s*([:,].*|$)", "i");

  public NodeList<Element> select(String selector, Node ctx) {

    if (nativePseudo.test(selector)) {
      // move gQuery filters at the end to improve performance, and deal with issue #220
      MatchResult r;
      while ((r = nativePseudo.exec(selector)) != null) {
        selector = r.getGroup(1) + ":" + r.getGroup(3);
        if (!r.getGroup(3).equals(r.getGroup(2))) {
          selector += ":" + r.getGroup(2);
        }
        selector += r.getGroup(4);
      }
    }

    if (gQueryPseudo.test(selector)) {
      JsNodeArray res = JsNodeArray.create();
      for (String s : selector.trim().split("\\s*,\\s*")) {
        NodeList<Element> nodes;
        MatchResult a = gQueryPseudo.exec(s);
        if (a != null) {
          String select = a.getGroup(1).isEmpty() ? "*" : a.getGroup(1);
          String pseudo = a.getGroup(2);
          Predicate pred = filters.get(pseudo.toLowerCase());
          if (pred != null) {
            nodes = filter(select(select, ctx), pred);
          } else if (nativePseudo.test(pseudo)) {
            nodes =  select(select, ctx);
          } else {
            nodes = select(select + "[type=" + pseudo + "]", ctx);
          }
        } else {
          nodes = select(s, ctx);
        }
        JsUtils.copyNodeList(res, nodes, false);
      }
      return res.<NodeList<Element>> cast();
    } else {
      return impl.select(selector, ctx);
    }
  }

  public native boolean contains(Element a, Element b) /*-{
    return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16)
  }-*/;

  public void setRoot(Node root) {
    assert root != null;
    this.root = root;
  }

  public String getName() {
    return getClass().getName().replaceAll("^.*\\.", "");
  }

  public boolean isDegradated() {
    return !hasQuerySelector;
  }

  /**
   * Check if the browser has native support for css selectors
   */
  public static native boolean hasQuerySelectorAll() /*-{
    return $doc.location.href.indexOf("_force_no_native") < 0 &&
           $doc.querySelectorAll &&
           /native/.test(String($doc.querySelectorAll)) ? true : false;
  }-*/;

  public static native boolean hasXpathEvaluate() /*-{
    return $doc.evaluate ? true : false;
  }-*/;

TOP

Related Classes of com.google.gwt.query.client.impl.SelectorEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.