From 96375a486ad02ebe30af85a7dddc48b7f3e7349d Mon Sep 17 00:00:00 2001 From: Ray Cromwell Date: Thu, 30 Apr 2009 21:43:29 +0000 Subject: Refactored to com.google.gwt.query Fixup javadocs Add tests --- .../main/java/com/google/gwt/query/Query.gwt.xml | 81 + .../main/java/com/google/gwt/query/client/$.java | 82 + .../google/gwt/query/client/DeferredGQuery.java | 33 + .../java/com/google/gwt/query/client/Effects.java | 109 + .../java/com/google/gwt/query/client/Events.java | 172 ++ .../google/gwt/query/client/EventsListener.java | 124 + .../java/com/google/gwt/query/client/Function.java | 50 + .../java/com/google/gwt/query/client/GQuery.java | 2479 ++++++++++++++++++++ .../java/com/google/gwt/query/client/JSArray.java | 72 + .../java/com/google/gwt/query/client/Plugin.java | 16 + .../com/google/gwt/query/client/Predicate.java | 10 + .../com/google/gwt/query/client/Properties.java | 51 + .../java/com/google/gwt/query/client/Regexp.java | 56 + .../java/com/google/gwt/query/client/Selector.java | 15 + .../google/gwt/query/client/SelectorEngine.java | 97 + .../com/google/gwt/query/client/Selectors.java | 8 + .../gwt/query/client/impl/DocumentStyleImpl.java | 41 + .../gwt/query/client/impl/DocumentStyleImplIE.java | 56 + .../gwt/query/client/impl/SelectorEngineImpl.java | 106 + .../gwt/query/client/impl/SelectorEngineJS.java | 689 ++++++ .../gwt/query/client/impl/SelectorEngineJSIE.java | 21 + .../query/client/impl/SelectorEngineNative.java | 17 + .../gwt/query/client/impl/SelectorEngineXPath.java | 229 ++ .../gwt/query/rebind/SelectorGeneratorBase.java | 191 ++ .../gwt/query/rebind/SelectorGeneratorJS.java | 31 + .../query/rebind/SelectorGeneratorJSOptimal.java | 174 ++ .../gwt/query/rebind/SelectorGeneratorNative.java | 32 + .../gwt/query/rebind/SelectorGeneratorXPath.java | 319 +++ .../src/main/java/gwtquery/GwtQuery.gwt.xml | 105 - gwtquery-core/src/main/java/gwtquery/client/$.java | 81 - .../main/java/gwtquery/client/DeferredGQuery.java | 14 - .../src/main/java/gwtquery/client/Effects.java | 152 -- .../src/main/java/gwtquery/client/Function.java | 26 - .../src/main/java/gwtquery/client/GQuery.java | 1950 --------------- .../src/main/java/gwtquery/client/JSArray.java | 72 - .../src/main/java/gwtquery/client/Plugin.java | 8 - .../src/main/java/gwtquery/client/Predicate.java | 10 - .../src/main/java/gwtquery/client/Properties.java | 35 - .../src/main/java/gwtquery/client/Regexp.java | 55 - .../src/main/java/gwtquery/client/Selector.java | 15 - .../main/java/gwtquery/client/SelectorEngine.java | 97 - .../src/main/java/gwtquery/client/Selectors.java | 7 - .../gwtquery/client/impl/DocumentStyleImpl.java | 41 - .../gwtquery/client/impl/DocumentStyleImplIE.java | 57 - .../gwtquery/client/impl/SelectorEngineImpl.java | 104 - .../gwtquery/client/impl/SelectorEngineJS.java | 698 ------ .../gwtquery/client/impl/SelectorEngineJSIE.java | 20 - .../gwtquery/client/impl/SelectorEngineNative.java | 16 - .../gwtquery/client/impl/SelectorEngineXPath.java | 237 -- .../gwtquery/rebind/SelectorGeneratorBase.java | 192 -- .../java/gwtquery/rebind/SelectorGeneratorJS.java | 174 -- .../gwtquery/rebind/SelectorGeneratorNative.java | 32 - .../gwtquery/rebind/SelectorGeneratorXPath.java | 317 --- .../rebind/gebcn/SelectorGeneratorJSGEBCN.java | 12 - .../rebind/gebcn/SelectorGeneratorNativeGEBCN.java | 13 - .../rebind/gebcn/SelectorGeneratorXPathGEBCN.java | 12 - 56 files changed, 5361 insertions(+), 4552 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/$.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/DeferredGQuery.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Events.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/EventsListener.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/JSArray.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Plugin.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Predicate.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Regexp.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Selector.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/SelectorEngine.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/Selectors.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImplIE.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineImpl.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJSIE.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineNative.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorBase.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJS.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJSOptimal.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorNative.java create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorXPath.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/GwtQuery.gwt.xml delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/$.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/DeferredGQuery.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Effects.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Function.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/GQuery.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/JSArray.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Plugin.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Predicate.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Properties.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Regexp.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Selector.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/SelectorEngine.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/Selectors.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImpl.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImplIE.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineImpl.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJS.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJSIE.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineNative.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineXPath.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorBase.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorJS.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorNative.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorXPath.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorJSGEBCN.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorNativeGEBCN.java delete mode 100644 gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorXPathGEBCN.java (limited to 'gwtquery-core/src/main/java') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml new file mode 100644 index 00000000..a09eeafc --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -0,0 +1,81 @@ + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/$.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/$.java new file mode 100644 index 00000000..16487834 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/$.java @@ -0,0 +1,82 @@ +package com.google.gwt.query.client; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; + +/** + * A facade class of forwarding functions which allow end users to refer to + * the GQuery class as '$' if they desire. + */ +public class $ { + + public static GQuery $(String selectorOrHtml) { + return GQuery.$(selectorOrHtml); + } + + public static T $(T gq) { + return GQuery.$(gq); + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is is a class + * reference to a plugin to be used. + */ + public static T $(String selector, Class plugin) { + return GQuery.$(selector, plugin); + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is the context to + * use for the selector. + */ + public static GQuery $(String selector, Node context) { + return GQuery.$(selector, context); + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is the context to + * use for the selector. The third parameter is the class plugin to use. + */ + public static GQuery $(String selector, Node context, + Class plugin) { + return GQuery.$(selector, context, plugin); + } + + /** + * Wrap a GQuery around existing Elements. + */ + public static GQuery $(NodeList elements) { + return GQuery.$(elements); + } + + /** + * Wrap a GQuery around an existing Element. + */ + public static GQuery $(Element element) { + return GQuery.$(element); + } + + /** + * Wrap a JSON object + */ + public static Properties $$(String properties) { + return GQuery.$$(properties); + } + + /** + * Registers a GQuery plugin + * @param plugin + * @param pluginFactory + */ + public static void registerPlugin(Class plugin, + Plugin pluginFactory) { + GQuery.registerPlugin(plugin, pluginFactory); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/DeferredGQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/DeferredGQuery.java new file mode 100644 index 00000000..28bb99ec --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/DeferredGQuery.java @@ -0,0 +1,33 @@ +package com.google.gwt.query.client; + +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; + +/** + * A compiled selector that can be lazily turned into a GQuery. + */ +public interface DeferredGQuery { + + /** + * The selector which was compiled. + * @return + */ + String getSelector(); + + /** + * Evaluate the compiled selector with the given DOM node as a context. + * Returns the result as a GQuery object. + * @param ctx + * @return + */ + GQuery eval(Node ctx); + + /** + * Evaluate the compiled selector with the given DOM node as a context. + * Returns a NodeList as a result. + * @param ctx + * @return + */ + NodeList array(Node ctx); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java new file mode 100644 index 00000000..ac69eb6e --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java @@ -0,0 +1,109 @@ +package com.google.gwt.query.client; + +import com.google.gwt.animation.client.Animation; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; + +public class Effects extends GQuery { + + static { + GQuery.registerPlugin(Effects.class, new EffectsPlugin()); + } + + public static final Class Effects = Effects.class; + + public Effects(Element element) { + super(element); + } + + public Effects(JSArray elements) { + super(elements); + } + + public Effects(NodeList list) { + super(list); + } + + public Effects hide() { + this.css("display", "none"); + return this; + } + + public Effects show() { + this.css("display", ""); + return this; + } + + public boolean visible() { + return !"none".equalsIgnoreCase(this.css("display")); + } + + public Effects toggle() { + for (Element e : elements()) { + Effects ef = new Effects(e); + if (ef.visible()) { + ef.hide(); + } else { + ef.show(); + } + } + return this; + } + + public Effects fadeOut() { + Animation a = new Animation() { + + public void onCancel() { + } + + public void onComplete() { + for (int i = 0; i < elements.getLength(); i++) { + elements.getItem(i).getStyle().setProperty("opacity", "0"); + elements.getItem(i).getStyle().setProperty("display", "none"); + } + } + + public void onStart() { + } + + public void onUpdate(double progress) { + for (int i = 0; i < elements.getLength(); i++) { + elements.getItem(i).getStyle() + .setProperty("opacity", String.valueOf(1.0 - progress)); + } + } + }; + a.run(1000); + return this; + } + + public Effects fadeIn() { + Animation a = new Animation() { + + public void onCancel() { + } + + public void onComplete() { + } + + public void onStart() { + } + + public void onUpdate(double progress) { + for (int i = 0; i < elements.getLength(); i++) { + elements.getItem(i).getStyle() + .setProperty("opacity", String.valueOf(progress)); + } + } + }; + a.run(1000); + return this; + } + + public static class EffectsPlugin implements Plugin { + + public Effects init(GQuery gq) { + return new Effects(gq.get()); + } + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Events.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Events.java new file mode 100644 index 00000000..14025ea9 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Events.java @@ -0,0 +1,172 @@ +package com.google.gwt.query.client; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.user.client.Event; + +/** + * GQuery Plugin for handling and queuing browser events + */ +public class Events extends GQuery { + + static { + GQuery.registerPlugin(Events.class, new Plugin() { + public Events init(GQuery gq) { + return new Events(gq.get()); + } + }); + } + + public static final Class Events = Events.class; + + public Events(Element element) { + super(element); + } + + public Events(JSArray elements) { + super(elements); + } + + public Events(NodeList list) { + super(list); + } + + /** + * Binds a handler to a particular Event for each matched element. + * + * The event handler is passed as a Function that you can use to prevent + * default behaviour. To stop both default action and event bubbling, the + * function event handler has to return false. + * + * You can pass an additional Object data to your Function as the second + * parameter + */ + public GQuery bind(int eventbits, final Object data, final Function f) { + for (Element e : elements()) { + EventsListener.getInstance(e).bind(eventbits, data, f); + } + return this; + } + + /** + * Fires an event on each matched element. + * + * Example: fire(Event.ONCLICK) + */ + public GQuery fire(int eventbits, int... keys) { + for (Element e : elements()) { + EventsListener.getInstance(e).fire(eventbits, keys); + } + return this; + } + + /** + * Removes all handlers, that matches the events bits passed, from each + * element. + * + * Example: unbind(Event.ONCLICK | Event.ONMOUSEOVER) + */ + public GQuery unbind(int eventbits) { + for (Element e : elements()) { + EventsListener.getInstance(e).unbind(eventbits); + } + return this; + } +} + +/** + * Just a class with static methods for firing element events on demand + */ +class FireEvents { + + private native static Event createMouseEventImpl(String type) /*-{ + var event = $doc.createEvent('MouseEvents'); + event.initEvent(type, true, true); + return event; + }-*/; + + private native static Event createKeyEventImpl(String type, int keycode) /*-{ + var event; + if( $wnd.KeyEvent ) { + event = $doc.createEvent('KeyEvents'); + event.initKeyEvent( type, true, true, $wnd, false, false, false, false, keycode, 0 ); + } else { + event = $doc.createEvent('UIEvents'); + event.initUIEvent( type, true, true, $wnd, 1 ); + event.keyCode = keycode; + } + return event; + }-*/; + + private native static Event createHtmlEventImpl(String type) /*-{ + var event = $doc.createEvent('HTMLEvents'); + event.initEvent( type, true, true); + return event; + }-*/; + + private native static void dispatchEvent(Element elem, Event event) /*-{ + elem.dispatchEvent(event); + if (event.type == 'focus' && elem.focus) + elem.focus(); + else if (event.type == 'blur' && elem.focus) + elem.blur(); + }-*/; + + private static String getEventTypeStr(int type) { + switch (type) { + case Event.ONBLUR: + return "blur"; + case Event.ONCHANGE: + return "change"; + case Event.ONCLICK: + return "click"; + case Event.ONDBLCLICK: + return "dblclick"; + case Event.ONFOCUS: + return "focus"; + case Event.ONKEYDOWN: + return "keydown"; + case Event.ONKEYPRESS: + return "keypress"; + case Event.ONKEYUP: + return "keyup"; + case Event.ONLOSECAPTURE: + return "losecapture"; + case Event.ONMOUSEDOWN: + return "mousedown"; + case Event.ONMOUSEMOVE: + return "mousemove"; + case Event.ONMOUSEOUT: + return "mouseout"; + case Event.ONMOUSEOVER: + return "mouseover"; + case Event.ONMOUSEUP: + return "mouseup"; + case Event.ONSCROLL: + return "scroll"; + case Event.ONERROR: + return "error"; + case Event.ONMOUSEWHEEL: + return "mousewheel"; + default: + return ""; + } + } + + public static void fire(Element element, int eventbits, int... keys) { + Event event = null; + + String type = getEventTypeStr(eventbits); + + if ((eventbits & Event.MOUSEEVENTS) != 0 + || (eventbits | Event.ONCLICK) == Event.ONCLICK) { + event = createMouseEventImpl(type); + } else if ((eventbits & Event.KEYEVENTS) != 0) { + event = createKeyEventImpl(type, keys[0]); + } else if ((eventbits & Event.FOCUSEVENTS) != 0) { + event = createHtmlEventImpl(type); + } + + dispatchEvent(element, event); + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/EventsListener.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/EventsListener.java new file mode 100644 index 00000000..37adcf60 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/EventsListener.java @@ -0,0 +1,124 @@ +package com.google.gwt.query.client; + +import com.google.gwt.user.client.EventListener; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.DOM; +import com.google.gwt.dom.client.Element; + +import java.util.List; +import java.util.ArrayList; + + +/** + * This class implements an event queue instance for one element. + * This queue instance is configured as the default event listener in GWT. + * + * The reference to this queue is stored as a uniq variable in the element's DOM + * + * The class takes care of calling the appropiate functions for each browser event + * and also calls sinkEvents methods. + * + */ +class EventsListener implements EventListener { + + private class BindFunction { + int type; + Function function; + Object data; + int times = -1; + + BindFunction(int t, Function f, Object d) { + type = t; + function = f; + data = d; + } + + BindFunction(int t, Function f, Object d, int times) { + this(t, f, d); + this.times = times; + } + + public boolean hasEventType(int etype) { + return (type | etype) == type; + } + + public boolean fire(Event event) { + if (times != 0) { + times--; + return function.f(event, data); + } + return true; + } + } + + private native static EventsListener getWidgetElementImpl( + Element elem) /*-{ + return elem.__gqueryevent; + }-*/; + + private native static void setWidgetElementImpl(Element elem, EventsListener gqevent) /*-{ + elem.__gqueryevent = gqevent; + }-*/; + + private native static void setFocusable(Element elem) /*-{ + elem.tabIndex = 0; + }-*/; + + + private List elementEvents = new ArrayList(); + private Element element; + + private EventsListener(Element e) { + element = e; + setWidgetElementImpl(element, this); + DOM.setEventListener((com.google.gwt.user.client.Element) e, this); + } + + public static EventsListener getInstance(Element e) { + EventsListener ret = getWidgetElementImpl(e); + return ret != null ? ret : new EventsListener(e); + } + + public void bind(int eventbits, final Object data, final Function function, int times) { + if (function == null) { + unbind(eventbits); + } else { + DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventbits + | DOM.getEventsSunk((com.google.gwt.user.client.Element) element)); + + if ((eventbits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS) + setFocusable(element); + + elementEvents.add(new EventsListener.BindFunction(eventbits, function, data, times)); + } + } + + public void bind(int eventbits, final Object data, final Function function) { + bind(eventbits, data, function, -1); + } + + public void fire(int eventbits, int... keys) { + FireEvents.fire(element, eventbits, keys); + } + + public void onBrowserEvent(Event event) { + int etype = DOM.eventGetType(event); + for (EventsListener.BindFunction listener : elementEvents) { + if (listener.hasEventType(etype)) { + if (!listener.fire(event)) { + event.cancelBubble(true); + event.preventDefault(); + } + } + } + } + + public void unbind(int eventbits) { + ArrayList newList = new ArrayList(); + for (EventsListener.BindFunction listener : elementEvents) + if (!listener.hasEventType(eventbits)) + newList.add(listener); + elementEvents = newList; + } + +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java new file mode 100644 index 00000000..d9c093e3 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java @@ -0,0 +1,50 @@ +package com.google.gwt.query.client; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.Event; + +/** + * Extend this class to implement functions callbacks. + */ +public abstract class Function { + + /** + * Override this for GQuery methods which loop over matched elements and + * invoke a callback on each element. + * @param e + * @param i + * @return + */ + public String f(Element e, int i) { + return ""; + } + + /** + * Override this for GQuery methods which take a callback, but do not expect + * a return value, apply to a single element only. + * @param e + */ + public void f(Element e) { + } + + /** + * Override this method for bound event handlers if you wish to deal with + * per-handler user data. + * @param e + * @param data + * @return + */ + public boolean f(Event e, Object data) { + return f(e); + } + + /** + * Override this method for bound event handlers. + * @param e + * @return + */ + public boolean f(Event e) { + f(e.getCurrentTarget()); + return true; + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java new file mode 100644 index 00000000..74cc5b85 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -0,0 +1,2479 @@ +package com.google.gwt.query.client; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.dom.client.BodyElement; +import com.google.gwt.dom.client.ButtonElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.IFrameElement; +import com.google.gwt.dom.client.InputElement; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.OptionElement; +import com.google.gwt.dom.client.SelectElement; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.TextAreaElement; +import static com.google.gwt.query.client.Effects.Effects; +import static com.google.gwt.query.client.Events.Events; +import com.google.gwt.query.client.impl.DocumentStyleImpl; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class GQuery { + + public static class Offset { + + public int top; + + public int left; + + Offset(int left, int top) { + this.left = left; + this.top = top; + } + } + + private static final class DataCache extends JavaScriptObject { + + protected DataCache() { + } + + public native void delete(String name) /*-{ + delete this[name]; + }-*/; + + public native void delete(int name) /*-{ + delete this[name]; + }-*/; + + public native boolean exists(int id) /*-{ + return !!this[id]; + }-*/; + + public native JavaScriptObject get(String id) /*-{ + return this[id]; + }-*/; + + public native JavaScriptObject get(int id) /*-{ + return this[id]; + }-*/; /*-{ + delete this[name]; + }-*/ + + public DataCache getCache(int id) { + return get(id).cast(); + } + + public native double getDouble(String id) /*-{ + return this[id]; + }-*/; + + public native double getDouble(int id) /*-{ + return this[id]; + }-*/; + + public native int getInt(String id) /*-{ + return this[id]; + }-*/; + + public native int getInt(int id) /*-{ + return this[id]; + }-*/; + + public native String getString(String id) /*-{ + return this[id]; + }-*/; + + public native String getString(int id) /*-{ + return this[id]; + }-*/; + + public native boolean isEmpty() /*-{ + var foo = ""; + for(foo in this) break; + return !foo; + }-*/; + + public native void put(String id, Object obj) /*-{ + return this[id]=obj; + }-*/; + + public native void put(int id, Object obj) /*-{ + return this[id]=obj; + }-*/; + } + + private static final class FastSet extends JavaScriptObject { + + public static FastSet create() { + return JavaScriptObject.createObject().cast(); + } + + protected FastSet() { + } + + public void add(Object o) { + add0(o.hashCode()); + } + + public boolean contains(Object o) { + return contains0(o.hashCode()); + } + + public void remove(Object o) { + remove0(o.hashCode()); + } + + private native void add0(int hc) /*-{ + this[hc]=true; + }-*/; + + private native boolean contains0(int hc) /*-{ + return this[hc] || false; + }-*/; + + private native void remove0(int hc) /*-{ + delete this[hc]; + }-*/; + } + + private static final class Queue extends JavaScriptObject { + + public static Queue newInstance() { + return createArray().cast(); + } + + protected Queue() { + } + + public native T dequeue() /*-{ + return this.shift(); + }-*/; + + public native void enqueue(T foo) /*-{ + this.push(foo); + }-*/; + + public native int length() /*-{ + return this.length; + }-*/; + + public native T peek(int i) /*-{ + return this[i]; + }-*/; + } + + public static boolean fxOff = false; + + private static Map, Plugin> plugins; + + private static Element windowData = null; + + private static DataCache dataCache = null; + + private static DocumentStyleImpl styleImpl; + + private static final int FUNC_PREPEND = 0, FUNC_APPEND = 1, FUNC_AFTER = 2, + FUNC_BEFORE = 3; + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. + */ + public static GQuery $(String selectorOrHtml) { + if (selectorOrHtml.trim().charAt(0) == '<') { + return innerHtml(selectorOrHtml); + } + return $(selectorOrHtml, Document.get()); + } + + public static T $(T gq) { + + return gq; + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is is a class + * reference to a plugin to be used. + */ + public static T $(String selector, Class plugin) { + try { + if (plugins != null) { + T gquery = (T) plugins.get(plugin).init($(selector, Document.get())); + return gquery; + } + throw new RuntimeException("No plugin for class " + plugin); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is the context to + * use for the selector. + */ + public static GQuery $(String selector, Node context) { + return new GQuery(select(selector, context)); + } + + /** + * This function accepts a string containing a CSS selector which is then used + * to match a set of elements, or it accepts raw HTML creating a GQuery + * element containing those elements. The second parameter is the context to + * use for the selector. The third parameter is the class plugin to use. + */ + public static GQuery $(String selector, Node context, + Class plugin) { + try { + if (plugins != null) { + T gquery = (T) plugins.get(plugin) + .init(new GQuery(select(selector, context))); + return gquery; + } + throw new RuntimeException("No plugin for class " + plugin); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Wrap a GQuery around existing Elements. + */ + public static GQuery $(NodeList elements) { + return new GQuery(elements); + } + + public static GQuery $(Element element) { + JSArray a = JSArray.create(); + a.addNode(element); + return new GQuery(a); + } + + /** + * Wrap a JSON object + */ + public static Properties $$(String properties) { + return Properties.create(properties); + } + + public static T[] asArray(NodeList nl) { + if (GWT.isScript()) { + return reinterpretCast(nl); + } else { + Node[] elts = new Node[nl.getLength()]; + for (int i = 0; i < elts.length; i++) { + elts[i] = nl.getItem(i); + } + return (T[]) elts; + } + } + + public static native String camelize(String s)/*-{ + return s.toLowerCase().replace(/-([a-z])/ig, function(a, c){return c.toUpperCase()} ); + }-*/; + + public static void registerPlugin(Class plugin, + Plugin pluginFactory) { + if (plugins == null) { + plugins = new HashMap(); + } + plugins.put(plugin, pluginFactory); + } + + /** + * Copied from UIObject * + */ + protected static void setStyleName(Element elem, String style, boolean add) { + + style = style.trim(); + + // Get the current style string. + String oldStyle = elem.getClassName(); + int idx = oldStyle.indexOf(style); + + // Calculate matching index. + while (idx != -1) { + if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') { + int last = idx + style.length(); + int lastPos = oldStyle.length(); + if ((last == lastPos) || ((last < lastPos) && (oldStyle.charAt(last) + == ' '))) { + break; + } + } + idx = oldStyle.indexOf(style, idx + 1); + } + + if (add) { + // Only add the style if it's not already present. + if (idx == -1) { + if (oldStyle.length() > 0) { + oldStyle += " "; + } + DOM.setElementProperty(elem.cast(), + "className", oldStyle + style); + } + } else { + // Don't try to remove the style if it's not there. + if (idx != -1) { + // Get the leading and trailing parts, without the removed name. + String begin = oldStyle.substring(0, idx).trim(); + String end = oldStyle.substring(idx + style.length()).trim(); + + // Some contortions to make sure we don't leave extra spaces. + String newClassName; + if (begin.length() == 0) { + newClassName = end; + } else if (end.length() == 0) { + newClassName = begin; + } else { + newClassName = begin + " " + end; + } + + DOM.setElementProperty(elem.cast(), + "className", newClassName); + } + } + } + + private static String curCSS(Element elem, String name) { + Style s = elem.getStyle(); + ensureStyleImpl(); + name = styleImpl.getPropertyName(name); + + if (SelectorEngine.truth(s.getProperty(name))) { + return s.getProperty(name); + } + return styleImpl.getCurrentStyle(elem, name); + } + + private static void ensureStyleImpl() { + if (styleImpl == null) { + styleImpl = GWT.create(DocumentStyleImpl.class); + } + } + + private static boolean hasClass(Element e, String clz) { + return ((" " + e.getClassName() + " ").matches(".*\\s" + clz + "\\s.*")); + } + + private static GQuery innerHtml(String html) { + Element div = DOM.createDiv(); + div.setInnerHTML(html); + return new GQuery((NodeList) (NodeList) div.getChildNodes()); + } + + private static native T[] reinterpretCast(NodeList nl) /*-{ + return nl; + }-*/; + + private static NodeList select(String selector, Node context) { + return new SelectorEngine().select(selector, context); + } + + protected NodeList elements = null; + + private String selector; + + private GQuery previousObject; + + public GQuery() { + elements = JavaScriptObject.createArray().cast(); + } + + public GQuery(NodeList list) { + elements = list; + } + + public GQuery(JSArray elements) { + this.elements = elements; + } + + public GQuery(Element element) { + elements = JSArray.create(element); + } + + /** + * Add elements to the set of matched elements if they are not included yet. + */ + + public GQuery add(String selector) { + return add($(selector)); + } + + /** + * Adds the specified classes to each matched element. Add elements to the set + * of matched elements if they are not included yet. + */ + public GQuery add(GQuery previousObject) { + return pushStack(unique(merge(elements, previousObject.elements)), "add", + getSelector() + "," + previousObject.getSelector()); + } + + /** + * Adds the specified classes to each matched element. + */ + public GQuery addClass(String... classes) { + for (Element e : elements()) { + for (String clz : classes) { + setStyleName(e, clz, true); + } + } + return this; + } + + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(Node n) { + return domManip(JSArray.create(n), FUNC_AFTER); + } + + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(String html) { + return domManip(html, FUNC_AFTER); + } + + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(GQuery query) { + return domManip(query.elements, FUNC_AFTER); + } + + /** + * Add the previous selection to the current selection. Useful for traversing + * elements, and then adding something that was matched before the last + * traversal. + */ + public GQuery andSelf() { + return add(previousObject); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(String html) { + return domManip(html, FUNC_APPEND); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(Node n) { + return domManip(JSArray.create(n), FUNC_APPEND); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(GQuery query) { + return domManip(query.elements, FUNC_APPEND); + } + + /** + * Append all of the matched elements to another, specified, set of elements. + * This operation is, essentially, the reverse of doing a regular + * $(A).append(B), in that instead of appending B to A, you're appending A to + * B. + */ + public GQuery appendTo(GQuery other) { + return other.append(this); + } + + /** + * Convert to Plugin interface provided by Class literal. + */ + public T as(Class plugin) { + if (plugins != null) { + return (T) plugins.get(plugin).init(this); + } + throw new RuntimeException("No plugin registered for class " + plugin); + } + + /** + * Access a property on the first matched element. This method makes it easy + * to retrieve a property value from the first matched element. If the element + * does not have an attribute with such a name, undefined is returned. + * Attributes include title, alt, src, href, width, style, etc. + */ + public String attr(String name) { + return elements.getItem(0).getAttribute(fixAttributeName(name)); + } + + /** + * Set a single property to a value, on all matched elements. + */ + public GQuery attr(String key, String value) { + key = fixAttributeName(key); + for (Element e : elements()) { + e.setAttribute(key, value); + } + return this; + } + + /** + * Set a key/value object as properties to all matched elements. + * + * Example: $("img").attr(new Properties("src: 'test.jpg', alt: 'Test + * Image'")) + */ + public GQuery attr(Properties properties) { + for (Element e : elements()) { + for (String name : properties.keys()) { + e.setAttribute(fixAttributeName(name), properties.get(name)); + } + } + return this; + } + + /** + * Set a single property to a computed value, on all matched elements. + */ + public GQuery attr(String key, Function closure) { + for (int i = 0; i < elements.getLength(); i++) { + Element e = elements.getItem(i); + e.setAttribute(fixAttributeName(key), closure.f(e, i)); + } + return this; + } + + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(Node n) { + return domManip(JSArray.create(n), FUNC_BEFORE); + } + + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(GQuery query) { + return domManip(query.elements, FUNC_BEFORE); + } + + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(String html) { + return domManip(html, FUNC_BEFORE); + } + + /** + * Binds a handler to a particular Event (like Event.ONCLICK) for each matched + * element. + * + * The event handler is passed as a Function that you can use to prevent + * default behaviour. To stop both default action and event bubbling, the + * function event handler has to return false. + * + * You can pass an additional Object data to your Function as the second + * parameter + */ + public GQuery bind(int eventbits, final Object data, final Function f) { + return as(Events).bind(eventbits, data, f); + } + + /** + * Bind a function to the blur event of each matched element. + */ + public GQuery blur(Function f) { + return bind(Event.ONBLUR, null, f); + } + + /** + * Trigger a blur event. + */ + public GQuery blur() { + return trigger(Document.get().createBlurEvent(), null); + } + + /** + * Bind a function to the change event of each matched element. + */ + public GQuery change(Function f) { + return bind(Event.ONCHANGE, null, f); + } + + /** + * Trigger a change event. + */ + public GQuery change() { + return trigger(Document.get().createChangeEvent(), null); + } + + /** + * Get a set of elements containing all of the unique children of each of the + * matched set of elements. This set is filtered with the expressions that + * will cause only elements matching any of the selectors to be collected. + */ + public GQuery children(String... filters) { + return find(filters); + } + + /** + * Get a set of elements containing all of the unique immediate children of + * each of the matched set of elements. Also note: while parents() will look + * at all ancestors, children() will only consider immediate child elements. + */ + public GQuery children() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + allNextSiblingElements(e.getFirstChildElement(), result, null); + } + return new GQuery(unique(result)); + } + + /** + * Trigger a click event. + */ + public GQuery click() { + return trigger( + Document.get().createClickEvent(0, 0, 0, 0, 0, false, false, false, + false), null); + } + + /** + * Triggers the click event of each matched element. Causes all of the + * functions that have been bound to that click event to be executed. + */ + public GQuery click(final Function f) { + return bind(Event.ONCLICK, null, f); + } + + /** + * Clone matched DOM Elements and select the clones. This is useful for moving + * copies of the elements to another location in the DOM. + */ + public GQuery clone() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + result.addNode(e.cloneNode(true)); + } + return new GQuery(result); + } + + /** + * Filter the set of elements to those that contain the specified text. + */ + public GQuery contains(String text) { + JSArray array = JSArray.create(); + for (Element e : elements()) { + if ($(e).text().contains(text)) { + array.addNode(e); + } + } + return $(array); + } + + /** + * Find all the child nodes inside the matched elements (including text + * nodes), or the content document, if the element is an iframe. + */ + public GQuery contents() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + NodeList children = e.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node n = children.getItem(i); + if (IFrameElement.is(n)) { + result.addNode(getContentDocument(n)); + } else { + result.addNode(n); + } + } + } + return new GQuery(unique(result)); + } + + /** + * Return a style property on the first matched element. + */ + public String css(String name) { + return curCSS(get(0), name); + } + + /** + * Set a key/value object as style properties to all matched elements. This + * serves as the best way to set a large number of style properties on all + * matched elements. + * + * Example: $(".item").css(Properties.create("color: 'red', background: + * 'blue'")) + */ + public GQuery css(Properties properties) { + for (String property : properties.keys()) { + css(property, properties.get(property)); + } + return this; + } + + /** + * Set a single style property to a value, on all matched elements. + */ + public GQuery css(String prop, String val) { + for (Element e : elements()) { + String property = camelize(prop); + e.getStyle().setProperty(property, val); + if ("opacity".equals(property)) { + e.getStyle().setProperty("zoom", "1"); + e.getStyle().setProperty("filter", + "alpha(opacity=" + (int) (Double.valueOf(val) * 100) + ")"); + } + } + return this; + } + + /** + * Returns value at named data store for the element, as set by data(name, + * value). + */ + public Object data(String name) { + return data(elements.getItem(0), name, null); + } + + /** + * Returns value at named data store for the element, as set by data(name, + * value) with desired return type. + * + * @param clz return type class literal + */ + public T data(String name, Class clz) { + return (T) data(elements.getItem(0), name, null); + } + + /** + * Stores the value in the named spot with desired return type. + */ + public void data(String name, String value) { + for (Element e : elements()) { + data(e, name, value); + } + } + + /** + * Trigger a double click event. + */ + public GQuery dblclick() { + return trigger( + Document.get().createDblClickEvent(0, 0, 0, 0, 0, false, false, false, + false), null); + } + + /** + * Bind a function to the dblclick event of each matched element. + */ + public GQuery dblclick(Function f) { + return bind(Event.ONDBLCLICK, null, f); + } + + /** + * Removes a queued function from the front of the queue and executes it. + */ + public GQuery dequeue(String type) { + for (Element e : elements()) { + dequeue(e, type); + } + return this; + } + + /** + * Removes a queued function from the front of the FX queue and executes it. + */ + public GQuery dequeue() { + return dequeue("__FX"); + } + + /** + * Run one or more Functions over each element of the GQuery. + */ + public GQuery each(Function... f) { + for (Function f1 : f) { + for (Element e : elements()) { + f1.f(e); + } + } + return this; + } + + /** + * Returns the working set of nodes as a Java array. Do NOT get() { + return elements; + } + + /** + * Return the ith element matched. + */ + public Element get(int i) { + return elements.getItem(i); + } + + /** + * Return the previous set of matched elements prior to the last destructive + * operation (e.g. query) + */ + public GQuery getPreviousObject() { + return previousObject; + } + + /** + * Return the selector representing the current set of matched elements. + */ + public String getSelector() { + return selector; + } + + /** + * Returns true any of the specified classes are present on any of the matched + * Reduce the set of matched elements to all elements after a given position. + * The position of the element in the set of matched elements starts at 0 and + * goes to length - 1. + */ + public GQuery gt(int pos) { + return $(slice(pos + 1, -1)); + } + + /** + * Returns true any of the specified classes are present on any of the matched + * elements. + */ + public boolean hasClass(String... classes) { + for (Element e : elements()) { + for (String clz : classes) { + if (hasClass(e, clz)) { + return true; + } + } + } + return false; + } + + /** + * Set the height of every element in the matched set. + */ + public GQuery height(int height) { + for (Element e : elements()) { + e.getStyle().setPropertyPx("height", height); + } + return this; + } + + /** + * Set the height style property of every matched element. It's useful for + * using 'percent' or 'em' units Example: $(".a").width("100%") + */ + public GQuery height(String height) { + return css("height", height); + } + + /** + * Get the current computed, pixel, height of the first matched element. + */ + public int height() { + return DOM + .getElementPropertyInt((com.google.gwt.user.client.Element) get(0), + "offsetHeight"); + } + + /** + * Make invisible all matched elements + */ + public GQuery hide() { + return $(as(Effects).hide()); + } + + /** + * Bind a function to the mouseover event of each matched element. A method + * for simulating hovering (moving the mouse on, and off, an object). This is + * a custom method which provides an 'in' to a frequent task. Whenever the + * mouse cursor is moved over a matched element, the first specified function + * is fired. Whenever the mouse moves off of the element, the second specified + * function fires. + */ + public GQuery hover(Function fover, Function fout) { + return bind(Event.ONMOUSEOVER, null, fover) + .bind(Event.ONMOUSEOUT, null, fout); + } + + /** + * Get the innerHTML of the first matched element. + */ + public String html() { + return get(0).getInnerHTML(); + } + + /** + * Set the innerHTML of every matched element. + */ + public GQuery html(String html) { + for (Element e : elements()) { + e.setInnerHTML(html); + } + return this; + } + + /** + * Find the index of the specified Element + */ + public int index(Element element) { + for (int i = 0; i < elements.getLength(); i++) { + if (elements.getItem(i) == element) { + return i; + } + } + return -1; + } + + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(String selector) { + return insertAfter($(selector)); + } + + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(Element elem) { + return insertAfter($(elem)); + } + + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(GQuery query) { + for (Element e : elements()) { + query.after(e); + } + return this; + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(Element item) { + return insertBefore($(item)); + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(GQuery query) { + for (Element e : elements()) { + query.before(e); + } + return this; + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(String selector) { + return insertBefore($(selector)); + } + + /** + * Checks the current selection against an expression and returns true, if at + * least one element of the selection fits the given expression. Does return + * false, if no element fits or the expression is not valid. + */ + public boolean is(String... filters) { + return filter(filters).size() > 0; + } + + /** + * Trigger a keydown event. + */ + public GQuery keydown() { + return trigger( + Document.get().createKeyDownEvent(false, false, false, false, 0, 0), + null); + } + + /** + * Bind a function to the keydown event of each matched element. + */ + public GQuery keydown(Function f) { + return bind(Event.ONKEYDOWN, null, f); + } + + /** + * Trigger a keypress event. + */ + public GQuery keypress() { + return trigger( + Document.get().createKeyPressEvent(false, false, false, false, 0, 0), + null); + } + + /** + * Bind a function to the keypress event of each matched element. + */ + public GQuery keypressed(Function f) { + return bind(Event.ONKEYPRESS, null, f); + } + + /** + * Trigger a keyup event. + */ + public GQuery keyup() { + return trigger( + Document.get().createKeyUpEvent(false, false, false, false, 0, 0), + null); + } + + /** + * Bind a function to the keyup event of each matched element. + */ + public GQuery keyup(Function f) { + return bind(Event.ONKEYUP, null, f); + } + + /** + * Returns the number of elements currently matched. The size function will + * return the same value. + */ + public int length() { + return size(); + } + + /** + * Bind a function to the load event of each matched element. + */ + public GQuery load(Function f) { + return bind(Event.ONLOAD, null, f); + } + + /** + * Reduce the set of matched elements to all elements before a given position. + * The position of the element in the set of matched elements starts at 0 and + * goes to length - 1. + */ + public GQuery lt(int pos) { + return $(slice(0, pos)); + } + + /** + * Bind a function to the mousedown event of each matched element. + */ + public GQuery mousedown(Function f) { + return bind(Event.ONMOUSEDOWN, null, f); + } + + /** + * Bind a function to the mousemove event of each matched element. + */ + public GQuery mousemove(Function f) { + return bind(Event.ONMOUSEMOVE, null, f); + } + + /** + * Bind a function to the mouseout event of each matched element. + */ + public GQuery mouseout(Function f) { + return bind(Event.ONMOUSEOUT, null, f); + } + + /** + * Bind a function to the mouseover event of each matched element. + */ + public GQuery mouseover(Function f) { + return bind(Event.ONMOUSEOVER, null, f); + } + + /** + * Bind a function to the mouseup event of each matched element. + */ + public GQuery mouseup(Function f) { + return bind(Event.ONMOUSEUP, null, f); + } + + /** + * Get a set of elements containing the unique next siblings of each of the + * given set of elements. next only returns the very next sibling for each + * element, not all next siblings see {#nextAll}. + */ + public GQuery next() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + Element next = e.getNextSiblingElement(); + if (next != null) { + result.addNode(next); + } + } + return new GQuery(unique(result)); + } + + /** + * Get a set of elements containing the unique next siblings of each of the + * given set of elements filtered by 1 or more selectors. next only returns + * the very next sibling for each element, not all next siblings see + * {#nextAll}. + */ + public GQuery next(String... selectors) { + JSArray result = JSArray.create(); + for (Element e : elements()) { + Element next = e.getNextSiblingElement(); + if (next != null) { + result.addNode(next); + } + } + return new GQuery(unique(result)).filter(selectors); + } + + /** + * Find all sibling elements after the current element. + */ + public GQuery nextAll() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + allNextSiblingElements(e.getNextSiblingElement(), result, null); + } + return new GQuery(unique(result)); + } + + /** + * Removes the specified Element from the set of matched elements. This method + * is used to remove a single Element from a jQuery object. + */ + public GQuery not(Element elem) { + JSArray array = JSArray.create(); + for (Element e : elements()) { + if (e != elem) { + array.addNode(e); + } + } + return $(array); + } + + /** + * Removes any elements inside the passed set of elements from the set of + * matched elements. + */ + public GQuery not(GQuery gq) { + GQuery ret = this; + for (Element e : gq.elements()) { + ret = ret.not(e); + } + return ret; + } + + /** + * Removes elements matching the specified expression from the set of matched + * elements. + */ + public GQuery not(String... filters) { + GQuery ret = this; + for (String f : filters) { + ret = ret.not($(f)); + } + return ret; + } + + public Offset offset() { + return new Offset(get(0).getOffsetLeft(), get(0).getOffsetTop()); + } + + /** + * Returns a GQuery collection with the positioned parent of the first matched + * element. This is the first parent of the element that has position (as in + * relative or absolute). This method only works with visible elements. + */ + public GQuery offsetParent() { + Element offParent = SelectorEngine + .or(elements.getItem(0).getOffsetParent(), Document.get().getBody()); + while (offParent != null && !"body".equalsIgnoreCase(offParent.getTagName()) + && !"html".equalsIgnoreCase(offParent.getTagName()) && "static" + .equals(curCSS(offParent, "position"))) { + offParent = offParent.getOffsetParent(); + } + return new GQuery(offParent); + } + + /** + * Binds a handler to a particular Event (like Event.ONCLICK) for each matched + * element. The handler is executed only once for each element. + * + * The event handler is passed as a Function that you can use to prevent + * default behaviour. To stop both default action and event bubbling, the + * function event handler has to return false. + * + * You can pass an additional Object data to your Function as the second + * parameter + */ + public GQuery one(int eventbits, final Object data, final Function f) { + for (Element e : elements()) { + EventsListener.getInstance(e).bind(eventbits, data, f, 1); + } + return this; + } + + /** + * Get a set of elements containing the unique parents of the matched set of + * elements. + */ + public GQuery parent() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + result.addNode(e.getParentElement()); + } + return new GQuery(unique(result)); + } + + /** + * Get a set of elements containing the unique parents of the matched set of + * elements. You may use an optional expressions to filter the set of parent + * elements that will match one of them. + */ + public GQuery parent(String... filters) { + return parent().filter(filters); + } + + /** + * Get a set of elements containing the unique ancestors of the matched set of + * elements (except for the root element). The matched elements are filtered, + * returning those that match any of the filters. + */ + public GQuery parents(String... filters) { + return parents().filter(filters); + } + + /** + * Get a set of elements containing the unique ancestors of the matched set of + * elements (except for the root element). + */ + public GQuery parents() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + Node par = e.getParentNode(); + while (par != null && par != Document.get()) { + result.addNode(par); + par = par.getParentNode(); + } + } + return new GQuery(unique(result)); + } + + /** + * Gets the top and left position of an element relative to its offset parent. + * The returned object contains two Integer properties, top and left. For + * accurate calculations make sure to use pixel values for margins, borders + * and padding. This method only works with visible elements. + */ + public Offset position() { + + if (size() > 0) { + GQuery offsetParent = offsetParent(); + Offset offset = offset(); + Element e = offsetParent.get(0); + + Offset parentOffset = BodyElement.is(e) || "html".equals(e.getTagName()) + ? new Offset(0, 0) : offsetParent.offset(); + offset.top -= num(this, "marginTop"); + offset.left -= num(this, "marginLeft"); + parentOffset.top += num(offsetParent, "borderTopWidth"); + parentOffset.left += num(offsetParent, "borderLeftWidth"); + return new Offset(offset.top - parentOffset.top, + offset.left - parentOffset.left); + } + return null; + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(String html) { + return domManip(html, FUNC_PREPEND); + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(GQuery query) { + return domManip(query.elements, FUNC_PREPEND); + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(Node n) { + return domManip(JSArray.create(n), FUNC_PREPEND); + } + + /** + * Prepend all of the matched elements to another, specified, set of elements. + * This operation is, essentially, the reverse of doing a regular + * $(A).prepend(B), in that instead of prepending B to A, you're prepending A + * to B. + */ + public GQuery prependTo(GQuery elms) { + return elms.prepend(this); + } + + /** + * Get a set of elements containing the unique previous siblings of each of + * the matched set of elements. Only the immediately previous sibling is + * returned, not all previous siblings. + */ + public GQuery prev() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + Element next = getPreviousSiblingElement(e); + if (next != null) { + result.addNode(next); + } + } + return new GQuery(unique(result)); + } + + /** + * Get a set of elements containing the unique previous siblings of each of + * the matched set of elements filtered by selector. Only the immediately + * previous sibling is returned, not all previous siblings. + */ + public GQuery prev(String... selectors) { + JSArray result = JSArray.create(); + for (Element e : elements()) { + Element next = getPreviousSiblingElement(e); + if (next != null) { + result.addNode(next); + } + } + return new GQuery(unique(result)).filter(selectors); + } + + /** + * Find all sibling elements in front of the current element. + */ + public GQuery prevAll() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + allPreviousSiblingElements(getPreviousSiblingElement(e), result); + } + return new GQuery(unique(result)); + } + + /** + * Returns a reference to the first element's queue (which is an array of + * functions). + */ + public Queue queue(String type) { + return queue(elements.getItem(0), type, null); + } + + /** + * Returns a reference to the FX queue. + */ + public Queue queue() { + return queue(elements.getItem(0), "__FX", null); + } + + /** + * Adds a new function, to be executed, onto the end of the queue of all + * matched elements. + */ + public GQuery queue(String type, Function data) { + for (Element e : elements()) { + queue(e, type, data); + } + return this; + } + + /** + * Replaces the current queue with the given queue on all matched elements. + */ + public GQuery queue(String type, Queue data) { + for (Element e : elements()) { + replacequeue(e, type, data); + } + return this; + } + + /** + * Adds a new function, to be executed, onto the end of the queue of all + * matched elements in the FX queue. + */ + public GQuery queue(Function data) { + return queue("__FX", data); + } + + /** + * Removes all matched elements from the DOM. + */ + public GQuery remove() { + for (Element e : elements()) { + //TODO: cleanup event bindings + removeData(e, null); + if (e.getParentNode() != null) { + e.getParentNode().removeChild(e); + } + } + return this; + } + + /** + * Remove the named attribute from every element in the matched set. + */ + public GQuery removeAttr(String key) { + for (Element e : elements()) { + e.removeAttribute(key); + } + return this; + } + + /** + * Removes the specified classes to each matched element. + */ + public GQuery removeClass(String... classes) { + for (Element e : elements()) { + for (String clz : classes) { + setStyleName(e, clz, false); + } + } + return this; + } + + /** + * Removes named data store from an element. + */ + public GQuery removeData(String name) { + for (Element e : elements()) { + removeData(e, name); + } + return this; + } + + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(GQuery query) { + for (Element e : elements()) { + $(e).replaceWith(query); + } + return this; + } + + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(String html) { + return replaceAll($(html)); + } + + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(Element elem) { + return replaceAll($(elem)); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(GQuery query) { + return after(query).remove(); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(String html) { + return replaceWith($(html)); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(Element elem) { + return replaceWith($(elem)); + } + + /** + * Bind a function to the scroll event of each matched element. + */ + public GQuery scroll(Function f) { + return bind(Event.ONSCROLL, null, f); + } + + /** + * When a value is passed in, the scroll left offset is set to that value on + * all matched elements. This method works for both visible and hidden + * elements. + */ + public GQuery scrollLeft(int left) { + for (Element e : elements()) { + if (e == window() || e == (Node) Document.get()) { + Window.scrollTo(left, $(e).scrollTop()); + } else { + e.setPropertyInt("scrollLeft", left); + } + } + return this; + } + + /** + * Gets the scroll left offset of the first matched element. This method works + * for both visible and hidden elements. + */ + public int scrollLeft() { + Element e = get(0); + if (e == window()) { + return Window.getScrollLeft(); + } else if (e == (Node) Document.get()) { + return Document.get().getScrollLeft(); + } else { + return e.getScrollLeft(); + } + } + + /** + * When a value is passed in, the scroll top offset is set to that value on + * all matched elements. This method works for both visible and hidden + * elements. + */ + public GQuery scrollTop(int top) { + for (Element e : elements()) { + if (e == window() || e == (Node) Document.get()) { + Window.scrollTo($(e).scrollLeft(), top); + } else { + e.setPropertyInt("scrollTop", top); + } + } + return this; + } + + /** + * Gets the scroll top offset of the first matched element. This method works + * for both visible and hidden elements. + */ + public int scrollTop() { + Element e = get(0); + if (e == window()) { + return Window.getScrollTop(); + } else if (e == (Node) Document.get()) { + return Document.get().getScrollTop(); + } else { + return e.getScrollTop(); + } + } + + public GQuery select() { + return trigger(Document.get().createHtmlEvent("select", false, false), + null); + } + + public void setPreviousObject(GQuery previousObject) { + this.previousObject = previousObject; + } + + public void setSelector(String selector) { + this.selector = selector; + } + + /** + * Return the number of elements in the matched set. Make visible all mached + * elements + */ + public GQuery show() { + return $(as(Effects).show()); + } + + /** + * Get a set of elements containing all of the unique siblings of each of the + * matched set of elements. + */ + public GQuery siblings() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + allNextSiblingElements(e.getParentElement().getFirstChildElement(), + result, e); + } + return new GQuery(unique(result)); + } + + /** + * Get a set of elements containing all of the unique siblings of each of the + * matched set of elements filtered by the provided set of selectors. + */ + public GQuery siblings(String... selectors) { + return siblings().filter(selectors); + } + + /** + * Return the number of elements in the matched set. + */ + public int size() { + return elements.getLength(); + } + + /** + * Selects a subset of the matched elements. + */ + public GQuery slice(int start, int end) { + JSArray slice = JSArray.create(); + if (end == -1 || end > elements.getLength()) { + end = elements.getLength(); + } + for (int i = start; i < end; i++) { + slice.addNode(elements.getItem(i)); + } + return new GQuery(slice); + } + + public GQuery submit() { + return trigger(Document.get().createHtmlEvent("submit", false, false), + null); + } + + /** + * Return the text contained in the first matched element. + */ + public String text() { + String result=""; + for(Element e : elements()) { + result += e.getInnerText(); + } + return result; + } + + /** + * Set the innerText of every matched element. + */ + public GQuery text(String txt) { + for (Element e : asArray(elements)) { + e.setInnerText(txt); + } + return this; + } + + /** + * Toggle among two or more function calls every other click. + */ + public GQuery toggle(final Function... fn) { + return click(new Function() { + int click = 0; + + @Override + public boolean f(Event e) { + return fn[(click++ % fn.length)].f(e); + } + }); + } + + /** + * Adds or removes the specified classes to each matched element. + */ + public GQuery toggleClass(String... classes) { + for (Element e : elements()) { + for (String clz : classes) { + if (hasClass(e, clz)) { + setStyleName(e, clz, false); + } else { + setStyleName(e, clz, true); + } + } + } + return this; + } + + /** + * Adds or removes the specified classes to each matched element. + */ + public GQuery toggleClass(String clz, boolean sw) { + for (Element e : elements()) { + setStyleName(e, clz, sw); + } + return this; + } + + /** + * Produces a string representation of the matched elements + */ + public String toString() { + return toString(false); + } + + /** + * Produces a string representation of the matched elements + */ + public String toString(boolean pretty) { + String r = ""; + for (Element e : elements()) { + r += (pretty && r.length() > 0 ? "\n " : "") + e.getString(); + } + return r; + } + + /** + * Trigger an event of type eventbits on every matched element. + */ + public GQuery trigger(int eventbits, int... keys) { + return as(Events).fire(eventbits, keys); + } + + /** + * Removes all events that match the eventbits + */ + public GQuery unbind(int eventbits) { + return as(Events).unbind(eventbits); + } + + /** + * Remove all duplicate elements from an array of elements. Note that this + * only works on arrays of DOM elements, not strings or numbers. + */ + public JSArray unique(JSArray result) { + FastSet f = FastSet.create(); + JSArray ret = JSArray.create(); + for (int i = 0; i < result.getLength(); i++) { + Element e = result.getElement(i); + if (!f.contains(e)) { + f.add(e); + ret.addNode(e); + } + } + return ret; + } + + /** + * Gets the content of the value attribute of the first matched element, + * returns only the first value even if it is a multivalued element. To get an + * array of all values in multivalues elements use vals() + * + * When the first element is a radio-button and is not checked, then it looks + * for a the first checked radio-button that has the same name in the list of + * matched elements. + */ + public String val() { + String[] v = vals(); + return (v != null && v.length > 0) ? v[0] : ""; + } + + /** + * Sets the value attribute of every matched element In the case of multivalue + * elements, all values are setted for other elements, only the first value is + * considered. + */ + public GQuery val(String... values) { + for (Element e : elements()) { + String name = e.getNodeName(); + if ("select".equalsIgnoreCase(name)) { + SelectElement s = SelectElement.as(e); + if (values.length > 1 && s.isMultiple()) { + s.setSelectedIndex(-1); + for (String v : values) { + for (int i = 0; i < s.getOptions().getLength(); i++) { + if (v.equals(s.getOptions().getItem(i).getValue())) { + s.getOptions().getItem(i).setSelected(true); + } + } + } + } else { + s.setValue(values[0]); + } + } else if ("input".equalsIgnoreCase(name)) { + InputElement ie = InputElement.as(e); + String type = ie.getType(); + if ("radio".equalsIgnoreCase((type)) || "checkbox" + .equalsIgnoreCase(type)) { + if ("checkbox".equalsIgnoreCase(type)) { + for (String val : values) { + if (ie.getValue().equals(val)) { + ie.setChecked(true); + } else { + ie.setChecked(false); + } + } + } else if (values[0].equals(ie.getValue())) { + ie.setChecked(true); + } + } else { + ie.setValue(values[0]); + } + } else if ("textarea".equalsIgnoreCase(name)) { + TextAreaElement.as(e).setValue(values[0]); + } else if ("button".equalsIgnoreCase(name)) { + ButtonElement.as(e).setValue(values[0]); + } + } + return this; + } + + /** + * Gets the content of the value attribute of the first matched element, + * returns more than one value if it is a multiple select. + * + * When the first element is a radio-button and is not checked, then it looks + * for a the first checked radio-button that has the same name in the list of + * matched elements. + * + * This method always returns an array. If no valid value can be determined + * the array will be empty, otherwise it will contain one or more values. + */ + public String[] vals() { + if (size() > 0) { + Element e = get(0); + if (e.getNodeName().equalsIgnoreCase("select")) { + SelectElement se = SelectElement.as(e); + if (se.isMultiple()) { + List result = new ArrayList(); + for (OptionElement oe : asArray(se.getOptions())) { + if (oe.isSelected()) { + result.add(oe.getValue()); + } + } + return result.toArray(new String[0]); + } else if (se.getSelectedIndex() >= 0) { + return new String[]{ + se.getOptions().getItem(se.getSelectedIndex()).getValue()}; + } + } else if (e.getNodeName().equalsIgnoreCase("input")) { + InputElement ie = InputElement.as(e); + if ("radio".equalsIgnoreCase(ie.getType())) { + for (Element e2 : elements()) { + if ("input".equalsIgnoreCase(e2.getNodeName())) { + InputElement ie2 = InputElement.as(e2); + if ("radio".equalsIgnoreCase(ie2.getType()) && ie2.isChecked() + && ie.getName().equals(ie2.getName())) { + return new String[]{ie2.getValue()}; + } + } + } + } else if ("checkbox".equalsIgnoreCase(ie.getType())) { + if (ie.isChecked()) { + return new String[]{ie.getValue()}; + } + } else { + return new String[]{ie.getValue()}; + } + } else if (e.getNodeName().equalsIgnoreCase("textarea")) { + return new String[]{TextAreaElement.as(e).getValue()}; + } else if (e.getNodeName().equalsIgnoreCase("button")) { + return new String[]{ButtonElement.as(e).getValue()}; + } + } + return new String[0]; + } + + /** + * Return true if the first element is visible. + */ + public boolean visible() { + return as(Effects).visible(); + } + + /** + * Set the width of every matched element. + */ + public GQuery width(int width) { + for (Element e : elements()) { + e.getStyle().setPropertyPx("width", width); + } + return this; + } + + /** + * Get the current computed, pixel, width of the first matched element. + */ + public int width() { + return DOM + .getElementPropertyInt((com.google.gwt.user.client.Element) get(0), + "offsetWidth"); + } + + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(GQuery query) { + for (Element e : elements()) { + $(e).wrapAll(query); + } + return this; + } + + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(Element elem) { + return wrap($(elem)); + } + + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(String html) { + return wrap($(html)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(String html) { + return wrapAll($(html)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(Element elem) { + return wrapAll($(elem)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(GQuery query) { + GQuery wrap = query.clone(); + if (elements.getItem(0).getParentNode() != null) { + wrap.insertBefore(elements.getItem(0)); + } + for (Element e : wrap.elements()) { + Node n = e; + while (n.getFirstChild() != null) { + n = n.getFirstChild(); + $((Element) n).append(this); + } + } + return this; + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(GQuery query) { + for (Element e : elements()) { + $(e).contents().wrapAll(query); + } + return this; + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(String html) { + return wrapInner($(html)); + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(Element elem) { + return wrapInner($(elem)); + } + + protected GQuery pushStack(JSArray elts, String name, String selector) { + GQuery g = new GQuery(elts); + g.setPreviousObject(this); + g.setSelector(selector); + return g; + } + + private void allNextSiblingElements(Element firstChildElement, JSArray result, + Element elem) { + while (firstChildElement != null) { + if (firstChildElement != elem) { + result.addNode(firstChildElement); + } + firstChildElement = firstChildElement.getNextSiblingElement(); + } + } + + private void allPreviousSiblingElements(Element firstChildElement, + JSArray result) { + while (firstChildElement != null) { + result.addNode(firstChildElement); + firstChildElement = getPreviousSiblingElement(firstChildElement); + } + } + + private JSArray clean(String elem) { + String tags = elem.trim().toLowerCase(); + String preWrap = "", postWrap = ""; + int wrapPos = 0; + if (tags.contains(""; + postWrap = ""; + } else if (tags.contains(" Object data(Element item, String name, S value) { + if (dataCache == null) { + windowData = JavaScriptObject.createObject().cast(); + dataCache = JavaScriptObject.createObject().cast(); + } + item = item == window() ? windowData : item; + int id = item.hashCode(); + if (name != null && !dataCache.exists(id)) { + dataCache.put(id, DataCache.createObject().cast()); + } + + DataCache d = dataCache.get(id).cast(); + if (name != null && value != null) { + d.put(name, value); + } + return name != null ? value : id; + } + + private void dequeue(Element elem, String type) { + Queue q = queue(elem, type, null); + Function f = q.dequeue(); + + if (q != null) { + if (SelectorEngine.eq(type, "__FX")) { + f = q.peek(0); + } + if (f != null) { + f.f(elem); + } + } + } + + private GQuery domManip(String html, int func) { + return domManip(clean(html), func); + } + + private GQuery domManip(NodeList nodes, int func) { + for (Element e : elements()) { + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.getItem(i); + if(size() > 1) n=n.cloneNode(true); + + switch (func) { + case FUNC_PREPEND: + e.insertBefore(n, e.getFirstChild()); + break; + case FUNC_APPEND: + e.appendChild(n); + break; + case FUNC_AFTER: + e.getParentNode().insertBefore(n, e.getNextSibling()); + break; + case FUNC_BEFORE: + e.getParentNode().insertBefore(n, e); + break; + } + } + } + return this; + } + + private String fixAttributeName(String key) { + return key; + } + + private native Document getContentDocument(Node n) /*-{ + return n.contentDocument || n.contentWindow.document; + }-*/; + + private native Element getPreviousSiblingElement(Element elem) /*-{ + var sib = elem.previousSibling; + while (sib && sib.nodeType != 1) + sib = sib.previousSibling; + return sib; + }-*/; + + private void init(GQuery gQuery) { + this.elements = gQuery.elements; + } + + private JSArray merge(NodeList first, NodeList second) { + JSArray res = JSArray.create(); + for (int i = 0; i < first.getLength(); i++) { + res.addNode(first.getItem(i)); + } + for (int i = 0; i < second.getLength(); i++) { + res.addNode(second.getItem(i)); + } + return res; + } + + private int num(GQuery gQuery, String val) { + Element elem = gQuery.get(0); + try { + if (elem != null) { + String v = GQuery.curCSS(elem, val); + return Integer.parseInt(v); + } + } catch (NumberFormatException e) { + + } + return 0; + } + + private Queue queue(Element elem, String type, Function data) { + if (elem != null) { + type = type + "queue"; + Object q = (Queue) data(elem, type, null); + if (q == null) { + q = data(elem, type, Queue.newInstance()); + } + Queue qq = (Queue) q; + if (data != null) { + qq.enqueue(data); + } + if (SelectorEngine.eq(type, "__FX") && qq.length() == 1) { + data.f(elem); + } + return qq; + } + return null; + } + + private void removeData(Element item, String name) { + if (dataCache == null) { + windowData = JavaScriptObject.createObject().cast(); + dataCache = JavaScriptObject.createObject().cast(); + } + item = item == window() ? windowData : item; + int id = item.hashCode(); + if (name != null) { + if (!dataCache.exists(id)) { + dataCache.getCache(id).delete(name); + } + if (dataCache.getCache(id).isEmpty()) { + removeData(item, null); + } + } else { + dataCache.delete(id); + } + } + + private void replacequeue(Element elem, String type, Queue data) { + if (elem != null) { + type = type + "queue"; + Object q = (Queue) data(elem, type, null); + data(elem, type, data); + } + } + + private GQuery trigger(NativeEvent event, Object o) { + for (Element e : elements()) { + e.dispatchEvent(event); + } + return this; + } + + private native Element window() /*-{ + return $wnd; + }-*/; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/JSArray.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/JSArray.java new file mode 100644 index 00000000..87242f56 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/JSArray.java @@ -0,0 +1,72 @@ +package com.google.gwt.query.client; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; + +/** + */ +public class JSArray extends NodeList { + + public static JSArray create() { + return (JSArray) JavaScriptObject.createArray(); + } + + public static native JSArray create(Node node) /*-{ + return [node]; + }-*/; + + public static native JSArray create(NodeList nl) /*-{ + var r = [], len=nl.length; + for(var i=0; i { + + /** + * Called by the GQuery.as() method in order to pass the current matched + * set. Typically a plugin will want to call a super class copy constructor + * in order to copy the internal matched set of elements. + * @param gQuery + * @return + */ + T init(GQuery gQuery); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Predicate.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Predicate.java new file mode 100644 index 00000000..89d78f28 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Predicate.java @@ -0,0 +1,10 @@ +package com.google.gwt.query.client; + +import com.google.gwt.dom.client.Element; + +/** + * A predicate function used by some GQuery methods. + */ +public interface Predicate { + boolean f(Element e, int index); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java new file mode 100644 index 00000000..c2954a49 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -0,0 +1,51 @@ +package com.google.gwt.query.client; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArrayString; + +/** + * JSO for accessing Javascript objective literals used by GwtQuery functions. + */ +public class Properties extends JavaScriptObject { + + protected Properties() { + } + + public static Properties create(String properties) { + String s = properties.replaceFirst("^[({]*(.*)[})]*$", "({$1})"); + return (Properties) createImpl(s); + } + + public final native static JavaScriptObject createImpl(String properties) /*-{ + return eval(properties); + }-*/; + + public final native String get(String name) /*-{ + return this[name]; + }-*/; + + public final native int getInt(String name) /*-{ + return this[name]; + }-*/; + + public final native float getFloat(String name) /*-{ + return this[name]; + }-*/; + + public final String[] keys() { + JsArrayString a = keysImpl(); + String[] ret = new String[a.length()]; + for (int i = 0; i < a.length(); i++) { + ret[i] = "" + a.get(i); + } + return ret; + } + + public final native JsArrayString keysImpl() /*-{ + var key, keys=[]; + for(key in this) { + keys.push("" + key); + } + return keys; + }-*/; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Regexp.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Regexp.java new file mode 100644 index 00000000..8a33ffd6 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Regexp.java @@ -0,0 +1,56 @@ +package com.google.gwt.query.client; + +import com.google.gwt.core.client.JavaScriptObject; + +/** + * A wrapper around Javascript Regexps. + */ +public class Regexp { + + private final JavaScriptObject regexp; + + public Regexp(String pattern) { + this.regexp = compile(pattern); + } + + public Regexp(String pat, String flags) { + this.regexp = compileFlags(pat, flags); + } + + public static native JavaScriptObject compile(String pat) /*-{ + return new RegExp(pat); + }-*/; + + public static native JavaScriptObject compileFlags(String pat, String flags) /*-{ + return new RegExp(pat, flags); + }-*/; + + public JSArray exec(String str) { + return exec0(regexp, str); + } + + + private static native JSArray exec0(JavaScriptObject regexp, String str) /*-{ + return regexp.exec(str); + }-*/; + + public JSArray match(String currentRule) { + return match0(regexp, currentRule); + } + + private native JSArray match0(JavaScriptObject regexp, String currentRule)/*-{ + return currentRule.match(regexp); + }-*/; + + public boolean test(String rule) { + return test0(regexp, rule); + } + + private native boolean test0(JavaScriptObject regexp, String rule) /*-{ + return regexp.test(rule); + }-*/; + + public static JSArray match(String regexp, String flags, String string) { + return new Regexp(regexp, flags).match(string); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Selector.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Selector.java new file mode 100644 index 00000000..23eae98e --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Selector.java @@ -0,0 +1,15 @@ +package com.google.gwt.query.client; + +import java.lang.annotation.Target; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import static java.lang.annotation.ElementType.METHOD; + +/** + * Used to pass a CSS Selector to a generator at compile time + */ +@Target({METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Selector { + String value(); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/SelectorEngine.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/SelectorEngine.java new file mode 100644 index 00000000..ebe36240 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/SelectorEngine.java @@ -0,0 +1,97 @@ +package com.google.gwt.query.client; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +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.impl.SelectorEngineImpl; + + +/** + * Core Selector engine functions, and native JS utility functions. + */ +public class SelectorEngine { + + private SelectorEngineImpl impl; + + public SelectorEngine() { + impl = (SelectorEngineImpl) GWT.create(SelectorEngineImpl.class); + } + + public static native boolean eq(String s1, String s2) /*-{ + return s1 == s2; + }-*/; + + public static native NodeList getElementsByClassName(String clazz, + Node ctx) /*-{ + return ctx.getElementsByClassName(clazz); + }-*/; + + public static native T or(T s1, T s2) /*-{ + return s1 || s2; + }-*/; + + public static native NodeList querySelectorAll(String selector) /*-{ + return $doc.querySelectorAll(selector); + }-*/; + + public static native NodeList querySelectorAll(String selector, + Node ctx) /*-{ + return ctx.querySelectorAll(selector); + }-*/; + + public NodeList select(String selector, Node ctx) { + return impl.select(selector, ctx); + } + + public static boolean truth(String a) { + return GWT.isScript() ? truth0(a) : a != null && !"".equals(a); + } + + public static boolean truth(JavaScriptObject a) { + return GWT.isScript() ? truth0(a) : a != null; + } + + public static NodeList xpathEvaluate(String selector, Node ctx) { + return xpathEvaluate(selector, ctx, JSArray.create()); + } + + public static native NodeList xpathEvaluate(String selector, + Node ctx, JSArray r) /*-{ + var node; + var result = $doc.evaluate(selector, ctx, null, 0, null); + while ((node = result.iterateNext())) { + r.push(node); + } + return r; + }-*/; + + private static native boolean truth0(String a) /*-{ + return a; + }-*/; + + private static native boolean truth0(JavaScriptObject a) /*-{ + return a; + }-*/; + + protected JSArray veryQuickId(Node context, String id) { + JSArray r = JSArray.create(); + if (context.getNodeType() == Node.DOCUMENT_NODE) { + r.addNode(((Document) context).getElementById(id)); + return r; + } else { + r.addNode(context.getOwnerDocument().getElementById(id)); + return r; + } + } + + public static native Node getNextSibling(Node n) /*-{ + return n.nextSibling || null; + }-*/; + + public static native Node getPreviousSibling(Node n) /*-{ + return n.previousSibling || null; + }-*/; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Selectors.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Selectors.java new file mode 100644 index 00000000..062df40e --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Selectors.java @@ -0,0 +1,8 @@ +package com.google.gwt.query.client; + +/** + * Tagging interface used to generate compile time selectors. + */ +public interface Selectors { + DeferredGQuery[] getAllSelectors(); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java new file mode 100644 index 00000000..eb3aa74c --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java @@ -0,0 +1,41 @@ +package com.google.gwt.query.client.impl; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.SelectorEngine; +import com.google.gwt.query.client.GQuery; + +/** + * A helper class to get computed CSS styles for elements. + */ +public class DocumentStyleImpl { + + public String getPropertyName(String name) { + if ("float".equals(name)) { + return "cssFloat"; + } else if ("class".equals(name)) { + return "className"; + } else if ("for".equals(name)) { + return "htmlFor"; + } + return GQuery.camelize(name); + } + + public String getCurrentStyle(Element elem, String name) { + name = hyphenize(name); + String propVal = getComputedStyle(elem, name, null); + if ("opacity".equals(name)) { + propVal = SelectorEngine.or(propVal, "1"); + } + return propVal; + } + + protected native String hyphenize(String name) /*-{ + return name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + }-*/; + + private native String getComputedStyle(Element elem, String name, + String pseudo) /*-{ + var cStyle = $doc.defaultView.getComputedStyle( elem, pseudo ); + return cStyle ? cStyle.getPropertyValue( name ) : null; + }-*/; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImplIE.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImplIE.java new file mode 100644 index 00000000..14450247 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImplIE.java @@ -0,0 +1,56 @@ +package com.google.gwt.query.client.impl; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.SelectorEngine; + +/** + * A helper class to get computed CSS styles for elements on IE6. + */ +public class DocumentStyleImplIE extends DocumentStyleImpl { + + public String getPropertyName(String name) { + if ("float".equals(name)) { + return "styleFloat"; + } else if ("class".equals(name)) { + return "className"; + } else if ("for".equals(name)) { + return "htmlFor"; + } + return name; + } + + public String getCurrentStyle(Element elem, String name) { + name = hyphenize(name); + String propVal = getComputedStyle(elem, name, null); + if ("opacity".equals(name)) { + propVal = SelectorEngine.or(propVal, "1"); + } + return propVal; + } + + // code lifted from jQuery + private native String getComputedStyle(Element elem, String name, + String pseudo) /*-{ + var style = elem.style; + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + var ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; + } + return ret; + }-*/; +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineImpl.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineImpl.java new file mode 100644 index 00000000..d42e7fa0 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineImpl.java @@ -0,0 +1,106 @@ +package com.google.gwt.query.client.impl; + +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.JSArray; +import com.google.gwt.query.client.Regexp; +import com.google.gwt.query.client.SelectorEngine; + +/** + * Base/Utility class for runtime selector engine implementations. + */ +public abstract class SelectorEngineImpl { + + public abstract NodeList select(String selector, Node ctx); + + protected static Sequence getSequence(String expression) { + int start = 0, add = 2, max = -1, modVal = -1; + Regexp expressionRegExp = new Regexp( + "^((odd|even)|([1-9]\\d*)|((([1-9]\\d*)?)n((\\+|\\-)(\\d+))?)|(\\-(([1-9]\\d*)?)n\\+(\\d+)))$"); + JSArray pseudoValue = expressionRegExp.exec(expression); + if (!SelectorEngine.truth(pseudoValue)) { + return null; + } else { + if (SelectorEngine.truth(pseudoValue.getStr(2))) { // odd or even + start = (SelectorEngine.eq(pseudoValue.getStr(2), "odd")) ? 1 : 2; + modVal = (start == 1) ? 1 : 0; + } else if (SelectorEngine + .truth(pseudoValue.getStr(3))) { // single digit + start = Integer.parseInt(pseudoValue.getStr(3), 10); + add = 0; + max = start; + } else if (SelectorEngine.truth(pseudoValue.getStr(4))) { // an+b + add = SelectorEngine.truth(pseudoValue.getStr(6)) ? Integer + .parseInt(pseudoValue.getStr(6), 10) : 1; + start = SelectorEngine.truth(pseudoValue.getStr(7)) ? Integer.parseInt( + (pseudoValue.getStr(8).charAt(0) == '+' ? "" + : pseudoValue.getStr(8)) + pseudoValue.getStr(9), 10) : 0; + while (start < 1) { + start += add; + } + modVal = (start > add) ? (start - add) % add + : ((start == add) ? 0 : start); + } else if (SelectorEngine.truth(pseudoValue.getStr(10))) { // -an+b + add = SelectorEngine.truth(pseudoValue.getStr(12)) ? Integer + .parseInt(pseudoValue.getStr(12), 10) : 1; + start = max = Integer.parseInt(pseudoValue.getStr(13), 10); + while (start > add) { + start -= add; + } + modVal = (max > add) ? (max - add) % add : ((max == add) ? 0 : max); + } + } + Sequence s = new Sequence(); + s.start = start; + s.add = add; + s.max = max; + s.modVal = modVal; + return s; + } + + public static class Sequence { + + public int start; + + public int max; + + public int add; + + public int modVal; + } + + public static class SplitRule { + + public String tag; + + public String id; + + public String allClasses; + + public String allAttr; + + public String allPseudos; + + public String tagRelation; + + public SplitRule(String tag, String id, String allClasses, String allAttr, + String allPseudos) { + this.tag = tag; + this.id = id; + this.allClasses = allClasses; + this.allAttr = allAttr; + this.allPseudos = allPseudos; + } + + public SplitRule(String tag, String id, String allClasses, String allAttr, + String allPseudos, String tagRelation) { + this.tag = tag; + this.id = id; + this.allClasses = allClasses; + this.allAttr = allAttr; + this.allPseudos = allPseudos; + this.tagRelation = tagRelation; + } + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java new file mode 100644 index 00000000..6c46e4d4 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java @@ -0,0 +1,689 @@ +package com.google.gwt.query.client.impl; + +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.SelectorEngine; +import com.google.gwt.query.client.Regexp; +import com.google.gwt.query.client.JSArray; + +/** + * Runtime selector engine implementation with no-XPath/native support based + * on DOMAssistant. + */ +public class SelectorEngineJS extends SelectorEngineImpl { + private Regexp cssSelectorRegExp; + private Regexp selectorSplitRegExp; + private Regexp childOrSiblingRefRegExp; + + + public SelectorEngineJS() { + selectorSplitRegExp = new Regexp("[^\\s]+", "g"); + childOrSiblingRefRegExp = new Regexp("^(>|\\+|~)$"); + cssSelectorRegExp = new Regexp( + "^(\\w+)?(#[\\w\\u00C0-\\uFFFF\\-\\_]+|(\\*))?((\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[\\w\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[\\w\\u00C0-\\uFFFF\\-_]+|((\\w*\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[\\w\\-]*))\\))?)*)?"); + } + + public static void clearAdded(JSArray a) { + for (int i = 0, len = a.size(); i < len; i++) { + clearAdded(a.getNode(i)); + } + } + + public static native void clearAdded(Node node) /*-{ + node.added = null; + }-*/; + + public static native NodeList getElementsByClassName(String clazz, + Node ctx) /*-{ + return ctx.getElementsByClassName(clazz); + }-*/; + + public static native boolean isAdded(Node prevRef) /*-{ + return prevRef.added || false; + }-*/; + + public static native void setAdded(Node prevRef, boolean added) /*-{ + prevRef.added = added; + }-*/; + + public static native void setSkipTag(JSArray prevElem, boolean skip) /*-{ + prevElem.skipTag = skip; + }-*/; + + private static String attrToRegExp(String attrVal, String op) { + if (SelectorEngine.eq("^", op)) { + return "^" + attrVal; + } + if (SelectorEngine.eq("$", op)) { + return attrVal + "$"; + } + if (SelectorEngine.eq("*", op)) { + return attrVal; + } + if (SelectorEngine.eq("|", op)) { + return "(^" + attrVal + "(\\-\\w+)*$)"; + } + if (SelectorEngine.eq("~", op)) { + return "\\b" + attrVal + "\\b"; + } + return SelectorEngine.truth(attrVal) ? "^" + attrVal + "$" : null; + } + + private static void clearChildElms(JSArray prevParents) { + for (int n = 0, nl = prevParents.size(); n < nl; n++) { + setHasChildElms(prevParents.getNode(n), false); + } + } + + protected String getAttr(Element current, String name) { + return current.getAttribute(name); + } + + private static void getDescendantNodes(JSArray matchingElms, + String nextTagStr, Node prevRef) { + NodeList children = getElementsByTagName(nextTagStr, prevRef); + for (int k = 0, klen = children.getLength(); k < klen; k++) { + Node child = children.getItem(k); + if (child.getParentNode() == prevRef) { + matchingElms.addNode(child); + } + } + } + + private JSArray getElementsByPseudo(JSArray previousMatch, String pseudoClass, + String pseudoValue) { + JSArray prevParents = JSArray.create(); + boolean previousDir = pseudoClass.startsWith("first") ? true : false; + JSArray matchingElms = JSArray.create(); + Node prev, next, previous; + if (SelectorEngine.eq("first-child", pseudoClass) || SelectorEngine + .eq("last-child", pseudoClass)) { + getFirstChildPseudo(previousMatch, previousDir, matchingElms); + } else if (SelectorEngine.eq("only-child", pseudoClass)) { + getOnlyChildPseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("nth-child", pseudoClass)) { + matchingElms = getNthChildPseudo(previousMatch, pseudoValue, prevParents, + matchingElms); + } else if (SelectorEngine.eq("first-of-type", pseudoClass) || SelectorEngine + .eq("last-of-type", pseudoClass)) { + getFirstOfTypePseudo(previousMatch, previousDir, matchingElms); + } else if (SelectorEngine.eq("only-of-type", pseudoClass)) { + getOnlyOfTypePseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("nth-of-type", pseudoClass)) { + matchingElms = getNthOfTypePseudo(previousMatch, pseudoValue, prevParents, + matchingElms); + } else if (SelectorEngine.eq("empty", pseudoClass)) { + getEmptyPseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("enabled", pseudoClass)) { + getEnabledPseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("disabled", pseudoClass)) { + getDisabledPseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("checked", pseudoClass)) { + getCheckedPseudo(previousMatch, matchingElms); + } else if (SelectorEngine.eq("contains", pseudoClass)) { + getContainsPseudo(previousMatch, pseudoValue, matchingElms); + } else if (SelectorEngine.eq("not", pseudoClass)) { + matchingElms = getNotPseudo(previousMatch, pseudoValue, matchingElms); + } else { + getDefaultPseudo(previousMatch, pseudoClass, pseudoValue, matchingElms); + } + return matchingElms; + } + + private void getDefaultPseudo(JSArray previousMatch, String pseudoClass, + String pseudoValue, JSArray matchingElms) { + Node previous; + for (int w = 0, wlen = previousMatch.size(); w < wlen; w++) { + previous = previousMatch.getElement(w); + if (SelectorEngine + .eq(((Element) previous).getAttribute(pseudoClass), pseudoValue)) { + matchingElms.addNode(previous); + } + } + } + + private JSArray getNotPseudo(JSArray previousMatch, String pseudoValue, + JSArray matchingElms) { + if (new Regexp("(:\\w+[\\w\\-]*)$").test(pseudoValue)) { + matchingElms = subtractArray(previousMatch, + getElementsByPseudo(previousMatch, pseudoValue.substring(1), "")); + } else { + pseudoValue = pseudoValue + .replace("^\\[#([\\w\\u00C0-\\uFFFF\\-\\_]+)\\]$", "[id=$1]"); + JSArray notTag = new Regexp("^(\\w+)").exec(pseudoValue); + JSArray notClass = new Regexp("^\\.([\\w\u00C0-\uFFFF\\-_]+)") + .exec(pseudoValue); + JSArray notAttr = new Regexp( + "\\[(\\w+)(\\^|\\$|\\*|\\||~)?=?([\\w\\u00C0-\\uFFFF\\s\\-_\\.]+)?\\]") + .exec(pseudoValue); + Regexp notRegExp = new Regexp( + "(^|\\s)" + (SelectorEngine.truth(notTag) ? notTag + .getStr(1) + : SelectorEngine.truth(notClass) ? notClass.getStr(1) : "") + + "(\\s|$)", "i"); + if (SelectorEngine.truth(notAttr)) { + String notAttribute = SelectorEngine.truth(notAttr.getStr(3)) ? notAttr + .getStr(3) + .replace("\\.", "\\.") : null; + String notMatchingAttrVal = attrToRegExp(notAttribute, + notAttr.getStr(2)); + notRegExp = new Regexp(notMatchingAttrVal, "i"); + } + for (int v = 0, vlen = previousMatch.size(); v < vlen; v++) { + Element notElm = previousMatch.getElement(v); + Element addElm = null; + if (SelectorEngine.truth(notTag) && !notRegExp + .test(notElm.getNodeName())) { + addElm = notElm; + } else if (SelectorEngine.truth(notClass) && !notRegExp + .test(notElm.getClassName())) { + addElm = notElm; + } else if (SelectorEngine.truth(notAttr)) { + String att = getAttr(notElm, notAttr.getStr(1)); + if (!SelectorEngine.truth(att) || !notRegExp.test(att)) { + addElm = notElm; + } + } + if (SelectorEngine.truth(addElm) && !isAdded(addElm)) { + setAdded(addElm, true); + matchingElms.addNode(addElm); + } + } + } + return matchingElms; + } + + private void getContainsPseudo(JSArray previousMatch, String pseudoValue, + JSArray matchingElms) { + Node previous; + for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { + previous = previousMatch.getNode(q); + if (!isAdded(previous)) { + if (((Element) previous).getInnerText().indexOf(pseudoValue) != -1) { + setAdded(previous, true); + matchingElms.addNode(previous); + } + } + } + } + + private void getCheckedPseudo(JSArray previousMatch, JSArray matchingElms) { + Node previous; + for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { + previous = previousMatch.getNode(q); + if (checked(previous)) { + matchingElms.addNode(previous); + } + } + } + + private void getDisabledPseudo(JSArray previousMatch, JSArray matchingElms) { + Node previous; + for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { + previous = previousMatch.getNode(q); + if (!enabled(previous)) { + matchingElms.addNode(previous); + } + } + } + + private void getEnabledPseudo(JSArray previousMatch, JSArray matchingElms) { + Node previous; + for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { + previous = previousMatch.getNode(q); + if (enabled(previous)) { + matchingElms.addNode(previous); + } + } + } + + private void getEmptyPseudo(JSArray previousMatch, JSArray matchingElms) { + Node previous; + for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { + previous = previousMatch.getNode(q); + if (!previous.hasChildNodes()) { + matchingElms.addNode(previous); + } + } + } + + private JSArray getNthOfTypePseudo(JSArray previousMatch, String pseudoValue, + JSArray prevParents, JSArray matchingElms) { + Node previous; + if (pseudoValue.startsWith("n")) { + matchingElms = previousMatch; + } else { + Sequence sequence = getSequence(pseudoValue); + if (sequence != null) { + for (int p = 0, plen = previousMatch.size(); p < plen; p++) { + previous = previousMatch.getNode(p); + Node prevParent = previous.getParentNode(); + if (!hasChildElms(prevParent)) { + int iteratorNext = sequence.start; + int childCount = 0; + Node childElm = prevParent.getFirstChild(); + while (SelectorEngine.truth(childElm) && (sequence.max < 0 + || iteratorNext <= sequence.max)) { + if (SelectorEngine + .eq(childElm.getNodeName(), previous.getNodeName())) { + if (++childCount == iteratorNext) { + matchingElms.addNode(childElm); + iteratorNext += sequence.add; + } + } + childElm = SelectorEngine.getNextSibling(childElm); + } + setHasChildElms(prevParent, true); + prevParents.addNode(prevParent); + } + } + clearChildElms(prevParents); + } + } + return matchingElms; + } + + private void getOnlyOfTypePseudo(JSArray previousMatch, + JSArray matchingElms) { + Node previous; + Node next; + Node prev; + Node oParent = null; + for (int o = 0, olen = previousMatch.size(); o < olen; o++) { + prev = next = previous = previousMatch.getNode(o); + Node prevParent = previous.getParentNode(); + if (prevParent != oParent) { + while ( + SelectorEngine.truth(prev = SelectorEngine.getPreviousSibling(prev)) + && !SelectorEngine + .eq(prev.getNodeName(), previous.getNodeName())) { + } + while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) + && !SelectorEngine.eq(next.getNodeName(), previous.getNodeName())) { + } + if (!SelectorEngine.truth(prev) && !SelectorEngine.truth(next)) { + matchingElms.addNode(previous); + } + oParent = prevParent; + } + } + } + + private void getFirstOfTypePseudo(JSArray previousMatch, boolean previousDir, + JSArray matchingElms) { + Node previous; + Node next; + for (int n = 0, nlen = previousMatch.size(); n < nlen; n++) { + next = previous = previousMatch.getNode(n); + + if (previousDir) { + while ( + SelectorEngine.truth(next = SelectorEngine.getPreviousSibling(next)) + && !SelectorEngine + .eq(next.getNodeName(), previous.getNodeName())) { + } + } else { + while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) + && !SelectorEngine.eq(next.getNodeName(), previous.getNodeName())) { + } + } + + if (!SelectorEngine.truth(next)) { + matchingElms.addNode(previous); + } + } + } + + private JSArray getNthChildPseudo(JSArray previousMatch, String pseudoValue, + JSArray prevParents, JSArray matchingElms) { + Node previous; + if (SelectorEngine.eq(pseudoValue, "n")) { + matchingElms = previousMatch; + } else { + Sequence sequence = getSequence(pseudoValue); + if (sequence != null) { + for (int l = 0, llen = previousMatch.size(); l < llen; l++) { + previous = previousMatch.getNode(l); + Node prevParent = previous.getParentNode(); + if (!hasChildElms(prevParent)) { + int iteratorNext = sequence.start; + int childCount = 0; + Node childElm = prevParent.getFirstChild(); + while (childElm != null && (sequence.max < 0 + || iteratorNext <= sequence.max)) { + if (childElm.getNodeType() == Node.ELEMENT_NODE) { + if (++childCount == iteratorNext) { + if (SelectorEngine + .eq(childElm.getNodeName(), previous.getNodeName())) { + matchingElms.addNode(childElm); + } + iteratorNext += sequence.add; + } + } + childElm = SelectorEngine.getNextSibling(childElm); + } + setHasChildElms(prevParent, true); + prevParents.addNode(prevParent); + } + } + clearChildElms(prevParents); + } + } + return matchingElms; + } + + private void getOnlyChildPseudo(JSArray previousMatch, JSArray matchingElms) { + Node previous; + Node next; + Node prev; + Node kParent = null; + for (int k = 0, klen = previousMatch.size(); k < klen; k++) { + prev = next = previous = previousMatch.getNode(k); + Node prevParent = previous.getParentNode(); + if (prevParent != kParent) { + while ( + SelectorEngine.truth(prev = SelectorEngine.getPreviousSibling(prev)) + && prev.getNodeType() != Node.ELEMENT_NODE) { + } + while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) + && next.getNodeType() != Node.ELEMENT_NODE) { + } + if (!SelectorEngine.truth(prev) && !SelectorEngine.truth(next)) { + matchingElms.addNode(previous); + } + kParent = prevParent; + } + } + } + + private void getFirstChildPseudo(JSArray previousMatch, boolean previousDir, + JSArray matchingElms) { + Node next; + Node previous; + for (int j = 0, jlen = previousMatch.size(); j < jlen; j++) { + previous = next = previousMatch.getElement(j); + if (previousDir) { + while (SelectorEngine + .truth((next = SelectorEngine.getPreviousSibling(next))) + && next.getNodeType() != Node.ELEMENT_NODE) { + } + } else { + while ( + SelectorEngine.truth((next = SelectorEngine.getNextSibling(next))) + && next.getNodeType() != Node.ELEMENT_NODE) { + } + } + if (!SelectorEngine.truth(next)) { + matchingElms.addNode(previous); + } + } + } + + private static native boolean checked(Node previous) /*-{ + return previous.checked || false; + }-*/; + + private static native boolean enabled(Node node) /*-{ + return !node.disabled; + }-*/; + + private static NodeList getElementsByTagName(String tag, Node ctx) { + return ((Element) ctx).getElementsByTagName(tag); + } + + private static void getGeneralSiblingNodes(JSArray matchingElms, + JSArray nextTag, Regexp nextRegExp, Node prevRef) { + while ( + SelectorEngine.truth((prevRef = SelectorEngine.getNextSibling(prevRef))) + && !isAdded(prevRef)) { + if (!SelectorEngine.truth(nextTag) || nextRegExp + .test(prevRef.getNodeName())) { + setAdded(prevRef, true); + matchingElms.addNode(prevRef); + } + } + } + + private static void getSiblingNodes(JSArray matchingElms, JSArray nextTag, + Regexp nextRegExp, Node prevRef) { + while ( + SelectorEngine.truth(prevRef = SelectorEngine.getNextSibling(prevRef)) + && prevRef.getNodeType() != Node.ELEMENT_NODE) { + } + if (SelectorEngine.truth(prevRef)) { + if (!SelectorEngine.truth(nextTag) || nextRegExp + .test(prevRef.getNodeName())) { + matchingElms.addNode(prevRef); + } + } + } + + private static native boolean hasChildElms(Node prevParent) /*-{ + return prevParent.childElms || false; + }-*/; + + private static native boolean isSkipped(JSArray prevElem) /*-{ + return prevElem.skipTag || false; + }-*/; + + private static native void setHasChildElms(Node prevParent, boolean bool) /*-{ + prevParent.childElms = bool ? bool : null; + }-*/; + + private static native JSArray subtractArray(JSArray previousMatch, + JSArray elementsByPseudo) /*-{ + for (var i=0, src1; (src1=arr1[i]); i++) { + var found = false; + for (var j=0, src2; (src2=arr2[j]); j++) { + if (src2 === src1) { + found = true; + break; + } + } + if (found) { + arr1.splice(i--, 1); + } + } + return arr; + }-*/; + + public NodeList select(String sel, Node ctx) { + String selectors[] = sel.replace("\\s*(,)\\s*", "$1").split(","); + boolean identical = false; + JSArray elm = JSArray.create(); + for (int a = 0, len = selectors.length; a < len; a++) { + if (a > 0) { + identical = false; + for (int b = 0, bl = a; b < bl; b++) { + if (SelectorEngine.eq(selectors[a], selectors[b])) { + identical = true; + break; + } + } + if (identical) { + continue; + } + } + String currentRule = selectors[a]; + JSArray cssSelectors = selectorSplitRegExp.match(currentRule); + JSArray prevElem = JSArray.create(ctx); + for (int i = 0, slen = cssSelectors.size(); i < slen; i++) { + JSArray matchingElms = JSArray.create(); + String rule = cssSelectors.getStr(i); + if (i > 0 && childOrSiblingRefRegExp.test(rule)) { + JSArray childOrSiblingRef = childOrSiblingRefRegExp.exec(rule); + if (SelectorEngine.truth(childOrSiblingRef)) { + JSArray nextTag = new Regexp("^\\w+") + .exec(cssSelectors.getStr(i + 1)); + Regexp nextRegExp = null; + String nextTagStr = null; + if (SelectorEngine.truth(nextTag)) { + nextTagStr = nextTag.getStr(0); + nextRegExp = new Regexp("(^|\\s)" + nextTagStr + "(\\s|$)", "i"); + } + for (int j = 0, jlen = prevElem.size(); j < jlen; j++) { + Node prevRef = prevElem.getNode(j); + String ref = childOrSiblingRef.getStr(0); + if (SelectorEngine.eq(">", ref)) { + getDescendantNodes(matchingElms, nextTagStr, prevRef); + } else if (SelectorEngine.eq("+", ref)) { + getSiblingNodes(matchingElms, nextTag, nextRegExp, prevRef); + } else if (SelectorEngine.eq("~", ref)) { + getGeneralSiblingNodes(matchingElms, nextTag, nextRegExp, + prevRef); + } + } + prevElem = matchingElms; + clearAdded(prevElem); + rule = cssSelectors.getStr(++i); + if (new Regexp("^\\w+$").test(rule)) { + continue; + } + setSkipTag(prevElem, true); + } + } + JSArray cssSelector = cssSelectorRegExp.exec(rule); + SplitRule splitRule = new SplitRule( + !SelectorEngine.truth(cssSelector.getStr(1)) || SelectorEngine + .eq(cssSelector.getStr(3), "*") ? "*" : cssSelector.getStr(1), + !SelectorEngine.eq(cssSelector.getStr(3), "*") ? cssSelector + .getStr(2) : null, cssSelector.getStr(4), cssSelector.getStr(6), + cssSelector.getStr(10)); + if (SelectorEngine.truth(splitRule.id)) { + Element domelem = Document.get() + .getElementById(splitRule.id.substring(1)); + if (SelectorEngine.truth(domelem)) { + matchingElms = JSArray.create(domelem); + } + prevElem = matchingElms; + } else if (SelectorEngine.truth(splitRule.tag) && !isSkipped(prevElem)) { + if (i == 0 && matchingElms.size() == 0 && prevElem.size() == 1) { + prevElem = matchingElms = JSArray.create( + getElementsByTagName(splitRule.tag, prevElem.getNode(0))); + } else { + NodeList tagCollectionMatches; + for (int l = 0, ll = prevElem.size(); l < ll; l++) { + tagCollectionMatches = getElementsByTagName(splitRule.tag, + prevElem.getNode(l)); + for (int m = 0, mlen = tagCollectionMatches.getLength(); m < mlen; + m++) { + Node tagMatch = tagCollectionMatches.getItem(m); + + if (!isAdded(tagMatch)) { + setAdded(tagMatch, true); + matchingElms.addNode(tagMatch); + } + } + } + prevElem = matchingElms; + clearAdded(prevElem); + } + if (matchingElms.size() == 0) { + break; + } + setSkipTag(prevElem, false); + if (SelectorEngine.truth(splitRule.allClasses)) { + String[] allClasses = splitRule.allClasses.replaceFirst("^\\.", "") + .split("\\."); + Regexp[] regExpClassNames = new Regexp[allClasses.length]; + for (int n = 0, nl = allClasses.length; n < nl; n++) { + regExpClassNames[n] = new Regexp( + "(^|\\s)" + allClasses[n] + "(\\s|$)"); + } + JSArray matchingClassElms = JSArray.create(); + for (int o = 0, olen = prevElem.size(); o < olen; o++) { + Element current = prevElem.getElement(o); + String elmClass = current.getClassName(); + boolean addElm = false; + if (SelectorEngine.truth(elmClass) && !isAdded(current)) { + for (int p = 0, pl = regExpClassNames.length; p < pl; p++) { + addElm = regExpClassNames[p].test(elmClass); + if (!addElm) { + break; + } + } + if (addElm) { + setAdded(current, true); + matchingClassElms.addNode(current); + } + } + } + clearAdded(prevElem); + prevElem = matchingElms = matchingClassElms; + } + if (SelectorEngine.truth(splitRule.allAttr)) { + JSArray allAttr = Regexp + .match("\\[[^\\]]+\\]", "g", splitRule.allAttr); + Regexp[] regExpAttributes = new Regexp[allAttr.size()]; + String[] regExpAttributesStr = new String[allAttr.size()]; + Regexp attributeMatchRegExp = new Regexp( + "(\\w+)(\\^|\\$|\\*|\\||~)?=?([\\w\u00C0-\uFFFF\\s\\-_\\.]+)?"); + for (int q = 0, ql = allAttr.size(); q < ql; q++) { + JSArray attributeMatch = attributeMatchRegExp + .exec(allAttr.getStr(q)); + String attributeValue = + SelectorEngine.truth(attributeMatch.getStr(3)) + ? attributeMatch.getStr(3).replaceAll("\\.", "\\.") + : null; + String attrVal = attrToRegExp(attributeValue, + (SelectorEngine.or(attributeMatch.getStr(2), null))); + regExpAttributes[q] = (SelectorEngine.truth(attrVal) ? new Regexp( + attrVal) : null); + regExpAttributesStr[q] = attributeMatch.getStr(1); + } + JSArray matchingAttributeElms = JSArray.create(); + + for (int r = 0, rlen = matchingElms.size(); r < rlen; r++) { + Element current = matchingElms.getElement(r); + boolean addElm = false; + for (int s = 0, sl = regExpAttributes.length, attributeRegExp; + s < sl; s++) { + addElm = false; + Regexp attributeRegExp2 = regExpAttributes[s]; + String currentAttr = getAttr(current, regExpAttributesStr[s]); + if (SelectorEngine.truth(currentAttr) + && currentAttr.length() != 0) { + if (attributeRegExp2 == null || attributeRegExp2 + .test(currentAttr)) { + addElm = true; + } + } + if (!addElm) { + break; + } + } + if (addElm) { + matchingAttributeElms.addNode(current); + } + } + prevElem = matchingElms = matchingAttributeElms; + } + if (SelectorEngine.truth(splitRule.allPseudos)) { + Regexp pseudoSplitRegExp = new Regexp( + ":(\\w[\\w\\-]*)(\\(([^\\)]+)\\))?"); + + JSArray allPseudos = Regexp.match( + "(:\\w+[\\w\\-]*)(\\([^\\)]+\\))?", "g", splitRule.allPseudos); + for (int t = 0, tl = allPseudos.size(); t < tl; t++) { + JSArray pseudo = pseudoSplitRegExp.match(allPseudos.getStr(t)); + String pseudoClass = SelectorEngine.truth(pseudo.getStr(1)) + ? pseudo.getStr(1) + .toLowerCase() : null; + String pseudoValue = SelectorEngine.truth(pseudo.getStr(3)) + ? pseudo.getStr(3) : null; + matchingElms = getElementsByPseudo(matchingElms, pseudoClass, + pseudoValue); + clearAdded(matchingElms); + } + prevElem = matchingElms; + } + } + } + elm.pushAll(prevElem); + } + + return elm; + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJSIE.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJSIE.java new file mode 100644 index 00000000..e2a2cf16 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJSIE.java @@ -0,0 +1,21 @@ +package com.google.gwt.query.client.impl; + +import com.google.gwt.dom.client.Element; + +/** + * Runtime implementaton of non-XPath/native for IE that fixes some + * DOM operation incompatibilities. + */ +public class SelectorEngineJSIE extends SelectorEngineJS { + public native String getAttr(Element elm, String attr) /*-{ + switch (attr) { + case "id": + return elm.id; + case "for": + return elm.htmlFor; + case "class": + return elm.className; + } + return elm.getAttribute(attr, 2); + }-*/; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineNative.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineNative.java new file mode 100644 index 00000000..130142b2 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineNative.java @@ -0,0 +1,17 @@ +package com.google.gwt.query.client.impl; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.Node; + +import com.google.gwt.query.client.SelectorEngine; + +/** + * Runtime selector engine implementation for browsers with native + * querySelectorAll support. + */ +public class SelectorEngineNative extends SelectorEngineImpl { + public NodeList select(String selector, Node ctx) { + return SelectorEngine.querySelectorAll(selector, ctx); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java new file mode 100644 index 00000000..4fa316fc --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java @@ -0,0 +1,229 @@ +package com.google.gwt.query.client.impl; + +import com.google.gwt.core.client.GWT; +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.Regexp; + +import com.google.gwt.query.client.JSArray; +import com.google.gwt.query.client.SelectorEngine; +import static com.google.gwt.query.client.SelectorEngine.eq; +import static com.google.gwt.query.client.SelectorEngine.truth; + +/** + * Runtime selector engine implementation which translates selectors to XPath + * and delegates to document.evaluate(). + */ +public class SelectorEngineXPath extends SelectorEngineImpl { + private Regexp cssSelectorRegExp; + private Regexp selectorSplitRegExp; + private Regexp COMBINATOR; + + public SelectorEngineXPath() { + } + + private void init() { + if (cssSelectorRegExp == null) { + cssSelectorRegExp = new Regexp( + "^(\\w+)?(#[\\w\\u00C0-\\uFFFF\\-\\_]+|(\\*))?((\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[\\w\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[\\w\\u00C0-\\uFFFF\\-_]+|((\\w*\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[\\w\\-]*))\\))?)*)?(>|\\+|~)?"); + selectorSplitRegExp = new Regexp("[^\\s]+", "g"); + COMBINATOR = new Regexp("(>|\\+|~)"); + } + } + + + public NodeList select(String sel, Node ctx) { + init(); + String selectors[] = sel.replaceAll("\\s*(,)\\s*", "$1").split(","); + boolean identical = false; + JSArray elm = JSArray.create(); + for (int a = 0, len = selectors.length; a < len; a++) { + if (a > 0) { + identical = false; + for (int b = 0, bl = a; b < bl; b++) { + if (eq(selectors[a], selectors[b])) { + identical = true; + break; + } + } + if (identical) { + continue; + } + } + String currentRule = selectors[a]; + JSArray cssSelectors = selectorSplitRegExp.match(currentRule); + String xPathExpression = "."; + for (int i = 0, slen = cssSelectors.size(); i < slen; i++) { + String rule = cssSelectors.getStr(i); + JSArray cssSelector = cssSelectorRegExp.exec(rule); + SplitRule splitRule = new SplitRule(!truth(cssSelector.getStr(1)) || eq( + cssSelector.getStr(3), "*") ? "*" : cssSelector.getStr(1), + !eq(cssSelector.getStr(3), "*") ? cssSelector.getStr(2) : null, + cssSelector.getStr(4), cssSelector.getStr(6), + cssSelector.getStr(10), cssSelector.getStr(22)); + if (truth(splitRule.tagRelation)) { + if (eq(">", splitRule.tagRelation)) { + xPathExpression += "/child::"; + } else if (eq("+", splitRule.tagRelation)) { + xPathExpression += "/following-sibling::*[1]/self::"; + } else if (eq("~", splitRule.tagRelation)) { + xPathExpression += "/following-sibling::"; + } + } else { + xPathExpression += + (i > 0 && COMBINATOR.test(cssSelectors.getStr(i - 1))) + ? splitRule.tag : ("/descendant::" + splitRule.tag); + } + if (truth(splitRule.id)) { + xPathExpression += "[@id = '" + splitRule.id.replaceAll("^#", "") + + "']"; + } + if (truth(splitRule.allClasses)) { + xPathExpression += splitRule.allClasses.replaceAll( + "\\.([\\w\\u00C0-\\uFFFF\\-_]+)", + "[contains(concat(' ', @class, ' '), ' $1 ')]"); + } + if (truth(splitRule.allAttr)) { + GWT.log("AllAttr is " + splitRule.allAttr, null); + xPathExpression += replaceAttr( + SelectorEngine.or(splitRule.allAttr, "")); + } + if (truth(splitRule.allPseudos)) { + Regexp pseudoSplitRegExp = new Regexp( + ":(\\w[\\w\\-]*)(\\(([^\\)]+)\\))?"); + Regexp pseudoMatchRegExp = new Regexp( + "(:\\w+[\\w\\-]*)(\\([^\\)]+\\))?", "g"); + JSArray allPseudos = pseudoMatchRegExp.match(splitRule.allPseudos); + for (int k = 0, kl = allPseudos.size(); k < kl; k++) { + JSArray pseudo = pseudoSplitRegExp.match(allPseudos.getStr(k)); + String pseudoClass = truth(pseudo.getStr(1)) ? pseudo.getStr(1) + .toLowerCase() : null; + String pseudoValue = truth(pseudo.getStr(3)) ? pseudo.getStr(3) + : null; + String xpath = pseudoToXPath(splitRule.tag, pseudoClass, + pseudoValue); + if (xpath.length() > 0) { + xPathExpression += "[" + xpath + "]"; + } + } + } + } + SelectorEngine.xpathEvaluate(xPathExpression, ctx, elm); + } + return elm; + } + + private String pseudoToXPath(String tag, String pseudoClass, + String pseudoValue) { + String xpath = ""; + if (eq("first-child", pseudoClass)) { + xpath = "not(preceding-sibling::*)"; + } else if (eq("first-of-type", pseudoClass)) { + xpath = "not(preceding-sibling::" + tag + ")"; + } else if (eq("last-child", pseudoClass)) { + xpath = "not(following-sibling::*)"; + } else if (eq("last-of-type", pseudoClass)) { + xpath = "not(following-sibling::" + tag + ")"; + } else if (eq("only-child", pseudoClass)) { + xpath = "not(preceding-sibling::* or following-sibling::*)"; + } else if (eq("only-of-type", pseudoClass)) { + xpath = "not(preceding-sibling::" + tag + " or following-sibling::" + tag + + ")"; + } else if (eq("nth-child", pseudoClass)) { + if (!eq("n", pseudoClass)) { + Sequence sequence = getSequence(pseudoValue); + if (sequence != null) { + if (sequence.start == sequence.max) { + xpath = "count(preceding-sibling::*) = " + (sequence.start - 1); + } else { + xpath = "(count(preceding-sibling::*) + 1) mod " + sequence.add + + " = " + sequence.modVal + ((sequence.start > 1) ? + " and count(preceding-sibling::*) >= " + (sequence.start - 1) + : "") + ((sequence.max > 0) ? + " and count(preceding-sibling::*) <= " + (sequence.max - 1) + : ""); + } + } + } + } else if (eq("nth-of-type", pseudoClass)) { + if (!pseudoValue.startsWith("n")) { + Sequence sequence = getSequence(pseudoValue); + if (sequence != null) { + if (sequence.start == sequence.max) { + xpath = pseudoValue; + } else { + xpath = "position() mod " + sequence.add + " = " + sequence.modVal + + ((sequence.start > 1) ? " and position() >= " + sequence + .start : "") + ((sequence.max > 0) ? " and position() <= " + + sequence.max : ""); + } + } + } + } else if (eq("empty", pseudoClass)) { + xpath = "count(child::*) = 0 and string-length(text()) = 0"; + } else if (eq("contains", pseudoClass)) { + xpath = "contains(., '" + pseudoValue + "')"; + } else if (eq("enabled", pseudoClass)) { + xpath = "not(@disabled)"; + } else if (eq("disabled", pseudoClass)) { + xpath = "@disabled"; + } else if (eq("checked", pseudoClass)) { + xpath = "@checked='checked'"; // Doesn't work in Opera 9.24 + } else if (eq("not", pseudoClass)) { + if (new Regexp("^(:\\w+[\\w\\-]*)$").test(pseudoValue)) { + xpath = "not(" + pseudoToXPath(tag, pseudoValue.substring(1), "") + ")"; + } else { + + pseudoValue = pseudoValue + .replaceFirst("^\\[#([\\w\\u00C0-\\uFFFF\\-\\_]+)\\]$", "[id=$1]"); + String notSelector = pseudoValue + .replaceFirst("^(\\w+)", "self::$1"); + notSelector = notSelector.replaceAll("^\\.([\\w\\u00C0-\\uFFFF\\-_]+)", + "contains(concat(' ', @class, ' '), ' $1 ')"); + notSelector = replaceAttr2(notSelector); + xpath = "not(" + notSelector + ")"; + } + } else { + xpath = "@" + pseudoClass + "='" + pseudoValue + "'"; + } + + return xpath; + } + + private static String attrToXPath(String match, String p1, String p2, + String p3) { + if (eq("^", p2)) { + return "starts-with(@" + p1 + ", '" + p3 + "')"; + } + if (eq("$", p2)) { + return "substring(@" + p1 + ", (string-length(@" + p1 + ") - " + + (p3.length() - 1) + "), " + p3.length() + ") = '" + p3 + "'"; + } + if (eq("*", p2)) { + return "contains(concat(' ', @" + p1 + ", ' '), '" + p3 + "')"; + } + if (eq("|", p2)) { + return "(@" + p1 + "='" + p3 + "' or starts-with(@" + p1 + ", '" + p3 + + "-'))"; + } + if (eq("~", p2)) { + return "contains(concat(' ', @" + p1 + ", ' '), ' " + p3 + " ')"; + } + return "@" + p1 + (truth(p3) ? "='" + p3 + "'" : ""); + } + + private native String replaceAttr(String allAttr) /*-{ + if(!allAttr) return ""; + return allAttr.replace(/(\w+)(\^|\$|\*|\||~)?=?([\w\u00C0-\uFFFF\s\-_\.]+)?/g, + function(a,b,c,d) { + return @gwtquery.client.impl.SelectorEngineXPath::attrToXPath(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)(a,b || "",c || "",d || ""); + }); + + }-*/; + + private native String replaceAttr2(String allAttr) /*-{ + if(!allAttr) return ""; + return allAttr.replace(/\[(\w+)(\^|\$|\*|\||~)?=?([\w\u00C0-\uFFFF\s\-_\.]+)?\]/g, @com.google.gwt.query.client.impl.SelectorEngineXPath::attrToXPath(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)); + }-*/; +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorBase.java new file mode 100644 index 00000000..e19d9b4d --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorBase.java @@ -0,0 +1,191 @@ +package com.google.gwt.query.rebind; + +import com.google.gwt.core.ext.Generator; +import com.google.gwt.core.ext.GeneratorContext; +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JClassType; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.core.ext.typeinfo.JParameter; +import com.google.gwt.core.ext.typeinfo.TypeOracle; +import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; +import com.google.gwt.user.rebind.SourceWriter; +import com.google.gwt.query.client.Selector; + +import java.io.PrintWriter; + +/** + * Base class for compile time selector generators. + */ +public abstract class SelectorGeneratorBase extends Generator { + + private TreeLogger treeLogger; + + protected JClassType NODE_TYPE = null; + + public String generate(TreeLogger treeLogger, + GeneratorContext generatorContext, String requestedClass) + throws UnableToCompleteException { + this.treeLogger = treeLogger; + TypeOracle oracle = generatorContext.getTypeOracle(); + NODE_TYPE = oracle.findType("com.google.gwt.dom.client.Node"); + + JClassType selectorType = oracle.findType(requestedClass); + SourceWriter sw = getSourceWriter(treeLogger, generatorContext, + selectorType.getPackage().getName(), + selectorType.getSimpleSourceName() + getImplSuffix(), requestedClass); + if (sw != null) { + for (JMethod method : selectorType.getMethods()) { + generateMethod(sw, method, treeLogger); + } + genGetAllMethod(sw, selectorType.getMethods(), treeLogger); + sw.commit(treeLogger); + } + + return selectorType.getPackage().getName() + "." + + selectorType.getSimpleSourceName() + getImplSuffix(); + } + + protected String getImplSuffix() { + return "Impl"; + } + + // used by benchmark harness + private void genGetAllMethod(SourceWriter sw, JMethod[] methods, + TreeLogger treeLogger) { + sw.println("public DeferredGQuery[] getAllSelectors() {"); + sw.indent(); + sw.println( + "DeferredGQuery[] dg = new DeferredGQuery[" + (methods.length) + "];"); + int i = 0; + for (JMethod m : methods) { + Selector selectorAnnotation = m.getAnnotation(Selector.class); + if(selectorAnnotation == null) continue; + String selector = selectorAnnotation.value(); + + sw.println("dg[" + i + "]=new DeferredGQuery() {"); + sw.indent(); + sw.println( + "public String getSelector() { return \"" + selector + "\"; }"); + sw.println("public GQuery eval(Node ctx) { return " + wrapJS(m, m.getName() + + (m.getParameters().length == 0 ? "()" : "(ctx)")+"") + " ;}"); + sw.println("public NodeList array(Node ctx) { return "+("NodeList".equals(m.getReturnType().getSimpleSourceName()) ? + (m.getName() + + (m.getParameters().length == 0 ? "(); " : "(ctx); ")) : + "eval"+(m.getParameters().length == 0 ? "(null).get(); " : "(ctx).get(); "))+"}"); + + i++; + sw.outdent(); + sw.println("};"); + } + sw.println("return dg;"); + sw.outdent(); + sw.println("}"); + } + + public void generateMethod(SourceWriter sw, JMethod method, TreeLogger logger) + throws UnableToCompleteException { + Selector selectorAnnotation = method.getAnnotation(Selector.class); + if(selectorAnnotation == null) return; + + String selector = selectorAnnotation.value(); + JParameter[] params = method.getParameters(); + + sw.indent(); + String retType = method.getReturnType().getParameterizedQualifiedSourceName(); + sw.print("public final "+retType+" "+method.getName()); + boolean hasContext = false; + if (params.length == 0) { + sw.print("()"); + } else if (params.length == 1) { + JClassType type = params[0].getType().isClassOrInterface(); + if (type != null && type.isAssignableTo(NODE_TYPE)) { + sw.print("(Node root)"); + hasContext = true; + } + } + sw.println(" {"); + sw.indent(); + Selector sel = method.getAnnotation(Selector.class); + + // short circuit #foo + if (sel != null && sel.value().matches("^#\\w+$")) { + sw.println("return "+wrap(method, "JSArray.create(((Document)" + (hasContext ? "root" : "(Node)Document.get()") + + ").getElementById(\"" + sel.value().substring(1) + "\"))")+";"); + } + // short circuit FOO + else if (sel != null && sel.value().matches("^\\w+$")) { + sw.println("return "+wrap(method, "JSArray.create(((Element)"+(hasContext ? "root" : "(Node)Document.get()") + + ").getElementsByTagName(\"" + sel.value() + "\"))")+";"); + } // short circuit .foo for browsers with native getElementsByClassName + else if (sel != null && sel.value().matches("^\\.\\w+$") + && hasGetElementsByClassName()) { + sw.println("return "+wrap(method, "JSArray.create(getElementsByClassName(\"" + + sel.value().substring(1) + "\", " + (hasContext ? "root" : "(Node)Document.get()") + + "))")+";"); + } else { + generateMethodBody(sw, method, logger, hasContext); + } + sw.outdent(); + sw.println("}"); + sw.outdent(); + } + + protected boolean hasGetElementsByClassName() { + return false; + } + + protected void debug(String s) { +// System.err.println(s); + treeLogger.log(TreeLogger.DEBUG, s, null); + } + + protected boolean notNull(String s) { + return s != null && !"".equals(s); + } + + protected SourceWriter getSourceWriter(TreeLogger logger, + GeneratorContext context, String packageName, String className, + String... interfaceNames) { + PrintWriter printWriter = context.tryCreate(logger, packageName, className); + if (printWriter == null) { + return null; + } + ClassSourceFileComposerFactory composerFactory + = new ClassSourceFileComposerFactory(packageName, className); + composerFactory.setSuperclass("com.google.gwt.query.client.SelectorEngine"); + composerFactory.addImport("com.google.gwt.core.client.GWT"); + composerFactory.addImport("gwtquery.client.*"); +// composerFactory.addImport("com.google.gwt.query.client.JSArray"); + + composerFactory.addImport("com.google.gwt.dom.client.*"); + for (String interfaceName : interfaceNames) { + composerFactory.addImplementedInterface(interfaceName); + } + + return composerFactory.createSourceWriter(context, printWriter); + } + + protected String wrap(JMethod method, String expr) { + if("NodeList".equals(method.getReturnType().getSimpleSourceName())) { + return expr; + } + else { + return "new GQuery("+expr+")"; + } + + } + + protected String wrapJS(JMethod method, String expr) { + if("GQuery".equals(method.getReturnType().getSimpleSourceName())) { + return expr; + } + else { + return "new GQuery("+expr+")"; + } + + } + + protected abstract void generateMethodBody(SourceWriter sw, JMethod method, + TreeLogger logger, boolean hasContext) throws UnableToCompleteException; +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJS.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJS.java new file mode 100644 index 00000000..67162e62 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJS.java @@ -0,0 +1,31 @@ +package com.google.gwt.query.rebind; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.query.client.Selector; +import com.google.gwt.user.rebind.SourceWriter; + +/** + * An implementaton of pure-JS compile time selectors. This implementation + * simply defers to the runtime selector engine. + */ +public class SelectorGeneratorJS extends SelectorGeneratorBase { + + protected String getImplSuffix() { + return "JS" + super.getImplSuffix(); + } + + protected void generateMethodBody(SourceWriter sw, JMethod method, + TreeLogger treeLogger, boolean hasContext) + throws UnableToCompleteException { + + String selector = method.getAnnotation(Selector.class).value(); + if (!hasContext) { + sw.println("Node root = Document.get();"); + } + + sw.println("return " + wrap(method, + "new SelectorEngine().select(\"" + selector + "\", root)") + ";"); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJSOptimal.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJSOptimal.java new file mode 100644 index 00000000..782b2d61 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorJSOptimal.java @@ -0,0 +1,174 @@ +package com.google.gwt.query.rebind; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.user.rebind.SourceWriter; + +import java.util.regex.Pattern; + +import com.google.gwt.query.client.Selector; + +/** + * + */ +public class SelectorGeneratorJSOptimal extends SelectorGeneratorBase { + + protected static Pattern nonSpace = Pattern.compile("\\S/"); + + private static final String trimReStr = "^\\s+|\\s+$"; + + protected static Pattern trimRe = Pattern.compile(trimReStr); + + protected static Pattern tplRe = Pattern.compile("\\{(\\d+)\\}"); + + protected static Pattern modeRe = Pattern + .compile("^(\\s?[\\/>+~]\\s?|\\s|$)"); + + protected static Pattern tagTokenRe = Pattern + .compile("^(#)?([a-zA-Z_0-9-\\*]+)"); + + protected static Pattern nthRe = Pattern.compile("(\\d*)n\\+?(\\d*)"); + + protected static Pattern nthRe2 = Pattern.compile("\\D"); + + protected static RuleMatcher[] matchers = new RuleMatcher[]{new RuleMatcher( + "^\\.([a-zA-Z_0-9-]+)", "n = byClassName(n, null, \"{0}\");"), + new RuleMatcher("^\\:([a-zA-Z_0-9-]+)(?:\\(((?:[^ >]*|.*?))\\))?", + "n = byPseudo(n, \"{0}\", \"{1}\");"), new RuleMatcher( + "^(?:([\\[\\{])(?:@)?([a-zA-Z_0-9-]+)\\s?(?:(=|.=)\\s?['\"]?(.*?)[\"']?)?[\\]\\}])", + "n = byAttribute(n, \"{1}\", \"{3}\", \"{2}\", \"{0}\");"), + new RuleMatcher("^#([a-zA-Z_0-9-]+)", "n = byId(n, null, \"{0}\");")}; + + protected String getImplSuffix() { + return "JS"+super.getImplSuffix(); + } + + protected void generateMethodBody(SourceWriter sw, JMethod method, + TreeLogger treeLogger, boolean hasContext) throws UnableToCompleteException { + + String selector = method.getAnnotation(Selector.class).value(); + if(!hasContext) sw.println("Node root = Document.get();"); + + sw.println("return "+wrap(method, "new SelectorEngine().select(\""+selector+"\", root)")+";"); +// sw.println("JSArray n = JSArray.create();"); +// if(!hasContext) { +// sw.println("Node root = Document.get();"); +// } +// +// // add root node as context. +// // TODO: support any context +// sw.println("n.addNode(root);"); +// String q = selector, lq = null; +// Matcher lmode = modeRe.matcher(q); +// Matcher mm = null; +// String mode = ""; +// if (lmode.lookingAt() && notNull(lmode.group(1))) { +// mode = lmode.group(1).replaceAll(trimReStr, "").trim(); +// q = q.replaceFirst("\\Q" + lmode.group(1) + "\\E", ""); +// } +// +// while (notNull(q) && !q.equals(lq)) { +// debug("Doing q=" + q); +// +// lq = q; +// Matcher tm = tagTokenRe.matcher(q); +// if (tm.lookingAt()) { +// if ("#".equals(tm.group(1))) { +// sw.println("n = quickId(n, \"" + mode + "\", root, \"" + tm.group(2) +// + "\");"); +// } else { +// String tagName = tm.group(2); +// tagName = "".equals(tagName) ? "*" : tagName; +// // sw.println("if (n.size() == 0) { n=JSArray.create(); }"); +// String func = ""; +// if ("".equals(mode)) { +// func = "getDescendentNodes"; +// } else if (">".equals(mode)) { +// func = "getChildNodes"; +// } else if ("+".equals(mode)) { +// func = "getSiblingNodes"; +// } else if ("~".equals(mode)) { +// func = "getGeneralSiblingNodes"; +// } else { +// treeLogger.log(TreeLogger.ERROR, "Error parsing selector, combiner " +// + mode + " not recognized in " + selector, null); +// throw new UnableToCompleteException(); +// } +// sw.println("n = " + func + "(n, \"" + tagName + "\");"); +// } +// debug("replacing in q, the value " + tm.group(0)); +// q = q.replaceFirst("\\Q" + tm.group(0) + "\\E", ""); +// } else { +// String func = ""; +// String tagName = "*"; +// if ("".equals(mode)) { +// func = "getDescendentNodes"; +// } else if (">".equals(mode)) { +// func = "getChildNodes"; +// } else if ("+".equals(mode)) { +// func = "getSiblingNodes"; +// } else if ("~".equals(mode)) { +// func = "getGeneralSiblingNodes"; +// } else { +// treeLogger.log(TreeLogger.ERROR, "Error parsing selector, combiner " +// + mode + " not recognized in " + selector, null); +// throw new UnableToCompleteException(); +// } +// sw.println("n = " + func + "(n, \"" + tagName + "\");"); +// } +// +// while (!(mm = modeRe.matcher(q)).lookingAt()) { +// debug("Looking at " + q); +// boolean matched = false; +// for (RuleMatcher rm : matchers) { +// Matcher rmm = rm.re.matcher(q); +// if (rmm.lookingAt()) { +// String res[] = new String[rmm.groupCount()]; +// for (int i = 1; i <= rmm.groupCount(); i++) { +// res[i - 1] = rmm.group(i); +// debug("added param " + res[i - 1]); +// } +// Object[] r = res; +// // inline enum, perhaps type-tightening will allow inlined eval() +// // call +// if (rm.fnTemplate.indexOf("byPseudo") != -1) { +// sw.println("n = Pseudo."+res[0].toUpperCase().replace("-", "_") + +// ".eval(n, \""+res[1]+"\");"); +// } else { +// sw.println(MessageFormat.format(rm.fnTemplate, r)); +// } +// q = q.replaceFirst("\\Q" + rmm.group(0) + "\\E", ""); +// matched = true; +// break; +// } +// } +// if (!matched) { +// treeLogger +// .log(TreeLogger.ERROR, "Error parsing selector at " + q, null); +// throw new UnableToCompleteException(); +// } +// } +// +// if (notNull(mm.group(1))) { +// mode = mm.group(1).replaceAll(trimReStr, ""); +// debug("replacing q=" + q + " this part:" + mm.group(1)); +// q = q.replaceFirst("\\Q" + mm.group(1) + "\\E", ""); +// } +// } +// sw.println("return "+wrap(method, "nodup(n)")+";"); + } + + + static class RuleMatcher { + + public Pattern re; + + public String fnTemplate; + + RuleMatcher(String pat, String fnT) { + this.re = Pattern.compile(pat); + this.fnTemplate = fnT; + } + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorNative.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorNative.java new file mode 100644 index 00000000..56880851 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorNative.java @@ -0,0 +1,32 @@ +package com.google.gwt.query.rebind; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.user.rebind.SourceWriter; +import com.google.gwt.query.client.Selector; + +/** + * Compile time selector generator which delegates to native browser + * methods. + */ +public class SelectorGeneratorNative extends SelectorGeneratorBase { + + protected String getImplSuffix() { + return "Native" + super.getImplSuffix(); + } + + protected void generateMethodBody(SourceWriter sw, JMethod method, + TreeLogger treeLogger, boolean hasContext) + throws UnableToCompleteException { + String selector = method.getAnnotation(Selector.class).value(); + if (!hasContext) { + sw.println("return " + + wrap(method, "querySelectorAll(\"" + selector + "\"") + ");"); + } else { + sw.println("return " + + wrap(method, "querySelectorAll(\"" + selector + "\", root)") + + ");"); + } + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorXPath.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorXPath.java new file mode 100644 index 00000000..e38b6df1 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/SelectorGeneratorXPath.java @@ -0,0 +1,319 @@ +package com.google.gwt.query.rebind; + +import com.google.gwt.core.ext.TreeLogger; +import com.google.gwt.core.ext.UnableToCompleteException; +import com.google.gwt.core.ext.typeinfo.JMethod; +import com.google.gwt.query.client.Selector; +import com.google.gwt.user.rebind.SourceWriter; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Compile time selector generator which translates selector into XPath at + * compile time. + */ +public class SelectorGeneratorXPath extends SelectorGeneratorBase { + + private static Pattern cssSelectorRegExp = Pattern.compile( + "^(\\w+)?(#[a-zA-Z_0-9\u00C0-\uFFFF\\-\\_]+|(\\*))?((\\.[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[a-zA-Z_0-9\u00C0-\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[a-zA-Z_0-9\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+|((\\w*\\.[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[a-zA-Z_0-9\u00C0-\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[a-zA-Z_0-9\\-]*))\\))?)*)?(>|\\+|~)?"); + + private static Pattern selectorSplitRegExp = Pattern + .compile("(?:\\[[^\\[]*\\]|\\(.*\\)|[^\\s\\+>~\\[\\(])+|[\\+>~]"); + + private String prefix = ""; + + static class SplitRule { + + public String tag; + + public String id; + + public String allClasses; + + public String allAttr; + + public String allPseudos; + + public String tagRelation; + } + + protected String getImplSuffix() { + return "XPath" + super.getImplSuffix(); + } + + protected void generateMethodBody(SourceWriter sw, JMethod method, + TreeLogger treeLogger, boolean hasContext) + throws UnableToCompleteException { + + String selector = method.getAnnotation(Selector.class).value(); + String[] cssRules = selector.replaceAll("\\s*(,)\\s*", "$1").split(","); + String currentRule; + boolean identical = false; + String xPathExpression = "."; + + for (int i = 0; i < cssRules.length; i++) { + currentRule = cssRules[i]; + + if (i > 0) { + identical = false; + for (int x = 0, xl = i; x < xl; x++) { + if (cssRules[i].equals(cssRules[x])) { + identical = true; + break; + } + } + if (identical) { + continue; + } + } + + ArrayList cssSelectors = new ArrayList(); + Matcher selm = selectorSplitRegExp.matcher(currentRule); + while (selm.find()) { + cssSelectors.add(selm.group(0)); + } + + Matcher cssSelector; + for (int j = 0, jl = cssSelectors.size(); j < jl; j++) { + cssSelector = cssSelectorRegExp.matcher(cssSelectors.get(j)); + if (cssSelector.matches()) { + + SplitRule splitRule = new SplitRule(); + splitRule.tag = prefix + ((!notNull(cssSelector.group(1)) || "*" + .equals(cssSelector.group(3))) ? "*" : cssSelector.group(1)); + splitRule.id = (!"*".equals(cssSelector.group(3))) ? cssSelector + .group(2) : null; + splitRule.allClasses = cssSelector.group(4); + splitRule.allAttr = cssSelector.group(6); + splitRule.allPseudos = cssSelector.group(10); + splitRule.tagRelation = cssSelector.group(22); + if (notNull(splitRule.tagRelation)) { + if (">".equals(splitRule.tagRelation)) { + xPathExpression += "/child::"; + } else if ("+".equals(splitRule.tagRelation)) { + xPathExpression += "/following-sibling::*[1]/self::"; + } else if ("~".equals(splitRule.tagRelation)) { + xPathExpression += "/following-sibling::"; + } + } else { + xPathExpression += + (j > 0 && cssSelectors.get(j - 1).matches("(>|\\+|~)")) + ? splitRule.tag : ("/descendant::" + splitRule.tag); + } + + if (notNull(splitRule.id)) { + xPathExpression += "[@id = '" + splitRule.id.replaceAll("^#", "") + + "']"; + } + if (notNull(splitRule.allClasses)) { + xPathExpression += splitRule.allClasses + .replaceAll("\\.([a-zA-Z_0-9\u00C0 -\uFFFF\\-_]+)", + "[contains(concat(' ', @class, ' '), ' $1 ')]"); + } + if (notNull(splitRule.allAttr)) { + xPathExpression += attrToXPath(splitRule.allAttr, + "(\\w+)(\\^|\\$|\\*|\\||~)?=?([a-zA-Z_0-9\u00C0-\uFFFF\\s\\-_\\.]+)?"); + } + if (notNull(splitRule.allPseudos)) { + Pattern pseudoSplitRegExp = Pattern + .compile(":(\\w[a-zA-Z_0-9\\-]*)(\\(([^\\)]+)\\))?"); + Matcher m = Pattern + .compile("(:\\w+[a-zA-Z_0-9\\-]*)(\\([^\\)]+\\))?") + .matcher(splitRule.allPseudos); + while (m.find()) { + String str = m.group(0); + Matcher pseudo = pseudoSplitRegExp + .matcher(str == null ? "" : str); + if (pseudo.matches()) { + String pseudoClass = notNull(pseudo.group(1)) ? pseudo.group(1) + .toLowerCase() : null; + String pseudoValue = notNull(pseudo.group(3)) ? pseudo.group(3) + : null; + String xpath = pseudoToXPath(splitRule.tag, pseudoClass, + pseudoValue); + if (notNull(xpath)) { + xPathExpression += "[" + xpath + "]"; + } + } + } + } + } + } + } + + if (!hasContext) { + sw.println("Node root = Document.get();"); + } + sw.println("return " + wrap(method, + "SelectorEngine.xpathEvaluate(\"" + xPathExpression + "\", root)") + + ";"); + } + + static class Sequence { + + public int start; + + public int max; + + public int add; + + public int modVal; + } + + private String pseudoToXPath(String tag, String pseudoClass, + String pseudoValue) { + tag = pseudoClass.matches(".*\\-child$") ? "*" : tag; + String xpath = ""; + String pseudo[] = pseudoClass.split("-"); + if ("first".equals(pseudo[0])) { + xpath = "not(preceding-sibling::" + tag + ")"; + } else if ("last".equals(pseudo[0])) { + xpath = "not(following-sibling::" + tag + ")"; + } else if ("only".equals(pseudo[0])) { + xpath = "not(preceding-sibling::" + tag + " or following-sibling::" + tag + + ")"; + } else if ("nth".equals(pseudo[0])) { + if (!pseudoValue.matches("^n$")) { + String position = + (("last".equals(pseudo[1])) ? "(count(following-sibling::" + : "(count(preceding-sibling::") + tag + ") + 1)"; + Sequence sequence = getSequence(pseudoValue); + if (sequence != null) { + if (sequence.start == sequence.max) { + xpath = position + " = " + sequence.start; + } else { + xpath = position + " mod " + sequence.add + " = " + sequence.modVal + + ((sequence.start > 1) ? " and " + position + " >= " + + sequence.start : "") + ((sequence.max > 0) ? " and " + + position + " <= " + sequence.max : ""); + } + } + } + } else if ("empty".equals(pseudo[0])) { + xpath = "count(child::*) = 0 and string-length(text()) = 0"; + } else if ("contains".equals(pseudo[0])) { + xpath = "contains(., '" + pseudoValue + "')"; + } else if ("enabled".equals(pseudo[0])) { + xpath = "not(@disabled)"; + } else if ("disabled".equals(pseudo[0])) { + xpath = "@disabled"; + } else if ("checked".equals(pseudo[0])) { + xpath = "@checked='checked'"; // Doesn't work in Opera 9.24 + } else if ("not".equals(pseudo[0])) { + if (pseudoValue.matches("^(:a-zA-Z_0-9+[a-zA-Z_0-9\\-]*)$")) { + xpath = "not(" + pseudoToXPath(tag, pseudoValue.substring(1), "") + ")"; + } else { + pseudoValue = pseudoValue + .replaceAll("^\\[#([a-zA-Z_0-9\u00C0-\uFFFF\\-\\_]+)\\]$", + "[id=$1]"); + String notSelector = pseudoValue + .replaceFirst("^(a-zA-Z_0-9+)", "self::$1"); + notSelector = notSelector + .replaceAll("^\\.([a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)", + "contains(concat(' ', @class, ' '), ' $1 ')"); + notSelector = attrToXPath(notSelector, + "\\[(a-zA-Z_0-9+)(\\^|\\$|\\*|\\||~)?=?([a-zA-Z_0-9\u00C0-\uFFFF\\s\\-_\\.]+)?\\]"); + xpath = "not(" + notSelector + ")"; + } + } else { + xpath = "@" + pseudoClass + "='" + pseudoValue + "'"; + } + return xpath; + } + + private String attrToXPath(String notSelector, String pattern) { + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(notSelector); + m.reset(); + boolean result = m.find(); + if (result) { + StringBuffer sb = new StringBuffer(); + do { + String replacement; + String p1 = m.group(1); + String p2 = m.group(2); + String p3 = m.group(3); + if ("^".equals(p2)) { + replacement = "starts-with(@" + p1 + ", '" + p3 + "')"; + } else if ("$".equals(p2)) { + replacement = "substring(@" + p1 + ", (string-length(@" + p1 + ") - " + + (p3.length() - 1) + "), " + p3.length() + ") = '" + p3 + "'"; + } else if ("*".equals(p2)) { + replacement = "contains(concat(' ', @" + p1 + ", ' '), '" + p3 + "')"; + } else if ("|".equals(p2)) { + replacement = "(@" + p1 + "='" + p3 + "' or starts-with(@" + p1 + + ", '" + p3 + "-'))"; + } else if ("~".equals(p2)) { + replacement = "contains(concat(' ', @" + p1 + ", ' '), ' " + p3 + + " ')"; + } else { + replacement = "@" + p1 + (notNull(p3) ? "='" + p3 + "'" : ""); + } + debug("p1=" + p1 + " p2=" + p2 + " p3=" + p3 + " replacement is " + + replacement); + m.appendReplacement(sb, replacement.replace("$", "\\$")); + result = m.find(); + } while (result); + m.appendTail(sb); + return sb.toString(); + } + return notSelector; + } + + private Sequence getSequence(String expression) { + int start = 0, add = 2, max = -1, modVal = -1; + Pattern expressionRegExp = Pattern.compile( + "^((odd|even)|([1-9]\\d*)|((([1-9]\\d*)?)n([\\+\\-]\\d+)?)|(\\-(([1-9]\\d*)?)n\\+(\\d+)))$"); + Matcher pseudoValue = expressionRegExp.matcher(expression); + if (!pseudoValue.matches()) { + return null; + } else { + if (notNull(pseudoValue.group(2))) { // odd or even + start = ("odd".equals(pseudoValue.group(2))) ? 1 : 2; + modVal = (start == 1) ? 1 : 0; + } else if (notNull(pseudoValue.group(3))) { // single digit + start = Integer.parseInt(pseudoValue.group(3), 10); + add = 0; + max = start; + } else if (notNull(pseudoValue.group(4))) { // an+b + add = notNull(pseudoValue.group(6)) ? getInt(pseudoValue.group(6), 1) + : 1; + start = notNull(pseudoValue.group(7)) ? getInt(pseudoValue.group(7), 0) + : 0; + while (start < 1) { + start += add; + } + modVal = (start > add) ? (start - add) % add + : ((start == add) ? 0 : start); + } else if (notNull(pseudoValue.group(8))) { // -an+b + add = notNull(pseudoValue.group(10)) ? Integer + .parseInt(pseudoValue.group(10), 10) : 1; + start = max = Integer.parseInt(pseudoValue.group(10), 10); + while (start > add) { + start -= add; + } + modVal = (max > add) ? (max - add) % add : ((max == add) ? 0 : max); + } + } + Sequence s = new Sequence(); + s.start = start; + s.add = add; + s.max = max; + s.modVal = modVal; + return s; + } + + private int getInt(String s, int i) { + try { + if (s.startsWith("+")) { + s = s.substring(1); + } + return Integer.parseInt(s); + } catch (Exception e) { + debug("error parsing Integer " + s); + return i; + } + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/GwtQuery.gwt.xml b/gwtquery-core/src/main/java/gwtquery/GwtQuery.gwt.xml deleted file mode 100644 index 8cfabdb0..00000000 --- a/gwtquery-core/src/main/java/gwtquery/GwtQuery.gwt.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/client/$.java b/gwtquery-core/src/main/java/gwtquery/client/$.java deleted file mode 100644 index 273c951c..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/$.java +++ /dev/null @@ -1,81 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; - -/** - * - */ -public class $ { - - public static GQuery $(String selectorOrHtml) { - return GQuery.$(selectorOrHtml); - } - - public static T $(T gq) { - return GQuery.$(gq); - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is is a class - * reference to a plugin to be used. - */ - public static T $(String selector, Class plugin) { - return GQuery.$(selector, plugin); - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is the context to - * use for the selector. - */ - public static GQuery $(String selector, Node context) { - return GQuery.$(selector, context); - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is the context to - * use for the selector. The third parameter is the class plugin to use. - */ - public static GQuery $(String selector, Node context, - Class plugin) { - return GQuery.$(selector, context, plugin); - } - - /** - * Wrap a GQuery around existing Elements. - */ - public static GQuery $(NodeList elements) { - return GQuery.$(elements); - } - - /** - * Wrap a GQuery around an existing Element. - */ - public static GQuery $(Element element) { - return GQuery.$(element); - } - - /** - * Wrap a JSON object - */ - public static Properties $$(String properties) { - return GQuery.$$(properties); - } - - /** - * Registers a GQuery plugin - * @param plugin - * @param pluginFactory - */ - public static void registerPlugin(Class plugin, - Plugin pluginFactory) { - GQuery.registerPlugin(plugin, pluginFactory); - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/DeferredGQuery.java b/gwtquery-core/src/main/java/gwtquery/client/DeferredGQuery.java deleted file mode 100644 index fe1165ae..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/DeferredGQuery.java +++ /dev/null @@ -1,14 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NodeList; - -/** - * A compiled selector that can be lazily turned into a GQuery - */ -public interface DeferredGQuery { - String getSelector(); - GQuery eval(Node ctx); - NodeList array(Node ctx); -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Effects.java b/gwtquery-core/src/main/java/gwtquery/client/Effects.java deleted file mode 100644 index 21fabb86..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Effects.java +++ /dev/null @@ -1,152 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.animation.client.Animation; - -public class Effects extends GQuery { - - static { - GQuery.registerPlugin(Effects.class, new EffectsPlugin()); - } - - public static final Class Effects = Effects.class; - - public Effects(Element element) { - super(element); - } - - public Effects(JSArray elements) { - super(elements); - } - - public Effects(NodeList list) { - super(list); - } - - /** - * function( prop, speed, easing, callback ) { - var optall = jQuery.speed(speed, easing, callback); - - return this[ optall.queue === false ? "each" : "queue" ](function(){ - - var opt = jQuery.extend({}, optall), p, - hidden = this.nodeType == 1 && jQuery(this).is(":hidden"), - self = this; - - for ( p in prop ) { - if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) - return opt.complete.call(this); - - if ( ( p == "height" || p == "width" ) && this.style ) { - // Store display property - opt.display = jQuery.css(this, "display"); - - // Make sure that nothing sneaks out - opt.overflow = this.style.overflow; - } - } - - if ( opt.overflow != null ) - this.style.overflow = "hidden"; - - opt.curAnim = jQuery.extend({}, prop); - - jQuery.each( prop, function(name, val){ - var e = new jQuery.fx( self, opt, name ); - - if ( /toggle|show|hide/.test(val) ) - e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); - else { - var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/), - start = e.cur(true) || 0; - - if ( parts ) { - var end = parseFloat(parts[2]), - unit = parts[3] || "px"; - - // We need to compute starting value - if ( unit != "px" ) { - self.style[ name ] = (end || 1) + unit; - start = ((end || 1) / e.cur(true)) * start; - self.style[ name ] = start + unit; - } - - // If a +=/-= token was provided, we're doing a relative animation - if ( parts[1] ) - end = ((parts[1] == "-=" ? -1 : 1) * end) + start; - - e.custom( start, end, unit ); - } else - e.custom( start, val, "" ); - } - }); - - // For JS strict compliance - return true; - }); - }, - * @return - */ - public Effects animate(Properties props, String speed, String easing, - Function callback) { - return this; - } - - public Effects fadeOut() { - Animation a = new Animation() { - - public void onCancel() { - } - - public void onComplete() { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle().setProperty("opacity", "0"); - elements.getItem(i).getStyle().setProperty("display", "none"); - } - } - - public void onStart() { - } - - public void onUpdate(double progress) { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle() - .setProperty("opacity", String.valueOf(1.0 - progress)); - } - } - }; - a.run(1000); - return this; - } - - public Effects fadeIn() { - Animation a = new Animation() { - - public void onCancel() { - } - - public void onComplete() { - } - - public void onStart() { - } - - public void onUpdate(double progress) { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle() - .setProperty("opacity", String.valueOf(progress)); - } - } - }; - a.run(1000); - return this; - } - - public static class EffectsPlugin implements Plugin { - - public Effects init(GQuery gq) { - return new Effects(gq.get()); - } - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Function.java b/gwtquery-core/src/main/java/gwtquery/client/Function.java deleted file mode 100644 index f9d70a4f..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Function.java +++ /dev/null @@ -1,26 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.dom.client.Element; -import com.google.gwt.user.client.Event; - -/** - * Extend this class to implement functions. - */ -public abstract class Function { - - public String f(Element e, int i) { - return ""; - } - - public void f(Element e) { - } - - public boolean f(Event e, Object data) { - return f(e); - } - - public boolean f(Event e) { - f(e.getCurrentTarget()); - return true; - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/GQuery.java b/gwtquery-core/src/main/java/gwtquery/client/GQuery.java deleted file mode 100644 index 3354bba8..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/GQuery.java +++ /dev/null @@ -1,1950 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.dom.client.BodyElement; -import com.google.gwt.dom.client.ButtonElement; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.IFrameElement; -import com.google.gwt.dom.client.InputElement; -import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.dom.client.OptionElement; -import com.google.gwt.dom.client.SelectElement; -import com.google.gwt.dom.client.Style; -import com.google.gwt.dom.client.TextAreaElement; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.EventListener; -import com.google.gwt.user.client.Window; - -import java.util.HashMap; -import java.util.Map; - -import gwtquery.client.impl.DocumentStyleImpl; - -/** - * - */ -public class GQuery { - - public static class Offset { - - public int top; - - public int left; - - Offset(int left, int top) { - this.left = left; - this.top = top; - } - } - - private static class DataCache extends JavaScriptObject { - - protected DataCache() { - } - - public native void delete(String name) /*-{ - delete this[name]; - }-*/; - - public native void delete(int name) /*-{ - delete this[name]; - }-*/; - - public native boolean exists(int id) /*-{ - return !!this[id]; - }-*/; - - public native JavaScriptObject get(String id) /*-{ - return this[id]; - }-*/; - - public native JavaScriptObject get(int id) /*-{ - return this[id]; - }-*/; /*-{ - delete this[name]; - }-*/ - - public DataCache getCache(int id) { - return get(id).cast(); - } - - public native double getDouble(String id) /*-{ - return this[id]; - }-*/; - - public native double getDouble(int id) /*-{ - return this[id]; - }-*/; - - public native int getInt(String id) /*-{ - return this[id]; - }-*/; - - public native int getInt(int id) /*-{ - return this[id]; - }-*/; - - public native String getString(String id) /*-{ - return this[id]; - }-*/; - - public native String getString(int id) /*-{ - return this[id]; - }-*/; - - public native boolean isEmpty() /*-{ - var foo = ""; - for(foo in this) break; - return !foo; - }-*/; - - public native void put(String id, Object obj) /*-{ - return this[id]=obj; - }-*/; - - public native void put(int id, Object obj) /*-{ - return this[id]=obj; - }-*/; - } - - private static class FastSet extends JavaScriptObject { - - public static FastSet create() { - return JavaScriptObject.createObject().cast(); - } - - protected FastSet() { - } - - public void add(Object o) { - add0(o.hashCode()); - } - - public boolean contains(Object o) { - return contains0(o.hashCode()); - } - - public void remove(Object o) { - remove0(o.hashCode()); - } - - private native void add0(int hc) /*-{ - this[hc]=true; - }-*/; - - private native boolean contains0(int hc) /*-{ - return this[hc]; - }-*/; - - private native void remove0(int hc) /*-{ - delete this[hc]; - }-*/; - } - - private static class Queue extends JavaScriptObject { - - public static Queue newInstance() { - return createArray().cast(); - } - - protected Queue() { - } - - public native T dequeue() /*-{ - return this.shift(); - }-*/; - - public native void enqueue(T foo) /*-{ - this.push(foo); - }-*/; - - public native int length() /*-{ - return this.length; - }-*/; - - public native T peek(int i) /*-{ - return this[i]; - }-*/; - } - - public static boolean fxOff = false; - - private static Map, Plugin> plugins; - - private static Element windowData = null; - - private static DataCache dataCache = null; - - private static DocumentStyleImpl styleImpl; - - private static final int FUNC_PREPEND = 0, FUNC_APPEND = 1, FUNC_AFTER = 2, - FUNC_BEFORE = 3; - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. - */ - public static GQuery $(String selectorOrHtml) { - if (selectorOrHtml.trim().charAt(0) == '<') { - return innerHtml(selectorOrHtml); - } - return $(selectorOrHtml, Document.get()); - } - - public static T $(T gq) { - - return gq; - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is is a class - * reference to a plugin to be used. - */ - public static T $(String selector, Class plugin) { - try { - if (plugins != null) { - T gquery = (T) plugins.get(plugin).init($(selector, Document.get())); - return gquery; - } - throw new RuntimeException("No plugin for class " + plugin); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is the context to - * use for the selector. - */ - public static GQuery $(String selector, Node context) { - return new GQuery(select(selector, context)); - } - - /** - * This function accepts a string containing a CSS selector which is then used - * to match a set of elements, or it accepts raw HTML creating a GQuery - * element containing those elements. The second parameter is the context to - * use for the selector. The third parameter is the class plugin to use. - */ - public static GQuery $(String selector, Node context, - Class plugin) { - try { - if (plugins != null) { - T gquery = (T) plugins.get(plugin) - .init(new GQuery(select(selector, context))); - return gquery; - } - throw new RuntimeException("No plugin for class " + plugin); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Wrap a GQuery around existing Elements. - */ - public static GQuery $(NodeList elements) { - return new GQuery(elements); - } - - public static GQuery $(Element element) { - JSArray a = JSArray.create(); - a.addNode(element); - return new GQuery(a); - } - - /** - * Wrap a JSON object - */ - public static Properties $$(String properties) { - return Properties.create(properties); - } - - public static T[] asArray(NodeList nl) { - if (GWT.isScript()) { - return reinterpretCast(nl); - } else { - Node[] elts = new Node[nl.getLength()]; - for (int i = 0; i < elts.length; i++) { - elts[i] = nl.getItem(i); - } - return (T[]) elts; - } - } - - public static void registerPlugin(Class plugin, - Plugin pluginFactory) { - if (plugins == null) { - plugins = new HashMap(); - } - plugins.put(plugin, pluginFactory); - } - - /** - * Copied from UIObject * - */ - protected static void setStyleName(Element elem, String style, boolean add) { - - style = style.trim(); - - // Get the current style string. - String oldStyle = elem.getClassName(); - int idx = oldStyle.indexOf(style); - - // Calculate matching index. - while (idx != -1) { - if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') { - int last = idx + style.length(); - int lastPos = oldStyle.length(); - if ((last == lastPos) || ((last < lastPos) && (oldStyle.charAt(last) - == ' '))) { - break; - } - } - idx = oldStyle.indexOf(style, idx + 1); - } - - if (add) { - // Only add the style if it's not already present. - if (idx == -1) { - if (oldStyle.length() > 0) { - oldStyle += " "; - } - DOM.setElementProperty(elem.cast(), - "className", oldStyle + style); - } - } else { - // Don't try to remove the style if it's not there. - if (idx != -1) { - // Get the leading and trailing parts, without the removed name. - String begin = oldStyle.substring(0, idx).trim(); - String end = oldStyle.substring(idx + style.length()).trim(); - - // Some contortions to make sure we don't leave extra spaces. - String newClassName; - if (begin.length() == 0) { - newClassName = end; - } else if (end.length() == 0) { - newClassName = begin; - } else { - newClassName = begin + " " + end; - } - - DOM.setElementProperty(elem.cast(), - "className", newClassName); - } - } - } - - private static String curCSS(Element elem, String name) { - Style s = elem.getStyle(); - ensureStyleImpl(); - name = styleImpl.getPropertyName(name); - - if (SelectorEngine.truth(s.getProperty(name))) { - return s.getProperty(name); - } - return styleImpl.getCurrentStyle(elem, name); - } - - private static void ensureStyleImpl() { - if (styleImpl != null) { - styleImpl = GWT.create(DocumentStyleImpl.class); - } - } - - private static boolean hasClass(Element e, String clz) { - return e.getClassName().matches("\\s" + clz + "\\s"); - } - - private static GQuery innerHtml(String html) { - Element div = DOM.createDiv(); - div.setInnerHTML(html); - return new GQuery((NodeList) (NodeList) div.getChildNodes()); - } - - private static native T[] reinterpretCast(NodeList nl) /*-{ - return nl; - }-*/; - - private static NodeList select(String selector, Node context) { - return new SelectorEngine().select(selector, context); - } - - protected NodeList elements = null; - - private String selector; - - private GQuery previousObject; - - public GQuery() { - elements = JavaScriptObject.createArray().cast(); - } - - public GQuery(NodeList list) { - elements = list; - } - - public GQuery(JSArray elements) { - this.elements = elements; - } - - public GQuery(Element element) { - elements = JSArray.create(element); - } - - public GQuery add(String selector) { - return add($(selector)); - } - - /** - * Adds the specified classes to each matched element. - */ - public GQuery addClass(String... classes) { - for (Element e : elements()) { - for (String clz : classes) { - setStyleName(e, clz, true); - } - } - return this; - } - - /** - * Insert content after each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element after - * another if it's not in the page). - */ - public GQuery after(Node n) { - return domManip(JSArray.create(n), FUNC_AFTER); - } - - /** - * Insert content after each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element after - * another if it's not in the page). - */ - public GQuery after(String html) { - return domManip(html, FUNC_AFTER); - } - - /** - * Insert content after each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element after - * another if it's not in the page). - */ - public GQuery after(GQuery query) { - return domManip(query.elements, FUNC_AFTER); - } - - /** - * Add the previous selection to the current selection. Useful for traversing - * elements, and then adding something that was matched before the last - * traversal. - */ - public GQuery andSelf() { - return add(previousObject); - } - - /** - * Append content to the inside of every matched element. This operation is - * similar to doing an appendChild to all the specified elements, adding them - * into the document. - */ - public GQuery append(String html) { - return domManip(html, FUNC_APPEND); - } - - /** - * Append content to the inside of every matched element. This operation is - * similar to doing an appendChild to all the specified elements, adding them - * into the document. - */ - public GQuery append(Node n) { - return domManip(JSArray.create(n), FUNC_APPEND); - } - - /** - * Append content to the inside of every matched element. This operation is - * similar to doing an appendChild to all the specified elements, adding them - * into the document. - */ - public GQuery append(GQuery query) { - return domManip(query.elements, FUNC_APPEND); - } - - /** - * Convert to Plugin interface provided by Class literal. - */ - public T as(Class plugin) { - if (plugins != null) { - return (T) plugins.get(plugin).init(this); - } - throw new RuntimeException("No plugin registered for class " + plugin); - } - - /** - * Access a property on the first matched element. This method makes it easy - * to retrieve a property value from the first matched element. If the element - * does not have an attribute with such a name, undefined is returned. - * Attributes include title, alt, src, href, width, style, etc. - */ - public String attr(String name) { - return elements.getItem(0).getAttribute(name); - } - - /** - * Set a single property to a value, on all matched elements. - */ - public GQuery attr(String key, String value) { - for (Element e : elements()) { - e.setAttribute(key, value); - } - return this; - } - - /** - * Set a key/value object as properties to all matched elements. - */ - public GQuery attr(Properties properties) { - for (Element e : elements()) { - for (String name : properties.keys()) { - e.setAttribute(name, properties.get(name)); - } - } - return this; - } - - /** - * Set a single property to a computed value, on all matched elements. - */ - public GQuery attr(String key, Function closure) { - for (int i = 0; i < elements.getLength(); i++) { - Element e = elements.getItem(i); - e.setAttribute(key, closure.f(e, i)); - } - return this; - } - - /** - * Insert content before each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element before - * another if it's not in the page). - */ - public GQuery before(Node n) { - return domManip(JSArray.create(n), FUNC_AFTER); - } - - /** - * Insert content before each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element before - * another if it's not in the page). - */ - public GQuery before(GQuery query) { - return domManip(query.elements, FUNC_AFTER); - } - - /** - * Insert content before each of the matched elements. The elements must - * already be inserted into the document (you can't insert an element before - * another if it's not in the page). - */ - public GQuery before(String html) { - return domManip(html, FUNC_AFTER); - } - - /** - * Binds a handler to one or more events (like click) for each matched - * element. - */ - public GQuery bind(int eventbits, final Object data, final Function f) { - EventListener listener = new EventListener() { - public void onBrowserEvent(Event event) { - if (!f.f(event, data)) { - event.cancelBubble(true); - event.preventDefault(); - } - } - }; - for (Element e : elements()) { - DOM.sinkEvents((com.google.gwt.user.client.Element) e, eventbits); - DOM.setEventListener((com.google.gwt.user.client.Element) e, listener); - } - return this; - } - - public GQuery blur(Function f) { - return bind(Event.ONBLUR, null, f); - } - - public GQuery blur() { - return trigger(Document.get().createBlurEvent(), null); - } - - public GQuery change(Function f) { - return bind(Event.ONCHANGE, null, f); - } - - public GQuery change() { - return trigger(Document.get().createChangeEvent(), null); - } - - /** - * Get a set of elements containing all of the unique immediate children of - * each of the matched set of elements. Also note: while parents() will look - * at all ancestors, children() will only consider immediate child elements. - */ - public GQuery children() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - allNextSiblingElements(e.getFirstChildElement(), result); - } - return new GQuery(unique(result)); - } - - public GQuery click() { - return trigger( - Document.get().createClickEvent(0, 0, 0, 0, 0, false, false, false, - false), null); - } - - /** - * Triggers the click event of each matched element. Causes all of the - * functions that have been bound to that click event to be executed. - */ - public GQuery click(final Function f) { - return bind(Event.ONCLICK, null, f); - } - - /** - * Clone matched DOM Elements and select the clones. This is useful for moving - * copies of the elements to another location in the DOM. - */ - public GQuery clone() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - result.addNode(e.cloneNode(true)); - } - return new GQuery(result); - } - - /** - * Find all the child nodes inside the matched elements (including text - * nodes), or the content document, if the element is an iframe. - */ - public GQuery contents() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - NodeList children = e.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - Node n = children.getItem(i); - if (IFrameElement.is(n)) { - result.addNode(getContentDocument(n)); - } else { - result.addNode(n); - } - } - } - return new GQuery(unique(result)); - } - - /** - * Return a style property on the first matched element. - */ - public String css(String name) { - return curCSS(get(0), name); - } - - /** - * Set a key/value object as style properties to all matched elements. This is - * the best way to set several style properties on all matched elements. Be - * aware, however, that when the key contains a hyphen, such as - * "background-color," it must either be placed within quotation marks or be - * written in camel case like so: backgroundColor. As "float" and "class" are - * reserved words in JavaScript, it's recommended to always surround those - * terms with quotes. gQuery normalizes the "opacity" property in Internet - * Explorer. - */ - public GQuery css(Properties properties) { - for (String property : properties.keys()) { - css(property, properties.get(property)); - } - return this; - } - - /** - * Set a single style property to a value on all matched elements. If a number - * is provided, it is automatically converted into a pixel value. - */ - public GQuery css(String prop, String val) { - for (Element e : elements()) { - e.getStyle().setProperty(prop, val); - } - return this; - } - - /** - * Returns value at named data store for the element, as set by data(name, - * value). - */ - public Object data(String name) { - return data(elements.getItem(0), name, null); - } - - /** - * Returns value at named data store for the element, as set by data(name, - * value) with desired return type. - * - * @param clz return type class literal - */ - public T data(String name, Class clz) { - return (T) data(elements.getItem(0), name, null); - } - - /** - * Stores the value in the named spot with desired return type. - */ - public void data(String name, String value) { - for (Element e : elements()) { - data(e, name, value); - } - } - - public GQuery dblclick() { - return trigger( - Document.get().createDblClickEvent(0, 0, 0, 0, 0, false, false, false, - false), null); - } - - public GQuery dblclick(Function f) { - return bind(Event.ONDBLCLICK, null, f); - } - - /** - * Removes a queued function from the front of the queue and executes it. - */ - public GQuery dequeue(String type) { - for (Element e : elements()) { - dequeue(e, type); - } - return this; - } - - /** - * Removes a queued function from the front of the FX queue and executes it. - */ - public GQuery dequeue() { - return dequeue("__FX"); - } - - /** - * Run one or more Functions over each element of the GQuery. - */ - public GQuery each(Function... f) { - for (Function f1 : f) { - for (Element e : elements()) { - f1.f(e); - } - } - return this; - } - - /** - * Returns the working set of nodes as a Java array. Do NOT get() { - return elements; - } - - /** - * Return the ith element matched. - */ - public Element get(int i) { - return elements.getItem(i); - } - - public GQuery getPreviousObject() { - return previousObject; - } - - public String getSelector() { - return selector; - } - - /** - * Returns true any of the specified classes are present on any of the matched - * elements. - */ - public boolean hasClass(String... classes) { - for (Element e : elements()) { - for (String clz : classes) { - if (hasClass(e, clz)) { - return true; - } - } - } - return false; - } - - /** - * Set the height of every element in the matched set. - */ - public GQuery height(int height) { - for (Element e : elements()) { - e.getStyle().setPropertyPx("height", height); - } - return this; - } - - /** - * Get the innerHTML of the first matched element. - */ - public String html() { - return get(0).getInnerHTML(); - } - - /** - * Set the innerHTML of every matched element. - */ - public GQuery html(String html) { - for (Element e : elements()) { - e.setInnerHTML(html); - } - return this; - } - - /** - * Find the index of the specified Element - */ - public int index(Element element) { - for (int i = 0; i < elements.getLength(); i++) { - if (elements.getItem(i) == element) { - return i; - } - } - return -1; - } - - /** - * Insert all of the matched elements after another, specified, set of - * elements. - */ - public GQuery insertAfter(String selector) { - return insertAfter($(selector)); - } - - /** - * Insert all of the matched elements after another, specified, set of - * elements. - */ - public GQuery insertAfter(Element elem) { - return insertAfter($(elem)); - } - - /** - * Insert all of the matched elements after another, specified, set of - * elements. - */ - public GQuery insertAfter(GQuery query) { - for (Element e : elements()) { - query.after(e); - } - return this; - } - - /** - * Insert all of the matched elements before another, specified, set of - * elements. - * - * The elements must already be inserted into the document (you can't insert - * an element after another if it's not in the page). - */ - public GQuery insertBefore(Element item) { - return insertBefore($(item)); - } - - /** - * Insert all of the matched elements before another, specified, set of - * elements. - * - * The elements must already be inserted into the document (you can't insert - * an element after another if it's not in the page). - */ - public GQuery insertBefore(GQuery query) { - for (Element e : elements()) { - query.before(e); - } - return this; - } - - /** - * Insert all of the matched elements before another, specified, set of - * elements. - * - * The elements must already be inserted into the document (you can't insert - * an element after another if it's not in the page). - */ - public GQuery insertBefore(String selector) { - return insertBefore($(selector)); - } - - public GQuery keydown() { - return trigger( - Document.get().createKeyDownEvent(false, false, false, false, 0, 0), - null); - } - - public GQuery keydown(Function f) { - return bind(Event.ONKEYDOWN, null, f); - } - - public GQuery keypress() { - return trigger( - Document.get().createKeyPressEvent(false, false, false, false, 0, 0), - null); - } - - public GQuery keypressed(Function f) { - return bind(Event.ONKEYPRESS, null, f); - } - - public GQuery keyup() { - return trigger( - Document.get().createKeyUpEvent(false, false, false, false, 0, 0), - null); - } - - public GQuery keyup(Function f) { - return bind(Event.ONKEYUP, null, f); - } - - public GQuery load(Function f) { - return bind(Event.ONLOAD, null, f); - } - - public GQuery mousedown(Function f) { - return bind(Event.ONMOUSEDOWN, null, f); - } - - public GQuery mousemove(Function f) { - return bind(Event.ONMOUSEMOVE, null, f); - } - - public GQuery mouseout(Function f) { - return bind(Event.ONMOUSEOUT, null, f); - } - - public GQuery mouseover(Function f) { - return bind(Event.ONMOUSEOVER, null, f); - } - - public GQuery mouseup(Function f) { - return bind(Event.ONMOUSEUP, null, f); - } - - /** - * Get a set of elements containing the unique next siblings of each of the - * given set of elements. next only returns the very next sibling for each - * element, not all next siblings see {#nextAll}. - */ - public GQuery next() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - Element next = e.getNextSiblingElement(); - if (next != null) { - result.addNode(next); - } - } - return new GQuery(unique(result)); - } - - /** - * Find all sibling elements after the current element. - */ - public GQuery nextAll() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - allNextSiblingElements(e.getNextSiblingElement(), result); - } - return new GQuery(unique(result)); - } - - public Offset offset() { - return new Offset(get(0).getOffsetLeft(), get(0).getOffsetTop()); - } - - /** - * Returns a GQuery collection with the positioned parent of the first matched - * element. This is the first parent of the element that has position (as in - * relative or absolute). This method only works with visible elements. - */ - public GQuery offsetParent() { - Element offParent = SelectorEngine - .or(elements.getItem(0).getOffsetParent(), Document.get().getBody()); - while (offParent != null && !"body".equalsIgnoreCase(offParent.getTagName()) - && !"html".equalsIgnoreCase(offParent.getTagName()) && "static" - .equals(curCSS(offParent, "position"))) { - offParent = offParent.getOffsetParent(); - } - return new GQuery(offParent); - } - - /** - * Get a set of elements containing the unique parents of the matched set of - * elements. - */ - public GQuery parent() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - result.addNode(e.getParentElement()); - } - return new GQuery(unique(result)); - } - - /** - * Get a set of elements containing the unique ancestors of the matched set of - * elements (except for the root element). - */ - public GQuery parents() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - Node par = e.getParentNode(); - while (par != null && par != Document.get()) { - result.addNode(par); - par = par.getParentNode(); - } - } - return new GQuery(unique(result)); - } - - /** - * Gets the top and left position of an element relative to its offset parent. - * The returned object contains two Integer properties, top and left. For - * accurate calculations make sure to use pixel values for margins, borders - * and padding. This method only works with visible elements. - */ - public Offset position() { - - if (size() > 0) { - GQuery offsetParent = offsetParent(); - Offset offset = offset(); - Element e = offsetParent.get(0); - - Offset parentOffset = BodyElement.is(e) || "html".equals(e.getTagName()) - ? new Offset(0, 0) : offsetParent.offset(); - offset.top -= num(this, "marginTop"); - offset.left -= num(this, "marginLeft"); - parentOffset.top += num(offsetParent, "borderTopWidth"); - parentOffset.left += num(offsetParent, "borderLeftWidth"); - return new Offset(offset.top - parentOffset.top, - offset.left - parentOffset.left); - } - return null; - } - - /** - * Prepend content to the inside of every matched element. This operation is - * the best way to insert elements inside, at the beginning, of all matched - * elements. - */ - public GQuery prepend(String html) { - return domManip(html, FUNC_PREPEND); - } - - /** - * Prepend content to the inside of every matched element. This operation is - * the best way to insert elements inside, at the beginning, of all matched - * elements. - */ - public GQuery prepend(GQuery query) { - return domManip(query.elements, FUNC_PREPEND); - } - - /** - * Prepend content to the inside of every matched element. This operation is - * the best way to insert elements inside, at the beginning, of all matched - * elements. - */ - public GQuery prepend(Node n) { - return domManip(JSArray.create(n), FUNC_PREPEND); - } - - /** - * Get a set of elements containing the unique previous siblings of each of - * the matched set of elements. Only the immediately previous sibling is - * returned, not all previous siblings. - */ - public GQuery prev() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - Element next = getPreviousSiblingElement(e); - if (next != null) { - result.addNode(next); - } - } - return new GQuery(unique(result)); - } - - /** - * Find all sibling elements in front of the current element. - */ - public GQuery prevAll() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - allPreviousSiblingElements(getPreviousSiblingElement(e), result); - } - return new GQuery(unique(result)); - } - - /** - * Returns a reference to the first element's queue (which is an array of - * functions). - */ - public Queue queue(String type) { - return queue(elements.getItem(0), type, null); - } - - /** - * Returns a reference to the FX queue. - */ - public Queue queue() { - return queue(elements.getItem(0), "__FX", null); - } - - /** - * Adds a new function, to be executed, onto the end of the queue of all - * matched elements. - */ - public GQuery queue(String type, Function data) { - for (Element e : elements()) { - queue(e, type, data); - } - return this; - } - - /** - * Replaces the current queue with the given queue on all matched elements. - */ - public GQuery queue(String type, Queue data) { - for (Element e : elements()) { - replacequeue(e, type, data); - } - return this; - } - - /** - * Adds a new function, to be executed, onto the end of the queue of all - * matched elements in the FX queue. - */ - public GQuery queue(Function data) { - return queue("__FX", data); - } - - /** - * Removes all matched elements from the DOM. - */ - public GQuery remove() { - for (Element e : elements()) { - //TODO: cleanup event bindings - removeData(e, null); - if (e.getParentNode() != null) { - e.getParentNode().removeChild(e); - } - } - return this; - } - - /** - * Remove the named attribute from every element in the matched set. - */ - public GQuery removeAttr(String key) { - for (Element e : elements()) { - e.removeAttribute(key); - } - return this; - } - - /** - * Removes the specified classes to each matched element. - */ - public GQuery removeClass(String... classes) { - for (Element e : elements()) { - for (String clz : classes) { - setStyleName(e, clz, false); - } - } - return this; - } - - /** - * Removes named data store from an element. - */ - public GQuery removeData(String name) { - for (Element e : elements()) { - removeData(e, name); - } - return this; - } - - /** - * Replaces the elements matched by the specified selector with the matched - * elements. This function is the complement to replaceWith() which does the - * same task with the parameters reversed. - */ - public GQuery replaceAll(GQuery query) { - for (Element e : elements()) { - $(e).replaceWith(query); - } - return this; - } - - /** - * Replaces the elements matched by the specified selector with the matched - * elements. This function is the complement to replaceWith() which does the - * same task with the parameters reversed. - */ - public GQuery replaceAll(String html) { - return replaceAll($(html)); - } - - /** - * Replaces the elements matched by the specified selector with the matched - * elements. This function is the complement to replaceWith() which does the - * same task with the parameters reversed. - */ - public GQuery replaceAll(Element elem) { - return replaceAll($(elem)); - } - - /** - * Replaces all matched elements with the specified HTML or DOM elements. This - * returns the GQuery element that was just replaced, which has been removed - * from the DOM. - */ - public GQuery replaceWith(GQuery query) { - return after(query).remove(); - } - - /** - * Replaces all matched elements with the specified HTML or DOM elements. This - * returns the GQuery element that was just replaced, which has been removed - * from the DOM. - */ - public GQuery replaceWith(String html) { - return replaceWith($(html)); - } - - /** - * Replaces all matched elements with the specified HTML or DOM elements. This - * returns the GQuery element that was just replaced, which has been removed - * from the DOM. - */ - public GQuery replaceWith(Element elem) { - return replaceWith($(elem)); - } - - public GQuery scroll(Function f) { - return bind(Event.ONSCROLL, null, f); - } - - /** - * When a value is passed in, the scroll left offset is set to that value on - * all matched elements. This method works for both visible and hidden - * elements. - */ - public GQuery scrollLeft(int left) { - for (Element e : elements()) { - if (e == window() || e == (Node) Document.get()) { - Window.scrollTo(left, $(e).scrollTop()); - } else { - e.setPropertyInt("scrollLeft", left); - } - } - return this; - } - - /** - * Gets the scroll left offset of the first matched element. This method works - * for both visible and hidden elements. - */ - public int scrollLeft() { - Element e = get(0); - if (e == window()) { - return Window.getScrollLeft(); - } else if (e == (Node) Document.get()) { - return Document.get().getScrollLeft(); - } else { - return e.getScrollLeft(); - } - } - - /** - * When a value is passed in, the scroll top offset is set to that value on - * all matched elements. This method works for both visible and hidden - * elements. - */ - public GQuery scrollTop(int top) { - for (Element e : elements()) { - if (e == window() || e == (Node) Document.get()) { - Window.scrollTo($(e).scrollLeft(), top); - } else { - e.setPropertyInt("scrollTop", top); - } - } - return this; - } - - /** - * Gets the scroll top offset of the first matched element. This method works - * for both visible and hidden elements. - */ - public int scrollTop() { - Element e = get(0); - if (e == window()) { - return Window.getScrollTop(); - } else if (e == (Node) Document.get()) { - return Document.get().getScrollTop(); - } else { - return e.getScrollTop(); - } - } - - public GQuery select() { - return trigger(Document.get().createHtmlEvent("select", false, false), - null); - } - - public void setPreviousObject(GQuery previousObject) { - this.previousObject = previousObject; - } - - public void setSelector(String selector) { - this.selector = selector; - } - - /** - * Get a set of elements containing all of the unique siblings of each of the - * matched set of elements. - */ - public GQuery siblings() { - JSArray result = JSArray.create(); - for (Element e : elements()) { - allNextSiblingElements(e.getParentElement().getFirstChildElement(), - result); - } - return new GQuery(unique(result)); - } - - /** - * Return the number of elements in the matched set. - */ - public int size() { - return elements.getLength(); - } - - /** - * Selects a subset of the matched elements. - */ - public GQuery slice(int start, int end) { - JSArray slice = JSArray.create(); - if (end == -1 || end > elements.getLength()) { - end = elements.getLength(); - } - for (int i = start; i < elements.getLength(); i++) { - slice.addNode(elements.getItem(i)); - } - return new GQuery(slice); - } - - public GQuery submit() { - return trigger(Document.get().createHtmlEvent("submit", false, false), - null); - } - - /** - * Return the text contained in the first matched element. - */ - public String text() { - return elements.getItem(0).getInnerText(); - } - - /** - * Set the innerText of every matched element. - */ - public GQuery text(String txt) { - for (Element e : asArray(elements)) { - e.setInnerText(txt); - } - return this; - } - - /** - * Adds or removes the specified classes to each matched element. - */ - public GQuery toggleClass(String... classes) { - for (Element e : elements()) { - for (String clz : classes) { - if (hasClass(e, clz)) { - setStyleName(e, clz, false); - } else { - setStyleName(e, clz, true); - } - } - } - return this; - } - - /** - * Adds or removes the specified classes to each matched element. - */ - public GQuery toggleClass(String clz, boolean sw) { - for (Element e : elements()) { - setStyleName(e, clz, sw); - } - return this; - } - - /** - * Remove all duplicate elements from an array of elements. Note that this - * only works on arrays of DOM elements, not strings or numbers. - */ - public JSArray unique(JSArray result) { - FastSet f = FastSet.create(); - JSArray ret = JSArray.create(); - for (int i = 0; i < result.getLength(); i++) { - Element e = result.getElement(i); - if (!f.contains(e)) { - f.add(e); - ret.addNode(e); - } - } - return ret; - } - - /** - * Get the content of the value attribute of the first matched element, - * returns more than one value if it is a multiple select. - */ - public String[] val() { - if (size() > 0) { - Element e = get(0); - if (e.getNodeName().equals("select")) { - SelectElement se = SelectElement.as(e); - if (se.getMultiple() != null) { - NodeList oel = se.getOptions(); - int count = 0; - for (OptionElement oe : asArray(oel)) { - if (oe.isSelected()) { - count++; - } - } - String result[] = new String[count]; - count = 0; - for (OptionElement oe : asArray(oel)) { - if (oe.isSelected()) { - result[count++] = oe.getValue(); - } - } - - return result; - } else { - int index = se.getSelectedIndex(); - if (index != -1) { - return new String[]{se.getOptions().getItem(index).getValue()}; - } - } - } else if (e.getNodeName().equals("input")) { - InputElement ie = InputElement.as(e); - return new String[]{ie.getValue()}; - } - } - return new String[0]; - } - - public GQuery val(String... values) { - for (Element e : elements()) { - String name = e.getNodeName(); - if ("select".equals(name)) { - - } else if ("input".equals(name)) { - InputElement ie = InputElement.as(e); - String type = ie.getType(); - if ("radio".equals((type)) || "checkbox".equals(type)) { - if ("checkbox".equals(type)) { - for (String val : values) { - if (ie.getValue().equals(val)) { - ie.setChecked(true); - } else if (ie.getValue().equals(val)) { - ie.setChecked(true); - } - } - } - } else { - ie.setValue(values[0]); - } - } else if ("textarea".equals(name)) { - TextAreaElement.as(e).setValue(values[0]); - } else if ("button".equals(name)) { - ButtonElement.as(e).setValue(values[0]); - } - } - return this; - } - - /** - * Set the width of every matched element. - */ - public GQuery width(int width) { - for (Element e : elements()) { - e.getStyle().setPropertyPx("width", width); - } - return this; - } - - /** - * Wrap each matched element with the specified HTML content. This wrapping - * process is most useful for injecting additional structure into a document, - * without ruining the original semantic qualities of a document. This works - * by going through the first element provided (which is generated, on the - * fly, from the provided HTML) and finds the deepest descendant element - * within its structure -- it is that element that will enwrap everything - * else. - */ - public GQuery wrap(GQuery query) { - for (Element e : elements()) { - $(e).wrapAll(query); - } - return this; - } - - /** - * Wrap each matched element with the specified HTML content. This wrapping - * process is most useful for injecting additional structure into a document, - * without ruining the original semantic qualities of a document. This works - * by going through the first element provided (which is generated, on the - * fly, from the provided HTML) and finds the deepest descendant element - * within its structure -- it is that element that will enwrap everything - * else. - */ - public GQuery wrap(Element elem) { - return wrap($(elem)); - } - - /** - * Wrap each matched element with the specified HTML content. This wrapping - * process is most useful for injecting additional structure into a document, - * without ruining the original semantic qualities of a document. This works - * by going through the first element provided (which is generated, on the - * fly, from the provided HTML) and finds the deepest descendant element - * within its structure -- it is that element that will enwrap everything - * else. - */ - public GQuery wrap(String html) { - return wrap($(html)); - } - - /** - * Wrap all the elements in the matched set into a single wrapper element. - * This is different from .wrap() where each element in the matched set would - * get wrapped with an element. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. - * - * This works by going through the first element provided (which is generated, - * on the fly, from the provided HTML) and finds the deepest descendant - * element within its structure -- it is that element that will enwrap - * everything else. - */ - public GQuery wrapAll(String html) { - return wrapAll($(html)); - } - - /** - * Wrap all the elements in the matched set into a single wrapper element. - * This is different from .wrap() where each element in the matched set would - * get wrapped with an element. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. - * - * This works by going through the first element provided (which is generated, - * on the fly, from the provided HTML) and finds the deepest descendant - * element within its structure -- it is that element that will enwrap - * everything else. - */ - public GQuery wrapAll(Element elem) { - return wrapAll($(elem)); - } - - /** - * Wrap all the elements in the matched set into a single wrapper element. - * This is different from .wrap() where each element in the matched set would - * get wrapped with an element. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. - * - * This works by going through the first element provided (which is generated, - * on the fly, from the provided HTML) and finds the deepest descendant - * element within its structure -- it is that element that will enwrap - * everything else. - */ - public GQuery wrapAll(GQuery query) { - GQuery wrap = query.clone(); - if (elements.getItem(0).getParentNode() != null) { - wrap.insertBefore(elements.getItem(0)); - } - for (Element e : wrap.elements()) { - Node n = e; - while (n.getFirstChild() != null) { - n = n.getFirstChild(); - $((Element) n).append(this); - } - } - return this; - } - - /** - * Wrap the inner child contents of each matched element (including text - * nodes) with an HTML structure. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. This works by going through the - * first element provided (which is generated, on the fly, from the provided - * HTML) and finds the deepest ancestor element within its structure -- it is - * that element that will enwrap everything else. - */ - public GQuery wrapInner(GQuery query) { - for (Element e : elements()) { - $(e).contents().wrapAll(query); - } - return this; - } - - /** - * Wrap the inner child contents of each matched element (including text - * nodes) with an HTML structure. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. This works by going through the - * first element provided (which is generated, on the fly, from the provided - * HTML) and finds the deepest ancestor element within its structure -- it is - * that element that will enwrap everything else. - */ - public GQuery wrapInner(String html) { - return wrapInner($(html)); - } - - /** - * Wrap the inner child contents of each matched element (including text - * nodes) with an HTML structure. This wrapping process is most useful for - * injecting additional structure into a document, without ruining the - * original semantic qualities of a document. This works by going through the - * first element provided (which is generated, on the fly, from the provided - * HTML) and finds the deepest ancestor element within its structure -- it is - * that element that will enwrap everything else. - */ - public GQuery wrapInner(Element elem) { - return wrapInner($(elem)); - } - - protected GQuery pushStack(JSArray elts, String name, String selector) { - GQuery g = new GQuery(elts); - g.setPreviousObject(this); - g.setSelector(selector); - return g; - } - - private GQuery add(GQuery previousObject) { - return pushStack(unique(merge(elements, previousObject.elements)), "add", - getSelector() + "," + previousObject.getSelector()); - } - - private void allNextSiblingElements(Element firstChildElement, - JSArray result) { - while (firstChildElement != null) { - result.addNode(firstChildElement); - firstChildElement = firstChildElement.getNextSiblingElement(); - } - } - - private void allPreviousSiblingElements(Element firstChildElement, - JSArray result) { - while (firstChildElement != null) { - result.addNode(firstChildElement); - firstChildElement = getPreviousSiblingElement(firstChildElement); - } - } - - private JSArray clean(String elem) { - String tags = elem.trim().toLowerCase(); - String preWrap = "", postWrap = ""; - int wrapPos = 0; - if (tags.contains(""; - postWrap = ""; - } else if (!tags.contains(" Object data(Element item, String name, S value) { - if (dataCache == null) { - windowData = JavaScriptObject.createObject().cast(); - dataCache = JavaScriptObject.createObject().cast(); - } - item = item == window() ? windowData : item; - int id = item.hashCode(); - if (name != null && !dataCache.exists(id)) { - dataCache.put(id, DataCache.createObject().cast()); - } - - DataCache d = dataCache.get(id).cast(); - if (name != null && value != null) { - d.put(name, value); - } - return name != null ? value : id; - } - - private void dequeue(Element elem, String type) { - Queue q = queue(elem, type, null); - Function f = q.dequeue(); - - if (q != null) { - if (SelectorEngine.eq(type, "__FX")) { - f = q.peek(0); - } - if (f != null) { - f.f(elem); - } - } - } - - private GQuery domManip(String html, int func) { - return domManip(clean(html), func); - } - - private GQuery domManip(NodeList nodes, int func) { - for (Element e : elements()) { - for (int i = 0; i < nodes.getLength(); i++) { - Node n = nodes.getItem(i).cloneNode(true); - switch (func) { - case FUNC_PREPEND: - e.insertBefore(n, e.getFirstChild()); - break; - case FUNC_APPEND: - e.appendChild(n); - break; - case FUNC_AFTER: - e.getParentNode().insertBefore(n, e.getNextSibling()); - break; - case FUNC_BEFORE: - e.getParentNode().insertBefore(n, e); - break; - } - } - } - return this; - } - - private native Document getContentDocument(Node n) /*-{ - return n.contentDocument || n.contentWindow.document; - }-*/; - - private native Element getPreviousSiblingElement(Element elem) /*-{ - var sib = elem.previousSibling; - while (sib && sib.nodeType != 1) - sib = sib.previousSibling; - return sib; - }-*/; - - private void init(GQuery gQuery) { - this.elements = gQuery.elements; - } - - private JSArray merge(NodeList first, NodeList second) { - JSArray res = JSArray.create(); - for (int i = 0; i < first.getLength(); i++) { - res.addNode(first.getItem(i)); - } - for (int i = 0; i < second.getLength(); i++) { - res.addNode(second.getItem(i)); - } - return res; - } - - private int num(GQuery gQuery, String val) { - Element elem = gQuery.get(0); - try { - if (elem != null) { - String v = GQuery.curCSS(elem, val); - return Integer.parseInt(v); - } - } catch (NumberFormatException e) { - - } - return 0; - } - - private Queue queue(Element elem, String type, Function data) { - if (elem != null) { - type = type + "queue"; - Object q = (Queue) data(elem, type, null); - if (q == null) { - q = data(elem, type, Queue.newInstance()); - } - Queue qq = (Queue) q; - if (data != null) { - qq.enqueue(data); - } - if (SelectorEngine.eq(type, "__FX") && qq.length() == 1) { - data.f(elem); - } - return qq; - } - return null; - } - - private void removeData(Element item, String name) { - if (dataCache == null) { - windowData = JavaScriptObject.createObject().cast(); - dataCache = JavaScriptObject.createObject().cast(); - } - item = item == window() ? windowData : item; - int id = item.hashCode(); - if (name != null) { - if (!dataCache.exists(id)) { - dataCache.getCache(id).delete(name); - } - if (dataCache.getCache(id).isEmpty()) { - removeData(item, null); - } - } else { - dataCache.delete(id); - } - } - - private void replacequeue(Element elem, String type, Queue data) { - if (elem != null) { - type = type + "queue"; - Object q = (Queue) data(elem, type, null); - data(elem, type, data); - } - } - - private GQuery trigger(NativeEvent event, Object o) { - for (Element e : elements()) { - e.dispatchEvent(event); - } - return this; - } - - private native Element window() /*-{ - return $wnd; - }-*/; -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/JSArray.java b/gwtquery-core/src/main/java/gwtquery/client/JSArray.java deleted file mode 100644 index a8049347..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/JSArray.java +++ /dev/null @@ -1,72 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.core.client.JavaScriptObject; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; - -/** - */ -public class JSArray extends NodeList { - - public static JSArray create() { - return (JSArray) JavaScriptObject.createArray(); - } - - public static native JSArray create(Node node) /*-{ - return [node]; - }-*/; - - public static native JSArray create(NodeList nl) /*-{ - var r = [], len=nl.length; - for(var i=0; i { - T init(GQuery gq); -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Predicate.java b/gwtquery-core/src/main/java/gwtquery/client/Predicate.java deleted file mode 100644 index feb7b644..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Predicate.java +++ /dev/null @@ -1,10 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.dom.client.Element; - -/** - * A predicate function used by some GQuery methods. - */ -public interface Predicate { - boolean f(Element e, int index); -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Properties.java b/gwtquery-core/src/main/java/gwtquery/client/Properties.java deleted file mode 100644 index 20030926..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Properties.java +++ /dev/null @@ -1,35 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.core.client.JavaScriptObject; - -/** - * - */ -public class Properties extends JavaScriptObject { - - protected Properties() { } - public native static Properties create(String properties) /*-{ - return eval(properties); - }-*/; - - public final native String get(String name) /*-{ - return this[name]; - }-*/; - - public final native int getInt(String name) /*-{ - return this[name]; - }-*/; - - public final native float getFloat(String name) /*-{ - return this[name]; - }-*/; - - public final native String[] keys() /*-{ - var key, keys=[]; - - for(key in this) { - keys.push(key); - } - return keys; - }-*/; -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Regexp.java b/gwtquery-core/src/main/java/gwtquery/client/Regexp.java deleted file mode 100644 index 5eae1c1d..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Regexp.java +++ /dev/null @@ -1,55 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.core.client.JavaScriptObject; - -/** - */ -public class Regexp { - - private final JavaScriptObject regexp; - - public Regexp(String pattern) { - this.regexp = compile(pattern); - } - - public Regexp(String pat, String flags) { - this.regexp = compileFlags(pat, flags); - } - - public static native JavaScriptObject compile(String pat) /*-{ - return new RegExp(pat); - }-*/; - - public static native JavaScriptObject compileFlags(String pat, String flags) /*-{ - return new RegExp(pat, flags); - }-*/; - - public JSArray exec(String str) { - return exec0(regexp, str); - } - - - private static native JSArray exec0(JavaScriptObject regexp, String str) /*-{ - return regexp.exec(str); - }-*/; - - public JSArray match(String currentRule) { - return match0(regexp, currentRule); - } - - private native JSArray match0(JavaScriptObject regexp, String currentRule)/*-{ - return currentRule.match(regexp); - }-*/; - - public boolean test(String rule) { - return test0(regexp, rule); - } - - private native boolean test0(JavaScriptObject regexp, String rule) /*-{ - return regexp.test(rule); - }-*/; - - public static JSArray match(String regexp, String flags, String string) { - return new Regexp(regexp, flags).match(string); - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Selector.java b/gwtquery-core/src/main/java/gwtquery/client/Selector.java deleted file mode 100644 index 0ec58e5e..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Selector.java +++ /dev/null @@ -1,15 +0,0 @@ -package gwtquery.client; - -import java.lang.annotation.Target; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import static java.lang.annotation.ElementType.METHOD; - -/** - * Used to pass a CSS Selector to a generator at compile time - */ -@Target({METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Selector { - String value(); -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/SelectorEngine.java b/gwtquery-core/src/main/java/gwtquery/client/SelectorEngine.java deleted file mode 100644 index 167a6758..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/SelectorEngine.java +++ /dev/null @@ -1,97 +0,0 @@ -package gwtquery.client; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.core.client.JavaScriptObject; -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 gwtquery.client.impl.SelectorEngineImpl; - -/** - * - */ -public class SelectorEngine { - - private SelectorEngineImpl impl; - - public SelectorEngine() { - impl = (SelectorEngineImpl) GWT.create(SelectorEngineImpl.class); - } - - public static native boolean eq(String s1, String s2) /*-{ - return s1 == s2; - }-*/; - - public static native NodeList getElementsByClassName(String clazz, - Node ctx) /*-{ - return ctx.getElementsByClassName(clazz); - }-*/; - - public static native T or(T s1, T s2) /*-{ - return s1 || s2; - }-*/; - - public static native NodeList querySelectorAll(String selector) /*-{ - return $doc.querySelectorAll(selector); - }-*/; - - public static native NodeList querySelectorAll(String selector, - Node ctx) /*-{ - return ctx.querySelectorAll(selector); - }-*/; - - public NodeList select(String selector, Node ctx) { - return impl.select(selector, ctx); - } - - public static boolean truth(String a) { - return GWT.isScript() ? truth0(a) : a != null && !"".equals(a); - } - - public static boolean truth(JavaScriptObject a) { - return GWT.isScript() ? truth0(a) : a != null; - } - - public static NodeList xpathEvaluate(String selector, Node ctx) { - return xpathEvaluate(selector, ctx, JSArray.create()); - } - - public static native NodeList xpathEvaluate(String selector, - Node ctx, JSArray r) /*-{ - var node; - var result = $doc.evaluate(selector, ctx, null, 0, null); - while ((node = result.iterateNext())) { - r.push(node); - } - return r; - }-*/; - - private static native boolean truth0(String a) /*-{ - return a; - }-*/; - - private static native boolean truth0(JavaScriptObject a) /*-{ - return a; - }-*/; - - protected JSArray veryQuickId(Node context, String id) { - JSArray r = JSArray.create(); - if (context.getNodeType() == Node.DOCUMENT_NODE) { - r.addNode(((Document) context).getElementById(id)); - return r; - } else { - r.addNode(context.getOwnerDocument().getElementById(id)); - return r; - } - } - - public static native Node getNextSibling(Node n) /*-{ - return n.nextSibling || null; - }-*/; - - public static native Node getPreviousSibling(Node n) /*-{ - return n.previousSibling || null; - }-*/; -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/Selectors.java b/gwtquery-core/src/main/java/gwtquery/client/Selectors.java deleted file mode 100644 index 6ebd5018..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/Selectors.java +++ /dev/null @@ -1,7 +0,0 @@ -package gwtquery.client; - -/** - */ -public interface Selectors { - DeferredGQuery[] getAllSelectors(); -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImpl.java b/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImpl.java deleted file mode 100644 index c61a88b9..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImpl.java +++ /dev/null @@ -1,41 +0,0 @@ -package gwtquery.client.impl; - -import com.google.gwt.dom.client.Element; - -import gwtquery.client.SelectorEngine; - -/** - * - */ -public class DocumentStyleImpl { - - public String getPropertyName(String name) { - if ("float".equals(name)) { - return "cssFloat"; - } else if ("class".equals(name)) { - return "className"; - } else if ("for".equals(name)) { - return "htmlFor"; - } - return name; - } - - public String getCurrentStyle(Element elem, String name) { - name = hyphenize(name); - String propVal = getComputedStyle(elem, name, null); - if ("opacity".equals(name)) { - propVal = SelectorEngine.or(propVal, "1"); - } - return propVal; - } - - protected native String hyphenize(String name) /*-{ - return name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - }-*/; - - private native String getComputedStyle(Element elem, String name, - String pseudo) /*-{ - var cStyle = $doc.defaultView.getComputedStyle( elem, pseudo ); - return cStyle ? cStyle.getPropertyValue( name ) : null; - }-*/; -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImplIE.java b/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImplIE.java deleted file mode 100644 index b9d95bcb..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/DocumentStyleImplIE.java +++ /dev/null @@ -1,57 +0,0 @@ -package gwtquery.client.impl; - -import com.google.gwt.dom.client.Element; - -import gwtquery.client.SelectorEngine; - -/** - * - */ -public class DocumentStyleImplIE extends DocumentStyleImpl { - - public String getPropertyName(String name) { - if ("float".equals(name)) { - return "styleFloat"; - } else if ("class".equals(name)) { - return "className"; - } else if ("for".equals(name)) { - return "htmlFor"; - } - return name; - } - - public String getCurrentStyle(Element elem, String name) { - name = hyphenize(name); - String propVal = getComputedStyle(elem, name, null); - if ("opacity".equals(name)) { - propVal = SelectorEngine.or(propVal, "1"); - } - return propVal; - } - - // code lifted from jQuery - private native String getComputedStyle(Element elem, String name, - String pseudo) /*-{ - var style = elem.style; - var camelCase = name.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - var ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { - // Remember the original values - var left = style.left, rsLeft = elem.runtimeStyle.left; - // Put in the new values to get a computed value out - elem.runtimeStyle.left = elem.currentStyle.left; - style.left = ret || 0; - ret = style.pixelLeft + "px"; - // Revert the changed values - style.left = left; - elem.runtimeStyle.left = rsLeft; - } - return ret; - }-*/; -} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineImpl.java b/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineImpl.java deleted file mode 100644 index 18774d0c..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineImpl.java +++ /dev/null @@ -1,104 +0,0 @@ -package gwtquery.client.impl; - -import gwtquery.client.Regexp; -import gwtquery.client.JSArray; -import gwtquery.client.SelectorEngine; -import com.google.gwt.dom.client.*; - -/** - * Copyright 2007 Timepedia.org - * 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. - * - * @author Ray Cromwell - */ -public abstract class SelectorEngineImpl { - - public abstract NodeList select(String selector, Node ctx); - - protected static Sequence getSequence(String expression) { - int start = 0, add = 2, max = -1, modVal = -1; - Regexp expressionRegExp = new Regexp( - "^((odd|even)|([1-9]\\d*)|((([1-9]\\d*)?)n((\\+|\\-)(\\d+))?)|(\\-(([1-9]\\d*)?)n\\+(\\d+)))$"); - JSArray pseudoValue = expressionRegExp.exec(expression); - if (!SelectorEngine.truth(pseudoValue)) { - return null; - } else { - if (SelectorEngine.truth(pseudoValue.getStr(2))) { // odd or even - start = (SelectorEngine.eq(pseudoValue.getStr(2), "odd")) ? 1 : 2; - modVal = (start == 1) ? 1 : 0; - } else if (SelectorEngine.truth(pseudoValue.getStr(3))) { // single digit - start = Integer.parseInt(pseudoValue.getStr(3), 10); - add = 0; - max = start; - } else if (SelectorEngine.truth(pseudoValue.getStr(4))) { // an+b - add = SelectorEngine.truth(pseudoValue.getStr(6)) ? Integer - .parseInt(pseudoValue.getStr(6), 10) : 1; - start = SelectorEngine.truth(pseudoValue.getStr(7)) ? Integer - .parseInt((pseudoValue.getStr(8).charAt(0) == '+' ? "" : pseudoValue.getStr(8)) + pseudoValue.getStr(9), 10) : 0; - while (start < 1) { - start += add; - } - modVal = (start > add) ? (start - add) % add - : ((start == add) ? 0 : start); - } else if (SelectorEngine.truth(pseudoValue.getStr(10))) { // -an+b - add = SelectorEngine.truth(pseudoValue.getStr(12)) ? Integer - .parseInt(pseudoValue.getStr(12), 10) : 1; - start = max = Integer.parseInt(pseudoValue.getStr(13), 10); - while (start > add) { - start -= add; - } - modVal = (max > add) ? (max - add) % add : ((max == add) ? 0 : max); - } - } - Sequence s = new Sequence(); - s.start = start; - s.add = add; - s.max = max; - s.modVal = modVal; - return s; - } - - public static class Sequence { - public int start; - public int max; - public int add; - public int modVal; - } - - public static class SplitRule { - - public String tag; - public String id; - public String allClasses; - public String allAttr; - public String allPseudos; - public String tagRelation; - - public SplitRule(String tag, String id, String allClasses, String allAttr, - String allPseudos) { - this.tag = tag; - this.id = id; - this.allClasses = allClasses; - this.allAttr = allAttr; - this.allPseudos = allPseudos; - } - - public SplitRule(String tag, String id, String allClasses, String allAttr, - String allPseudos, String tagRelation) { - this.tag = tag; - this.id = id; - this.allClasses = allClasses; - this.allAttr = allAttr; - this.allPseudos = allPseudos; - this.tagRelation = tagRelation; - } - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJS.java b/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJS.java deleted file mode 100644 index a65e1cdc..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJS.java +++ /dev/null @@ -1,698 +0,0 @@ -package gwtquery.client.impl; - -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 gwtquery.client.JSArray; -import gwtquery.client.Regexp; -import gwtquery.client.SelectorEngine; - -/** - * Copyright 2007 Timepedia.org 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. - * - * @author Ray Cromwell - */ -public class SelectorEngineJS extends SelectorEngineImpl { - private Regexp cssSelectorRegExp; - private Regexp selectorSplitRegExp; - private Regexp childOrSiblingRefRegExp; - - - public SelectorEngineJS() { - selectorSplitRegExp = new Regexp("[^\\s]+", "g"); - childOrSiblingRefRegExp = new Regexp("^(>|\\+|~)$"); - cssSelectorRegExp = new Regexp( - "^(\\w+)?(#[\\w\\u00C0-\\uFFFF\\-\\_]+|(\\*))?((\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[\\w\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[\\w\\u00C0-\\uFFFF\\-_]+|((\\w*\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[\\w\\-]*))\\))?)*)?"); - } - - public static void clearAdded(JSArray a) { - for (int i = 0, len = a.size(); i < len; i++) { - clearAdded(a.getNode(i)); - } - } - - public static native void clearAdded(Node node) /*-{ - node.added = null; - }-*/; - - public static native NodeList getElementsByClassName(String clazz, - Node ctx) /*-{ - return ctx.getElementsByClassName(clazz); - }-*/; - - public static native boolean isAdded(Node prevRef) /*-{ - return prevRef.added || false; - }-*/; - - public static native void setAdded(Node prevRef, boolean added) /*-{ - prevRef.added = added; - }-*/; - - public static native void setSkipTag(JSArray prevElem, boolean skip) /*-{ - prevElem.skipTag = skip; - }-*/; - - private static String attrToRegExp(String attrVal, String op) { - if (SelectorEngine.eq("^", op)) { - return "^" + attrVal; - } - if (SelectorEngine.eq("$", op)) { - return attrVal + "$"; - } - if (SelectorEngine.eq("*", op)) { - return attrVal; - } - if (SelectorEngine.eq("|", op)) { - return "(^" + attrVal + "(\\-\\w+)*$)"; - } - if (SelectorEngine.eq("~", op)) { - return "\\b" + attrVal + "\\b"; - } - return SelectorEngine.truth(attrVal) ? "^" + attrVal + "$" : null; - } - - private static void clearChildElms(JSArray prevParents) { - for (int n = 0, nl = prevParents.size(); n < nl; n++) { - setHasChildElms(prevParents.getNode(n), false); - } - } - - protected String getAttr(Element current, String name) { - return current.getAttribute(name); - } - - private static void getDescendantNodes(JSArray matchingElms, - String nextTagStr, Node prevRef) { - NodeList children = getElementsByTagName(nextTagStr, prevRef); - for (int k = 0, klen = children.getLength(); k < klen; k++) { - Node child = children.getItem(k); - if (child.getParentNode() == prevRef) { - matchingElms.addNode(child); - } - } - } - - private JSArray getElementsByPseudo(JSArray previousMatch, String pseudoClass, - String pseudoValue) { - JSArray prevParents = JSArray.create(); - boolean previousDir = pseudoClass.startsWith("first") ? true : false; - JSArray matchingElms = JSArray.create(); - Node prev, next, previous; - if (SelectorEngine.eq("first-child", pseudoClass) || SelectorEngine - .eq("last-child", pseudoClass)) { - getFirstChildPseudo(previousMatch, previousDir, matchingElms); - } else if (SelectorEngine.eq("only-child", pseudoClass)) { - getOnlyChildPseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("nth-child", pseudoClass)) { - matchingElms = getNthChildPseudo(previousMatch, pseudoValue, prevParents, - matchingElms); - } else if (SelectorEngine.eq("first-of-type", pseudoClass) || SelectorEngine - .eq("last-of-type", pseudoClass)) { - getFirstOfTypePseudo(previousMatch, previousDir, matchingElms); - } else if (SelectorEngine.eq("only-of-type", pseudoClass)) { - getOnlyOfTypePseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("nth-of-type", pseudoClass)) { - matchingElms = getNthOfTypePseudo(previousMatch, pseudoValue, prevParents, - matchingElms); - } else if (SelectorEngine.eq("empty", pseudoClass)) { - getEmptyPseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("enabled", pseudoClass)) { - getEnabledPseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("disabled", pseudoClass)) { - getDisabledPseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("checked", pseudoClass)) { - getCheckedPseudo(previousMatch, matchingElms); - } else if (SelectorEngine.eq("contains", pseudoClass)) { - getContainsPseudo(previousMatch, pseudoValue, matchingElms); - } else if (SelectorEngine.eq("not", pseudoClass)) { - matchingElms = getNotPseudo(previousMatch, pseudoValue, matchingElms); - } else { - getDefaultPseudo(previousMatch, pseudoClass, pseudoValue, matchingElms); - } - return matchingElms; - } - - private void getDefaultPseudo(JSArray previousMatch, String pseudoClass, - String pseudoValue, JSArray matchingElms) { - Node previous; - for (int w = 0, wlen = previousMatch.size(); w < wlen; w++) { - previous = previousMatch.getElement(w); - if (SelectorEngine - .eq(((Element) previous).getAttribute(pseudoClass), pseudoValue)) { - matchingElms.addNode(previous); - } - } - } - - private JSArray getNotPseudo(JSArray previousMatch, String pseudoValue, - JSArray matchingElms) { - if (new Regexp("(:\\w+[\\w\\-]*)$").test(pseudoValue)) { - matchingElms = subtractArray(previousMatch, - getElementsByPseudo(previousMatch, pseudoValue.substring(1), "")); - } else { - pseudoValue = pseudoValue - .replace("^\\[#([\\w\\u00C0-\\uFFFF\\-\\_]+)\\]$", "[id=$1]"); - JSArray notTag = new Regexp("^(\\w+)").exec(pseudoValue); - JSArray notClass = new Regexp("^\\.([\\w\u00C0-\uFFFF\\-_]+)") - .exec(pseudoValue); - JSArray notAttr = new Regexp( - "\\[(\\w+)(\\^|\\$|\\*|\\||~)?=?([\\w\\u00C0-\\uFFFF\\s\\-_\\.]+)?\\]") - .exec(pseudoValue); - Regexp notRegExp = new Regexp( - "(^|\\s)" + (SelectorEngine.truth(notTag) ? notTag - .getStr(1) - : SelectorEngine.truth(notClass) ? notClass.getStr(1) : "") - + "(\\s|$)", "i"); - if (SelectorEngine.truth(notAttr)) { - String notAttribute = SelectorEngine.truth(notAttr.getStr(3)) ? notAttr - .getStr(3) - .replace("\\.", "\\.") : null; - String notMatchingAttrVal = attrToRegExp(notAttribute, - notAttr.getStr(2)); - notRegExp = new Regexp(notMatchingAttrVal, "i"); - } - for (int v = 0, vlen = previousMatch.size(); v < vlen; v++) { - Element notElm = previousMatch.getElement(v); - Element addElm = null; - if (SelectorEngine.truth(notTag) && !notRegExp - .test(notElm.getNodeName())) { - addElm = notElm; - } else if (SelectorEngine.truth(notClass) && !notRegExp - .test(notElm.getClassName())) { - addElm = notElm; - } else if (SelectorEngine.truth(notAttr)) { - String att = getAttr(notElm, notAttr.getStr(1)); - if (!SelectorEngine.truth(att) || !notRegExp.test(att)) { - addElm = notElm; - } - } - if (SelectorEngine.truth(addElm) && !isAdded(addElm)) { - setAdded(addElm, true); - matchingElms.addNode(addElm); - } - } - } - return matchingElms; - } - - private void getContainsPseudo(JSArray previousMatch, String pseudoValue, - JSArray matchingElms) { - Node previous; - for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { - previous = previousMatch.getNode(q); - if (!isAdded(previous)) { - if (((Element) previous).getInnerText().indexOf(pseudoValue) != -1) { - setAdded(previous, true); - matchingElms.addNode(previous); - } - } - } - } - - private void getCheckedPseudo(JSArray previousMatch, JSArray matchingElms) { - Node previous; - for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { - previous = previousMatch.getNode(q); - if (checked(previous)) { - matchingElms.addNode(previous); - } - } - } - - private void getDisabledPseudo(JSArray previousMatch, JSArray matchingElms) { - Node previous; - for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { - previous = previousMatch.getNode(q); - if (!enabled(previous)) { - matchingElms.addNode(previous); - } - } - } - - private void getEnabledPseudo(JSArray previousMatch, JSArray matchingElms) { - Node previous; - for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { - previous = previousMatch.getNode(q); - if (enabled(previous)) { - matchingElms.addNode(previous); - } - } - } - - private void getEmptyPseudo(JSArray previousMatch, JSArray matchingElms) { - Node previous; - for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { - previous = previousMatch.getNode(q); - if (!previous.hasChildNodes()) { - matchingElms.addNode(previous); - } - } - } - - private JSArray getNthOfTypePseudo(JSArray previousMatch, String pseudoValue, - JSArray prevParents, JSArray matchingElms) { - Node previous; - if (pseudoValue.startsWith("n")) { - matchingElms = previousMatch; - } else { - Sequence sequence = getSequence(pseudoValue); - if (sequence != null) { - for (int p = 0, plen = previousMatch.size(); p < plen; p++) { - previous = previousMatch.getNode(p); - Node prevParent = previous.getParentNode(); - if (!hasChildElms(prevParent)) { - int iteratorNext = sequence.start; - int childCount = 0; - Node childElm = prevParent.getFirstChild(); - while (SelectorEngine.truth(childElm) && (sequence.max < 0 - || iteratorNext <= sequence.max)) { - if (SelectorEngine - .eq(childElm.getNodeName(), previous.getNodeName())) { - if (++childCount == iteratorNext) { - matchingElms.addNode(childElm); - iteratorNext += sequence.add; - } - } - childElm = SelectorEngine.getNextSibling(childElm); - } - setHasChildElms(prevParent, true); - prevParents.addNode(prevParent); - } - } - clearChildElms(prevParents); - } - } - return matchingElms; - } - - private void getOnlyOfTypePseudo(JSArray previousMatch, - JSArray matchingElms) { - Node previous; - Node next; - Node prev; - Node oParent = null; - for (int o = 0, olen = previousMatch.size(); o < olen; o++) { - prev = next = previous = previousMatch.getNode(o); - Node prevParent = previous.getParentNode(); - if (prevParent != oParent) { - while ( - SelectorEngine.truth(prev = SelectorEngine.getPreviousSibling(prev)) - && !SelectorEngine - .eq(prev.getNodeName(), previous.getNodeName())) { - } - while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) - && !SelectorEngine.eq(next.getNodeName(), previous.getNodeName())) { - } - if (!SelectorEngine.truth(prev) && !SelectorEngine.truth(next)) { - matchingElms.addNode(previous); - } - oParent = prevParent; - } - } - } - - private void getFirstOfTypePseudo(JSArray previousMatch, boolean previousDir, - JSArray matchingElms) { - Node previous; - Node next; - for (int n = 0, nlen = previousMatch.size(); n < nlen; n++) { - next = previous = previousMatch.getNode(n); - - if (previousDir) { - while ( - SelectorEngine.truth(next = SelectorEngine.getPreviousSibling(next)) - && !SelectorEngine - .eq(next.getNodeName(), previous.getNodeName())) { - } - } else { - while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) - && !SelectorEngine.eq(next.getNodeName(), previous.getNodeName())) { - } - } - - if (!SelectorEngine.truth(next)) { - matchingElms.addNode(previous); - } - } - } - - private JSArray getNthChildPseudo(JSArray previousMatch, String pseudoValue, - JSArray prevParents, JSArray matchingElms) { - Node previous; - if (SelectorEngine.eq(pseudoValue, "n")) { - matchingElms = previousMatch; - } else { - Sequence sequence = getSequence(pseudoValue); - if (sequence != null) { - for (int l = 0, llen = previousMatch.size(); l < llen; l++) { - previous = previousMatch.getNode(l); - Node prevParent = previous.getParentNode(); - if (!hasChildElms(prevParent)) { - int iteratorNext = sequence.start; - int childCount = 0; - Node childElm = prevParent.getFirstChild(); - while (childElm != null && (sequence.max < 0 - || iteratorNext <= sequence.max)) { - if (childElm.getNodeType() == Node.ELEMENT_NODE) { - if (++childCount == iteratorNext) { - if (SelectorEngine - .eq(childElm.getNodeName(), previous.getNodeName())) { - matchingElms.addNode(childElm); - } - iteratorNext += sequence.add; - } - } - childElm = SelectorEngine.getNextSibling(childElm); - } - setHasChildElms(prevParent, true); - prevParents.addNode(prevParent); - } - } - clearChildElms(prevParents); - } - } - return matchingElms; - } - - private void getOnlyChildPseudo(JSArray previousMatch, JSArray matchingElms) { - Node previous; - Node next; - Node prev; - Node kParent = null; - for (int k = 0, klen = previousMatch.size(); k < klen; k++) { - prev = next = previous = previousMatch.getNode(k); - Node prevParent = previous.getParentNode(); - if (prevParent != kParent) { - while ( - SelectorEngine.truth(prev = SelectorEngine.getPreviousSibling(prev)) - && prev.getNodeType() != Node.ELEMENT_NODE) { - } - while (SelectorEngine.truth(next = SelectorEngine.getNextSibling(next)) - && next.getNodeType() != Node.ELEMENT_NODE) { - } - if (!SelectorEngine.truth(prev) && !SelectorEngine.truth(next)) { - matchingElms.addNode(previous); - } - kParent = prevParent; - } - } - } - - private void getFirstChildPseudo(JSArray previousMatch, boolean previousDir, - JSArray matchingElms) { - Node next; - Node previous; - for (int j = 0, jlen = previousMatch.size(); j < jlen; j++) { - previous = next = previousMatch.getElement(j); - if (previousDir) { - while (SelectorEngine - .truth((next = SelectorEngine.getPreviousSibling(next))) - && next.getNodeType() != Node.ELEMENT_NODE) { - } - } else { - while ( - SelectorEngine.truth((next = SelectorEngine.getNextSibling(next))) - && next.getNodeType() != Node.ELEMENT_NODE) { - } - } - if (!SelectorEngine.truth(next)) { - matchingElms.addNode(previous); - } - } - } - - private static native boolean checked(Node previous) /*-{ - return previous.checked || false; - }-*/; - - private static native boolean enabled(Node node) /*-{ - return !node.disabled; - }-*/; - - private static NodeList getElementsByTagName(String tag, Node ctx) { - return ((Element) ctx).getElementsByTagName(tag); - } - - private static void getGeneralSiblingNodes(JSArray matchingElms, - JSArray nextTag, Regexp nextRegExp, Node prevRef) { - while ( - SelectorEngine.truth((prevRef = SelectorEngine.getNextSibling(prevRef))) - && !isAdded(prevRef)) { - if (!SelectorEngine.truth(nextTag) || nextRegExp - .test(prevRef.getNodeName())) { - setAdded(prevRef, true); - matchingElms.addNode(prevRef); - } - } - } - - private static void getSiblingNodes(JSArray matchingElms, JSArray nextTag, - Regexp nextRegExp, Node prevRef) { - while ( - SelectorEngine.truth(prevRef = SelectorEngine.getNextSibling(prevRef)) - && prevRef.getNodeType() != Node.ELEMENT_NODE) { - } - if (SelectorEngine.truth(prevRef)) { - if (!SelectorEngine.truth(nextTag) || nextRegExp - .test(prevRef.getNodeName())) { - matchingElms.addNode(prevRef); - } - } - } - - private static native boolean hasChildElms(Node prevParent) /*-{ - return prevParent.childElms || false; - }-*/; - - private static native boolean isSkipped(JSArray prevElem) /*-{ - return prevElem.skipTag || false; - }-*/; - - private static native void setHasChildElms(Node prevParent, boolean bool) /*-{ - prevParent.childElms = bool ? bool : null; - }-*/; - - private static native JSArray subtractArray(JSArray previousMatch, - JSArray elementsByPseudo) /*-{ - for (var i=0, src1; (src1=arr1[i]); i++) { - var found = false; - for (var j=0, src2; (src2=arr2[j]); j++) { - if (src2 === src1) { - found = true; - break; - } - } - if (found) { - arr1.splice(i--, 1); - } - } - return arr; - }-*/; - - public NodeList select(String sel, Node ctx) { - String selectors[] = sel.replace("\\s*(,)\\s*", "$1").split(","); - boolean identical = false; - JSArray elm = JSArray.create(); - for (int a = 0, len = selectors.length; a < len; a++) { - if (a > 0) { - identical = false; - for (int b = 0, bl = a; b < bl; b++) { - if (SelectorEngine.eq(selectors[a], selectors[b])) { - identical = true; - break; - } - } - if (identical) { - continue; - } - } - String currentRule = selectors[a]; - JSArray cssSelectors = selectorSplitRegExp.match(currentRule); - JSArray prevElem = JSArray.create(ctx); - for (int i = 0, slen = cssSelectors.size(); i < slen; i++) { - JSArray matchingElms = JSArray.create(); - String rule = cssSelectors.getStr(i); - if (i > 0 && childOrSiblingRefRegExp.test(rule)) { - JSArray childOrSiblingRef = childOrSiblingRefRegExp.exec(rule); - if (SelectorEngine.truth(childOrSiblingRef)) { - JSArray nextTag = new Regexp("^\\w+") - .exec(cssSelectors.getStr(i + 1)); - Regexp nextRegExp = null; - String nextTagStr = null; - if (SelectorEngine.truth(nextTag)) { - nextTagStr = nextTag.getStr(0); - nextRegExp = new Regexp("(^|\\s)" + nextTagStr + "(\\s|$)", "i"); - } - for (int j = 0, jlen = prevElem.size(); j < jlen; j++) { - Node prevRef = prevElem.getNode(j); - String ref = childOrSiblingRef.getStr(0); - if (SelectorEngine.eq(">", ref)) { - getDescendantNodes(matchingElms, nextTagStr, prevRef); - } else if (SelectorEngine.eq("+", ref)) { - getSiblingNodes(matchingElms, nextTag, nextRegExp, prevRef); - } else if (SelectorEngine.eq("~", ref)) { - getGeneralSiblingNodes(matchingElms, nextTag, nextRegExp, - prevRef); - } - } - prevElem = matchingElms; - clearAdded(prevElem); - rule = cssSelectors.getStr(++i); - if (new Regexp("^\\w+$").test(rule)) { - continue; - } - setSkipTag(prevElem, true); - } - } - JSArray cssSelector = cssSelectorRegExp.exec(rule); - SplitRule splitRule = new SplitRule( - !SelectorEngine.truth(cssSelector.getStr(1)) || SelectorEngine - .eq(cssSelector.getStr(3), "*") ? "*" : cssSelector.getStr(1), - !SelectorEngine.eq(cssSelector.getStr(3), "*") ? cssSelector - .getStr(2) : null, cssSelector.getStr(4), cssSelector.getStr(6), - cssSelector.getStr(10)); - if (SelectorEngine.truth(splitRule.id)) { - Element domelem = Document.get() - .getElementById(splitRule.id.substring(1)); - if (SelectorEngine.truth(domelem)) { - matchingElms = JSArray.create(domelem); - } - prevElem = matchingElms; - } else if (SelectorEngine.truth(splitRule.tag) && !isSkipped(prevElem)) { - if (i == 0 && matchingElms.size() == 0 && prevElem.size() == 1) { - prevElem = matchingElms = JSArray.create( - getElementsByTagName(splitRule.tag, prevElem.getNode(0))); - } else { - NodeList tagCollectionMatches; - for (int l = 0, ll = prevElem.size(); l < ll; l++) { - tagCollectionMatches = getElementsByTagName(splitRule.tag, - prevElem.getNode(l)); - for (int m = 0, mlen = tagCollectionMatches.getLength(); m < mlen; - m++) { - Node tagMatch = tagCollectionMatches.getItem(m); - - if (!isAdded(tagMatch)) { - setAdded(tagMatch, true); - matchingElms.addNode(tagMatch); - } - } - } - prevElem = matchingElms; - clearAdded(prevElem); - } - if (matchingElms.size() == 0) { - break; - } - setSkipTag(prevElem, false); - if (SelectorEngine.truth(splitRule.allClasses)) { - String[] allClasses = splitRule.allClasses.replaceFirst("^\\.", "") - .split("\\."); - Regexp[] regExpClassNames = new Regexp[allClasses.length]; - for (int n = 0, nl = allClasses.length; n < nl; n++) { - regExpClassNames[n] = new Regexp( - "(^|\\s)" + allClasses[n] + "(\\s|$)"); - } - JSArray matchingClassElms = JSArray.create(); - for (int o = 0, olen = prevElem.size(); o < olen; o++) { - Element current = prevElem.getElement(o); - String elmClass = current.getClassName(); - boolean addElm = false; - if (SelectorEngine.truth(elmClass) && !isAdded(current)) { - for (int p = 0, pl = regExpClassNames.length; p < pl; p++) { - addElm = regExpClassNames[p].test(elmClass); - if (!addElm) { - break; - } - } - if (addElm) { - setAdded(current, true); - matchingClassElms.addNode(current); - } - } - } - clearAdded(prevElem); - prevElem = matchingElms = matchingClassElms; - } - if (SelectorEngine.truth(splitRule.allAttr)) { - JSArray allAttr = Regexp - .match("\\[[^\\]]+\\]", "g", splitRule.allAttr); - Regexp[] regExpAttributes = new Regexp[allAttr.size()]; - String[] regExpAttributesStr = new String[allAttr.size()]; - Regexp attributeMatchRegExp = new Regexp( - "(\\w+)(\\^|\\$|\\*|\\||~)?=?([\\w\u00C0-\uFFFF\\s\\-_\\.]+)?"); - for (int q = 0, ql = allAttr.size(); q < ql; q++) { - JSArray attributeMatch = attributeMatchRegExp - .exec(allAttr.getStr(q)); - String attributeValue = - SelectorEngine.truth(attributeMatch.getStr(3)) - ? attributeMatch.getStr(3).replaceAll("\\.", "\\.") - : null; - String attrVal = attrToRegExp(attributeValue, - (SelectorEngine.or(attributeMatch.getStr(2), null))); - regExpAttributes[q] = (SelectorEngine.truth(attrVal) ? new Regexp( - attrVal) : null); - regExpAttributesStr[q] = attributeMatch.getStr(1); - } - JSArray matchingAttributeElms = JSArray.create(); - - for (int r = 0, rlen = matchingElms.size(); r < rlen; r++) { - Element current = matchingElms.getElement(r); - boolean addElm = false; - for (int s = 0, sl = regExpAttributes.length, attributeRegExp; - s < sl; s++) { - addElm = false; - Regexp attributeRegExp2 = regExpAttributes[s]; - String currentAttr = getAttr(current, regExpAttributesStr[s]); - if (SelectorEngine.truth(currentAttr) - && currentAttr.length() != 0) { - if (attributeRegExp2 == null || attributeRegExp2 - .test(currentAttr)) { - addElm = true; - } - } - if (!addElm) { - break; - } - } - if (addElm) { - matchingAttributeElms.addNode(current); - } - } - prevElem = matchingElms = matchingAttributeElms; - } - if (SelectorEngine.truth(splitRule.allPseudos)) { - Regexp pseudoSplitRegExp = new Regexp( - ":(\\w[\\w\\-]*)(\\(([^\\)]+)\\))?"); - - JSArray allPseudos = Regexp.match( - "(:\\w+[\\w\\-]*)(\\([^\\)]+\\))?", "g", splitRule.allPseudos); - for (int t = 0, tl = allPseudos.size(); t < tl; t++) { - JSArray pseudo = pseudoSplitRegExp.match(allPseudos.getStr(t)); - String pseudoClass = SelectorEngine.truth(pseudo.getStr(1)) - ? pseudo.getStr(1) - .toLowerCase() : null; - String pseudoValue = SelectorEngine.truth(pseudo.getStr(3)) - ? pseudo.getStr(3) : null; - matchingElms = getElementsByPseudo(matchingElms, pseudoClass, - pseudoValue); - clearAdded(matchingElms); - } - prevElem = matchingElms; - } - } - } - elm.pushAll(prevElem); - } - - return elm; - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJSIE.java b/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJSIE.java deleted file mode 100644 index e7aad623..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineJSIE.java +++ /dev/null @@ -1,20 +0,0 @@ -package gwtquery.client.impl; - -import com.google.gwt.dom.client.Element; - -/** - * Fix some DOM ops for IE - */ -public class SelectorEngineJSIE extends SelectorEngineJS { - public native String getAttr(Element elm, String attr) /*-{ - switch (attr) { - case "id": - return elm.id; - case "for": - return elm.htmlFor; - case "class": - return elm.className; - } - return elm.getAttribute(attr, 2); - }-*/; -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineNative.java b/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineNative.java deleted file mode 100644 index b9e96bd8..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineNative.java +++ /dev/null @@ -1,16 +0,0 @@ -package gwtquery.client.impl; - -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NodeList; -import com.google.gwt.dom.client.Node; - -import gwtquery.client.SelectorEngine; - -/** - * - */ -public class SelectorEngineNative extends SelectorEngineImpl { - public NodeList select(String selector, Node ctx) { - return SelectorEngine.querySelectorAll(selector, ctx); - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineXPath.java b/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineXPath.java deleted file mode 100644 index cbc2ca3b..00000000 --- a/gwtquery-core/src/main/java/gwtquery/client/impl/SelectorEngineXPath.java +++ /dev/null @@ -1,237 +0,0 @@ -package gwtquery.client.impl; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Node; -import com.google.gwt.dom.client.NodeList; - -import gwtquery.client.JSArray; -import gwtquery.client.Regexp; -import gwtquery.client.SelectorEngine; -import static gwtquery.client.SelectorEngine.eq; -import static gwtquery.client.SelectorEngine.truth; - -/** - * Copyright 2007 Timepedia.org 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. - * - * @author Ray Cromwell - */ -public class SelectorEngineXPath extends SelectorEngineImpl { - private Regexp cssSelectorRegExp; - private Regexp selectorSplitRegExp; - private Regexp COMBINATOR; - - public SelectorEngineXPath() { - } - - private void init() { - if (cssSelectorRegExp == null) { - cssSelectorRegExp = new Regexp( - "^(\\w+)?(#[\\w\\u00C0-\\uFFFF\\-\\_]+|(\\*))?((\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[\\w\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[\\w\\u00C0-\\uFFFF\\-_]+|((\\w*\\.[\\w\\u00C0-\\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[\\w\\u00C0-\\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[\\w\\-]*))\\))?)*)?(>|\\+|~)?"); - selectorSplitRegExp = new Regexp("[^\\s]+", "g"); - COMBINATOR = new Regexp("(>|\\+|~)"); - } - } - - - public NodeList select(String sel, Node ctx) { - init(); - String selectors[] = sel.replaceAll("\\s*(,)\\s*", "$1").split(","); - boolean identical = false; - JSArray elm = JSArray.create(); - for (int a = 0, len = selectors.length; a < len; a++) { - if (a > 0) { - identical = false; - for (int b = 0, bl = a; b < bl; b++) { - if (eq(selectors[a], selectors[b])) { - identical = true; - break; - } - } - if (identical) { - continue; - } - } - String currentRule = selectors[a]; - JSArray cssSelectors = selectorSplitRegExp.match(currentRule); - String xPathExpression = "."; - for (int i = 0, slen = cssSelectors.size(); i < slen; i++) { - String rule = cssSelectors.getStr(i); - JSArray cssSelector = cssSelectorRegExp.exec(rule); - SplitRule splitRule = new SplitRule(!truth(cssSelector.getStr(1)) || eq( - cssSelector.getStr(3), "*") ? "*" : cssSelector.getStr(1), - !eq(cssSelector.getStr(3), "*") ? cssSelector.getStr(2) : null, - cssSelector.getStr(4), cssSelector.getStr(6), - cssSelector.getStr(10), cssSelector.getStr(22)); - if (truth(splitRule.tagRelation)) { - if (eq(">", splitRule.tagRelation)) { - xPathExpression += "/child::"; - } else if (eq("+", splitRule.tagRelation)) { - xPathExpression += "/following-sibling::*[1]/self::"; - } else if (eq("~", splitRule.tagRelation)) { - xPathExpression += "/following-sibling::"; - } - } else { - xPathExpression += - (i > 0 && COMBINATOR.test(cssSelectors.getStr(i - 1))) - ? splitRule.tag : ("/descendant::" + splitRule.tag); - } - if (truth(splitRule.id)) { - xPathExpression += "[@id = '" + splitRule.id.replaceAll("^#", "") - + "']"; - } - if (truth(splitRule.allClasses)) { - xPathExpression += splitRule.allClasses.replaceAll( - "\\.([\\w\\u00C0-\\uFFFF\\-_]+)", - "[contains(concat(' ', @class, ' '), ' $1 ')]"); - } - if (truth(splitRule.allAttr)) { - GWT.log("AllAttr is " + splitRule.allAttr, null); - xPathExpression += replaceAttr( - SelectorEngine.or(splitRule.allAttr, "")); - } - if (truth(splitRule.allPseudos)) { - Regexp pseudoSplitRegExp = new Regexp( - ":(\\w[\\w\\-]*)(\\(([^\\)]+)\\))?"); - Regexp pseudoMatchRegExp = new Regexp( - "(:\\w+[\\w\\-]*)(\\([^\\)]+\\))?", "g"); - JSArray allPseudos = pseudoMatchRegExp.match(splitRule.allPseudos); - for (int k = 0, kl = allPseudos.size(); k < kl; k++) { - JSArray pseudo = pseudoSplitRegExp.match(allPseudos.getStr(k)); - String pseudoClass = truth(pseudo.getStr(1)) ? pseudo.getStr(1) - .toLowerCase() : null; - String pseudoValue = truth(pseudo.getStr(3)) ? pseudo.getStr(3) - : null; - String xpath = pseudoToXPath(splitRule.tag, pseudoClass, - pseudoValue); - if (xpath.length() > 0) { - xPathExpression += "[" + xpath + "]"; - } - } - } - } - SelectorEngine.xpathEvaluate(xPathExpression, ctx, elm); - } - return elm; - } - - private String pseudoToXPath(String tag, String pseudoClass, - String pseudoValue) { - String xpath = ""; - if (eq("first-child", pseudoClass)) { - xpath = "not(preceding-sibling::*)"; - } else if (eq("first-of-type", pseudoClass)) { - xpath = "not(preceding-sibling::" + tag + ")"; - } else if (eq("last-child", pseudoClass)) { - xpath = "not(following-sibling::*)"; - } else if (eq("last-of-type", pseudoClass)) { - xpath = "not(following-sibling::" + tag + ")"; - } else if (eq("only-child", pseudoClass)) { - xpath = "not(preceding-sibling::* or following-sibling::*)"; - } else if (eq("only-of-type", pseudoClass)) { - xpath = "not(preceding-sibling::" + tag + " or following-sibling::" + tag - + ")"; - } else if (eq("nth-child", pseudoClass)) { - if (!eq("n", pseudoClass)) { - Sequence sequence = getSequence(pseudoValue); - if (sequence != null) { - if (sequence.start == sequence.max) { - xpath = "count(preceding-sibling::*) = " + (sequence.start - 1); - } else { - xpath = "(count(preceding-sibling::*) + 1) mod " + sequence.add - + " = " + sequence.modVal + ((sequence.start > 1) ? - " and count(preceding-sibling::*) >= " + (sequence.start - 1) - : "") + ((sequence.max > 0) ? - " and count(preceding-sibling::*) <= " + (sequence.max - 1) - : ""); - } - } - } - } else if (eq("nth-of-type", pseudoClass)) { - if (!pseudoValue.startsWith("n")) { - Sequence sequence = getSequence(pseudoValue); - if (sequence != null) { - if (sequence.start == sequence.max) { - xpath = pseudoValue; - } else { - xpath = "position() mod " + sequence.add + " = " + sequence.modVal - + ((sequence.start > 1) ? " and position() >= " + sequence - .start : "") + ((sequence.max > 0) ? " and position() <= " - + sequence.max : ""); - } - } - } - } else if (eq("empty", pseudoClass)) { - xpath = "count(child::*) = 0 and string-length(text()) = 0"; - } else if (eq("contains", pseudoClass)) { - xpath = "contains(., '" + pseudoValue + "')"; - } else if (eq("enabled", pseudoClass)) { - xpath = "not(@disabled)"; - } else if (eq("disabled", pseudoClass)) { - xpath = "@disabled"; - } else if (eq("checked", pseudoClass)) { - xpath = "@checked='checked'"; // Doesn't work in Opera 9.24 - } else if (eq("not", pseudoClass)) { - if (new Regexp("^(:\\w+[\\w\\-]*)$").test(pseudoValue)) { - xpath = "not(" + pseudoToXPath(tag, pseudoValue.substring(1), "") + ")"; - } else { - - pseudoValue = pseudoValue - .replaceFirst("^\\[#([\\w\\u00C0-\\uFFFF\\-\\_]+)\\]$", "[id=$1]"); - String notSelector = pseudoValue - .replaceFirst("^(\\w+)", "self::$1"); - notSelector = notSelector.replaceAll("^\\.([\\w\\u00C0-\\uFFFF\\-_]+)", - "contains(concat(' ', @class, ' '), ' $1 ')"); - notSelector = replaceAttr2(notSelector); - xpath = "not(" + notSelector + ")"; - } - } else { - xpath = "@" + pseudoClass + "='" + pseudoValue + "'"; - } - - return xpath; - } - - private static String attrToXPath(String match, String p1, String p2, - String p3) { - if (eq("^", p2)) { - return "starts-with(@" + p1 + ", '" + p3 + "')"; - } - if (eq("$", p2)) { - return "substring(@" + p1 + ", (string-length(@" + p1 + ") - " - + (p3.length() - 1) + "), " + p3.length() + ") = '" + p3 + "'"; - } - if (eq("*", p2)) { - return "contains(concat(' ', @" + p1 + ", ' '), '" + p3 + "')"; - } - if (eq("|", p2)) { - return "(@" + p1 + "='" + p3 + "' or starts-with(@" + p1 + ", '" + p3 - + "-'))"; - } - if (eq("~", p2)) { - return "contains(concat(' ', @" + p1 + ", ' '), ' " + p3 + " ')"; - } - return "@" + p1 + (truth(p3) ? "='" + p3 + "'" : ""); - } - - private native String replaceAttr(String allAttr) /*-{ - if(!allAttr) return ""; - return allAttr.replace(/(\w+)(\^|\$|\*|\||~)?=?([\w\u00C0-\uFFFF\s\-_\.]+)?/g, - function(a,b,c,d) { - return @gwtquery.client.impl.SelectorEngineXPath::attrToXPath(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)(a,b || "",c || "",d || ""); - }); - - }-*/; - - private native String replaceAttr2(String allAttr) /*-{ - if(!allAttr) return ""; - return allAttr.replace(/\[(\w+)(\^|\$|\*|\||~)?=?([\w\u00C0-\uFFFF\s\-_\.]+)?\]/g, @gwtquery.client.impl.SelectorEngineXPath::attrToXPath(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)); - }-*/; -} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorBase.java b/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorBase.java deleted file mode 100644 index 3cf2c2e7..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorBase.java +++ /dev/null @@ -1,192 +0,0 @@ -package gwtquery.rebind; - -import com.google.gwt.core.ext.Generator; -import com.google.gwt.core.ext.GeneratorContext; -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JClassType; -import com.google.gwt.core.ext.typeinfo.JMethod; -import com.google.gwt.core.ext.typeinfo.JParameter; -import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; -import com.google.gwt.user.rebind.SourceWriter; - -import java.io.PrintWriter; - -import gwtquery.client.Selector; - -/** - * - */ -public abstract class SelectorGeneratorBase extends Generator { - - private TreeLogger treeLogger; - - protected JClassType NODE_TYPE = null; - - public String generate(TreeLogger treeLogger, - GeneratorContext generatorContext, String requestedClass) - throws UnableToCompleteException { - this.treeLogger = treeLogger; - TypeOracle oracle = generatorContext.getTypeOracle(); - NODE_TYPE = oracle.findType("com.google.gwt.dom.client.Node"); - - JClassType selectorType = oracle.findType(requestedClass); - SourceWriter sw = getSourceWriter(treeLogger, generatorContext, - selectorType.getPackage().getName(), - selectorType.getSimpleSourceName() + getImplSuffix(), requestedClass); - if (sw != null) { - for (JMethod method : selectorType.getMethods()) { - generateMethod(sw, method, treeLogger); - } - genGetAllMethod(sw, selectorType.getMethods(), treeLogger); - sw.commit(treeLogger); - } - - return selectorType.getPackage().getName() + "." - + selectorType.getSimpleSourceName() + getImplSuffix(); - } - - protected String getImplSuffix() { - return "Impl"; - } - - // used by benchmark harness - private void genGetAllMethod(SourceWriter sw, JMethod[] methods, - TreeLogger treeLogger) { - sw.println("public DeferredGQuery[] getAllSelectors() {"); - sw.indent(); - sw.println( - "DeferredGQuery[] dg = new DeferredGQuery[" + (methods.length) + "];"); - int i = 0; - for (JMethod m : methods) { - Selector selectorAnnotation = m.getAnnotation(Selector.class); - if(selectorAnnotation == null) continue; - String selector = selectorAnnotation.value(); - - sw.println("dg[" + i + "]=new DeferredGQuery() {"); - sw.indent(); - sw.println( - "public String getSelector() { return \"" + selector + "\"; }"); - sw.println("public GQuery eval(Node ctx) { return " + wrapJS(m, m.getName() - + (m.getParameters().length == 0 ? "()" : "(ctx)")+"") + " ;}"); - sw.println("public NodeList array(Node ctx) { return "+("NodeList".equals(m.getReturnType().getSimpleSourceName()) ? - (m.getName() - + (m.getParameters().length == 0 ? "(); " : "(ctx); ")) : - "eval"+(m.getParameters().length == 0 ? "(null).get(); " : "(ctx).get(); "))+"}"); - - i++; - sw.outdent(); - sw.println("};"); - } - sw.println("return dg;"); - sw.outdent(); - sw.println("}"); - } - - public void generateMethod(SourceWriter sw, JMethod method, TreeLogger logger) - throws UnableToCompleteException { - Selector selectorAnnotation = method.getAnnotation(Selector.class); - if(selectorAnnotation == null) return; - - String selector = selectorAnnotation.value(); - JParameter[] params = method.getParameters(); - - sw.indent(); - String retType = method.getReturnType().getParameterizedQualifiedSourceName(); - sw.print("public final "+retType+" "+method.getName()); - boolean hasContext = false; - if (params.length == 0) { - sw.print("()"); - } else if (params.length == 1) { - JClassType type = params[0].getType().isClassOrInterface(); - if (type != null && type.isAssignableTo(NODE_TYPE)) { - sw.print("(Node root)"); - hasContext = true; - } - } - sw.println(" {"); - sw.indent(); - Selector sel = method.getAnnotation(Selector.class); - - // short circuit #foo - if (sel != null && sel.value().matches("^#\\w+$")) { - sw.println("return "+wrap(method, "JSArray.create(((Document)" + (hasContext ? "root" : "(Node)Document.get()") - + ").getElementById(\"" + sel.value().substring(1) + "\"))")+";"); - } - // short circuit FOO - else if (sel != null && sel.value().matches("^\\w+$")) { - sw.println("return "+wrap(method, "JSArray.create(((Element)"+(hasContext ? "root" : "(Node)Document.get()") - + ").getElementsByTagName(\"" + sel.value() + "\"))")+";"); - } // short circuit .foo for browsers with native getElementsByClassName - else if (sel != null && sel.value().matches("^\\.\\w+$") - && hasGetElementsByClassName()) { - sw.println("return "+wrap(method, "JSArray.create(getElementsByClassName(\"" - + sel.value().substring(1) + "\", " + (hasContext ? "root" : "(Node)Document.get()") - + "))")+";"); - } else { - generateMethodBody(sw, method, logger, hasContext); - } - sw.outdent(); - sw.println("}"); - sw.outdent(); - } - - protected boolean hasGetElementsByClassName() { - return false; - } - - protected void debug(String s) { -// System.err.println(s); - treeLogger.log(TreeLogger.DEBUG, s, null); - } - - protected boolean notNull(String s) { - return s != null && !"".equals(s); - } - - protected SourceWriter getSourceWriter(TreeLogger logger, - GeneratorContext context, String packageName, String className, - String... interfaceNames) { - PrintWriter printWriter = context.tryCreate(logger, packageName, className); - if (printWriter == null) { - return null; - } - ClassSourceFileComposerFactory composerFactory - = new ClassSourceFileComposerFactory(packageName, className); - composerFactory.setSuperclass("gwtquery.client.SelectorEngine"); - composerFactory.addImport("com.google.gwt.core.client.GWT"); - composerFactory.addImport("gwtquery.client.*"); -// composerFactory.addImport("gwtquery.client.JSArray"); - - composerFactory.addImport("com.google.gwt.dom.client.*"); - for (String interfaceName : interfaceNames) { - composerFactory.addImplementedInterface(interfaceName); - } - - return composerFactory.createSourceWriter(context, printWriter); - } - - protected String wrap(JMethod method, String expr) { - if("NodeList".equals(method.getReturnType().getSimpleSourceName())) { - return expr; - } - else { - return "new GQuery("+expr+")"; - } - - } - - protected String wrapJS(JMethod method, String expr) { - if("GQuery".equals(method.getReturnType().getSimpleSourceName())) { - return expr; - } - else { - return "new GQuery("+expr+")"; - } - - } - - protected abstract void generateMethodBody(SourceWriter sw, JMethod method, - TreeLogger logger, boolean hasContext) throws UnableToCompleteException; -} diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorJS.java b/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorJS.java deleted file mode 100644 index 8917f4c9..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorJS.java +++ /dev/null @@ -1,174 +0,0 @@ -package gwtquery.rebind; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JMethod; -import com.google.gwt.user.rebind.SourceWriter; - -import java.util.regex.Pattern; - -import gwtquery.client.Selector; - -/** - * - */ -public class SelectorGeneratorJS extends SelectorGeneratorBase { - - protected static Pattern nonSpace = Pattern.compile("\\S/"); - - private static final String trimReStr = "^\\s+|\\s+$"; - - protected static Pattern trimRe = Pattern.compile(trimReStr); - - protected static Pattern tplRe = Pattern.compile("\\{(\\d+)\\}"); - - protected static Pattern modeRe = Pattern - .compile("^(\\s?[\\/>+~]\\s?|\\s|$)"); - - protected static Pattern tagTokenRe = Pattern - .compile("^(#)?([a-zA-Z_0-9-\\*]+)"); - - protected static Pattern nthRe = Pattern.compile("(\\d*)n\\+?(\\d*)"); - - protected static Pattern nthRe2 = Pattern.compile("\\D"); - - protected static RuleMatcher[] matchers = new RuleMatcher[]{new RuleMatcher( - "^\\.([a-zA-Z_0-9-]+)", "n = byClassName(n, null, \"{0}\");"), - new RuleMatcher("^\\:([a-zA-Z_0-9-]+)(?:\\(((?:[^ >]*|.*?))\\))?", - "n = byPseudo(n, \"{0}\", \"{1}\");"), new RuleMatcher( - "^(?:([\\[\\{])(?:@)?([a-zA-Z_0-9-]+)\\s?(?:(=|.=)\\s?['\"]?(.*?)[\"']?)?[\\]\\}])", - "n = byAttribute(n, \"{1}\", \"{3}\", \"{2}\", \"{0}\");"), - new RuleMatcher("^#([a-zA-Z_0-9-]+)", "n = byId(n, null, \"{0}\");")}; - - protected String getImplSuffix() { - return "JS"+super.getImplSuffix(); - } - - protected void generateMethodBody(SourceWriter sw, JMethod method, - TreeLogger treeLogger, boolean hasContext) throws UnableToCompleteException { - - String selector = method.getAnnotation(Selector.class).value(); - if(!hasContext) sw.println("Node root = Document.get();"); - - sw.println("return "+wrap(method, "new SelectorEngine().select(\""+selector+"\", root)")+";"); -// sw.println("JSArray n = JSArray.create();"); -// if(!hasContext) { -// sw.println("Node root = Document.get();"); -// } -// -// // add root node as context. -// // TODO: support any context -// sw.println("n.addNode(root);"); -// String q = selector, lq = null; -// Matcher lmode = modeRe.matcher(q); -// Matcher mm = null; -// String mode = ""; -// if (lmode.lookingAt() && notNull(lmode.group(1))) { -// mode = lmode.group(1).replaceAll(trimReStr, "").trim(); -// q = q.replaceFirst("\\Q" + lmode.group(1) + "\\E", ""); -// } -// -// while (notNull(q) && !q.equals(lq)) { -// debug("Doing q=" + q); -// -// lq = q; -// Matcher tm = tagTokenRe.matcher(q); -// if (tm.lookingAt()) { -// if ("#".equals(tm.group(1))) { -// sw.println("n = quickId(n, \"" + mode + "\", root, \"" + tm.group(2) -// + "\");"); -// } else { -// String tagName = tm.group(2); -// tagName = "".equals(tagName) ? "*" : tagName; -// // sw.println("if (n.size() == 0) { n=JSArray.create(); }"); -// String func = ""; -// if ("".equals(mode)) { -// func = "getDescendentNodes"; -// } else if (">".equals(mode)) { -// func = "getChildNodes"; -// } else if ("+".equals(mode)) { -// func = "getSiblingNodes"; -// } else if ("~".equals(mode)) { -// func = "getGeneralSiblingNodes"; -// } else { -// treeLogger.log(TreeLogger.ERROR, "Error parsing selector, combiner " -// + mode + " not recognized in " + selector, null); -// throw new UnableToCompleteException(); -// } -// sw.println("n = " + func + "(n, \"" + tagName + "\");"); -// } -// debug("replacing in q, the value " + tm.group(0)); -// q = q.replaceFirst("\\Q" + tm.group(0) + "\\E", ""); -// } else { -// String func = ""; -// String tagName = "*"; -// if ("".equals(mode)) { -// func = "getDescendentNodes"; -// } else if (">".equals(mode)) { -// func = "getChildNodes"; -// } else if ("+".equals(mode)) { -// func = "getSiblingNodes"; -// } else if ("~".equals(mode)) { -// func = "getGeneralSiblingNodes"; -// } else { -// treeLogger.log(TreeLogger.ERROR, "Error parsing selector, combiner " -// + mode + " not recognized in " + selector, null); -// throw new UnableToCompleteException(); -// } -// sw.println("n = " + func + "(n, \"" + tagName + "\");"); -// } -// -// while (!(mm = modeRe.matcher(q)).lookingAt()) { -// debug("Looking at " + q); -// boolean matched = false; -// for (RuleMatcher rm : matchers) { -// Matcher rmm = rm.re.matcher(q); -// if (rmm.lookingAt()) { -// String res[] = new String[rmm.groupCount()]; -// for (int i = 1; i <= rmm.groupCount(); i++) { -// res[i - 1] = rmm.group(i); -// debug("added param " + res[i - 1]); -// } -// Object[] r = res; -// // inline enum, perhaps type-tightening will allow inlined eval() -// // call -// if (rm.fnTemplate.indexOf("byPseudo") != -1) { -// sw.println("n = Pseudo."+res[0].toUpperCase().replace("-", "_") + -// ".eval(n, \""+res[1]+"\");"); -// } else { -// sw.println(MessageFormat.format(rm.fnTemplate, r)); -// } -// q = q.replaceFirst("\\Q" + rmm.group(0) + "\\E", ""); -// matched = true; -// break; -// } -// } -// if (!matched) { -// treeLogger -// .log(TreeLogger.ERROR, "Error parsing selector at " + q, null); -// throw new UnableToCompleteException(); -// } -// } -// -// if (notNull(mm.group(1))) { -// mode = mm.group(1).replaceAll(trimReStr, ""); -// debug("replacing q=" + q + " this part:" + mm.group(1)); -// q = q.replaceFirst("\\Q" + mm.group(1) + "\\E", ""); -// } -// } -// sw.println("return "+wrap(method, "nodup(n)")+";"); - } - - - static class RuleMatcher { - - public Pattern re; - - public String fnTemplate; - - RuleMatcher(String pat, String fnT) { - this.re = Pattern.compile(pat); - this.fnTemplate = fnT; - } - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorNative.java b/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorNative.java deleted file mode 100644 index e7db5da7..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorNative.java +++ /dev/null @@ -1,32 +0,0 @@ -package gwtquery.rebind; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JMethod; -import com.google.gwt.user.rebind.SourceWriter; - -import gwtquery.client.Selector; - -/** - * - */ -public class SelectorGeneratorNative extends SelectorGeneratorBase { - - protected String getImplSuffix() { - return "Native" + super.getImplSuffix(); - } - - protected void generateMethodBody(SourceWriter sw, JMethod method, - TreeLogger treeLogger, boolean hasContext) - throws UnableToCompleteException { - String selector = method.getAnnotation(Selector.class).value(); - if (!hasContext) { - sw.println("return " - + wrap(method, "querySelectorAll(\"" + selector + "\"") + ");"); - } else { - sw.println("return " - + wrap(method, "querySelectorAll(\"" + selector + "\", root)") - + ");"); - } - } -} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorXPath.java b/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorXPath.java deleted file mode 100644 index d43cfd3e..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/SelectorGeneratorXPath.java +++ /dev/null @@ -1,317 +0,0 @@ -package gwtquery.rebind; - -import com.google.gwt.core.ext.TreeLogger; -import com.google.gwt.core.ext.UnableToCompleteException; -import com.google.gwt.core.ext.typeinfo.JMethod; -import com.google.gwt.user.rebind.SourceWriter; - -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import gwtquery.client.Selector; - -/** - * - */ -public class SelectorGeneratorXPath extends SelectorGeneratorBase { - - private static Pattern cssSelectorRegExp = Pattern.compile( - "^(\\w+)?(#[a-zA-Z_0-9\u00C0-\uFFFF\\-\\_]+|(\\*))?((\\.[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)*)?((\\[\\w+(\\^|\\$|\\*|\\||~)?(=[a-zA-Z_0-9\u00C0-\uFFFF\\s\\-\\_\\.]+)?\\]+)*)?(((:\\w+[a-zA-Z_0-9\\-]*)(\\((odd|even|\\-?\\d*n?((\\+|\\-)\\d+)?|[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+|((\\w*\\.[a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)*)?|(\\[#?\\w+(\\^|\\$|\\*|\\||~)?=?[a-zA-Z_0-9\u00C0-\uFFFF\\s\\-\\_\\.]+\\]+)|(:\\w+[a-zA-Z_0-9\\-]*))\\))?)*)?(>|\\+|~)?"); - - private static Pattern selectorSplitRegExp = Pattern - .compile("(?:\\[[^\\[]*\\]|\\(.*\\)|[^\\s\\+>~\\[\\(])+|[\\+>~]"); - - private String prefix = ""; - - static class SplitRule { - - public String tag; - - public String id; - - public String allClasses; - - public String allAttr; - - public String allPseudos; - - public String tagRelation; - } - - protected String getImplSuffix() { - return "XPath"+super.getImplSuffix(); - } - - protected void generateMethodBody(SourceWriter sw, JMethod method, - TreeLogger treeLogger, boolean hasContext) - throws UnableToCompleteException { - - String selector = method.getAnnotation(Selector.class).value(); - String[] cssRules = selector.replaceAll("\\s*(,)\\s*", "$1").split(","); - String currentRule; - boolean identical = false; - String xPathExpression = "."; - - for (int i = 0; i < cssRules.length; i++) { - currentRule = cssRules[i]; - - if (i > 0) { - identical = false; - for (int x = 0, xl = i; x < xl; x++) { - if (cssRules[i].equals(cssRules[x])) { - identical = true; - break; - } - } - if (identical) { - continue; - } - } - - ArrayList cssSelectors = new ArrayList(); - Matcher selm = selectorSplitRegExp.matcher(currentRule); - while (selm.find()) { - cssSelectors.add(selm.group(0)); - } - - Matcher cssSelector; - for (int j = 0, jl = cssSelectors.size(); j < jl; j++) { - cssSelector = cssSelectorRegExp.matcher(cssSelectors.get(j)); - if (cssSelector.matches()) { - - SplitRule splitRule = new SplitRule(); - splitRule.tag = prefix + ((!notNull(cssSelector.group(1)) || "*" - .equals(cssSelector.group(3))) ? "*" : cssSelector.group(1)); - splitRule.id = (!"*".equals(cssSelector.group(3))) ? cssSelector - .group(2) : null; - splitRule.allClasses = cssSelector.group(4); - splitRule.allAttr = cssSelector.group(6); - splitRule.allPseudos = cssSelector.group(10); - splitRule.tagRelation = cssSelector.group(22); - if (notNull(splitRule.tagRelation)) { - if (">".equals(splitRule.tagRelation)) { - xPathExpression += "/child::"; - } else if ("+".equals(splitRule.tagRelation)) { - xPathExpression += "/following-sibling::*[1]/self::"; - } else if ("~".equals(splitRule.tagRelation)) { - xPathExpression += "/following-sibling::"; - } - } else { - xPathExpression += - (j > 0 && cssSelectors.get(j - 1).matches("(>|\\+|~)")) - ? splitRule.tag : ("/descendant::" + splitRule.tag); - } - - if (notNull(splitRule.id)) { - xPathExpression += "[@id = '" + splitRule.id.replaceAll("^#", "") - + "']"; - } - if (notNull(splitRule.allClasses)) { - xPathExpression += splitRule.allClasses.replaceAll( - "\\.([a-zA-Z_0-9\u00C0 -\uFFFF\\-_]+)", - "[contains(concat(' ', @class, ' '), ' $1 ')]"); - } - if (notNull(splitRule.allAttr)) { - xPathExpression += attrToXPath(splitRule.allAttr, - "(\\w+)(\\^|\\$|\\*|\\||~)?=?([a-zA-Z_0-9\u00C0-\uFFFF\\s\\-_\\.]+)?"); - } - if (notNull(splitRule.allPseudos)) { - Pattern pseudoSplitRegExp = Pattern - .compile(":(\\w[a-zA-Z_0-9\\-]*)(\\(([^\\)]+)\\))?"); - Matcher m = Pattern - .compile("(:\\w+[a-zA-Z_0-9\\-]*)(\\([^\\)]+\\))?") - .matcher(splitRule.allPseudos); - while (m.find()) { - String str = m.group(0); - Matcher pseudo = pseudoSplitRegExp - .matcher(str == null ? "" : str); - if (pseudo.matches()) { - String pseudoClass = notNull(pseudo.group(1)) ? pseudo.group(1) - .toLowerCase() : null; - String pseudoValue = notNull(pseudo.group(3)) ? pseudo.group(3) - : null; - String xpath = pseudoToXPath(splitRule.tag, pseudoClass, - pseudoValue); - if (notNull(xpath)) { - xPathExpression += "[" + xpath + "]"; - } - } - } - } - } - } - } - - if (!hasContext) { - sw.println("Node root = Document.get();"); - } - sw.println("return "+wrap(method, "SelectorEngine.xpathEvaluate(\"" - + xPathExpression + "\", root)")+";"); - } - - static class Sequence { - - public int start; - - public int max; - - public int add; - - public int modVal; - } - - private String pseudoToXPath(String tag, String pseudoClass, - String pseudoValue) { - tag = pseudoClass.matches(".*\\-child$") ? "*" : tag; - String xpath = ""; - String pseudo[] = pseudoClass.split("-"); - if ("first".equals(pseudo[0])) { - xpath = "not(preceding-sibling::" + tag + ")"; - } else if ("last".equals(pseudo[0])) { - xpath = "not(following-sibling::" + tag + ")"; - } else if ("only".equals(pseudo[0])) { - xpath = "not(preceding-sibling::" + tag + " or following-sibling::" + tag - + ")"; - } else if ("nth".equals(pseudo[0])) { - if (!pseudoValue.matches("^n$")) { - String position = (("last".equals(pseudo[1])) - ? "(count(following-sibling::" : "(count(preceding-sibling::") + tag - + ") + 1)"; - Sequence sequence = getSequence(pseudoValue); - if (sequence != null) { - if (sequence.start == sequence.max) { - xpath = position + " = " + sequence.start; - } else { - xpath = position + " mod " + sequence.add + " = " + sequence.modVal - + ((sequence.start > 1) ? " and " + position + " >= " + sequence - .start : "") + ((sequence.max > 0) ? " and " + position + " <= " - + sequence.max : ""); - } - } - } - } else if ("empty".equals(pseudo[0])) { - xpath = "count(child::*) = 0 and string-length(text()) = 0"; - } else if ("contains".equals(pseudo[0])) { - xpath = "contains(., '" + pseudoValue + "')"; - } else if ("enabled".equals(pseudo[0])) { - xpath = "not(@disabled)"; - } else if ("disabled".equals(pseudo[0])) { - xpath = "@disabled"; - } else if ("checked".equals(pseudo[0])) { - xpath = "@checked='checked'"; // Doesn't work in Opera 9.24 - } else if ("not".equals(pseudo[0])) { - if (pseudoValue.matches("^(:a-zA-Z_0-9+[a-zA-Z_0-9\\-]*)$")) { - xpath = "not(" + pseudoToXPath(tag, pseudoValue.substring(1), "") + ")"; - } else { - pseudoValue = pseudoValue.replaceAll( - "^\\[#([a-zA-Z_0-9\u00C0-\uFFFF\\-\\_]+)\\]$", "[id=$1]"); - String notSelector = pseudoValue - .replaceFirst("^(a-zA-Z_0-9+)", "self::$1"); - notSelector = notSelector.replaceAll( - "^\\.([a-zA-Z_0-9\u00C0-\uFFFF\\-_]+)", - "contains(concat(' ', @class, ' '), ' $1 ')"); - notSelector = attrToXPath(notSelector, - "\\[(a-zA-Z_0-9+)(\\^|\\$|\\*|\\||~)?=?([a-zA-Z_0-9\u00C0-\uFFFF\\s\\-_\\.]+)?\\]"); - xpath = "not(" + notSelector + ")"; - } - } else { - xpath = "@" + pseudoClass + "='" + pseudoValue + "'"; - } - return xpath; - } - - private String attrToXPath(String notSelector, String pattern) { - Pattern p = Pattern.compile(pattern); - Matcher m = p.matcher(notSelector); - m.reset(); - boolean result = m.find(); - if (result) { - StringBuffer sb = new StringBuffer(); - do { - String replacement; - String p1 = m.group(1); - String p2 = m.group(2); - String p3 = m.group(3); - if ("^".equals(p2)) { - replacement = "starts-with(@" + p1 + ", '" + p3 + "')"; - } else if ("$".equals(p2)) { - replacement = "substring(@" + p1 + ", (string-length(@" + p1 + ") - " - + (p3.length() - 1) + "), " + p3.length() + ") = '" + p3 + "'"; - } else if ("*".equals(p2)) { - replacement = "contains(concat(' ', @" + p1 + ", ' '), '" + p3 + "')"; - } else if ("|".equals(p2)) { - replacement = "(@" + p1 + "='" + p3 + "' or starts-with(@" + p1 - + ", '" + p3 + "-'))"; - } else if ("~".equals(p2)) { - replacement = "contains(concat(' ', @" + p1 + ", ' '), ' " + p3 - + " ')"; - } else { - replacement = "@" + p1 + (notNull(p3) ? "='" + p3 + "'" : ""); - } - debug("p1=" + p1 + " p2=" + p2 + " p3=" + p3 + " replacement is " - + replacement); - m.appendReplacement(sb, replacement.replace("$", "\\$")); - result = m.find(); - } while (result); - m.appendTail(sb); - return sb.toString(); - } - return notSelector; - } - - private Sequence getSequence(String expression) { - int start = 0, add = 2, max = -1, modVal = -1; - Pattern expressionRegExp = Pattern.compile( - "^((odd|even)|([1-9]\\d*)|((([1-9]\\d*)?)n([\\+\\-]\\d+)?)|(\\-(([1-9]\\d*)?)n\\+(\\d+)))$"); - Matcher pseudoValue = expressionRegExp.matcher(expression); - if (!pseudoValue.matches()) { - return null; - } else { - if (notNull(pseudoValue.group(2))) { // odd or even - start = ("odd".equals(pseudoValue.group(2))) ? 1 : 2; - modVal = (start == 1) ? 1 : 0; - } else if (notNull(pseudoValue.group(3))) { // single digit - start = Integer.parseInt(pseudoValue.group(3), 10); - add = 0; - max = start; - } else if (notNull(pseudoValue.group(4))) { // an+b - add = notNull(pseudoValue.group(6)) ? getInt(pseudoValue.group(6), 1) - : 1; - start = notNull(pseudoValue.group(7)) ? getInt(pseudoValue.group(7), 0) - : 0; - while (start < 1) { - start += add; - } - modVal = (start > add) ? (start - add) % add - : ((start == add) ? 0 : start); - } else if (notNull(pseudoValue.group(8))) { // -an+b - add = notNull(pseudoValue.group(10)) ? Integer - .parseInt(pseudoValue.group(10), 10) : 1; - start = max = Integer.parseInt(pseudoValue.group(10), 10); - while (start > add) { - start -= add; - } - modVal = (max > add) ? (max - add) % add : ((max == add) ? 0 : max); - } - } - Sequence s = new Sequence(); - s.start = start; - s.add = add; - s.max = max; - s.modVal = modVal; - return s; - } - - private int getInt(String s, int i) { - try { - if (s.startsWith("+")) { - s = s.substring(1); - } - return Integer.parseInt(s); - } catch (Exception e) { - debug("error parsing Integer " + s); - return i; - } - } -} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorJSGEBCN.java b/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorJSGEBCN.java deleted file mode 100644 index a287303a..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorJSGEBCN.java +++ /dev/null @@ -1,12 +0,0 @@ -package gwtquery.rebind.gebcn; - -import gwtquery.rebind.SelectorGeneratorJS; - -/** - */ -public class SelectorGeneratorJSGEBCN extends SelectorGeneratorJS { - - protected boolean hasGetElementsByClassName() { - return true; - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorNativeGEBCN.java b/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorNativeGEBCN.java deleted file mode 100644 index 04226dbd..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorNativeGEBCN.java +++ /dev/null @@ -1,13 +0,0 @@ -package gwtquery.rebind.gebcn; - -import gwtquery.rebind.SelectorGeneratorNative; - -/** - * - */ -public class SelectorGeneratorNativeGEBCN extends SelectorGeneratorNative { - - protected boolean hasGetElementsByClassName() { - return true; - } -} diff --git a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorXPathGEBCN.java b/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorXPathGEBCN.java deleted file mode 100644 index 9bcce9ce..00000000 --- a/gwtquery-core/src/main/java/gwtquery/rebind/gebcn/SelectorGeneratorXPathGEBCN.java +++ /dev/null @@ -1,12 +0,0 @@ -package gwtquery.rebind.gebcn; - -import gwtquery.rebind.SelectorGeneratorXPath; - -/** - */ -public class SelectorGeneratorXPathGEBCN extends SelectorGeneratorXPath { - - protected boolean hasGetElementsByClassName() { - return true; - } -} -- cgit v1.2.3