예제 #1
0
    /** Add a {@link BindFunction} for a specific css selector. */
    public void addBindFunctionForSelector(String cssSelector, BindFunction f) {
      JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
      if (bindFunctions == null) {
        bindFunctions = JsObjectArray.create();
        bindFunctionBySelector.put(cssSelector, bindFunctions);
      }

      bindFunctions.add(f);
    }
예제 #2
0
 /** Return true if the element is listening for the given eventBit or eventName. */
 public boolean hasHandlers(int eventBits, String eventName) {
   for (int i = 0, j = elementEvents.length(); i < j; i++) {
     BindFunction function = elementEvents.get(i);
     if (function.hasEventType(eventBits) || function.isTypeOf(eventName)) {
       return true;
     }
   }
   return false;
 }
예제 #3
0
  private void resultsBuild() {

    selectItems = new SelectParser().parse(selectElement);

    if (isMultiple && choices > 0) {
      searchChoices.find("li." + css.searchChoice()).remove();
      choices = 0;
    } else if (!isMultiple) {
      selectedItem.addClass(css.chznDefault()).find("span").text(defaultText);

      if (selectElement.getOptions().getLength() <= options.getDisableSearchThreshold()) {
        container.addClass(css.chznContainerSingleNoSearch());
      } else {
        container.removeClass(css.chznContainerSingleNoSearch());
      }
    }

    SafeHtmlBuilder content = new SafeHtmlBuilder();

    for (int i = 0; i < selectItems.length(); i++) {
      SelectItem item = selectItems.get(i);

      if (item.isGroup()) {
        SafeHtml result = resultAddGroup((GroupItem) item);
        if (result != null) {
          content.append(result);
        }
      } else {
        OptionItem optionItem = (OptionItem) item;

        if (optionItem.isEmpty()) {
          continue;
        }

        SafeHtml optionHtml = resultAddOption(optionItem);
        if (optionHtml != null) {
          content.append(optionHtml);
        }

        if (optionItem.isSelected() && isMultiple) {
          choiceBuild(optionItem);
        } else if (optionItem.isSelected() && !isMultiple) {
          selectedItem.removeClass(css.chznDefault()).find("span").text(optionItem.getText());
          if (allowSingleDeselect) {
            singleDeselectControlBuild();
          }
        }
      }
    }
    searchFieldDisabled();
    showSearchFieldDefault();
    searchFieldScale();

    searchResults.html(content.toSafeHtml().asString());
  }
예제 #4
0
 /** Dispatch an event in this element but changing the type, it's useful for special events. */
 public void dispatchEvent(Event event, String eventName) {
   int etype = Event.getTypeInt(eventName);
   Object[] handlerData = $(element).data(EVENT_DATA);
   for (int i = 0, l = elementEvents.length(); i < l; i++) {
     BindFunction listener = elementEvents.get(i);
     String namespace = JsUtils.prop(event, "namespace");
     boolean matchEV =
         listener != null && (listener.hasEventType(etype) || listener.isTypeOf(eventName));
     boolean matchNS =
         matchEV && (isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace));
     if (matchEV && matchNS) {
       if (!listener.fire(event, handlerData)) {
         event.stopPropagation();
         event.preventDefault();
       }
     }
   }
 }
예제 #5
0
 private JsNodeArray getNotPseudo(
     JsNodeArray previousMatch, String pseudoValue, JsNodeArray matchingElms) {
   if (new JsRegexp("(:\\w+[\\w\\-]*)$").test(pseudoValue)) {
     matchingElms =
         subtractArray(
             previousMatch, getElementsByPseudo(previousMatch, pseudoValue.substring(1), ""));
   } else {
     pseudoValue = pseudoValue.replace("^\\[#([\\w\\u00C0-\\uFFFF\\-\\_]+)\\]$", "[id=$1]");
     JsObjectArray<String> notTag = new JsRegexp("^(\\w+)").exec(pseudoValue);
     JsObjectArray<String> notClass =
         new JsRegexp("^\\.([\\w\u00C0-\uFFFF\\-_]+)").exec(pseudoValue);
     JsObjectArray<String> notAttr =
         new JsRegexp("\\[(\\w+)(\\^|\\$|\\*|\\||~)?=?([\\w\\u00C0-\\uFFFF\\s\\-_\\.]+)?\\]")
             .exec(pseudoValue);
     JsRegexp notRegExp =
         new JsRegexp(
             "(^|\\s)"
                 + (JsUtils.truth(notTag)
                     ? notTag.get(1)
                     : JsUtils.truth(notClass) ? notClass.get(1) : "")
                 + "(\\s|$)",
             "i");
     if (JsUtils.truth(notAttr)) {
       String notAttribute =
           JsUtils.truth(notAttr.get(3)) ? notAttr.get(3).replace("\\.", "\\.") : null;
       String notMatchingAttrVal = attrToRegExp(notAttribute, notAttr.get(2));
       notRegExp = new JsRegexp(notMatchingAttrVal, "i");
     }
     for (int v = 0, vlen = previousMatch.size(); v < vlen; v++) {
       Element notElm = previousMatch.getElement(v);
       Element addElm = null;
       if (JsUtils.truth(notTag) && !notRegExp.test(notElm.getNodeName())) {
         addElm = notElm;
       } else if (JsUtils.truth(notClass) && !notRegExp.test(notElm.getClassName())) {
         addElm = notElm;
       } else if (JsUtils.truth(notAttr)) {
         String att = getAttr(notElm, notAttr.get(1));
         if (!JsUtils.truth(att) || !notRegExp.test(att)) {
           addElm = notElm;
         }
       }
       if (JsUtils.truth(addElm) && !isAdded(addElm)) {
         setAdded(addElm, true);
         matchingElms.addNode(addElm);
       }
     }
   }
   return matchingElms;
 }
예제 #6
0
 public void bind(
     int eventbits,
     String namespace,
     String eventName,
     Object data,
     Function function,
     int times) {
   sink(eventbits, eventName);
   elementEvents.add(new BindFunction(eventbits, eventName, namespace, function, data, times));
 }
예제 #7
0
  public void unbind(int eventbits, String namespace, String eventName, Function f) {
    JsObjectArray<BindFunction> newList = JsObjectArray.createArray().cast();
    for (int i = 0; i < elementEvents.length(); i++) {
      BindFunction listener = elementEvents.get(i);
      boolean matchNS = isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace);
      boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits);
      boolean matchEVN = matchEV || listener.isTypeOf(eventName);
      boolean matchFC = f == null || listener.isEquals(f);

      if (matchNS && matchEV && matchEVN && matchFC) {
        int currentEventbits = listener.unsink(eventbits);
        if (currentEventbits == 0) {
          // the BindFunction doesn't listen anymore on any events
          continue;
        }
      }
      newList.add(listener);
    }
    elementEvents = newList;
  }
예제 #8
0
  private void liveBitlessEvent(
      String eventName, String nameSpace, String cssSelector, Object data, Function... funcs) {
    LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName);

    if (liveBindFunction == null) {
      liveBindFunction = new LiveBindFunction(eventName, "live", data);
      sink(BITLESS, eventName);
      elementEvents.add(liveBindFunction);
      liveBindFunctionByEventName.put(eventName, liveBindFunction);
    }

    for (Function f : funcs) {
      liveBindFunction.addBindFunctionForSelector(
          cssSelector, new BindFunction(BITLESS, eventName, nameSpace, f, data, -1));
    }
  }
예제 #9
0
  private void resultSelect(Event e) {
    if (resultHighlight != null) {
      GQuery high = resultHighlight;
      String highId = high.attr("id");

      resultClearHighlight();

      if (isMultiple) {
        resultDeactivate(high);
      } else {
        searchResults.find("." + css.resultSelected()).removeClass(css.resultSelected());
        resultSingleSelected = high;
        selectedItem.removeClass(css.chznDefault());
      }

      high.addClass(css.resultSelected());

      int position = Integer.parseInt(highId.substring(highId.lastIndexOf("_") + 1));
      OptionItem item = (OptionItem) selectItems.get(position);
      item.setSelected(true);
      selectElement.getOptions().getItem(item.getOptionsIndex()).setSelected(true);

      if (isMultiple) {
        choiceBuild(item);
      } else {
        selectedItem.find("span").text(item.getText());
        if (allowSingleDeselect) {
          singleDeselectControlBuild();
        }
      }

      if (!e.getMetaKey() || !isMultiple) {
        resultsHide();
      }

      searchField.val("");

      if (isMultiple || currentValue == null || !currentValue.equals($selectElement.val())) {
        String value = selectElement.getOptions().getItem(item.getOptionsIndex()).getValue();
        fireEvent(new ChosenChangeEvent(value, this));
      }

      currentValue = $selectElement.val();

      searchFieldScale();
    }
  }
예제 #10
0
  private void resultDeselect(int index) {
    OptionItem item = (OptionItem) selectItems.get(index);

    item.setSelected(false);

    // select option in original element
    OptionElement option = selectElement.getOptions().getItem(item.getOptionsIndex());
    option.setSelected(false);

    $("#" + containerId + "_o_" + index)
        .removeClass(css.resultSelected())
        .addClass(css.activeResult())
        .show();

    resultClearHighlight();
    winnowResults();

    fireEvent(new ChosenChangeEvent(option.getValue(), false, this));

    searchFieldScale();
  }
예제 #11
0
  private void liveBitEvent(
      int eventbits, String nameSpace, String cssSelector, Object data, Function... funcs) {
    for (int i = 0; i < 28; i++) {
      int event = (int) Math.pow(2, i);
      if ((eventbits & event) == event) {

        // is a LiveBindFunction already attached for this kind of event
        LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(event);
        if (liveBindFunction == null) {
          liveBindFunction = new LiveBindFunction(event, "live", data);
          sink(eventbits, null);
          elementEvents.add(liveBindFunction);
          liveBindFunctionByEventType.put(event, liveBindFunction);
        }

        for (Function f : funcs) {
          liveBindFunction.addBindFunctionForSelector(
              cssSelector, new BindFunction(event, null, nameSpace, f, data, -1));
        }
      }
    }
  }
예제 #12
0
    /** Remove the BindFunction associated to this cssSelector. */
    public void removeBindFunctionForSelector(String cssSelector, String nameSpace) {
      if (nameSpace == null) {
        bindFunctionBySelector.delete(cssSelector);
      } else {
        JsObjectArray<BindFunction> functions = bindFunctionBySelector.get(cssSelector);

        if (functions == null || functions.length() == 0) {
          return;
        }
        JsObjectArray<BindFunction> newFunctions = JsObjectArray.create();

        for (int i = 0; i < functions.length(); i++) {
          BindFunction f = functions.get(i);
          if (nameSpace != null && !nameSpace.equals(f.nameSpace)) {
            newFunctions.add(f);
          }
        }

        bindFunctionBySelector.delete(cssSelector);
        if (newFunctions.length() > 0) {
          bindFunctionBySelector.put(cssSelector, newFunctions);
        }
      }
    }
예제 #13
0
/**
 * This class implements an event queue instance for one Element. The queue instance is configured
 * as the default event listener in GWT.
 *
 * <p>The reference to this queue is stored as a unique variable in the element's DOM.
 *
 * <p>The class takes care of calling the appropriate functions for each browser event and it also
 * calls sinkEvents method.
 */
public class EventsListener implements EventListener {

  /** Used for simulating mouseenter and mouseleave events. */
  private static class MouseSpecialEvent extends DefaultSpecialEvent {
    public MouseSpecialEvent(final String type, String delegateType) {
      super(type, delegateType);
      handler =
          new Function() {
            public boolean f(Event e, Object... arg) {
              EventTarget eventTarget = e.getCurrentEventTarget();
              Element target = eventTarget != null ? eventTarget.<Element>cast() : null;

              EventTarget relatedEventTarget = e.getRelatedEventTarget();
              Element related =
                  relatedEventTarget != null ? relatedEventTarget.<Element>cast() : null;

              if (related == null || (related != target && !GQuery.contains(target, related))) {
                getInstance(target).dispatchEvent(e, type);
              }
              return true;
            };
          };
    }
  }

  /** Utility class to split a list of events with or without namespaces. */
  public static class EventName {
    public final String nameSpace;
    public final String eventName;

    public EventName(String n, String e) {
      nameSpace = n;
      eventName = e;
    }

    public static List<EventName> split(String events) {
      List<EventName> ret = new ArrayList<EventName>();
      String[] parts = events.split("[\\s,]+");
      for (String event : parts) {
        String[] tmp = event.split("\\.", 2);
        String eventName = tmp[0];
        String nameSpace = tmp.length > 1 ? tmp[1] : null;
        ret.add(new EventName(nameSpace, eventName));
      }
      return ret;
    }
  }

  /** The function used per each element event. */
  private static class BindFunction {
    Object data;
    Function function;
    String nameSpace;
    int times;
    int type;
    String eventName;

    BindFunction(
        int type, String eventName, String nameSpace, Function function, Object data, int times) {
      this.times = times;
      this.eventName = eventName;
      this.type = type;
      this.function = function;
      this.data = data;
      this.nameSpace = nameSpace != null ? nameSpace : "";
    }

    public boolean fire(Event event, Object[] eventData) {
      if (times != 0) {
        times--;
        Object[] arguments;
        eventData = eventData != null ? eventData : new Object[0];
        // The argument of the function will be first the data attached to the handler then the
        // data attached to the event.
        if (data != null) {
          Object[] handlerData = data.getClass().isArray() ? (Object[]) data : new Object[] {data};
          arguments = new Object[handlerData.length + eventData.length];
          System.arraycopy(handlerData, 0, arguments, 0, handlerData.length);
          System.arraycopy(eventData, 0, arguments, handlerData.length, eventData.length);
        } else {
          arguments = eventData;
        }
        // FIXME(manolo): figure out when this is null, and fix or comment it.
        if (function != null) {
          return function.fe(event, arguments);
        }
      }
      return true;
    }

    public boolean hasEventType(int etype) {
      return type != BITLESS && etype != BITLESS && (type & etype) != 0;
    }

    public boolean isTypeOf(String eName) {
      return eventName != null && eventName.equalsIgnoreCase(eName);
    }

    /**
     * Remove a set of events. The bind function will not be fire anymore for those events
     *
     * @param eventBits the set of events to unsink
     */
    public int unsink(int eventBits) {
      if (eventBits <= 0) {
        type = 0;
      } else {
        type = type & ~eventBits;
      }

      return type;
    }

    @Override
    public String toString() {
      return "bind function for event type " + (eventName != null ? eventName : "" + type);
    }

    public boolean isEquals(Function f) {
      assert f != null : "function f cannot be null";
      return f.equals(function);
    }
  }

  /** {@link BindFunction} used for live() method. */
  private static class LiveBindFunction extends BindFunction {

    JsNamedArray<JsObjectArray<BindFunction>> bindFunctionBySelector;

    LiveBindFunction(String eventName, String namespace, Object data) {
      super(BITLESS, eventName, namespace, null, data, -1);
      clean();
    }

    LiveBindFunction(int type, String namespace, Object data) {
      super(type, null, namespace, null, data, -1);
      clean();
    }

    /** Add a {@link BindFunction} for a specific css selector. */
    public void addBindFunctionForSelector(String cssSelector, BindFunction f) {
      JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
      if (bindFunctions == null) {
        bindFunctions = JsObjectArray.create();
        bindFunctionBySelector.put(cssSelector, bindFunctions);
      }

      bindFunctions.add(f);
    }

    public void clean() {
      bindFunctionBySelector = JsNamedArray.create();
    }

    @Override
    public boolean fire(Event event, Object[] eventData) {
      if (isEmpty()) {
        return true;
      }

      // first element where the event was fired
      Element eventTarget = getEventTarget(event);
      // last element where the event was dispatched on
      Element liveContextElement = getCurrentEventTarget(event);

      if (eventTarget == null || liveContextElement == null) {
        return true;
      }

      // Compute the live selectors which respond to this event type
      List<String> validSelectors = new ArrayList<String>();
      for (String cssSelector : bindFunctionBySelector.keys()) {
        JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
        for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
          BindFunction f = bindFunctions.get(i);
          if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
            validSelectors.add(cssSelector);
            break;
          }
        }
      }

      // Create a structure of elements which matches the selectors
      JsNamedArray<NodeList<Element>> realCurrentTargetBySelector =
          $(eventTarget).closest(validSelectors.toArray(new String[0]), liveContextElement);
      // nothing matches the selectors
      if (realCurrentTargetBySelector.length() == 0) {
        return true;
      }

      Element stopElement = null;
      GqEvent gqEvent = GqEvent.create(event);
      for (String cssSelector : realCurrentTargetBySelector.keys()) {
        JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
        for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
          BindFunction f = bindFunctions.get(i);
          if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
            NodeList<Element> n = realCurrentTargetBySelector.get(cssSelector);
            for (int j = 0; n != null && j < n.getLength(); j++) {
              Element element = n.getItem(j);
              // When an event fired in an element stops bubbling we have to fire also all other
              // handlers for this element bound to this element
              if (stopElement == null || element.equals(stopElement)) {
                gqEvent.setCurrentElementTarget(element);
                // data
                eventData = $(element).data(EVENT_DATA);
                if (!f.fire(gqEvent, eventData)) {
                  stopElement = element;
                }
              }
            }
          }
        }
      }

      // trick to reset the right currentTarget on the original event on ie
      gqEvent.setCurrentElementTarget(liveContextElement);
      return stopElement == null;
    }

    /** Remove the BindFunction associated to this cssSelector. */
    public void removeBindFunctionForSelector(String cssSelector, String nameSpace) {
      if (nameSpace == null) {
        bindFunctionBySelector.delete(cssSelector);
      } else {
        JsObjectArray<BindFunction> functions = bindFunctionBySelector.get(cssSelector);

        if (functions == null || functions.length() == 0) {
          return;
        }
        JsObjectArray<BindFunction> newFunctions = JsObjectArray.create();

        for (int i = 0; i < functions.length(); i++) {
          BindFunction f = functions.get(i);
          if (nameSpace != null && !nameSpace.equals(f.nameSpace)) {
            newFunctions.add(f);
          }
        }

        bindFunctionBySelector.delete(cssSelector);
        if (newFunctions.length() > 0) {
          bindFunctionBySelector.put(cssSelector, newFunctions);
        }
      }
    }

    /**
     * Tell if no {@link BindFunction} are linked to this object.
     *
     * @return
     */
    public boolean isEmpty() {
      return bindFunctionBySelector.length() == 0;
    }

    @Override
    public String toString() {
      return "live bind function for selector " + bindFunctionBySelector.<JsCache>cast().tostring();
    }

    /**
     * Return the element whose the listener fired last. It represent the context element where the
     * {@link LiveBindFunction} was binded.
     */
    private Element getCurrentEventTarget(Event e) {
      EventTarget currentEventTarget = e.getCurrentEventTarget();

      if (!Element.is(currentEventTarget)) {
        return null;
      }

      return Element.as(currentEventTarget);
    }

    /** Return the element that was the actual target of the element. */
    private Element getEventTarget(Event e) {
      EventTarget eventTarget = e.getEventTarget();

      if (!Element.is(eventTarget)) {
        return null;
      }

      return Element.as(eventTarget);
    }
  }

  public static final String EVENT_DATA = "___event_datas";
  public static final int BITLESS = -1;

  public static String MOUSEENTER = "mouseenter";
  public static String MOUSELEAVE = "mouseleave";

  public static Map<String, SpecialEvent> special;

  static {
    // Register some special events which already exist in jQuery
    special = new HashMap<String, SpecialEvent>();
    special.put(MOUSEENTER, new MouseSpecialEvent(MOUSEENTER, "mouseover"));
    special.put(MOUSELEAVE, new MouseSpecialEvent(MOUSELEAVE, "mouseout"));
  }

  public static void clean(Element e) {
    EventsListener ret = getGQueryEventListener(e);
    if (ret != null) {
      ret.clean();
    }
  }

  public static EventsListener getInstance(Element e) {
    EventsListener ret = getGQueryEventListener(e);
    return ret != null ? ret : new EventsListener(e);
  }

  /**
   * We have to set the gQuery event listener to the element again when the element is a widget,
   * because when GWT detaches a widget it removes the event listener.
   */
  public static void rebind(Element e) {
    EventsListener ret = getGQueryEventListener(e);
    if (ret != null) {
      DOM.setEventListener((com.google.gwt.user.client.Element) e, ret);
    }
  }

  private static native void cleanGQListeners(Element elem) /*-{
    if (elem.__gwtlistener) {
      @com.google.gwt.user.client.DOM::setEventListener(*)(elem, elem.__gwtlistener);
    }
    elem.__gwtlistener = elem.__gqueryevent = elem.__gquery = null;
  }-*/;

  private static native EventsListener getGQueryEventListener(Element elem) /*-{
    return elem.__gqueryevent;
  }-*/;

  private static native EventListener getGwtEventListener(Element elem) /*-{
    return elem.__gwtlistener;
  }-*/;

  private static native void init(Element elem, EventsListener gqevent) /*-{
    elem.__gwtlistener = @com.google.gwt.user.client.DOM::getEventListener(*)(elem);
    elem.__gqueryevent = gqevent;
    // Someone has reported that in IE the init can be called multiple times
    // causing a loop. We need some test to demonstrate this behaviour though.
    // Anyway we check this condition to avoid looping
    if (elem.__gwtlistener == gqevent) elem.__gwtlistener = null;
  }-*/;

  private static native void sinkBitlessEvent(Element elem, String name) /*-{
    if (!elem.__gquery)
      elem.__gquery = [];
    if (elem.__gquery[name])
      return;
    elem.__gquery[name] = true;

    var handle = function(event) {
      elem.__gqueryevent.@com.google.gwt.query.client.plugins.events.EventsListener::onBrowserEvent(Lcom/google/gwt/user/client/Event;)(event);
    };

    if (elem.addEventListener)
      elem.addEventListener(name, handle, true);
    else
      elem.attachEvent("on" + name, handle);
  }-*/;

  int eventBits = 0;
  double lastEvnt = 0;
  String lastType = "";

  private Element element;
  private JsObjectArray<BindFunction> elementEvents = JsObjectArray.createArray().cast();
  private JsMap<Integer, LiveBindFunction> liveBindFunctionByEventType = JsMap.create();
  private JsMap<String, LiveBindFunction> liveBindFunctionByEventName = JsMap.create();

  private EventsListener(Element element) {
    this.element = element;
    init(element, this);
  }

  public void bind(int eventbits, final Object data, Function... funcs) {
    bind(eventbits, null, data, funcs);
  }

  public void bind(int eventbits, final Object data, final Function function, int times) {
    bind(eventbits, null, null, data, function, times);
  }

  public void bind(int eventbits, String name, final Object data, Function... funcs) {
    for (Function function : funcs) {
      bind(eventbits, name, null, data, function, -1);
    }
  }

  public void bind(int eventbits, String namespace, Object data, Function function, int times) {
    bind(eventbits, namespace, null, data, function, times);
  }

  public void bind(String events, final Object data, Function... funcs) {
    if (funcs.length == 0 || funcs[0] == null) {
      unbind(events, null);
    }

    for (EventName ev : EventName.split(events)) {
      SpecialEvent hook = special.get(ev.eventName);
      boolean bind = hook == null || hook.setup(element) == false;
      for (Function function : funcs) {
        int b = Event.getTypeInt(ev.eventName);
        if (bind) {
          bind(b, ev.nameSpace, ev.eventName, data, function, -1);
        }
        if (hook != null) {
          hook.add(element, ev.eventName, ev.nameSpace, data, function);
        }
      }
    }
  }

  public void bind(
      int eventbits,
      String namespace,
      String eventName,
      Object data,
      Function function,
      int times) {
    sink(eventbits, eventName);
    elementEvents.add(new BindFunction(eventbits, eventName, namespace, function, data, times));
  }

  public void die(String events, String cssSelector) {
    for (EventName ev : EventName.split(events)) {
      SpecialEvent hook = special.get(ev.eventName);
      boolean unbind = hook == null || hook.tearDown(element) == false;
      if (unbind) {
        die(Event.getTypeInt(ev.eventName), ev.nameSpace, ev.eventName, cssSelector);
      }
      if (hook != null) {
        hook.remove(element, ev.eventName, ev.nameSpace, null);
      }
    }
  }

  public void die(int eventbits, String nameSpace, String eventName, String cssSelector) {
    if (eventbits <= 0) {
      if (eventName != null && eventName.length() > 0) {
        LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName);
        maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eventName, nameSpace);
      } else {
        // if eventbits == -1 and eventName is null, remove all event handlers for this selector
        for (String k : liveBindFunctionByEventType.keys()) {
          int bits = Integer.parseInt(k);
          LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(bits);
          maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, bits, null, nameSpace);
        }

        for (String k : liveBindFunctionByEventName.keys()) {
          int realKey = Integer.parseInt(k);
          LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(realKey);
          if (liveBindFunction != null) {
            String eName = liveBindFunction.eventName;
            maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eName, nameSpace);
          }
        }
      }
    } else {
      LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(eventbits);
      maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, eventbits, null, nameSpace);
    }
  }

  private void maybeRemoveLiveBindFunction(
      LiveBindFunction liveBindFunction,
      String cssSelector,
      int eventbits,
      String eventName,
      String nameSpace) {
    if (liveBindFunction != null) {
      liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace);
      if (liveBindFunction.isEmpty()) {
        if (eventbits != BITLESS) {
          liveBindFunctionByEventType.remove(eventbits);
        } else {
          liveBindFunctionByEventName.remove(eventName);
        }
      }
    }
  }

  /** Dispatch an event in this element. */
  public void dispatchEvent(Event event) {
    dispatchEvent(event, event.getType());
  }

  /** Dispatch an event in this element but changing the type, it's useful for special events. */
  public void dispatchEvent(Event event, String eventName) {
    int etype = Event.getTypeInt(eventName);
    Object[] handlerData = $(element).data(EVENT_DATA);
    for (int i = 0, l = elementEvents.length(); i < l; i++) {
      BindFunction listener = elementEvents.get(i);
      String namespace = JsUtils.prop(event, "namespace");
      boolean matchEV =
          listener != null && (listener.hasEventType(etype) || listener.isTypeOf(eventName));
      boolean matchNS =
          matchEV && (isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace));
      if (matchEV && matchNS) {
        if (!listener.fire(event, handlerData)) {
          event.stopPropagation();
          event.preventDefault();
        }
      }
    }
  }

  /**
   * Return the original gwt EventListener associated with this element, before gquery replaced it
   * to introduce its own event handler.
   */
  public EventListener getOriginalEventListener() {
    return getGwtEventListener(element);
  }

  public void live(String events, String cssSelector, Object data, Function... funcs) {
    for (EventName ev : EventName.split(events)) {
      SpecialEvent hook = special.get(ev.eventName);
      boolean bind = hook == null || hook.setup(element) == false;
      for (Function function : funcs) {
        int b = Event.getTypeInt(ev.eventName);
        if (bind) {
          live(b, ev.nameSpace, ev.eventName, cssSelector, data, function);
        }
        if (hook != null) {
          hook.add(element, ev.eventName, ev.nameSpace, data, function);
        }
      }
    }
  }

  public void live(
      int eventbits,
      String nameSpace,
      String eventName,
      String cssSelector,
      Object data,
      Function... funcs) {
    if (eventbits != BITLESS) {
      liveBitEvent(eventbits, nameSpace, cssSelector, data, funcs);
    } else {
      liveBitlessEvent(eventName, nameSpace, cssSelector, data, funcs);
    }
  }

  private void liveBitlessEvent(
      String eventName, String nameSpace, String cssSelector, Object data, Function... funcs) {
    LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName);

    if (liveBindFunction == null) {
      liveBindFunction = new LiveBindFunction(eventName, "live", data);
      sink(BITLESS, eventName);
      elementEvents.add(liveBindFunction);
      liveBindFunctionByEventName.put(eventName, liveBindFunction);
    }

    for (Function f : funcs) {
      liveBindFunction.addBindFunctionForSelector(
          cssSelector, new BindFunction(BITLESS, eventName, nameSpace, f, data, -1));
    }
  }

  private void liveBitEvent(
      int eventbits, String nameSpace, String cssSelector, Object data, Function... funcs) {
    for (int i = 0; i < 28; i++) {
      int event = (int) Math.pow(2, i);
      if ((eventbits & event) == event) {

        // is a LiveBindFunction already attached for this kind of event
        LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(event);
        if (liveBindFunction == null) {
          liveBindFunction = new LiveBindFunction(event, "live", data);
          sink(eventbits, null);
          elementEvents.add(liveBindFunction);
          liveBindFunctionByEventType.put(event, liveBindFunction);
        }

        for (Function f : funcs) {
          liveBindFunction.addBindFunctionForSelector(
              cssSelector, new BindFunction(event, null, nameSpace, f, data, -1));
        }
      }
    }
  }

  public void onBrowserEvent(Event event) {
    double now = Duration.currentTimeMillis();
    // Workaround for Issue_20
    if (lastType.equals(event.getType())
        && now - lastEvnt < 10
        && "body".equalsIgnoreCase(element.getTagName())) {
      return;
    }
    lastEvnt = now;
    lastType = event.getType();

    // Execute the original Gwt listener
    if (getOriginalEventListener() != null && getOriginalEventListener() != this) {
      getOriginalEventListener().onBrowserEvent(event);
    }

    dispatchEvent(event);
  }

  public void unbind(int eventbits) {
    unbind(eventbits, null, null, null);
  }

  public void unbind(int eventbits, String namespace, String eventName, Function f) {
    JsObjectArray<BindFunction> newList = JsObjectArray.createArray().cast();
    for (int i = 0; i < elementEvents.length(); i++) {
      BindFunction listener = elementEvents.get(i);
      boolean matchNS = isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace);
      boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits);
      boolean matchEVN = matchEV || listener.isTypeOf(eventName);
      boolean matchFC = f == null || listener.isEquals(f);

      if (matchNS && matchEV && matchEVN && matchFC) {
        int currentEventbits = listener.unsink(eventbits);
        if (currentEventbits == 0) {
          // the BindFunction doesn't listen anymore on any events
          continue;
        }
      }
      newList.add(listener);
    }
    elementEvents = newList;
  }

  /** Return true if the element is listening for the given eventBit or eventName. */
  public boolean hasHandlers(int eventBits, String eventName) {
    for (int i = 0, j = elementEvents.length(); i < j; i++) {
      BindFunction function = elementEvents.get(i);
      if (function.hasEventType(eventBits) || function.isTypeOf(eventName)) {
        return true;
      }
    }
    return false;
  }

  private static boolean isNullOrEmpty(String s) {
    return s == null || s.isEmpty();
  }

  public void unbind(String events, Function f) {
    for (EventName ev : EventName.split(events)) {
      SpecialEvent hook = special.get(ev.eventName);
      boolean unbind = hook == null || hook.tearDown(element) == false;
      if (unbind) {
        unbind(Event.getTypeInt(ev.eventName), ev.nameSpace, ev.eventName, f);
      }
      if (hook != null) {
        hook.remove(element, ev.eventName, ev.nameSpace, f);
      }
    }
  }

  public void clean() {
    cleanGQListeners(element);
    elementEvents = JsObjectArray.createArray().cast();
    liveBindFunctionByEventType = JsMap.create();
    eventBits = 0;
  }

  private void sink(int eventbits, String eventName) {
    // ensure that the gwtQuery's event listener is set as event listener of the element
    DOM.setEventListener((com.google.gwt.user.client.Element) element, this);

    if (eventbits != BITLESS) {
      eventBits |= eventbits;

      if ((eventBits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS
          && JsUtils.isElement(element)
          && element.getAttribute("tabIndex").length() == 0) {
        element.setAttribute("tabIndex", "0");
      }
      DOM.sinkEvents(
          (com.google.gwt.user.client.Element) element,
          eventBits | DOM.getEventsSunk((com.google.gwt.user.client.Element) element));
    } else {
      sinkBitlessEvent(element, eventName);
    }
  }

  public void cleanEventDelegation() {
    for (String k : liveBindFunctionByEventType.keys()) {
      LiveBindFunction function = liveBindFunctionByEventType.<JsCache>cast().get(k);
      function.clean();
    }
  }
}
예제 #14
0
    @Override
    public boolean fire(Event event, Object[] eventData) {
      if (isEmpty()) {
        return true;
      }

      // first element where the event was fired
      Element eventTarget = getEventTarget(event);
      // last element where the event was dispatched on
      Element liveContextElement = getCurrentEventTarget(event);

      if (eventTarget == null || liveContextElement == null) {
        return true;
      }

      // Compute the live selectors which respond to this event type
      List<String> validSelectors = new ArrayList<String>();
      for (String cssSelector : bindFunctionBySelector.keys()) {
        JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
        for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
          BindFunction f = bindFunctions.get(i);
          if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
            validSelectors.add(cssSelector);
            break;
          }
        }
      }

      // Create a structure of elements which matches the selectors
      JsNamedArray<NodeList<Element>> realCurrentTargetBySelector =
          $(eventTarget).closest(validSelectors.toArray(new String[0]), liveContextElement);
      // nothing matches the selectors
      if (realCurrentTargetBySelector.length() == 0) {
        return true;
      }

      Element stopElement = null;
      GqEvent gqEvent = GqEvent.create(event);
      for (String cssSelector : realCurrentTargetBySelector.keys()) {
        JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
        for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
          BindFunction f = bindFunctions.get(i);
          if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
            NodeList<Element> n = realCurrentTargetBySelector.get(cssSelector);
            for (int j = 0; n != null && j < n.getLength(); j++) {
              Element element = n.getItem(j);
              // When an event fired in an element stops bubbling we have to fire also all other
              // handlers for this element bound to this element
              if (stopElement == null || element.equals(stopElement)) {
                gqEvent.setCurrentElementTarget(element);
                // data
                eventData = $(element).data(EVENT_DATA);
                if (!f.fire(gqEvent, eventData)) {
                  stopElement = element;
                }
              }
            }
          }
        }
      }

      // trick to reset the right currentTarget on the original event on ie
      gqEvent.setCurrentElementTarget(liveContextElement);
      return stopElement == null;
    }
예제 #15
0
 protected static Sequence getSequence(String expression) {
   int start = 0, add = 2, max = -1, modVal = -1;
   JsRegexp expressionRegExp =
       new JsRegexp(
           "^((odd|even)|([1-9]\\d*)|((([1-9]\\d*)?)n((\\+|\\-)(\\d+))?)|(\\-(([1-9]\\d*)?)n\\+(\\d+)))$");
   JsObjectArray<String> pseudoValue = expressionRegExp.exec(expression);
   if (!truth(pseudoValue)) {
     return null;
   } else {
     if (truth(pseudoValue.get(2))) { // odd or even
       start = (eq(pseudoValue.get(2), "odd")) ? 1 : 2;
       modVal = (start == 1) ? 1 : 0;
     } else if (JsUtils.truth(pseudoValue.get(3))) { // single digit
       start = Integer.parseInt(pseudoValue.get(3), 10);
       add = 0;
       max = start;
     } else if (truth(pseudoValue.get(4))) { // an+b
       add = truth(pseudoValue.get(6)) ? Integer.parseInt(pseudoValue.get(6), 10) : 1;
       start =
           truth(pseudoValue.get(7))
               ? Integer.parseInt(
                   (pseudoValue.get(8).charAt(0) == '+' ? "" : pseudoValue.get(8))
                       + pseudoValue.get(9),
                   10)
               : 0;
       while (start < 1) {
         start += add;
       }
       modVal = (start > add) ? (start - add) % add : ((start == add) ? 0 : start);
     } else if (truth(pseudoValue.get(10))) { // -an+b
       add = truth(pseudoValue.get(12)) ? Integer.parseInt(pseudoValue.get(12), 10) : 1;
       start = max = Integer.parseInt(pseudoValue.get(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;
 }
예제 #16
0
  public NodeList<Element> select(String sel, Node ctx) {
    String selectors[] = sel.replace("\\s*(,)\\s*", "$1").split(",");
    boolean identical = false;
    JsNodeArray elm = JsNodeArray.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 (JsUtils.eq(selectors[a], selectors[b])) {
            identical = true;
            break;
          }
        }
        if (identical) {
          continue;
        }
      }
      String currentRule = selectors[a];
      JsObjectArray<String> cssSelectors = selectorSplitRegExp.match(currentRule);
      JsNodeArray prevElem = JsNodeArray.create(ctx);
      for (int i = 0, slen = cssSelectors.length(); i < slen; i++) {
        JsNodeArray matchingElms = JsNodeArray.create();
        String rule = cssSelectors.get(i);
        if (i > 0 && childOrSiblingRefRegExp.test(rule)) {
          JsObjectArray<String> childOrSiblingRef = childOrSiblingRefRegExp.exec(rule);
          if (JsUtils.truth(childOrSiblingRef)) {
            JsObjectArray<String> nextTag = new JsRegexp("^\\w+").exec(cssSelectors.get(i + 1));
            JsRegexp nextRegExp = null;
            String nextTagStr = null;
            if (JsUtils.truth(nextTag)) {
              nextTagStr = nextTag.get(0);
              nextRegExp = new JsRegexp("(^|\\s)" + nextTagStr + "(\\s|$)", "i");
            }
            for (int j = 0, jlen = prevElem.size(); j < jlen; j++) {
              Node prevRef = prevElem.getNode(j);
              String ref = childOrSiblingRef.get(0);
              if (JsUtils.eq(">", ref)) {
                getDescendantNodes(matchingElms, nextTagStr, prevRef);
              } else if (JsUtils.eq("+", ref)) {
                getSiblingNodes(matchingElms, nextTag, nextRegExp, prevRef);
              } else if (JsUtils.eq("~", ref)) {
                getGeneralSiblingNodes(matchingElms, nextTag, nextRegExp, prevRef);
              }
            }
            prevElem = matchingElms;
            clearAdded(prevElem);
            rule = cssSelectors.get(++i);
            if (new JsRegexp("^\\w+$").test(rule)) {
              continue;
            }
            setSkipTag(prevElem, true);
          }
        }
        JsObjectArray<String> cssSelector = cssSelectorRegExp.exec(rule);
        SplitRule splitRule =
            new SplitRule(
                !JsUtils.truth(cssSelector.get(1)) || JsUtils.eq(cssSelector.get(3), "*")
                    ? "*"
                    : cssSelector.get(1),
                !JsUtils.eq(cssSelector.get(3), "*") ? cssSelector.get(2) : null,
                cssSelector.get(4),
                cssSelector.get(6),
                cssSelector.get(10));
        if (JsUtils.truth(splitRule.id)) {
          Element domelem = Document.get().getElementById(splitRule.id.substring(1));
          if (JsUtils.truth(domelem)) {
            matchingElms = JsNodeArray.create(domelem);
          }
          prevElem = matchingElms;
        } else if (JsUtils.truth(splitRule.tag) && !isSkipped(prevElem)) {
          if (i == 0 && matchingElms.size() == 0 && prevElem.size() == 1) {
            prevElem =
                matchingElms =
                    JsNodeArray.create(getElementsByTagName(splitRule.tag, prevElem.getNode(0)));
          } else {
            NodeList<Element> 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 (JsUtils.truth(splitRule.allClasses)) {
            String[] allClasses = splitRule.allClasses.replaceFirst("^\\.", "").split("\\.");
            JsRegexp[] regExpClassNames = new JsRegexp[allClasses.length];
            for (int n = 0, nl = allClasses.length; n < nl; n++) {
              regExpClassNames[n] = new JsRegexp("(^|\\s)" + allClasses[n] + "(\\s|$)");
            }
            JsNodeArray matchingClassElms = JsNodeArray.create();
            for (int o = 0, olen = prevElem.size(); o < olen; o++) {
              Element current = prevElem.getElement(o);
              String elmClass = current.getClassName();
              boolean addElm = false;
              if (JsUtils.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 (JsUtils.truth(splitRule.allAttr)) {
            JsObjectArray<String> allAttr = JsRegexp.match("\\[[^\\]]+\\]", "g", splitRule.allAttr);
            JsRegexp[] regExpAttributes = new JsRegexp[allAttr.length()];
            String[] regExpAttributesStr = new String[allAttr.length()];
            JsRegexp attributeMatchRegExp =
                new JsRegexp("(\\w+)(\\^|\\$|\\*|\\||~)?=?[\"']?([\\w\u00C0-\uFFFF\\s\\-_\\.]+)?");
            for (int q = 0, ql = allAttr.length(); q < ql; q++) {
              JsObjectArray<String> attributeMatch = attributeMatchRegExp.exec(allAttr.get(q));
              String attributeValue =
                  JsUtils.truth(attributeMatch.get(3))
                      ? attributeMatch.get(3).replaceAll("\\.", "\\.")
                      : null;
              String attrVal =
                  attrToRegExp(attributeValue, (JsUtils.or(attributeMatch.get(2), null)));
              regExpAttributes[q] = (JsUtils.truth(attrVal) ? new JsRegexp(attrVal) : null);
              regExpAttributesStr[q] = attributeMatch.get(1);
            }
            JsNodeArray matchingAttributeElms = JsNodeArray.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; s < sl; s++) {
                addElm = false;
                JsRegexp attributeRegexp = regExpAttributes[s];
                String currentAttr = getAttr(current, regExpAttributesStr[s]);
                if (JsUtils.truth(currentAttr) && currentAttr.length() != 0) {
                  if (attributeRegexp == null || attributeRegexp.test(currentAttr)) {
                    addElm = true;
                  }
                }
                if (!addElm) {
                  break;
                }
              }
              if (addElm) {
                matchingAttributeElms.addNode(current);
              }
            }
            prevElem = matchingElms = matchingAttributeElms;
          }
          if (JsUtils.truth(splitRule.allPseudos)) {
            JsRegexp pseudoSplitRegExp = new JsRegexp(":(\\w[\\w\\-]*)(\\(([^\\)]+)\\))?");

            JsObjectArray<String> allPseudos =
                JsRegexp.match("(:\\w+[\\w\\-]*)(\\([^\\)]+\\))?", "g", splitRule.allPseudos);
            for (int t = 0, tl = allPseudos.length(); t < tl; t++) {
              JsObjectArray<String> pseudo = pseudoSplitRegExp.match(allPseudos.get(t));
              String pseudoClass =
                  JsUtils.truth(pseudo.get(1)) ? pseudo.get(1).toLowerCase() : null;
              String pseudoValue = JsUtils.truth(pseudo.get(3)) ? pseudo.get(3) : null;
              matchingElms = getElementsByPseudo(matchingElms, pseudoClass, pseudoValue);
              clearAdded(matchingElms);
            }
            prevElem = matchingElms;
          }
        }
      }
      elm.pushAll(prevElem);
    }

    return JsUtils.unique(elm.<JsArray<Element>>cast()).cast();
  }
예제 #17
0
 public void clean() {
   cleanGQListeners(element);
   elementEvents = JsObjectArray.createArray().cast();
   liveBindFunctionByEventType = JsMap.create();
   eventBits = 0;
 }
예제 #18
0
  private void winnowResults() {

    noResultClear();

    int results = 0;

    String searchText = defaultText.equals(searchField.val()) ? "" : searchField.val().trim();
    searchText = SafeHtmlUtils.htmlEscape(searchText);

    String regexAnchor = options.isSearchContains() ? "" : "^";
    // escape reg exp special chars
    String escapedSearchText = regExpChars.replace(searchText, "\\$&");
    String test2 = "test";
    test2.substring(1);
    RegExp regex = RegExp.compile(regexAnchor + escapedSearchText, "i");
    RegExp zregex = RegExp.compile("(" + escapedSearchText + ")", "i");

    for (int i = 0; i < selectItems.length(); i++) {
      SelectItem item = selectItems.get(i);

      if (item.isDisabled() || item.isEmpty()) {
        continue;
      }

      if (item.isGroup()) {
        $('#' + item.getDomId()).css("display", "none");
      } else {
        OptionItem option = (OptionItem) item;

        if (!(isMultiple && option.isSelected())) {
          boolean found = false;
          String resultId = option.getDomId();
          GQuery result = $("#" + resultId);
          String optionContent = option.getHtml();

          if (regex.test(optionContent)) {
            found = true;
            results++;
          } else if (optionContent.indexOf(" ") >= 0 || optionContent.indexOf("[") == 0) {
            String[] parts = optionContent.replaceAll("\\[|\\]", "").split(" ");
            for (String part : parts) {
              if (regex.test(part)) {
                found = true;
                results++;
              }
            }
          }

          if (found) {
            String text;
            if (searchText.length() > 0) {
              text = zregex.replace(optionContent, "<em>$1</em>");
            } else {
              text = optionContent;
            }

            result.html(text);
            resultActivate(result);

            if (option.getGroupArrayIndex() != -1) {
              $("#" + selectItems.get(option.getGroupArrayIndex()).getDomId())
                  .css("display", "list-item");
            }
          } else {
            if (resultHighlight != null && resultId.equals(resultHighlight.attr("id"))) {
              resultClearHighlight();
            }
            resultDeactivate(result);
          }
        }
      }
    }

    if (results < 1 && searchText.length() > 0) {
      noResults(searchText);
    } else {
      winnowResultsSetHighlight();
    }
  }