You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.7 KiB
165 lines
4.7 KiB
10 years ago
|
/**
|
||
|
* Copyright 2013-2015, Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*
|
||
|
* @providesModule SyntheticEvent
|
||
|
* @typechecks static-only
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var PooledClass = require("./PooledClass");
|
||
|
|
||
|
var assign = require("./Object.assign");
|
||
|
var emptyFunction = require("./emptyFunction");
|
||
|
var getEventTarget = require("./getEventTarget");
|
||
|
|
||
|
/**
|
||
|
* @interface Event
|
||
|
* @see http://www.w3.org/TR/DOM-Level-3-Events/
|
||
|
*/
|
||
|
var EventInterface = {
|
||
|
type: null,
|
||
|
target: getEventTarget,
|
||
|
// currentTarget is set when dispatching; no use in copying it here
|
||
|
currentTarget: emptyFunction.thatReturnsNull,
|
||
|
eventPhase: null,
|
||
|
bubbles: null,
|
||
|
cancelable: null,
|
||
|
timeStamp: function(event) {
|
||
|
return event.timeStamp || Date.now();
|
||
|
},
|
||
|
defaultPrevented: null,
|
||
|
isTrusted: null
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Synthetic events are dispatched by event plugins, typically in response to a
|
||
|
* top-level event delegation handler.
|
||
|
*
|
||
|
* These systems should generally use pooling to reduce the frequency of garbage
|
||
|
* collection. The system should check `isPersistent` to determine whether the
|
||
|
* event should be released into the pool after being dispatched. Users that
|
||
|
* need a persisted event should invoke `persist`.
|
||
|
*
|
||
|
* Synthetic events (and subclasses) implement the DOM Level 3 Events API by
|
||
|
* normalizing browser quirks. Subclasses do not necessarily have to implement a
|
||
|
* DOM interface; custom application-specific events can also subclass this.
|
||
|
*
|
||
|
* @param {object} dispatchConfig Configuration used to dispatch this event.
|
||
|
* @param {string} dispatchMarker Marker identifying the event target.
|
||
|
* @param {object} nativeEvent Native browser event.
|
||
|
*/
|
||
|
function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
|
||
|
this.dispatchConfig = dispatchConfig;
|
||
|
this.dispatchMarker = dispatchMarker;
|
||
|
this.nativeEvent = nativeEvent;
|
||
|
|
||
|
var Interface = this.constructor.Interface;
|
||
|
for (var propName in Interface) {
|
||
|
if (!Interface.hasOwnProperty(propName)) {
|
||
|
continue;
|
||
|
}
|
||
|
var normalize = Interface[propName];
|
||
|
if (normalize) {
|
||
|
this[propName] = normalize(nativeEvent);
|
||
|
} else {
|
||
|
this[propName] = nativeEvent[propName];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var defaultPrevented = nativeEvent.defaultPrevented != null ?
|
||
|
nativeEvent.defaultPrevented :
|
||
|
nativeEvent.returnValue === false;
|
||
|
if (defaultPrevented) {
|
||
|
this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
|
||
|
} else {
|
||
|
this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
|
||
|
}
|
||
|
this.isPropagationStopped = emptyFunction.thatReturnsFalse;
|
||
|
}
|
||
|
|
||
|
assign(SyntheticEvent.prototype, {
|
||
|
|
||
|
preventDefault: function() {
|
||
|
this.defaultPrevented = true;
|
||
|
var event = this.nativeEvent;
|
||
|
if (event.preventDefault) {
|
||
|
event.preventDefault();
|
||
|
} else {
|
||
|
event.returnValue = false;
|
||
|
}
|
||
|
this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
|
||
|
},
|
||
|
|
||
|
stopPropagation: function() {
|
||
|
var event = this.nativeEvent;
|
||
|
if (event.stopPropagation) {
|
||
|
event.stopPropagation();
|
||
|
} else {
|
||
|
event.cancelBubble = true;
|
||
|
}
|
||
|
this.isPropagationStopped = emptyFunction.thatReturnsTrue;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* We release all dispatched `SyntheticEvent`s after each event loop, adding
|
||
|
* them back into the pool. This allows a way to hold onto a reference that
|
||
|
* won't be added back into the pool.
|
||
|
*/
|
||
|
persist: function() {
|
||
|
this.isPersistent = emptyFunction.thatReturnsTrue;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Checks if this event should be released back into the pool.
|
||
|
*
|
||
|
* @return {boolean} True if this should not be released, false otherwise.
|
||
|
*/
|
||
|
isPersistent: emptyFunction.thatReturnsFalse,
|
||
|
|
||
|
/**
|
||
|
* `PooledClass` looks for `destructor` on each instance it releases.
|
||
|
*/
|
||
|
destructor: function() {
|
||
|
var Interface = this.constructor.Interface;
|
||
|
for (var propName in Interface) {
|
||
|
this[propName] = null;
|
||
|
}
|
||
|
this.dispatchConfig = null;
|
||
|
this.dispatchMarker = null;
|
||
|
this.nativeEvent = null;
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
SyntheticEvent.Interface = EventInterface;
|
||
|
|
||
|
/**
|
||
|
* Helper to reduce boilerplate when creating subclasses.
|
||
|
*
|
||
|
* @param {function} Class
|
||
|
* @param {?object} Interface
|
||
|
*/
|
||
|
SyntheticEvent.augmentClass = function(Class, Interface) {
|
||
|
var Super = this;
|
||
|
|
||
|
var prototype = Object.create(Super.prototype);
|
||
|
assign(prototype, Class.prototype);
|
||
|
Class.prototype = prototype;
|
||
|
Class.prototype.constructor = Class;
|
||
|
|
||
|
Class.Interface = assign({}, Super.Interface, Interface);
|
||
|
Class.augmentClass = Super.augmentClass;
|
||
|
|
||
|
PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
|
||
|
};
|
||
|
|
||
|
PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);
|
||
|
|
||
|
module.exports = SyntheticEvent;
|