devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
182 lines (180 loc) • 6.29 kB
JavaScript
/**
* DevExtreme (esm/events/click.js)
* Version: 21.1.4
* Build date: Mon Jun 21 2021
*
* Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import $ from "../core/renderer";
import eventsEngine from "../events/core/events_engine";
import devices from "../core/devices";
import domAdapter from "../core/dom_adapter";
import {
resetActiveElement,
contains,
closestCommonParent
} from "../core/utils/dom";
import {
requestAnimationFrame,
cancelAnimationFrame
} from "../animation/frame";
import {
addNamespace,
fireEvent,
eventDelta,
eventData
} from "./utils/index";
import {
subscribeNodesDisposing,
unsubscribeNodesDisposing
} from "./utils/event_nodes_disposing";
import pointerEvents from "./pointer";
import Emitter from "./core/emitter";
import registerEmitter from "./core/emitter_registrator";
import {
compare as compareVersions
} from "../core/utils/version";
var CLICK_EVENT_NAME = "dxclick";
var TOUCH_BOUNDARY = 10;
var abs = Math.abs;
var isInput = function(element) {
return $(element).is("input, textarea, select, button ,:focus, :focus *")
};
var misc = {
requestAnimationFrame: requestAnimationFrame,
cancelAnimationFrame: cancelAnimationFrame
};
var ClickEmitter = Emitter.inherit({
ctor: function(element) {
this.callBase(element);
this._makeElementClickable($(element))
},
_makeElementClickable: function($element) {
if (!$element.attr("onclick")) {
$element.attr("onclick", "void(0)")
}
},
start: function(e) {
this._blurPrevented = e.isDefaultPrevented();
this._startTarget = e.target;
this._startEventData = eventData(e)
},
end: function(e) {
if (this._eventOutOfElement(e, this.getElement().get(0)) || e.type === pointerEvents.cancel) {
this._cancel(e);
return
}
if (!isInput(e.target) && !this._blurPrevented) {
resetActiveElement()
}
this._accept(e);
this._clickAnimationFrame = misc.requestAnimationFrame(function() {
this._fireClickEvent(e)
}.bind(this))
},
_eventOutOfElement: function(e, element) {
var target = e.target;
var targetChanged = !contains(element, target) && element !== target;
var gestureDelta = eventDelta(eventData(e), this._startEventData);
var boundsExceeded = abs(gestureDelta.x) > TOUCH_BOUNDARY || abs(gestureDelta.y) > TOUCH_BOUNDARY;
return targetChanged || boundsExceeded
},
_fireClickEvent: function(e) {
this._fireEvent(CLICK_EVENT_NAME, e, {
target: closestCommonParent(this._startTarget, e.target)
})
},
dispose: function() {
misc.cancelAnimationFrame(this._clickAnimationFrame)
}
});
var realDevice = devices.real();
var useNativeClick = realDevice.generic || realDevice.ios && compareVersions(realDevice.version, [9, 3]) >= 0 || realDevice.android && compareVersions(realDevice.version, [5]) >= 0;
! function() {
var isNativeClickEvent = function(target) {
return useNativeClick || $(target).closest(".dx-native-click").length
};
var prevented = null;
var lastFiredEvent = null;
function onNodeRemove() {
lastFiredEvent = null
}
var clickHandler = function(e) {
var originalEvent = e.originalEvent;
var eventAlreadyFired = lastFiredEvent === originalEvent || originalEvent && originalEvent.DXCLICK_FIRED;
var leftButton = !e.which || 1 === e.which;
if (leftButton && !prevented && isNativeClickEvent(e.target) && !eventAlreadyFired) {
if (originalEvent) {
originalEvent.DXCLICK_FIRED = true
}
unsubscribeNodesDisposing(lastFiredEvent, onNodeRemove);
lastFiredEvent = originalEvent;
subscribeNodesDisposing(lastFiredEvent, onNodeRemove);
fireEvent({
type: CLICK_EVENT_NAME,
originalEvent: e
})
}
};
ClickEmitter = ClickEmitter.inherit({
_makeElementClickable: function($element) {
if (!isNativeClickEvent($element)) {
this.callBase($element)
}
eventsEngine.on($element, "click", clickHandler)
},
configure: function(data) {
this.callBase(data);
if (data.useNative) {
this.getElement().addClass("dx-native-click")
}
},
start: function(e) {
prevented = null;
if (!isNativeClickEvent(e.target)) {
this.callBase(e)
}
},
end: function(e) {
if (!isNativeClickEvent(e.target)) {
this.callBase(e)
}
},
cancel: function() {
prevented = true
},
dispose: function() {
this.callBase();
eventsEngine.off(this.getElement(), "click", clickHandler)
}
})
}();
! function() {
var desktopDevice = devices.real().generic;
if (!desktopDevice) {
var startTarget = null;
var blurPrevented = false;
var document = domAdapter.getDocument();
eventsEngine.subscribeGlobal(document, addNamespace(pointerEvents.down, "NATIVE_CLICK_FIXER"), (function(e) {
startTarget = e.target;
blurPrevented = e.isDefaultPrevented()
}));
eventsEngine.subscribeGlobal(document, addNamespace("click", "NATIVE_CLICK_FIXER"), (function(e) {
var $target = $(e.target);
if (!blurPrevented && startTarget && !$target.is(startTarget) && !$(startTarget).is("label") && isInput($target)) {
resetActiveElement()
}
startTarget = null;
blurPrevented = false
}))
}
}();
registerEmitter({
emitter: ClickEmitter,
bubble: true,
events: [CLICK_EVENT_NAME]
});
export {
CLICK_EVENT_NAME as name
};