mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
fix-next: navigation events' workflow in modal dialog scenarios (#5341)
This commit is contained in:
@@ -141,4 +141,4 @@ else {
|
||||
|
||||
console.log(`TIME TO LOAD APP: ${time} ms`);
|
||||
|
||||
application.start({ moduleName: "app/mainPage" });
|
||||
application.run({ moduleName: "app/appRoot" });
|
||||
|
||||
1
tests/app/app/appRoot.xml
Normal file
1
tests/app/app/appRoot.xml
Normal file
@@ -0,0 +1 @@
|
||||
<Frame defaultPage="app/mainPage" />
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Page } from "tns-core-modules/ui/page";
|
||||
import * as trace from "tns-core-modules/trace";
|
||||
import * as tests from "../testRunner";
|
||||
import { Label } from "tns-core-modules/ui/label";
|
||||
import * as application from "tns-core-modules/application";
|
||||
import * as platform from "tns-core-modules/platform";
|
||||
|
||||
trace.enable();
|
||||
trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
|
||||
@@ -18,46 +15,12 @@ trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
|
||||
// trace.categories.VisualTreeEvents
|
||||
// ));
|
||||
|
||||
let page = new Page();
|
||||
page.id = "mainPage";
|
||||
|
||||
page.on(Page.navigatedToEvent, onNavigatedTo);
|
||||
|
||||
function runTests() {
|
||||
setTimeout(() => tests.runAll(''), 10);
|
||||
}
|
||||
|
||||
function onNavigatedTo(args) {
|
||||
let label = new Label();
|
||||
label.text = "Running non-UI tests...";
|
||||
page.content = label;
|
||||
args.object.off(Page.navigatedToEvent, onNavigatedTo);
|
||||
|
||||
// Request permission to write test-results.xml file for API >= 23
|
||||
// if (platform.isAndroid && parseInt(platform.device.sdkVersion) >= 23) {
|
||||
// let handler = (args: application.AndroidActivityRequestPermissionsEventData) => {
|
||||
// application.android.off(application.AndroidApplication.activityRequestPermissionsEvent, handler);
|
||||
// if (args.requestCode === 1234 && args.grantResults.length > 0 && args.grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
// runTests();
|
||||
// } else {
|
||||
// trace.write("Permission for write to external storage not granted!", trace.categories.Error, trace.messageType.error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, handler);
|
||||
|
||||
// if ((<any>android.support.v4.content.ContextCompat).checkSelfPermission(application.android.currentContext, (<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE) !== android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
// (<any>android.support.v4.app.ActivityCompat).requestPermissions(application.android.currentContext, [(<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE], 1234);
|
||||
// } else {
|
||||
// runTests();
|
||||
// }
|
||||
// } else {
|
||||
// runTests();
|
||||
// }
|
||||
export function onNavigatedTo(args) {
|
||||
args.object.off(Page.loadedEvent, onNavigatedTo);
|
||||
|
||||
runTests();
|
||||
}
|
||||
|
||||
export function createPage() {
|
||||
return page;
|
||||
}
|
||||
3
tests/app/app/mainPage.xml
Normal file
3
tests/app/app/mainPage.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<Page navigatedTo="onNavigatedTo">
|
||||
<Label text="Running non-UI tests..." />
|
||||
</Page>
|
||||
@@ -19,6 +19,7 @@ import * as helper from "../helper";
|
||||
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
|
||||
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { View, PercentLength, Observable, unsetValue, EventData, isIOS } from "tns-core-modules/ui/core/view";
|
||||
import { Frame } from "tns-core-modules/ui/frame";
|
||||
import { Label } from "tns-core-modules/ui/label";
|
||||
import { Color } from "tns-core-modules/color";
|
||||
|
||||
@@ -538,6 +539,271 @@ export function test_WhenPageIsNavigatedToItCanShowAnotherPageAsModal() {
|
||||
masterPage.off(Page.navigatedToEvent, navigatedToEventHandler);
|
||||
}
|
||||
|
||||
export function test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised() {
|
||||
let hostNavigatingToCount = 0;
|
||||
let hostNavigatedToCount = 0;
|
||||
let hostNavigatingFromCount = 0;
|
||||
let hostNavigatedFromCount = 0;
|
||||
|
||||
let ready = false;
|
||||
|
||||
const modalCloseCallback = function (returnValue: any) {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
const hostNavigatingToEventHandler = function () {
|
||||
hostNavigatingToCount++;
|
||||
};
|
||||
|
||||
const hostNavigatedToEventHandler = function () {
|
||||
hostNavigatedToCount++;
|
||||
};
|
||||
|
||||
const hostNavigatingFromEventHandler = function () {
|
||||
hostNavigatingFromCount++;
|
||||
};
|
||||
|
||||
const hostNavigatedFromEventHandler = function () {
|
||||
hostNavigatedFromCount++;
|
||||
};
|
||||
|
||||
const hostNavigatedToEventHandler2 = function(args: NavigatedData) {
|
||||
const page = <Page>args.object;
|
||||
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler2);
|
||||
|
||||
const basePath = "ui/page/";
|
||||
const entry: NavigationEntry = {
|
||||
moduleName: basePath + "modal-page"
|
||||
};
|
||||
|
||||
const modalPage = createViewFromEntry(entry) as Page;
|
||||
page.showModal(modalPage, {}, modalCloseCallback, false, false);
|
||||
}
|
||||
|
||||
const masterPageFactory = function (): Page {
|
||||
const masterPage = new Page();
|
||||
masterPage.id = "masterPage_test_WhenModalPageShownHostPageNavigationEventsShouldNotBeRaised";
|
||||
masterPage.on(Page.navigatingToEvent, hostNavigatingToEventHandler);
|
||||
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler2);
|
||||
masterPage.on(Page.navigatingFromEvent, hostNavigatingFromEventHandler);
|
||||
masterPage.on(Page.navigatedFromEvent, hostNavigatedFromEventHandler);
|
||||
|
||||
const label = new Label();
|
||||
label.text = "Text";
|
||||
masterPage.content = label;
|
||||
return masterPage;
|
||||
};
|
||||
|
||||
helper.navigate(masterPageFactory);
|
||||
|
||||
TKUnit.waitUntilReady(() => ready);
|
||||
|
||||
// only raised by the initial navigation to the master page
|
||||
TKUnit.assertTrue(hostNavigatingToCount === 1);
|
||||
TKUnit.assertTrue(hostNavigatedToCount === 1);
|
||||
|
||||
TKUnit.assertTrue(hostNavigatingFromCount === 0);
|
||||
TKUnit.assertTrue(hostNavigatedFromCount === 0);
|
||||
}
|
||||
|
||||
export function test_WhenModalPageShownModalNavigationToEventsShouldBeRaised() {
|
||||
let modalNavigatingToCount = 0;
|
||||
let modalNavigatedToCount = 0;
|
||||
let modalNavigatingFromCount = 0;
|
||||
let modalNavigatedFromCount = 0;
|
||||
|
||||
let ready = false;
|
||||
|
||||
const modalCloseCallback = function (returnValue: any) {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
const modalNavigatingToEventHandler = function () {
|
||||
modalNavigatingToCount++;
|
||||
};
|
||||
|
||||
const modalNavigatedToEventHandler = function (args: NavigatedData) {
|
||||
modalNavigatedToCount++;
|
||||
|
||||
(args.object as View).closeModal();
|
||||
};
|
||||
|
||||
const modalNavigatingFromEventHandler = function () {
|
||||
modalNavigatingFromCount++;
|
||||
};
|
||||
|
||||
const modalNavigatedFromEventHandler = function () {
|
||||
modalNavigatedFromCount++;
|
||||
};
|
||||
|
||||
const modalFrameShownModallyEventHandler = function(args) {
|
||||
const basePath = "ui/page/";
|
||||
const entry: NavigationEntry = {
|
||||
moduleName: basePath + "modal-page"
|
||||
};
|
||||
|
||||
const modalPage = createViewFromEntry(entry) as Page;
|
||||
modalPage.on(Page.navigatingToEvent, modalNavigatingToEventHandler);
|
||||
modalPage.on(Page.navigatedToEvent, modalNavigatedToEventHandler);
|
||||
modalPage.on(Page.navigatingFromEvent, modalNavigatingFromEventHandler);
|
||||
modalPage.on(Page.navigatedFromEvent, modalNavigatedFromEventHandler);
|
||||
|
||||
(args.object as Frame).navigate(() => modalPage);
|
||||
}
|
||||
|
||||
let modalFrame;
|
||||
|
||||
const hostNavigatedToEventHandler = function(args) {
|
||||
const page = <Page>args.object;
|
||||
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
modalFrame = new Frame();
|
||||
modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
|
||||
|
||||
page.showModal(modalFrame, {}, modalCloseCallback, false, false);
|
||||
}
|
||||
|
||||
const masterPageFactory = function (): Page {
|
||||
const masterPage = new Page();
|
||||
masterPage.id = "masterPage_test_WhenModalPageShownModalNavigationToEventsShouldBeRaised";
|
||||
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
const label = new Label();
|
||||
label.text = "Text";
|
||||
masterPage.content = label;
|
||||
return masterPage;
|
||||
};
|
||||
|
||||
helper.navigate(masterPageFactory);
|
||||
|
||||
TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
|
||||
|
||||
// only raised by the initial show modal navigation
|
||||
TKUnit.assertTrue(modalNavigatingToCount === 1);
|
||||
TKUnit.assertTrue(modalNavigatedToCount === 1);
|
||||
|
||||
TKUnit.assertTrue(modalNavigatingFromCount === 0);
|
||||
TKUnit.assertTrue(modalNavigatedFromCount === 0);
|
||||
}
|
||||
|
||||
export function test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame() {
|
||||
let showingModallyCount = 0;
|
||||
let shownModallyCount = 0;
|
||||
|
||||
let ready = false;
|
||||
|
||||
const modalCloseCallback = function (returnValue: any) {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
const modalFrameShowingModallyEventHandler = function(args: ShownModallyData) {
|
||||
showingModallyCount++;
|
||||
}
|
||||
|
||||
const modalFrameShownModallyEventHandler = function(args: ShownModallyData) {
|
||||
shownModallyCount++;
|
||||
|
||||
args.closeCallback("return value");
|
||||
}
|
||||
|
||||
let modalFrame;
|
||||
|
||||
const hostNavigatedToEventHandler = function(args) {
|
||||
const page = <Page>args.object;
|
||||
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
const basePath = "ui/page/";
|
||||
const entry: NavigationEntry = {
|
||||
moduleName: basePath + "modal-page"
|
||||
};
|
||||
|
||||
const modalPage = createViewFromEntry(entry) as Page;
|
||||
|
||||
modalFrame = new Frame();
|
||||
modalFrame.on(Frame.showingModallyEvent, modalFrameShowingModallyEventHandler);
|
||||
modalFrame.on(Frame.shownModallyEvent, modalFrameShownModallyEventHandler);
|
||||
modalFrame.navigate(() => modalPage);
|
||||
|
||||
page.showModal(modalFrame, {}, modalCloseCallback, false, false);
|
||||
}
|
||||
|
||||
const masterPageFactory = function (): Page {
|
||||
const masterPage = new Page();
|
||||
masterPage.id = "masterPage_test_WhenModalFrameShownModalEventsRaisedOnRootModalFrame";
|
||||
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
const label = new Label();
|
||||
label.text = "Text";
|
||||
masterPage.content = label;
|
||||
return masterPage;
|
||||
};
|
||||
|
||||
helper.navigate(masterPageFactory);
|
||||
|
||||
TKUnit.waitUntilReady(() => ready && !modalFrame.isLoaded);
|
||||
|
||||
TKUnit.assertTrue(showingModallyCount === 1);
|
||||
TKUnit.assertTrue(shownModallyCount === 1);
|
||||
}
|
||||
|
||||
export function test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage() {
|
||||
let showingModallyCount = 0;
|
||||
let shownModallyCount = 0;
|
||||
|
||||
let ready = false;
|
||||
|
||||
const modalCloseCallback = function (returnValue: any) {
|
||||
ready = true;
|
||||
}
|
||||
|
||||
const modalPageShowingModallyEventHandler = function(args: ShownModallyData) {
|
||||
showingModallyCount++;
|
||||
}
|
||||
|
||||
const modalPageShownModallyEventHandler = function(args: ShownModallyData) {
|
||||
shownModallyCount++;
|
||||
|
||||
setTimeout(() => {
|
||||
args.closeCallback("return value");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
const hostNavigatedToEventHandler = function(args) {
|
||||
const page = <Page>args.object;
|
||||
page.off(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
const basePath = "ui/page/";
|
||||
const entry: NavigationEntry = {
|
||||
moduleName: basePath + "modal-page"
|
||||
};
|
||||
|
||||
const modalPage = createViewFromEntry(entry) as Page;
|
||||
modalPage.on(Page.showingModallyEvent, modalPageShowingModallyEventHandler);
|
||||
modalPage.on(Page.shownModallyEvent, modalPageShownModallyEventHandler);
|
||||
|
||||
page.showModal(modalPage, {}, modalCloseCallback, false, false);
|
||||
}
|
||||
|
||||
const masterPageFactory = function (): Page {
|
||||
const masterPage = new Page();
|
||||
masterPage.id = "masterPage_test_WhenModalPageShownShowModalEventsRaisedOnRootModalPage";
|
||||
masterPage.on(Page.navigatedToEvent, hostNavigatedToEventHandler);
|
||||
|
||||
const label = new Label();
|
||||
label.text = "Text";
|
||||
masterPage.content = label;
|
||||
return masterPage;
|
||||
};
|
||||
|
||||
helper.navigate(masterPageFactory);
|
||||
|
||||
TKUnit.waitUntilReady(() => ready);
|
||||
|
||||
TKUnit.assertTrue(showingModallyCount === 1);
|
||||
TKUnit.assertTrue(shownModallyCount === 1);
|
||||
}
|
||||
|
||||
export function test_percent_width_and_height_support() {
|
||||
const testPage = new Page();
|
||||
testPage.id = "test_percent_width_and_height_support";
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"nativescript": {
|
||||
"id": "org.nativescript.UnitTestApp",
|
||||
"tns-ios": {
|
||||
"version": "3.2.0"
|
||||
"version": "3.4.1"
|
||||
},
|
||||
"tns-android": {
|
||||
"version": "3.2.0"
|
||||
"version": "3.4.1"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -40,7 +40,10 @@
|
||||
"snapshot": {
|
||||
"android": {
|
||||
"tns-java-classes": {
|
||||
"modules": ["ui/frame/activity", "ui/frame/fragment"]
|
||||
"modules": [
|
||||
"ui/frame/activity",
|
||||
"ui/frame/fragment"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
tns-core-modules/ui/core/view/view.d.ts
vendored
10
tns-core-modules/ui/core/view/view.d.ts
vendored
@@ -85,6 +85,16 @@ export interface ShownModallyData extends EventData {
|
||||
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
|
||||
*/
|
||||
export abstract class View extends ViewBase {
|
||||
/**
|
||||
* String value used when hooking to showingModally event.
|
||||
*/
|
||||
public static showingModallyEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to shownModally event.
|
||||
*/
|
||||
public static shownModallyEvent: string;
|
||||
|
||||
/**
|
||||
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
|
||||
*/
|
||||
|
||||
@@ -58,9 +58,18 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
@profile
|
||||
public onLoaded() {
|
||||
super.onLoaded();
|
||||
|
||||
this._pushInFrameStack();
|
||||
this._processNextNavigationEntry();
|
||||
}
|
||||
|
||||
@profile
|
||||
public onUnloaded() {
|
||||
super.onUnloaded();
|
||||
|
||||
this._popFromFrameStack();
|
||||
}
|
||||
|
||||
public canGoBack(): boolean {
|
||||
let backstack = this._backStack.length;
|
||||
let previousForwardNotInBackstack = false;
|
||||
@@ -183,8 +192,6 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
// app.on(app.orientationChangedEvent, (data) => this._onOrientationChanged());
|
||||
// }
|
||||
|
||||
this._pushInFrameStack();
|
||||
|
||||
const backstackEntry: BackstackEntry = {
|
||||
entry: entry,
|
||||
resolvedPage: page,
|
||||
|
||||
10
tns-core-modules/ui/page/page.d.ts
vendored
10
tns-core-modules/ui/page/page.d.ts
vendored
@@ -39,16 +39,6 @@ export module knownCollections {
|
||||
* Represents a logical unit for navigation (inside Frame).
|
||||
*/
|
||||
export class Page extends ContentView {
|
||||
/**
|
||||
* String value used when hooking to showingModally event.
|
||||
*/
|
||||
public static showingModallyEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to shownModally event.
|
||||
*/
|
||||
public static shownModallyEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to navigatingTo event.
|
||||
*/
|
||||
|
||||
@@ -180,10 +180,11 @@ class UIViewControllerImpl extends UIViewController {
|
||||
}
|
||||
|
||||
const frame = owner.frame;
|
||||
// Skip navigation events if we are hiding because we are about to show modal page
|
||||
// Skip navigation events if we are hiding because we are about to show a modal page,
|
||||
// or because we are closing a modal page,
|
||||
// or because we are in tab and another controller is selected.
|
||||
const tab = this.tabBarController;
|
||||
if (!owner._presentedViewController && frame && frame.currentPage === owner) {
|
||||
if (!owner._presentedViewController && !this.presentingViewController && frame && frame.currentPage === owner) {
|
||||
const willSelectViewController = tab && (<any>tab)._willSelectViewController;
|
||||
if (!willSelectViewController
|
||||
|| willSelectViewController === tab.selectedViewController) {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
{
|
||||
"name": "tns-platform-declarations",
|
||||
"version": "4.0.0",
|
||||
"description":
|
||||
"Platform-specific TypeScript declarations for NativeScript for accessing native objects",
|
||||
"description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
|
||||
"main": "",
|
||||
"scripts": {
|
||||
"test": "tsc",
|
||||
"package-tag":
|
||||
"npm version $npm_package_version-$PACKAGE_VERSION --no-git-tag-version"
|
||||
"package-tag": "npm version $npm_package_version-$PACKAGE_VERSION --no-git-tag-version"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
Reference in New Issue
Block a user