Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Remote Application Platform (RAP) » Extraneous mouseout event when mouseover fires for custom widget(simulating mouseenter and mouseleave doesn't help)
Extraneous mouseout event when mouseover fires for custom widget [message #824459] Mon, 19 March 2012 17:45 Go to next message
Mark Leone is currently offline Mark LeoneFriend
Messages: 123
Registered: July 2009
Senior Member
I created a custom RAP widget because I needed to implement the equivalent of MouseTrackListener, and do something when the cursor enters and leaves the widget. My custom Java widget extends Composite, and adds a Label and a Hyperlink as children. The Javascript implementation of the widget extends CanvasLayout and adds event listeners to the widget for 'mouseover' and 'mouseout' events. The script makes a request to the server with the mouse location whenever a mouseover or mouseout event occurs.

Everything works well except that around 50% of the time, when the mouse enters the widget, a 'mouseout' event fires in addition to the 'mouseover' event, even though the mouse enters and does not leave the widget. If the 'mouseout' event fires after the 'mouseover' event, which it often does, then it cancels out the 'mouseover' event.

I figured this may be due to the fact that 'mouseover' and 'mouseout' are "bubbling" events, meaning that the lsiteners will be called not only when the event occurs on the widget, but also for all the widgets children. Equivalent events "mouseenter" and "mouseleave" do not bubble, and as of recently they are supported by Firefox (after being IE-only events for some time). However, these are not supported by Qooxdoo.

So I found a site with Javascript code that simulates mouseenter and mouseleave, for browsers that only support mouseover and mouseout. The code and an explanation are provided in this post.

This looks like it should work, but it does not. I still get the extraneous 'mouseout' event when the cursor enters the widget. The event simulation code depends on determining whether the "relatedTarget" for a Mouse Event is either the widget or a descendant of the widget. I wonder if I need to implement this differently for Qooxdoo. I don't understand how the parent-child relationships are established on the Javascript side. I just instantiate a class with a name that points to the Java implementation of the widget, and it's not clear to me how the Javascript widget is generated wrt parent-child relationships.

Here is the Javascript code I'm using to determine if a relatedTarget of a mouse event is the widget or a child of the widget:

function isAChildOf(_parent, _child)
{
   if (_parent === _child) { return false; }
      while (_child && _child !== _parent)
   { _child = _child.parentNode; }

   return _child === _parent;
}


Should I be able to determine proper parent-child relationships in a Qooxdoo widget with this code? Or is there some other reason I'm getting the extraneous event?

I can filter the extraneous event in the Java implementation of the widget, by testing whether the cursor is on the widget somewhere when the event fires. But this seems like a bad implementation, getting a mouseout event and then testing whether the mouse has indeed exited the widget. Something is not working properly upstream if I have to do that.
Re: Extraneous mouseout event when mouseover fires for custom widget [message #824978 is a reply to message #824459] Tue, 20 March 2012 10:07 Go to previous messageGo to next message
Tim Buschtoens is currently offline Tim BuschtoensFriend
Messages: 396
Registered: July 2009
Senior Member
Hi.

One thing that we need to ensure is that we are talking about the same
thing here. There are the native DOM-events, and then there are the
event-wrapper the RAP-Client uses most of the time. If you use
widget.addEventListener( type, listener ) you get the wrapper, from
which you can also get the actual event. For your case, there is no need
to handle the actual events.

So your problem seems to be that
a) the mouse-events bubble (a problem when moving between children), and
b) the events also fire when you move the mouse between the
parent-widget and a child. (In that case the target is still the
parent-widget).

If i'm right, the fix should look like this.

_onMouseEvent : function( event ) {
var target = event.getTarget();
var related = event.getRelatedTarget();
if( target === this && !this.contains( related ) ) ) {
// your code
}
}

Hope it helps.

Greetings,
Tim


Am 19.03.2012 18:45, schrieb Mark Leone:
> I created a custom RAP widget because I needed to implement the
> equivalent of MouseTrackListener, and do something when the cursor
> enters and leaves the widget. My custom Java widget extends Composite,
> and adds a Label and a Hyperlink as children. The Javascript
> implementation of the widget extends CanvasLayout and adds event
> listeners to the widget for 'mouseover' and 'mouseout' events. The
> script makes a request to the server with the mouse location whenever a
> mouseover or mouseout event occurs.
>
> Everything works well except that around 50% of the time, when the mouse
> enters the widget, a 'mouseout' event fires in addition to the
> 'mouseover' event, even though the mouse enters and does not leave the
> widget. If the 'mouseout' event fires after the 'mouseover' event, which
> it often does, then it cancels out the 'mouseover' event.
>
> I figured this may be due to the fact that 'mouseover' and 'mouseout'
> are "bubbling" events, meaning that the lsiteners will be called not
> only when the event occurs on the widget, but also for all the widgets
> children. Equivalent events "mouseenter" and "mouseleave" do not bubble,
> and as of recently they are supported by Firefox (after being IE-only
> events for some time). However, these are not supported by Qooxdoo.
>
> So I found a site with Javascript code that simulates mouseenter and
> mouseleave, for browsers that only support mouseover and mouseout. The
> code and an explanation are provided in
> http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/.
>
>
> This looks like it should work, but it does not. I still get the
> extraneous 'mouseout' event when the cursor enters the widget. The event
> simulation code depends on determining whether the "relatedTarget" for a
> Mouse Event is either the widget or a descendant of the widget. I wonder
> if I need to implement this differently for Qooxdoo. I don't understand
> how the parent-child relationships are established on the Javascript
> side. I just instantiate a class with a name that points to the Java
> implementation of the widget, and it's not clear to me how the
> Javascript widget is generated wrt parent-child relationships.
>
> Here is the Javascript code I'm using to determine if a relatedTarget of
> a mouse event is the widget or a child of the widget:
>
> function isAChildOf(_parent, _child)
> {
> if (_parent === _child) { return false; }
> while (_child && _child !== _parent)
> { _child = _child.parentNode; }
>
> return _child === _parent;
> }
>
> Should I be able to determine proper parent-child relationships in a
> Qooxdoo widget with this code? Or is there some other reason I'm getting
> the extraneous event?
>
> I can filter the extraneous event in the Java implementation of the
> widget, by testing whether the cursor is on the widget somewhere when
> the event fires. But this seems like a bad implementation, getting a
> mouseout event and then testing whether the mouse has indeed exited the
> widget. Something is not working properly upstream if I have to do that.

--
Tim Buschtöns

Twitter: @EclipseRAP
Blog: http://eclipsesource.com/blogs/

Professional services for RAP and RCP?
http://eclipsesource.com/services/rap/
Re: Extraneous mouseout event when mouseover fires for custom widget [message #825302 is a reply to message #824978] Tue, 20 March 2012 17:49 Go to previous messageGo to next message
Mark Leone is currently offline Mark LeoneFriend
Messages: 123
Registered: July 2009
Senior Member
Thanks for your response, Tim.

When I tried your code, I get no events firing at all. To make sure we're on the same page, here's an excerpt from my client-side code. There's a little indirection as I incorporated the code I mentioned in my original post to simulate mouseenter and mouseleave events in a cross-browser context. But you'll see that the end result is that I'm invoking Widget#addEventListener.

qx.Class.define("...", {
    extend: qx.ui.layout.CanvasLayout,

construct: function(id) {
    ...
    this.addEvent(this, 'mouseenter', this.mouseIn, this);
    this.addEvent(this, 'mouseleave', this.mouseOut, this);
    ...
}
...

members: {
    addEvent: function(_elem, _evtName, _fn, _useCapture) {
        if (typeof _elem.addEventListener != 'undefined') {
            if (_evtName === 'mouseenter') {
                _elem.addEventListener('mouseover', this.mouseEvent(_fn), _useCapture);
            } else if (_evtName === 'mouseleave') {
                 _elem.addEventListener('mouseout', this.mouseEvent(_fn), _useCapture);
            }
        } else...
          //handle other browser types
    },

    mouseEvent: function(_fn) {
        return function(_evt) {
            var related = _evt.getRelatedTarget();
            if (this === related || this.isAChildOf(this, related) || !related) {
                return;
            }
            _fn.call(this, _evt);
        }
    },

    isAChildOf: Function(_parent, _child) {
        if (_parent === _child) {
            return false;
        }
        while (_child && _child !== _parent) {
            _child = _child.parentNode;
        }
        return _child === _parent
    },

    mouseIn: function(e) {
        //handle event by making request to server
    },

     mouseOut: function(e) {
        //handle event by making request to server
    },
...


With the above code, everything works except that I get the extraneous mouseout events. I incorporated your suggestion by replacing the contents of function mouseEvent above with the following:

 mouseEvent: function(_fn) {
        return function(_evt) {
            var related = _evt.getRelatedTarget();
            var target = _evt.getTarget();
            if (this === target && !this.contains(related)) {
                _fn.call(this, _evt);
            }
        }
 }


I also tried

 mouseEvent: function(_fn) {
        return function(_evt) {
            var related = _evt.getRelatedTarget();
            var target = _evt.getTarget();
            if (this === target && !this.isAChildOf(this, related)) {
                _fn.call(this, _evt);
            }
        }
 }


IN either case, I don't get any events firing when I mouse over or out of the widget.
Re: Extraneous mouseout event when mouseover fires for custom widget [message #826823 is a reply to message #825302] Thu, 22 March 2012 14:50 Go to previous messageGo to next message
Tim Buschtoens is currently offline Tim BuschtoensFriend
Messages: 396
Registered: July 2009
Senior Member
Hi.

> qx.Class.define("...", {
> extend: qx.ui.layout.CanvasLayout,
>
> construct: function(id) {
> ...
> this.addEvent(this, 'mouseenter', this.mouseIn, this);
> this.addEvent(this, 'mouseleave', this.mouseOut, this);
> ...
> }
> ..
>
> members: {
> addEvent: function(_elem, _evtName, _fn, _useCapture) {
> if (typeof _elem.addEventListener != 'undefined') {

I think you are confusing DOM event handling with widget event handling.
"this"/"_elem" seems to be the widget itself, not the html element. So
no need to check for addEventListener, its there, even in IE.

> isAChildOf: Function(_parent, _child) {

This will almost always return false because ...

> while (_child && _child !== _parent) {
> _child = _child.parentNode;
> }

"parentNode" does not exist on _child. Its a widget,
not an html element. It would be getParent().

> mouseEvent: function(_fn) {
> return function(_evt) {
> var related = _evt.getRelatedTarget();
> var target = _evt.getTarget();
> if (this === target && !this.contains(related)) {
> _fn.call(this, _evt);
> }
> }
> }

I'm sorry to say that i cant really say why its not working.
Try a js debugger or console.log to see what the variables contain and
which part of the expression fails.

Greetings,
Tim


--
Tim Buschtöns

Twitter: @EclipseRAP
Blog: http://eclipsesource.com/blogs/

Professional services for RAP and RCP?
http://eclipsesource.com/services/rap/
Re: Extraneous mouseout event when mouseover fires for custom widget [message #826966 is a reply to message #826823] Thu, 22 March 2012 18:18 Go to previous messageGo to next message
Mark Leone is currently offline Mark LeoneFriend
Messages: 123
Registered: July 2009
Senior Member
Thanks for clarifying about the DOM vs widget event handling. I'm trying to use firebug to troubleshoot, but can't get it to workquite right. The RAP docuemtation says not to follow the qx documentation because it's not fully implemetned in the RAP client, but then I don't know what javascript documentation I can follow. I'm trying to invoke console.log(), which qx documentation says will give me a link to let me inspect the runtime instance of the widget, but I get an error "console is undefined". I guess I'm missing something in how I'm supposed to use console.log, but lots of googling turns up nothing except people just invoking it the way I am.

I can inspect the widget structure, in the DOM tab looking at qx_Widget attribute of the outer HTML element, but I'd really like to look at the runtime instances as the code filters out objects to invoke the listener method on.

[Updated on: Thu, 22 March 2012 18:58]

Report message to a moderator

Re: Extraneous mouseout event when mouseover fires for custom widget [message #827058 is a reply to message #826966] Thu, 22 March 2012 21:01 Go to previous messageGo to next message
Mark Leone is currently offline Mark LeoneFriend
Messages: 123
Registered: July 2009
Senior Member
I found a way to get stringified object representations in the logger, and that was sufficient to enable me to solve the problem.

I used the following log code:

_logger = this.getLogger();
_logger.error(myObj, this._id) /* _id set in constructor to value of the constructor parameter "id" */


_logger.info() seems to be not supported, unless I was doing something wrong.

I removed the unneeded indirection for cross-browser code, so I call addEventListener() directly on the widget, for mouseover and mouseout events. I used the following code for filtering events to eliminate the extraneous mouseout events.

 mouseEvent: function(_fn) {
        return function(_evt) {
            var related = _evt.getRelatedTarget();
            var target = _evt.getTarget();
            if (this === target && !this.contains(related)) {
                _fn.call(this, _evt);
            }
        }
 }


This resulted in proper behavior for mouseover events (no extraneous mouseout events), but mouseout events were not firing when I did move the mouse out of the widget. Based on the log output I was getting, I changed the above code to

 mouseEvent: function(_fn) {
        return function(_evt) {
            var related = _evt.getRelatedTarget();
            var target = _evt.getTarget();
            if (this === target) {
                if (!this.contains(related)) {
                    _fn.call(this, _evt);
                }
            } else {
                 _fn.call(this, _evt);
            }
        }
 }


And that works. What I saw from the log output was that for a true mouseout event, target was an instance of qx.ui.basic.Atom, and related was an instance of org.eclipse.swt.widgets.Composite. From inspection of the DOM it looks like the Atom instance corresponds to the SWT Label instance that was added as a child to my custom Widget on the Java side. (As a reminder, the custom widget extends Composite and has a Label and a Hyperlink as children.) I'm not sure why there's a Composite instance being referenced as related. It's apparently contained by the custom widget, and therefore the previous "if" clause was not sufficient to handle real mouseout events.

Thanks for your help, Tim. I'd be grateful for any further explanation you may have for what I observed. And could you also tell me where I might find more specific documentation of the Javascript API for the RAP client, including what I should use in place of qx documentation, and how I can get access to qx objects in runtime in Firebug? I can't figure out how to set breakpoints directly in Firebug for RAP code, because in the Script tab I just see a high level script, not the Javascript that comprises my custom widget.

[Updated on: Thu, 22 March 2012 21:05]

Report message to a moderator

Re: Extraneous mouseout event when mouseover fires for custom widget [message #827427 is a reply to message #827058] Fri, 23 March 2012 10:08 Go to previous message
Tim Buschtoens is currently offline Tim BuschtoensFriend
Messages: 396
Registered: July 2009
Senior Member
Hi.

About console.log:

This is only present if the browser you use has that feature. For
Firefox, that means Firebug is installed and activated. For IE you need
version 8 or 9 and have the console open. Chrome and Safari support it
always. The way you do it is not recommanded anymore.

>
> mouseEvent: function(_fn) {
> return function(_evt) {
> var related = _evt.getRelatedTarget();
> var target = _evt.getTarget();
> if (this === target && !this.contains(related)) {
> _fn.call(this, _evt);
> }
> }
> }

Vs.

> mouseEvent: function(_fn) {
> return function(_evt) {
> var related = _evt.getRelatedTarget();
> var target = _evt.getTarget();
> if (this === target) {
> if (!this.contains(related)) {
> _fn.call(this, _evt);
> }
> } else {
> _fn.call(this, _evt);
> }
> }
> }

In case of the latter, i think you should get events that are not fired
on the custom widget, but its subwidgets (target !== this, event bubbles).

>
> And that works. What I saw from the log output was that for a true
> mouseout event, target was an instance of qx.ui.basic.Atom, and related
> was an instance of org.eclipse.swt.widgets.Composite. From inspection of
> the DOM it looks like the Atom instance corresponds to the SWT Label
> instance that was added as a child to my custom Widget on the Java side.
> (As a reminder, the custom widget extends Composite and has a Label and
> Hyperlink as children.) I'm not sure why there's a Composite instance
> being referenced as related. It's apparently contained by the custom
> widget, and therefore the previous "if" clause was not sufficient to
> handle real mouseout events.

Its hard to tell whats going on without seeing all your code, but
something seems off. The target should be the class you define for your
custom widget, and the related target either the custom widgets parent
(which likely will be Composite), or a custom widgets child (e.g. an
Atom/Label).

>
> you may have for what I observed. And could you also tell me where I
> might find more specific documentation of the Javascript API for the RAP
> client, including what I should use in pace of qx documentation and how

It depends a bit on the RAP version you are using. The documentation for
qx0.7[1] can get you started, it's just that more and more qx API has
been removed or altered for later versions of RAP. (Though the most
important classes, Widget, Target, Parent, Request and all the Events
remain almost unchanged).

I have to admit, there currently is no real documentation for the client
side API because there really isn't any public, stable client side API.
That is the main reason we discourage custom widgets development based
directly on the LCA/JS architecture (referenced as "native" custom
widgets in the RAP help[2]). We currently recommand the Browser Widget
as an alternative base for js-based custom widgets (example here[3]), or
the ClientScripting feature[4], which is in early development.

Native Custom Widget development will hopefully get easier with next
years RAP 2.0. It will defintely have the full RAP Protocol[5][6]
implemented, and perhaps we will finally get around to define public
client API[7] (which was planned for 1.4 originally).

> I can get access to qx objects in runtime in Firebug? I can't figure out

You already managed that, the qx_Widget reference is the runtime
instance of the widget. I guess what you want to is to use the debugger.

> to set breakpoints directly in Firebug for RAP code, because in the
> Script tab I just see a high level script, not the Javascript that
> comprises my custom widget.

The Script tab should let you access all JavaScript. There is a dropdown
menu (same bar that has the play/pause button) that gives you a list of
all scripts. You might have to search for a piece of your code to find
it. Remember to use the debug variant of the js client (can be set in
the launch config).

Greetings,
Tim


[1]http://demo.qooxdoo.org/0.7.x/apiviewer/
[2]
http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.rap.help%2Fhelp%2Fhtml%2Fadvanced%2Fcustom-widget.html
[3] https://github.com/eclipsesource/rap-ckeditor
[4] http://wiki.eclipse.org/RAP/ClientScripting
[5] http://wiki.eclipse.org/RAP/Protocol
[6] https://bugs.eclipse.org/bugs/show_bug.cgi?id=311355
[7] https://bugs.eclipse.org/bugs/show_bug.cgi?id=324434
--
Tim Buschtöns

Twitter: @EclipseRAP
Blog: http://eclipsesource.com/blogs/

Professional services for RAP and RCP?
http://eclipsesource.com/services/rap/
Previous Topic:Is there a tutorial?
Next Topic:How to integrate custom javascript
Goto Forum:
  


Current Time: Fri Mar 29 14:27:48 GMT 2024

Powered by FUDForum. Page generated in 0.03620 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top