build nested navigation context based on the hierarchy of navigators.
Reviewed By: zjj010104 Differential Revision: D2598388 fb-gh-sync-id: 9655bcc86021678984e2a29df20ad2496a1762d1
This commit is contained in:
parent
854689dcfa
commit
a33fe94dac
|
@ -30,6 +30,8 @@ var NavigationEvent = require('NavigationEvent');
|
|||
var NavigationEventEmitter = require('NavigationEventEmitter');
|
||||
var NavigationTreeNode = require('NavigationTreeNode');
|
||||
|
||||
var Set = require('Set');
|
||||
|
||||
var emptyFunction = require('emptyFunction');
|
||||
var invariant = require('invariant');
|
||||
|
||||
|
@ -41,6 +43,13 @@ var {
|
|||
CAPTURING_PHASE,
|
||||
} = NavigationEvent;
|
||||
|
||||
// Event types that do not support event bubbling, capturing and
|
||||
// reconciliation API (e.g event.preventDefault(), event.stopPropagation()).
|
||||
var LegacyEventTypes = new Set([
|
||||
'willfocus',
|
||||
'didfocus',
|
||||
]);
|
||||
|
||||
/**
|
||||
* Class that contains the info and methods for app navigation.
|
||||
*/
|
||||
|
@ -88,9 +97,14 @@ class NavigationContext {
|
|||
context: ?Object,
|
||||
useCapture: ?boolean
|
||||
): EventSubscription {
|
||||
if (LegacyEventTypes.has(eventType)) {
|
||||
useCapture = false;
|
||||
}
|
||||
|
||||
var emitter = useCapture ?
|
||||
this._captureEventEmitter :
|
||||
this._bubbleEventEmitter;
|
||||
|
||||
if (emitter) {
|
||||
return emitter.addListener(eventType, listener, context);
|
||||
} else {
|
||||
|
@ -109,50 +123,65 @@ class NavigationContext {
|
|||
|
||||
this._emitCounter++;
|
||||
|
||||
var targets = [this];
|
||||
var parentTarget = this.parent;
|
||||
while (parentTarget) {
|
||||
targets.unshift(parentTarget);
|
||||
parentTarget = parentTarget.parent;
|
||||
if (LegacyEventTypes.has(eventType)) {
|
||||
// Legacy events does not support event bubbling and reconciliation.
|
||||
this.__emit(
|
||||
eventType,
|
||||
data,
|
||||
null,
|
||||
{
|
||||
defaultPrevented: false,
|
||||
eventPhase: AT_TARGET,
|
||||
propagationStopped: true,
|
||||
target: this,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
var targets = [this];
|
||||
var parentTarget = this.parent;
|
||||
while (parentTarget) {
|
||||
targets.unshift(parentTarget);
|
||||
parentTarget = parentTarget.parent;
|
||||
}
|
||||
|
||||
var propagationStopped = false;
|
||||
var defaultPrevented = false;
|
||||
var callback = (event) => {
|
||||
propagationStopped = propagationStopped || event.isPropagationStopped();
|
||||
defaultPrevented = defaultPrevented || event.defaultPrevented;
|
||||
};
|
||||
|
||||
// Capture phase
|
||||
targets.some((currentTarget) => {
|
||||
if (propagationStopped) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var extraInfo = {
|
||||
defaultPrevented,
|
||||
eventPhase: CAPTURING_PHASE,
|
||||
propagationStopped,
|
||||
target: this,
|
||||
};
|
||||
|
||||
currentTarget.__emit(eventType, data, callback, extraInfo);
|
||||
}, this);
|
||||
|
||||
// bubble phase
|
||||
targets.reverse().some((currentTarget) => {
|
||||
if (propagationStopped) {
|
||||
return true;
|
||||
}
|
||||
var extraInfo = {
|
||||
defaultPrevented,
|
||||
eventPhase: BUBBLING_PHASE,
|
||||
propagationStopped,
|
||||
target: this,
|
||||
};
|
||||
currentTarget.__emit(eventType, data, callback, extraInfo);
|
||||
}, this);
|
||||
}
|
||||
|
||||
var propagationStopped = false;
|
||||
var defaultPrevented = false;
|
||||
var callback = (event) => {
|
||||
propagationStopped = propagationStopped || event.isPropagationStopped();
|
||||
defaultPrevented = defaultPrevented || event.defaultPrevented;
|
||||
};
|
||||
|
||||
// capture phase
|
||||
targets.some((currentTarget) => {
|
||||
if (propagationStopped) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var extraInfo = {
|
||||
defaultPrevented,
|
||||
eventPhase: CAPTURING_PHASE,
|
||||
propagationStopped,
|
||||
target: this,
|
||||
};
|
||||
|
||||
currentTarget.__emit(eventType, data, callback, extraInfo);
|
||||
}, this);
|
||||
|
||||
// bubble phase
|
||||
targets.reverse().some((currentTarget) => {
|
||||
if (propagationStopped) {
|
||||
return true;
|
||||
}
|
||||
var extraInfo = {
|
||||
defaultPrevented,
|
||||
eventPhase: BUBBLING_PHASE,
|
||||
propagationStopped,
|
||||
target: this,
|
||||
};
|
||||
currentTarget.__emit(eventType, data, callback, extraInfo);
|
||||
}, this);
|
||||
|
||||
if (didEmitCallback) {
|
||||
var event = NavigationEvent.pool(eventType, this, data);
|
||||
propagationStopped && event.stopPropagation();
|
||||
|
@ -189,9 +218,15 @@ class NavigationContext {
|
|||
case CAPTURING_PHASE: // phase = 1
|
||||
emitter = this._captureEventEmitter;
|
||||
break;
|
||||
|
||||
case AT_TARGET: // phase = 2
|
||||
emitter = this._bubbleEventEmitter;
|
||||
break;
|
||||
|
||||
case BUBBLING_PHASE: // phase = 3
|
||||
emitter = this._bubbleEventEmitter;
|
||||
break;
|
||||
|
||||
default:
|
||||
invariant(false, 'invalid event phase %s', extraInfo.eventPhase);
|
||||
}
|
||||
|
@ -214,8 +249,10 @@ class NavigationContext {
|
|||
_onFocus(event: NavigationEvent): void {
|
||||
invariant(
|
||||
event.data && event.data.hasOwnProperty('route'),
|
||||
'didfocus event should provide route'
|
||||
'event type "%s" should provide route',
|
||||
event.type
|
||||
);
|
||||
|
||||
this._currentRoute = event.data.route;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue