/**
* This plugin calls a callback whenever the mouse enters or leaves descendant
* elements of its host component identified by a {@link Ext.plugin.MouseEnter#delegate delegate}
* query selector string.
*
* This is useful for components which render arbitrary and transient child elements
* such as DataViews and Charts. It allows notification of mousenter events from
* child nodes without having to add listeners to each child element.
*/
Ext.define('Ext.plugin.MouseEnter', {
extend: 'Ext.plugin.Abstract',
alias: 'plugin.mouseenter',
/**
* @cfg {Ext.dom.Element/String} [element="el"] The element, or component element reference
* name to which to add the mouse listener.
*/
element: 'el',
/**
* @cfg {String} delegate A query selector string to identify descendant elements
* which trigger a call to the handler.
*/
/**
* @cfg {String/Function} handler A callback to invoke when a the mouse enters a
* descendant delegate.
* @cfg {Ext.event.Event} handler.e The `mouseover` event which triggered the mouse enter.
* @cfg {HTMLElement} handler.target The delegate element into which the mouse just entered.
*/
/**
* @cfg {String/Function} [leaveHandler] A callback to invoke when a the mouse leaves a
* descendant delegate.
* @cfg {Ext.event.Event} leaveHandler.e The `mouseover` event which triggered the mouse leave.
* @cfg {HTMLElement} leaveHandler.target The delegate element which the mouse just left.
*/
/**
* @cfg {Object} [scope] The scope (`this` pointer) in which to execute the callback(s).
*/
/**
* @cfg {Number} [delay] The time in milliseconds to wait before processing the mouse event.
* This can prevent unwanted processing when the user swipes the mouse rapidly across
* the component.
*/
init: function(component) {
//<debug>
if (!this.delegate) {
Ext.raise('mouseenter plugin must be configured with a delegate selector');
}
if (!this.handler) {
Ext.raise('mouseenter plugin must be configured with handler callback');
}
//</debug>
// eslint-disable-next-line vars-on-top
var me = this,
listeners = {
mouseover: 'onMouseEvent',
scope: me,
destroyable: true
},
element = me.element;
// Need the mouseout listener if there's a delay, so that we get an event
// in which to cancel the mouseover handling.
if (me.leaveHandler || me.delay) {
listeners.mouseout = 'onMouseEvent';
}
// Element being a string means a referenced element name in the Component
if (typeof element === 'string') {
element = component[me.element];
}
// If the component has the element, add the listener.
// Modern components always will have their elements.
if (element) {
me.mouseListener = Ext.get(element).on(listeners);
}
// For classic, we have to wait until render.
// destroyable: true does not work on named element listeners on a component
// https://sencha.jira.com/browse/EXTJS-22866
else {
component.on({
render: function() {
me.mouseListener = component[me.element].on(listeners);
},
single: true
});
}
},
onMouseEvent: function(e) {
var me = this,
delegate = e.getTarget(me.delegate);
// If we have changed delegates, fire (or schedule, if we are delaying) the handler
if (delegate && delegate !== e.getRelatedTarget(me.delegate)) {
if (me.delay) {
Ext.undefer(me.mouseEventTimer);
me.mouseEventTimer = Ext.defer(me.handleMouseEvent, me.delay, me, [e, delegate]);
}
else {
me.handleMouseEvent(e, delegate);
}
}
},
handleMouseEvent: function(e, delegate) {
var me = this;
if (e.type === 'mouseover') {
Ext.callback(me.handler, null, [e, delegate], 0, me.cmp, me.scope);
}
else if (me.leaveHandler) {
Ext.callback(me.leaveHandler, null, [e, delegate], 0, me.cmp, me.scope);
}
},
destroy: function() {
Ext.destroy(this.mouseListener);
this.callParent();
}
});