devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
202 lines (161 loc) • 6.27 kB
JavaScript
var $ = require("../core/renderer"),
eventsEngine = require("../events/core/events_engine"),
devices = require("../core/devices"),
domAdapter = require("../core/dom_adapter"),
domUtils = require("../core/utils/dom"),
animationFrame = require("../animation/frame"),
eventUtils = require("./utils"),
pointerEvents = require("./pointer"),
Emitter = require("./core/emitter"),
registerEmitter = require("./core/emitter_registrator"),
compareVersions = require("../core/utils/version").compare;
var CLICK_EVENT_NAME = "dxclick",
TOUCH_BOUNDARY = 10,
abs = Math.abs;
var isInput = function isInput(element) {
return $(element).is("input, textarea, select, button ,:focus, :focus *");
};
var misc = { requestAnimationFrame: animationFrame.requestAnimationFrame, cancelAnimationFrame: animationFrame.cancelAnimationFrame };
var ClickEmitter = Emitter.inherit({
ctor: function ctor(element) {
this.callBase(element);
this._makeElementClickable($(element));
},
_makeElementClickable: function _makeElementClickable($element) {
if (!$element.attr("onclick")) {
$element.attr("onclick", "void(0)");
}
},
start: function start(e) {
this._blurPrevented = e.isDefaultPrevented();
this._startTarget = e.target;
this._startEventData = eventUtils.eventData(e);
},
end: function end(e) {
if (this._eventOutOfElement(e, this.getElement().get(0)) || e.type === pointerEvents.cancel) {
this._cancel(e);
return;
}
if (!isInput(e.target) && !this._blurPrevented) {
domUtils.resetActiveElement();
}
this._accept(e);
this._clickAnimationFrame = misc.requestAnimationFrame(function () {
this._fireClickEvent(e);
}.bind(this));
},
_eventOutOfElement: function _eventOutOfElement(e, element) {
var target = e.target,
targetChanged = !domUtils.contains(element, target) && element !== target,
gestureDelta = eventUtils.eventDelta(eventUtils.eventData(e), this._startEventData),
boundsExceeded = abs(gestureDelta.x) > TOUCH_BOUNDARY || abs(gestureDelta.y) > TOUCH_BOUNDARY;
return targetChanged || boundsExceeded;
},
_fireClickEvent: function _fireClickEvent(e) {
this._fireEvent(CLICK_EVENT_NAME, e, {
target: domUtils.closestCommonParent(this._startTarget, e.target)
});
},
dispose: function dispose() {
misc.cancelAnimationFrame(this._clickAnimationFrame);
}
});
// NOTE: native strategy for desktop, iOS 9.3+, Android 5+
(function () {
var NATIVE_CLICK_CLASS = "dx-native-click";
var realDevice = devices.real(),
useNativeClick = realDevice.generic || realDevice.ios && compareVersions(realDevice.version, [9, 3]) >= 0 || realDevice.android && compareVersions(realDevice.version, [5]) >= 0;
var isNativeClickEvent = function isNativeClickEvent(target) {
return useNativeClick || $(target).closest("." + NATIVE_CLICK_CLASS).length;
};
var prevented = null,
lastFiredEvent = null;
var clickHandler = function clickHandler(e) {
var originalEvent = e.originalEvent,
eventAlreadyFired = lastFiredEvent !== originalEvent,
leftButton = !e.which || e.which === 1;
if (leftButton && !prevented && isNativeClickEvent(e.target) && eventAlreadyFired) {
lastFiredEvent = originalEvent;
eventUtils.fireEvent({
type: CLICK_EVENT_NAME,
originalEvent: e
});
}
};
ClickEmitter = ClickEmitter.inherit({
_makeElementClickable: function _makeElementClickable($element) {
if (!isNativeClickEvent($element)) {
this.callBase($element);
}
eventsEngine.on($element, "click", clickHandler);
},
configure: function configure(data) {
this.callBase(data);
if (data.useNative) {
this.getElement().addClass(NATIVE_CLICK_CLASS);
}
},
start: function start(e) {
prevented = null;
if (!isNativeClickEvent(e.target)) {
this.callBase(e);
}
},
end: function end(e) {
if (!isNativeClickEvent(e.target)) {
this.callBase(e);
}
},
cancel: function cancel() {
prevented = true;
},
dispose: function dispose() {
this.callBase();
eventsEngine.off(this.getElement(), "click", clickHandler);
}
});
///#DEBUG
exports.useNativeClick = useNativeClick;
///#ENDDEBUG
})();
// NOTE: fixes native click blur on slow devices
(function () {
var desktopDevice = devices.real().generic;
if (!desktopDevice) {
var startTarget = null,
blurPrevented = false;
var pointerDownHandler = function pointerDownHandler(e) {
startTarget = e.target;
blurPrevented = e.isDefaultPrevented();
};
var clickHandler = function clickHandler(e) {
var $target = $(e.target);
if (!blurPrevented && startTarget && !$target.is(startTarget) && !$(startTarget).is("label") && isInput($target)) {
domUtils.resetActiveElement();
}
startTarget = null;
blurPrevented = false;
};
var NATIVE_CLICK_FIXER_NAMESPACE = "NATIVE_CLICK_FIXER",
document = domAdapter.getDocument();
eventsEngine.subscribeGlobal(document, eventUtils.addNamespace(pointerEvents.down, NATIVE_CLICK_FIXER_NAMESPACE), pointerDownHandler);
eventsEngine.subscribeGlobal(document, eventUtils.addNamespace("click", NATIVE_CLICK_FIXER_NAMESPACE), clickHandler);
}
})();
/**
* @name ui events.dxclick
* @publicName dxclick
* @type eventType
* @type_function_param1 event:event
* @module events/click
*/
registerEmitter({
emitter: ClickEmitter,
bubble: true,
events: [CLICK_EVENT_NAME]
});
exports.name = CLICK_EVENT_NAME;
///#DEBUG
exports.misc = misc;
///#ENDDEBUG
;