From a33fe94dace7863131a3fa8d87a8ad75bfeaff02 Mon Sep 17 00:00:00 2001 From: Hedger Wang Date: Fri, 30 Oct 2015 11:06:35 -0700 Subject: [PATCH] build nested navigation context based on the hierarchy of navigators. Reviewed By: zjj010104 Differential Revision: D2598388 fb-gh-sync-id: 9655bcc86021678984e2a29df20ad2496a1762d1 --- .../Navigator/Navigation/NavigationContext.js | 123 ++++++++++++------ 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js index dfce209bf..f1280295b 100644 --- a/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js +++ b/Libraries/CustomComponents/Navigator/Navigation/NavigationContext.js @@ -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; } }