2

I am trying to write a code to differentiate between simgle and double clicks using GWT and GWTQuery. I got the idea here. So I translated it into GWT like this: (my app can't have global variables, so I am doing that part with element attributes instead):

$("img").live("click", new Function() {
         public boolean f(Event event) {
            String clicksString = $(event).attr("clicks");
            int clicks = Integer.parseInt(clicksString);
            clicks++;
            $(event).attr("clicks",String.valueOf(clicks));
            Timer t = new Timer() {

                @Override
                public void run() {
                    Window.alert("Click");
                    $(event).attr("clicks","0");
                }
            };

            if (clicks == 1) {
              t.schedule(200);
            }

            else {
              t.cancel();
              $(event).attr("clicks","0");
              Window.alert("Double Click");
            }
            return true;
          }
});

Here, when the image is clicked, an alert should pop up showing Single Click, and if the user double clicks (within 200 ms), it should pop up Double Click. It works fine for the single click, but on double click, even though the Double Click alert pops up, on clicking Ok to get rid of it, I find the Single Click alert waiting to be get rid of.

Somehow, I think the t.cancel() is not firing on double-click. Can anyone tell me how to fix this?

Update:

The accepted solution works fine for alerting, but when I need the event parameter as well, it has to be slightly tweaked. After doing that, again, the problem comes back, the timer is not cleared, and now I get two alerts, Double Click and Click..:

          $("img").live("click", new Function() {
              int clicks = 0;

            public boolean f(Event event) {

                  Timer t = new Timer() {

                    @Override
                    public void run() {
                        clicks = 0;
//                            Here I need the event paramater

                    }
                };
                if (clicks++%2 == 0) {
                    t.schedule(5000);
                }
                else {
                    t.cancel();
                    clicks = 0;
 //                       Here also I need the event paramater
                }
                return true;
            }
          });

Updated by @Manolo: Based on my comment below last code should be:

      $("img").live("click", new Function() {
        int clicks = 0;
        Event event;
        Timer t = new Timer() {
           @Override
            public void run() {
               // Use the event
               event....
            }
        };
       public boolean f(Event event) {
            this.event = event;
            if (clicks++%2 == 0) {
                t.schedule(5000);
            } else {
                t.cancel();
                // Use the event
                event....
            }
            return true;
        }
      });
Manolo Carrasco Moñino
  • 9,723
  • 1
  • 22
  • 27
SexyBeast
  • 7,913
  • 28
  • 108
  • 196
  • First in your updated code, you cannot create the `Timer` instance in the body or the `f()` method because in this way you are not sharing the timer between consecutive calls to the method. Think that in the first call you create a `Timer` and you run it, but in the second click you create a new `Timer` and you try to cancel it, but not the first you run. Second in your code you can use the event parameter in both places, just declare it as final, but because mi first point you have to extract the `Timer` as an attribute of the inner function, to use the event create a variable as well. – Manolo Carrasco Moñino Mar 31 '13 at 18:23
  • I have edited your query, so as you can use the events, and the cancel() call works as I say in my other comment – Manolo Carrasco Moñino Mar 31 '13 at 18:28

2 Answers2

1

Do you feel GWT's DoubleClickEvent is insufficient. Why not listen to Double Click event from Dom instead of Click Event even if you take GwtQuery? Using timer is horribly bad approach for distinguishing Double Clicks.

In plain GWT Double Click would be -

public void onModuleLoad() {
    final Image button = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Katrina_Kaif.jpg/220px-Katrina_Kaif.jpg");

    button.addDoubleClickHandler( new DoubleClickHandler() {
        @Override
        public void onDoubleClick(DoubleClickEvent event) {
            Window.alert("DoubleClick");
        }
    });
    button.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            Window.alert("Click");
        }
    });
    RootPanel.get("slot1").add(button);
}

In GwtQuery you might try using 'dblclick'

$("img").live("dblclick", new Function() {
// Your code....
}

Update

You might have to borrow solution from Jquery community.This seems to be a travelled ground by jquery community here @ Jquery bind double click and single click separately

Quote from .dblclick() at the jQuery site

It is inadvisable to bind handlers to both the click and dblclick events for the same element. The sequence of events triggered varies from browser to browser, with some receiving two click events before the dblclick and others only one. Double-click sensitivity (maximum time between clicks that is detected as a double click) can vary by operating system and browser, and is often user-configurable.

Community
  • 1
  • 1
appbootup
  • 9,537
  • 3
  • 33
  • 65
  • 1
    The problem is I need to fire separate events for single and double clicks. Binding to the native `dblclick` will also fire the handler for `click`. – SexyBeast Mar 29 '13 at 18:49
  • Native click and native double click are different events. You definitely DO NOT need a timer to differentiate between them. – Andrei Volgin Mar 29 '13 at 18:53
  • But in Javascript, the click handler fires on double click as well. Isn't it the same in GWT also? – SexyBeast Mar 29 '13 at 19:53
  • 1
    Nope, doesn't work with GWT native `clickHandler` and `doubleClickHandler`. In fact there it is worse, there, on double clicking, the handler for the click fires immediately on the first click of the double click, thus the double click handler never fires at all (unlike normal Javascript, where both fire simultaneously).. :) – SexyBeast Mar 29 '13 at 20:05
  • 1
    Yep, that's what I said last, they both do not fire all right, only the click handler fires, it fires immediately on the first click of the double click, no matter how quickly you are doing the second click following the first click... – SexyBeast Mar 30 '13 at 22:02
  • Did you try Manolo solution. It seems a fairly correct implementation of timer to distinguish click/double click. Note - You are better served by avoiding this entire approach of single element serving click and double click. – appbootup Mar 31 '13 at 04:54
1

The following code does exactly the same than in the jsfiddle example you say:

  $("img").click(new Function() {
    boolean b = false;
    Timer t = new Timer() {
      public void run() {
        Window.alert("Click");
      }
    };
    public void f() {
      if (b = !b) {
        t.schedule(200);
      } else  {
        t.cancel();
        Window.alert("Double Click");
      }
     }
  });

The prevent default fragment is not necessary unless you previously were sunk events to the element, but in the case, the code should be:

  $("img").dblclick(new Function() {
    public boolean f(Event e) {
      return false;
    }
  });

EDITED: If you want to have unique variables per matched element, the best way is to create as many functions as elements. Using GQuery.each() is the easier way:

  $("img").each(new Function() {
    public void f() {
      $(this).click(new Function() {
        boolean b = false;
        Timer t = new Timer() {
          public void run() {
            Window.alert("Click");
          }
        };
        public void f() {
          if (b = !b) {
            t.schedule(200);
          } else  {
            t.cancel();
            Window.alert("Double Click");
          }
         }
      });
  }});

You could even use only one function and store variables in the element, but you should store not only the counter like you pretend in your query but a timer per element as well:

  $("img").click(new Function() {
    public void f() {
      boolean b = $(this).prop("c", Boolean.class);
      Timer t = $(this).prop("f");
      if (t == null) {
        t = new Timer() {
          public void run() {
            Window.alert("Click");
          }
        };
        $(this).prop("f", t);
      }
      if (b = !b) {
        t.schedule(200);
      } else  {
        t.cancel();
        Window.alert("Double Click");
      }
      $(this).prop("c", b);
     }
  });
Manolo Carrasco Moñino
  • 9,723
  • 1
  • 22
  • 27
  • Ummm, I can't rely on global variables because I have to attach these event to many elements, that's why I tried to replace the global variable through an attribute of the element itself. Why doesn't it work that way? – SexyBeast Mar 31 '13 at 06:55
  • Hi, I also edited my question, there is a new issue, please see whether you can help me.. – SexyBeast Mar 31 '13 at 11:22