diff --git a/apps/tests/ui/page/page-tests-common.ts b/apps/tests/ui/page/page-tests-common.ts index 5e6f97dd7..002305997 100644 --- a/apps/tests/ui/page/page-tests-common.ts +++ b/apps/tests/ui/page/page-tests-common.ts @@ -394,6 +394,46 @@ export function test_WhenPageIsLoadedFrameCurrentPageIsTheSameInstance() { } } +export function test_WhenNavigatingForwardAndBack_IsBackNavigationIsCorrect() { + var page1; + var page2; + var forwardCounter = 0; + var backCounter = 0; + var loadedEventHandler = function (args: PageModule.NavigatedData) { + if (args.isBackNavigation) { + backCounter++; + } + else { + forwardCounter++; + } + } + + var pageFactory1 = function (): PageModule.Page { + page1 = new PageModule.Page(); + page1.on(PageModule.Page.navigatedToEvent, loadedEventHandler); + return page1; + }; + + var pageFactory2 = function (): PageModule.Page { + page2 = new PageModule.Page(); + page2.on(PageModule.Page.navigatedToEvent, loadedEventHandler); + return page2; + }; + + try { + helper.navigate(pageFactory1); + helper.navigate(pageFactory2); + helper.goBack(); + TKUnit.assertEqual(forwardCounter, 2, "Forward navigation counter should be 1"); + TKUnit.assertEqual(backCounter, 1, "Backward navigation counter should be 1"); + page1.off(PageModule.Page.navigatedToEvent, loadedEventHandler); + page2.off(PageModule.Page.navigatedToEvent, loadedEventHandler); + } + finally { + helper.goBack(); + } +} + //export function test_ModalPage_Layout_is_Correct() { // var testPage: PageModule.Page; // var label: LabelModule.Label; diff --git a/ui/frame/frame-common.ts b/ui/frame/frame-common.ts index e3eff59fc..92d7676d1 100644 --- a/ui/frame/frame-common.ts +++ b/ui/frame/frame-common.ts @@ -222,7 +222,7 @@ export class Frame extends view.CustomLayoutView implements definition.Frame { private performNavigation(navigationContext: NavigationContext) { var navContext = navigationContext.entry; - this._onNavigatingTo(navContext); + this._onNavigatingTo(navContext, navigationContext.isBackNavigation); if (navigationContext.entry.entry.clearHistory) { this._backStack.length = 0; @@ -237,7 +237,7 @@ export class Frame extends view.CustomLayoutView implements definition.Frame { private performGoBack(navigationContext: NavigationContext) { var navContext = navigationContext.entry; - this._onNavigatingTo(navContext); + this._onNavigatingTo(navContext, navigationContext.isBackNavigation); this._goBackCore(navContext); this._onNavigatedTo(navContext, true); } @@ -250,12 +250,12 @@ export class Frame extends view.CustomLayoutView implements definition.Frame { // } - public _onNavigatingTo(backstackEntry: definition.BackstackEntry) { + public _onNavigatingTo(backstackEntry: definition.BackstackEntry, isBack: boolean) { if (this.currentPage) { - this.currentPage.onNavigatingFrom(); + this.currentPage.onNavigatingFrom(isBack); } - backstackEntry.resolvedPage.onNavigatingTo(backstackEntry.entry.context); + backstackEntry.resolvedPage.onNavigatingTo(backstackEntry.entry.context, isBack); } public _onNavigatedTo(backstackEntry: definition.BackstackEntry, isBack: boolean) { diff --git a/ui/frame/frame.android.ts b/ui/frame/frame.android.ts index cddc78f77..24e83e3ac 100644 --- a/ui/frame/frame.android.ts +++ b/ui/frame/frame.android.ts @@ -159,11 +159,22 @@ function onFragmentShown(fragment: PageFragmentBody) { var entry: definition.BackstackEntry = fragment.entry; var page: pages.Page = entry.resolvedPage; + let currentNavigationContext; + let navigationQueue = (frame)._navigationQueue; + for (let i = 0; i < navigationQueue.length; i++) { + if (navigationQueue[i].entry === entry) { + currentNavigationContext = navigationQueue[i]; + break; + } + } + + var isBack = currentNavigationContext ? currentNavigationContext.isBackNavigation : false; + frame._currentEntry = entry; // notify the page frame._addView(page); - page.onNavigatedTo(); + page.onNavigatedTo(isBack); frame._processNavigationQueue(page); } @@ -351,7 +362,7 @@ export class Frame extends frameCommon.Frame { var backstackEntry = this.currentEntry || this._delayedNavigationEntry; if (isRestart) { - this._onNavigatingTo(backstackEntry); + this._onNavigatingTo(backstackEntry, false); this._onNavigatedTo(backstackEntry, false); } else { diff --git a/ui/frame/frame.ios.ts b/ui/frame/frame.ios.ts index dc3a830ae..0f784b336 100644 --- a/ui/frame/frame.ios.ts +++ b/ui/frame/frame.ios.ts @@ -304,6 +304,18 @@ class UINavigationControllerImpl extends UINavigationController implements UINav // This code check if navigation happened through UI (e.g. back button or swipe gesture). // When calling goBack on frame isBack will be false. let isBack: boolean = currentEntry && newEntry === currentEntry; + + let currentNavigationContext; + let navigationQueue = (frame)._navigationQueue; + for (let i = 0; i < navigationQueue.length; i++) { + if (navigationQueue[i].entry === newEntry) { + currentNavigationContext = navigationQueue[i]; + break; + } + } + + var isBackNavigation = currentNavigationContext ? currentNavigationContext.isBackNavigation : false; + if (isBack) { try { frame._shouldSkipNativePop = true; @@ -334,7 +346,7 @@ class UINavigationControllerImpl extends UINavigationController implements UINav frame._updateActionBar(newPage); // notify the page - newPage.onNavigatedTo(); + newPage.onNavigatedTo(isBack || isBackNavigation); frame._processNavigationQueue(newPage); } diff --git a/ui/page/page-common.ts b/ui/page/page-common.ts index debcaadd1..2f2549171 100644 --- a/ui/page/page-common.ts +++ b/ui/page/page-common.ts @@ -8,11 +8,11 @@ import fs = require("file-system"); import frameCommon = require("../frame/frame-common"); import {ActionBar} from "ui/action-bar"; import {DependencyObservable, PropertyMetadata, PropertyMetadataSettings, PropertyChangeData, Property, ValueSource} from "ui/core/dependency-observable"; -import platform = require("platform"); + import proxy = require("ui/core/proxy"); // on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call). -var AffectsLayout = platform.device.os === platform.platformNames.android ? PropertyMetadataSettings.None : PropertyMetadataSettings.AffectsLayout; +var AffectsLayout = global.android ? PropertyMetadataSettings.None : PropertyMetadataSettings.AffectsLayout; var backgroundSpanUnderStatusBarProperty = new Property("backgroundSpanUnderStatusBar", "Page", new proxy.PropertyMetadata(false, AffectsLayout)); @@ -163,38 +163,30 @@ export class Page extends ContentView implements dts.Page { return this.parent; } - public onNavigatingTo(context: any) { + private createNavigatedData(eventName: string, isBackNavigation: boolean): dts.NavigatedData { + return { + eventName: eventName, + object: this, + context: this.navigationContext, + isBackNavigation: isBackNavigation + }; + } + + public onNavigatingTo(context: any, isBackNavigation: boolean) { this._navigationContext = context; - - this.notify({ - eventName: Page.navigatingToEvent, - object: this, - context: this.navigationContext - }); + this.notify(this.createNavigatedData(Page.navigatingToEvent, isBackNavigation)); } - public onNavigatedTo() { - this.notify({ - eventName: Page.navigatedToEvent, - object: this, - context: this.navigationContext - }); + public onNavigatedTo(isBackNavigation: boolean) { + this.notify(this.createNavigatedData(Page.navigatedToEvent, isBackNavigation)); } - public onNavigatingFrom() { - this.notify({ - eventName: Page.navigatingFromEvent, - object: this, - context: this.navigationContext - }); + public onNavigatingFrom(isBackNavigation: boolean) { + this.notify(this.createNavigatedData(Page.navigatingFromEvent, isBackNavigation)); } public onNavigatedFrom(isBackNavigation: boolean) { - this.notify({ - eventName: Page.navigatedFromEvent, - object: this, - context: this.navigationContext - }); + this.notify(this.createNavigatedData(Page.navigatedFromEvent, isBackNavigation)); this._navigationContext = undefined; } diff --git a/ui/page/page.d.ts b/ui/page/page.d.ts index eb9dc86e2..1b4d8015c 100644 --- a/ui/page/page.d.ts +++ b/ui/page/page.d.ts @@ -21,6 +21,11 @@ declare module "ui/page" { * The navigation context (optional, may be undefined) passed to the page navigation events method. */ context: any; + + /** + * Represents if a navigation is forward or backward. + */ + isBackNavigation: boolean; } /** @@ -187,18 +192,21 @@ declare module "ui/page" { /** * A method called before navigating to the page. * @param context - The data passed to the page through the NavigationEntry.context property. + * @param isBackNavigation - True if the Page is being navigated from using the Frame.goBack() method, false otherwise. */ - onNavigatingTo(context: any): void; + onNavigatingTo(context: any, isBackNavigation: boolean): void; /** * A method called after navigated to the page. + * @param isBackNavigation - True if the Page is being navigated from using the Frame.goBack() method, false otherwise. */ - onNavigatedTo(): void; + onNavigatedTo(isBackNavigation: boolean): void; /** * A method called before navigating from the page. + * @param isBackNavigation - True if the Page is being navigated from using the Frame.goBack() method, false otherwise. */ - onNavigatingFrom(): void; + onNavigatingFrom(isBackNavigation: boolean): void; /** * A method called after navigated from the page.