mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge remote-tracking branch 'origin/master' into merge-release-in-master
This commit is contained in:
@@ -279,7 +279,7 @@ if (a) return "winning";
|
||||
|
||||
```TypeScript
|
||||
|
||||
if(condition) {
|
||||
if (condition) {
|
||||
console.log("winning");
|
||||
}
|
||||
|
||||
@@ -293,15 +293,15 @@ if (!condition) {
|
||||
|
||||
```TypeScript
|
||||
|
||||
if(condition === true) {
|
||||
if (condition === true) {
|
||||
console.log("losing");
|
||||
}
|
||||
|
||||
if(condition !== true) {
|
||||
if (condition !== true) {
|
||||
console.log("losing");
|
||||
}
|
||||
|
||||
if(condition !== false) {
|
||||
if (condition !== false) {
|
||||
console.log("losing");
|
||||
}
|
||||
|
||||
@@ -314,7 +314,7 @@ Do not use the **Yoda Conditions** when writing boolean expressions:
|
||||
|
||||
```TypeScript
|
||||
let num;
|
||||
if(num >= 0) {
|
||||
if (num >= 0) {
|
||||
console.log("winning");
|
||||
}
|
||||
```
|
||||
@@ -323,14 +323,14 @@ if(num >= 0) {
|
||||
|
||||
```TypeScript
|
||||
let num;
|
||||
if(0 <= num) {
|
||||
if (0 <= num) {
|
||||
console.log("losing");
|
||||
}
|
||||
```
|
||||
|
||||
**NOTE** It is OK to use constants on the left when comparing for a range.
|
||||
```TypeScript
|
||||
if(0 <= num && num <= 100) {
|
||||
if (0 <= num && num <= 100) {
|
||||
console.log("winning");
|
||||
}
|
||||
```
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2015-2018 Progress Software Corporation
|
||||
Copyright (c) 2015-2019 Progress Software Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -81,6 +81,13 @@ application.on(application.uncaughtErrorEvent, function(args: application.Unhand
|
||||
console.log("### stack: " + args.error.stack);
|
||||
});
|
||||
|
||||
application.on(application.discardedErrorEvent, function(args: application.DiscardedErrorEventData) {
|
||||
console.log("### [Discarded] NativeScriptError: " + args.error);
|
||||
console.log("### [Discarded] nativeException: " + (<any>args.error).nativeException);
|
||||
console.log("### [Discarded] stackTrace: " + (<any>args.error).stackTrace);
|
||||
console.log("### [Discarded] stack: " + args.error.stack);
|
||||
});
|
||||
|
||||
application.setCssFileName("ui-tests-app/app.css");
|
||||
|
||||
application.start({ moduleName: "ui-tests-app/main-page" });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--timeout 80000
|
||||
--timeout 300000
|
||||
--recursive e2e
|
||||
--reporter mocha-multi
|
||||
--reporter-options spec=-,mocha-junit-reporter=test-results.xml
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium";
|
||||
import { Screen } from "./screen"
|
||||
import { Screen, driverDefaultWaitTime, elementDefaultWaitTimeInSeconds } from "./screen"
|
||||
import { assert } from "chai";
|
||||
|
||||
const exampleAndroidBackBtnEvents = "Android Back Btn Events";
|
||||
@@ -10,6 +10,7 @@ describe("android-navigate-back", () => {
|
||||
|
||||
before(async () => {
|
||||
driver = await createDriver();
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
screen = new Screen(driver);
|
||||
const btnShowNestedModalFrame = await driver.findElementByText(exampleAndroidBackBtnEvents);
|
||||
await btnShowNestedModalFrame.click();
|
||||
@@ -31,7 +32,7 @@ describe("android-navigate-back", () => {
|
||||
}
|
||||
|
||||
await driver.navBack();
|
||||
const textElement = await driver.findElementsByText("will cancel next back press: false", SearchOptions.contains, 10);
|
||||
const textElement = await driver.findElementsByText("will cancel next back press: false", SearchOptions.contains, elementDefaultWaitTimeInSeconds);
|
||||
assert.isTrue(textElement !== null);
|
||||
await driver.navBack();
|
||||
await screen.loadedHome();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen } from "./screen"
|
||||
import { Screen, driverDefaultWaitTime } from "./screen"
|
||||
import {
|
||||
roots,
|
||||
modalFrameBackground,
|
||||
@@ -17,6 +17,7 @@ describe("modal-frame:", () => {
|
||||
|
||||
before(async () => {
|
||||
driver = await createDriver();
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
screen = new Screen(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen } from "./screen"
|
||||
import { Screen, driverDefaultWaitTime } from "./screen"
|
||||
import {
|
||||
roots,
|
||||
modalFrameBackground,
|
||||
@@ -17,6 +17,7 @@ describe("modal-layout:", () => {
|
||||
|
||||
before(async () => {
|
||||
driver = await createDriver();
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
screen = new Screen(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen } from "./screen"
|
||||
import { Screen, driverDefaultWaitTime } from "./screen"
|
||||
import {
|
||||
roots,
|
||||
modalPageBackground,
|
||||
@@ -16,6 +16,7 @@ describe("modal-page:", () => {
|
||||
|
||||
before(async () => {
|
||||
driver = await createDriver();
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
screen = new Screen(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen } from "./screen"
|
||||
import { Screen, driverDefaultWaitTime } from "./screen"
|
||||
import {
|
||||
roots,
|
||||
modalFrameBackground,
|
||||
@@ -19,6 +19,7 @@ describe("modal-tab:", () => {
|
||||
|
||||
before(async () => {
|
||||
driver = await createDriver();
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
screen = new Screen(driver);
|
||||
});
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ const closeModalNested = "Close Modal Nested";
|
||||
const closeModal = "Close Modal";
|
||||
const goBack = "Go Back";
|
||||
|
||||
export const driverDefaultWaitTime = 10000;
|
||||
export const elementDefaultWaitTimeInSeconds = 10;
|
||||
|
||||
export class Screen {
|
||||
|
||||
private _driver: AppiumDriver
|
||||
@@ -37,30 +40,30 @@ export class Screen {
|
||||
}
|
||||
|
||||
loadedHome = async () => {
|
||||
const lblHome = await this._driver.findElementByText(home);
|
||||
const lblHome = await this._driver.waitForElement(home);
|
||||
assert.isTrue(await lblHome.isDisplayed());
|
||||
console.log(home + " loaded!");
|
||||
}
|
||||
|
||||
resetFrameRootView = async () => {
|
||||
console.log("Setting frame root ...");
|
||||
const btnResetFrameRootView = await this._driver.findElementByText(resetFrameRootView);
|
||||
const btnResetFrameRootView = await this._driver.waitForElement(resetFrameRootView);
|
||||
await btnResetFrameRootView.tap();
|
||||
}
|
||||
|
||||
resetLayoutRootView = async () => {
|
||||
console.log("Setting layout root ...");
|
||||
const btnResetLayoutRootView = await this._driver.findElementByText(resetLayoutRootView);
|
||||
const btnResetLayoutRootView = await this._driver.waitForElement(resetLayoutRootView);
|
||||
await btnResetLayoutRootView.tap();
|
||||
}
|
||||
|
||||
resetTabRootView = async () => {
|
||||
const btnResetTabRootView = await this._driver.findElementByText(resetTabRootView);
|
||||
const btnResetTabRootView = await this._driver.waitForElement(resetTabRootView);
|
||||
await btnResetTabRootView.tap();
|
||||
}
|
||||
|
||||
loadedTabRootView = async () => {
|
||||
const tabFirst = await this._driver.findElementByText(first);
|
||||
const tabFirst = await this._driver.waitForElement(first);
|
||||
assert.isTrue(await tabFirst.isDisplayed());
|
||||
console.log("Tab root view loaded!");
|
||||
}
|
||||
@@ -89,29 +92,29 @@ export class Screen {
|
||||
}
|
||||
|
||||
showModalFrame = async () => {
|
||||
const btnModalFrame = await this._driver.findElementByText(modalFrame);
|
||||
const btnModalFrame = await this._driver.waitForElement(modalFrame);
|
||||
await btnModalFrame.tap();
|
||||
}
|
||||
|
||||
loadedModalFrame = async () => {
|
||||
const lblModal = await this._driver.findElementByText(modal);
|
||||
const lblModal = await this._driver.waitForElement(modal);
|
||||
assert.isTrue(await lblModal.isDisplayed());
|
||||
console.log(modal + " loaded!");
|
||||
}
|
||||
|
||||
showModalPage = async () => {
|
||||
const btnModalPage = await this._driver.findElementByText(modalPage);
|
||||
const btnModalPage = await this._driver.waitForElement(modalPage);
|
||||
await btnModalPage.tap();
|
||||
}
|
||||
|
||||
loadedModalPage = async () => {
|
||||
const btnShowNestedModalPage = await this._driver.findElementByText(showNestedModalPage);
|
||||
const btnShowNestedModalPage = await this._driver.waitForElement(showNestedModalPage);
|
||||
assert.isTrue(await btnShowNestedModalPage.isDisplayed());
|
||||
console.log("Modal Page loaded!");
|
||||
}
|
||||
|
||||
showModalLayout = async () => {
|
||||
const btnModalLayout = await this._driver.findElementByText(modalLayout);
|
||||
const btnModalLayout = await this._driver.waitForElement(modalLayout);
|
||||
await btnModalLayout.tap();
|
||||
}
|
||||
|
||||
@@ -120,99 +123,99 @@ export class Screen {
|
||||
}
|
||||
|
||||
showModalTabView = async () => {
|
||||
const btnModalTabView = await this._driver.findElementByText(modalTabView);
|
||||
const btnModalTabView = await this._driver.waitForElement(modalTabView);
|
||||
await btnModalTabView.tap();
|
||||
}
|
||||
|
||||
loadedModalTabView = async () => {
|
||||
const itemModalFirst = await this._driver.findElementByText(modalFirst);
|
||||
const itemModalFirst = await this._driver.waitForElement(modalFirst);
|
||||
assert.isTrue(await itemModalFirst.isDisplayed());
|
||||
console.log("Modal TabView loaded!");
|
||||
}
|
||||
|
||||
navigateToSecondPage = async () => {
|
||||
const btnNavToSecondPage = await this._driver.findElementByText(navToSecondPage);
|
||||
const btnNavToSecondPage = await this._driver.waitForElement(navToSecondPage);
|
||||
await btnNavToSecondPage.tap();
|
||||
}
|
||||
|
||||
showDialogConfirm = async () => {
|
||||
const btnShowDialogConfirm = await this._driver.findElementByText(showDialog);
|
||||
const btnShowDialogConfirm = await this._driver.waitForElement(showDialog);
|
||||
await btnShowDialogConfirm.tap();
|
||||
}
|
||||
|
||||
navigateToFirstItem = async () => {
|
||||
const itemModalFirst = await this._driver.findElementByText(modalFirst);
|
||||
const itemModalFirst = await this._driver.waitForElement(modalFirst);
|
||||
await itemModalFirst.tap();
|
||||
}
|
||||
|
||||
navigateToSecondItem = async () => {
|
||||
const itemModalSecond = await this._driver.findElementByText(modalSecond);
|
||||
const itemModalSecond = await this._driver.waitForElement(modalSecond);
|
||||
await itemModalSecond.tap();
|
||||
}
|
||||
|
||||
loadedConfirmDialog = async () => {
|
||||
const lblDialogMessage = await this._driver.findElementByText(confirmDialogMessage);
|
||||
const lblDialogMessage = await this._driver.waitForElement(confirmDialogMessage);
|
||||
assert.isTrue(await lblDialogMessage.isDisplayed());
|
||||
console.log(dialogConfirm + " shown!");
|
||||
}
|
||||
|
||||
loadedSecondPage = async () => {
|
||||
const lblModalSecond = await this._driver.findElementByText(modalSecond);
|
||||
const lblModalSecond = await this._driver.waitForElement(modalSecond);
|
||||
assert.isTrue(await lblModalSecond.isDisplayed());
|
||||
console.log(modalSecond + " loaded!");
|
||||
}
|
||||
|
||||
loadedFirstItem = async () => {
|
||||
const lblModal = await this._driver.findElementByText(modal);
|
||||
const lblModal = await this._driver.waitForElement(modal);
|
||||
assert.isTrue(await lblModal.isDisplayed());
|
||||
console.log("First Item loaded!");
|
||||
}
|
||||
|
||||
loadedSecondItem = async () => {
|
||||
const btnGoBack = await this._driver.findElementByText(goBack);
|
||||
const btnGoBack = await this._driver.waitForElement(goBack);
|
||||
assert.isTrue(await btnGoBack.isDisplayed());
|
||||
console.log("Second Item loaded!");
|
||||
}
|
||||
|
||||
closeDialog = async () => {
|
||||
const btnYesDialog = await this._driver.findElementByText(confirmDialog);
|
||||
const btnYesDialog = await this._driver.waitForElement(confirmDialog);
|
||||
await btnYesDialog.tap();
|
||||
}
|
||||
|
||||
goBackFromSecondPage = async () => {
|
||||
const btnGoBackFromSecondPage = await this._driver.findElementByText(goBack);
|
||||
const btnGoBackFromSecondPage = await this._driver.waitForElement(goBack);
|
||||
await btnGoBackFromSecondPage.tap();
|
||||
}
|
||||
|
||||
showNestedModalFrame = async () => {
|
||||
const btnShowNestedModalFrame = await this._driver.findElementByText(showNestedModalFrame);
|
||||
const btnShowNestedModalFrame = await this._driver.waitForElement(showNestedModalFrame);
|
||||
await btnShowNestedModalFrame.tap();
|
||||
}
|
||||
|
||||
loadedNestedModalFrame = async () => {
|
||||
const lblModalNested = await this._driver.findElementByText(modalNested);
|
||||
const lblModalNested = await this._driver.waitForElement(modalNested);
|
||||
assert.isTrue(await lblModalNested.isDisplayed());
|
||||
console.log(modalNested + " loaded!");
|
||||
}
|
||||
|
||||
closeModalNested = async () => {
|
||||
const btnCloseNestedModal = await this._driver.findElementByText(closeModalNested);
|
||||
const btnCloseNestedModal = await this._driver.waitForElement(closeModalNested);
|
||||
await btnCloseNestedModal.tap();
|
||||
}
|
||||
|
||||
showNestedModalPage = async () => {
|
||||
const btnShowNestedModalPage = await this._driver.findElementByText(showNestedModalPage);
|
||||
const btnShowNestedModalPage = await this._driver.waitForElement(showNestedModalPage);
|
||||
await btnShowNestedModalPage.tap();
|
||||
}
|
||||
|
||||
loadedNestedModalPage = async () => {
|
||||
const btnCloseModalNested = await this._driver.findElementByText(closeModalNested);
|
||||
const btnCloseModalNested = await this._driver.waitForElement(closeModalNested);
|
||||
assert.isTrue(await btnCloseModalNested.isDisplayed());
|
||||
console.log(closeModalNested + " loaded!");
|
||||
}
|
||||
|
||||
closeModal = async () => {
|
||||
const btnCloseModal = await this._driver.findElementByText(closeModal);
|
||||
const btnCloseModal = await this._driver.waitForElement(closeModal);
|
||||
await btnCloseModal.tap();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function onNavigateSlide(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export function onNavigateFlip(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ export function onNavigateSlide(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export function onNavigateFlip(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page codeFile="~/frame-root/frame-home-page" xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
|
||||
<ActionBar class="action-bar">
|
||||
<NavigationButton text="frameHomeBack" tap="onBackButtonTap" android.systemIcon="ic_menu_back" />
|
||||
|
||||
@@ -3,11 +3,11 @@ import { EventData } from "tns-core-modules/ui/core/view";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
|
||||
export function onNavigateToLayoutFrame(args: EventData) {
|
||||
application._resetRootView({ moduleName: "layout-root/layout-root-frame" });
|
||||
application._resetRootView({ moduleName: "layout-root/layout-frame-root" });
|
||||
}
|
||||
|
||||
export function onNavigateToLayoutMultiFrame(args: EventData) {
|
||||
application._resetRootView({ moduleName: "layout-root/layout-root-multi-frame" });
|
||||
application._resetRootView({ moduleName: "layout-root/layout-multi-frame-root" });
|
||||
}
|
||||
|
||||
export function onNavigateToPageFrame(args: EventData) {
|
||||
@@ -31,9 +31,9 @@ export function onNavigateToTabsBottomPage(args: EventData) {
|
||||
}
|
||||
|
||||
export function onNavigateToTabsTopRoot(args: EventData) {
|
||||
application._resetRootView({ moduleName: "tab-root/tab-root-top" });
|
||||
application._resetRootView({ moduleName: "tab-root/tab-top-root" });
|
||||
}
|
||||
|
||||
export function onNavigateToTabsBottomRoot(args: EventData) {
|
||||
application._resetRootView({ moduleName: "tab-root/tab-root-bottom" });
|
||||
application._resetRootView({ moduleName: "tab-root/tab-bottom-root" });
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<Button text="Layout w/ multi frame" tap="onNavigateToLayoutMultiFrame" />
|
||||
<Button text="Page w/ frame" tap="onNavigateToPageFrame" />
|
||||
<Button text="Page w/ multi frame" tap="onNavigateToPageMultiFrame" />
|
||||
<Button ios:visibility="collapsed" text="Page w/ tabs (top)" tap="onNavigateToTabsTopPage" />
|
||||
<Button text="Page w/ tabs (top)" tap="onNavigateToTabsTopPage" />
|
||||
<Button text="Page w/ tabs (bottom)" tap="onNavigateToTabsBottomPage" />
|
||||
<Button ios:visibility="collapsed" text="Root tabs (top)" tap="onNavigateToTabsTopRoot" />
|
||||
<Button text="Root tabs (top)" tap="onNavigateToTabsTopRoot" />
|
||||
<Button text="Root tabs (bottom)" tap="onNavigateToTabsBottomRoot" />
|
||||
</StackLayout>
|
||||
</GridLayout>
|
||||
|
||||
@@ -21,7 +21,7 @@ export function onNavigateSlide(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export function onNavigateFlip(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ export function onNavigateSlide(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
@@ -34,7 +34,7 @@ export function onNavigateFlip(args: EventData) {
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<GridLayout codeFile="~/layout-root/layout-root-frame" rows="auto, *, *">
|
||||
<GridLayout rows="auto, *, *">
|
||||
<Button text="reset app" tap="onReset" />
|
||||
<GridLayout row="1">
|
||||
<Frame defaultPage="layout-root/layout-home-page" />
|
||||
@@ -38,14 +38,14 @@ export function onItemTap(args: ItemEventData) {
|
||||
case "slide":
|
||||
entry.transition = {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
};
|
||||
break;
|
||||
case "flip":
|
||||
entry.transition = {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
};
|
||||
break;
|
||||
|
||||
46
e2e/nested-frame-navigation/app/tab-page/tabs-bottom-page.ts
Normal file
46
e2e/nested-frame-navigation/app/tab-page/tabs-bottom-page.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { EventData } from "tns-core-modules/ui/page";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
|
||||
export function onNavigate(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate("some-page/some-page");
|
||||
}
|
||||
|
||||
export function onNavigateNone(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: false
|
||||
});
|
||||
}
|
||||
|
||||
export function onNavigateSlide(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onNavigateFlip(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onBackButtonTap(args: EventData): void {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.goBack();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page codeFile="~/tab-page/tabs-page" xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
|
||||
<ActionBar class="action-bar">
|
||||
<NavigationButton text="tabBottomBack" tap="onBackButtonTap" android.systemIcon="ic_menu_back" />
|
||||
|
||||
46
e2e/nested-frame-navigation/app/tab-page/tabs-top-page.ts
Normal file
46
e2e/nested-frame-navigation/app/tab-page/tabs-top-page.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { EventData } from "tns-core-modules/ui/page";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
|
||||
export function onNavigate(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate("some-page/some-page");
|
||||
}
|
||||
|
||||
export function onNavigateNone(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: false
|
||||
});
|
||||
}
|
||||
|
||||
export function onNavigateSlide(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "slide",
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onNavigateFlip(args: EventData) {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.navigate({
|
||||
moduleName: "some-page/some-page",
|
||||
animated: true,
|
||||
transition: {
|
||||
name: "flip",
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function onBackButtonTap(args: EventData): void {
|
||||
const button = <Button>args.object;
|
||||
button.page.frame.goBack();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Page codeFile="~/tab-page/tabs-page" xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" class="page">
|
||||
|
||||
<ActionBar class="action-bar">
|
||||
<NavigationButton text="tabTopBack" tap="onBackButtonTap" android.systemIcon="ic_menu_back" />
|
||||
@@ -13,16 +13,18 @@
|
||||
<Button text="navigate to some page (flip transition)" tap="onNavigateFlip" />
|
||||
</StackLayout>
|
||||
|
||||
<TabView row="1" androidTabsPosition="top">
|
||||
<TabViewItem title="Players">
|
||||
<Frame defaultPage="players/players-items-page" />
|
||||
</TabViewItem>
|
||||
<TabViewItem title="Dummy">
|
||||
<Label text="this is a tab" />
|
||||
</TabViewItem>
|
||||
<TabViewItem title="Teams">
|
||||
<Frame defaultPage="teams/teams-items-page" />
|
||||
</TabViewItem>
|
||||
</TabView>
|
||||
<GridLayout row="1">
|
||||
<TabView androidTabsPosition="top">
|
||||
<TabViewItem title="Players">
|
||||
<Frame defaultPage="players/players-items-page" />
|
||||
</TabViewItem>
|
||||
<TabViewItem title="Dummy">
|
||||
<Label text="this is a tab" />
|
||||
</TabViewItem>
|
||||
<TabViewItem title="Teams">
|
||||
<Frame defaultPage="teams/teams-items-page" />
|
||||
</TabViewItem>
|
||||
</TabView>
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
@@ -0,0 +1,5 @@
|
||||
import * as application from "tns-core-modules/application";
|
||||
|
||||
export function onReset() {
|
||||
application._resetRootView({ moduleName: "app-root" });
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<TabView codeFile="~/tab-root/tab-root" androidTabsPosition="bottom">
|
||||
<TabView androidTabsPosition="bottom">
|
||||
<TabViewItem title="Players">
|
||||
<GridLayout rows="auto, auto, *">
|
||||
<Label text="tab root bottom home" />
|
||||
5
e2e/nested-frame-navigation/app/tab-root/tab-top-root.ts
Normal file
5
e2e/nested-frame-navigation/app/tab-root/tab-top-root.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as application from "tns-core-modules/application";
|
||||
|
||||
export function onReset() {
|
||||
application._resetRootView({ moduleName: "app-root" });
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<TabView codeFile="~/tab-root/tab-root" androidTabsPosition="top">
|
||||
<TabView androidTabsPosition="top">
|
||||
<TabViewItem title="Players">
|
||||
<GridLayout rows="auto, auto, *">
|
||||
<Label text="tab root top home" />
|
||||
@@ -38,14 +38,14 @@ export function onItemTap(args: ItemEventData) {
|
||||
case "slide":
|
||||
entry.transition = {
|
||||
name: "slide",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
};
|
||||
break;
|
||||
case "flip":
|
||||
entry.transition = {
|
||||
name: "flip",
|
||||
duration: 380,
|
||||
duration: 300,
|
||||
curve: "easeIn"
|
||||
};
|
||||
break;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const suspendTime = 1;
|
||||
export const appSuspendResume = true;
|
||||
export const dontKeepActivities = true;
|
||||
export const transitions = ["Default", "None", "Slide", "Flip"];
|
||||
// TODO: restore "slide" when https://github.com/NativeScript/NativeScript/issues/6728 is fixed
|
||||
export const transitions = ["Default", "None", /*"Slide", */"Flip"];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen, playersData, home, somePage, teamsData } from "./screen";
|
||||
|
||||
import { Screen, playersData, home, somePage, teamsData, driverDefaultWaitTime } from "./screen";
|
||||
import * as shared from "./shared.e2e-spec";
|
||||
import { suspendTime, appSuspendResume, dontKeepActivities, transitions } from "./config";
|
||||
|
||||
@@ -13,6 +14,8 @@ describe("frame-root:", () => {
|
||||
if (dontKeepActivities) {
|
||||
await driver.setDontKeepActivities(true);
|
||||
}
|
||||
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -76,7 +79,12 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
@@ -95,7 +103,12 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
|
||||
await screen.goBackToPlayersList();
|
||||
@@ -152,7 +165,12 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
@@ -171,7 +189,12 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
await screen.loadedTeamsList(); // assert visible & no changes
|
||||
|
||||
@@ -206,7 +229,11 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -230,7 +257,12 @@ describe("frame-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo); // assert no changes after back navigation
|
||||
await screen.loadedTeamDetails(teamTwo);
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen, playersData, somePage, teamsData } from "./screen";
|
||||
|
||||
import { Screen, playersData, somePage, teamsData, driverDefaultWaitTime } from "./screen";
|
||||
import * as shared from "./shared.e2e-spec";
|
||||
import { suspendTime, appSuspendResume, dontKeepActivities, transitions } from "./config";
|
||||
|
||||
// NOTE: TabTop is Android only scenario (for iOS we will essentially execute 2x TabBottom)
|
||||
const roots = ["TabTop", "TabBottom"];
|
||||
|
||||
function hyphenate(s: string) {
|
||||
@@ -19,6 +21,8 @@ describe("frame-tab-root:", () => {
|
||||
if (dontKeepActivities) {
|
||||
await driver.setDontKeepActivities(true);
|
||||
}
|
||||
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -88,7 +92,12 @@ describe("frame-tab-root:", () => {
|
||||
await driver.waitForElement(somePage) // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
@@ -107,7 +116,12 @@ describe("frame-tab-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
|
||||
await screen.goBackToPlayersList();
|
||||
@@ -151,7 +165,11 @@ describe("frame-tab-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -183,7 +201,11 @@ describe("frame-tab-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
import { Screen, playersData, home, somePage, otherPage, teamsData } from "./screen";
|
||||
|
||||
import { Screen, playersData, home, somePage, otherPage, teamsData, driverDefaultWaitTime } from "./screen";
|
||||
import * as shared from "./shared.e2e-spec";
|
||||
import { suspendTime, appSuspendResume, dontKeepActivities, transitions } from "./config";
|
||||
|
||||
@@ -13,6 +14,8 @@ describe("layout-root:", () => {
|
||||
if (dontKeepActivities) {
|
||||
await driver.setDontKeepActivities(true);
|
||||
}
|
||||
|
||||
driver.defaultWaitTime = driverDefaultWaitTime;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -39,16 +42,16 @@ describe("layout-root:", () => {
|
||||
it("loaded home page", async () => {
|
||||
await screen.loadedHome();
|
||||
});
|
||||
|
||||
|
||||
it("loaded layout root with nested frames", async () => {
|
||||
await screen.navigateToLayoutWithFrame();
|
||||
await screen.loadedLayoutWithFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded player details and go back twice", async () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
|
||||
@@ -67,7 +70,7 @@ describe("layout-root:", () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
await shared.testPlayerNavigatedBack(screen, driver);
|
||||
});
|
||||
|
||||
|
||||
it("navigate parent frame and go back", async () => {
|
||||
await shared[`testSomePageNavigated${transition}`](screen);
|
||||
|
||||
@@ -76,10 +79,15 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded player details and navigate parent frame and go back", async () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
|
||||
@@ -94,14 +102,19 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
|
||||
|
||||
await screen.goBackToPlayersList();
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded home page again", async () => {
|
||||
await screen.resetToHome();
|
||||
await screen.loadedHome();
|
||||
@@ -111,20 +124,20 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(home); // wait for home page
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it("loaded layout root with multi nested frames", async () => {
|
||||
await screen.navigateToLayoutWithMultiFrame();
|
||||
await screen.loadedLayoutWithMultiFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded teams list", async () => {
|
||||
await screen.loadedTeamsList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded player details and go back twice", async () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
|
||||
@@ -139,11 +152,11 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(playerOne.name) // wait for players list
|
||||
}
|
||||
|
||||
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
await shared.testPlayerNavigatedBack(screen, driver);
|
||||
});
|
||||
|
||||
|
||||
it("navigate players parent frame and go back", async () => {
|
||||
await shared[`testSomePageNavigated${transition}`](screen);
|
||||
|
||||
@@ -151,11 +164,16 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players details and navigate parent frame and go back", async () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
|
||||
@@ -170,44 +188,53 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
|
||||
|
||||
await screen.goBackToPlayersList();
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded layout root with multi nested frames again", async () => {
|
||||
await screen.loadedLayoutWithMultiFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
|
||||
|
||||
it("loaded teams list", async () => {
|
||||
await screen.loadedTeamsList();
|
||||
});
|
||||
|
||||
it ("mix player and team list actions and go back", async () => {
|
||||
|
||||
it("mix player and team list actions and go back", async () => {
|
||||
await shared.testPlayerNavigated(playerTwo, screen);
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(playerTwo.name); // wait for player
|
||||
}
|
||||
|
||||
|
||||
await shared[`testOtherPageNavigated${transition}`](screen); // "teams" parent frame navigation
|
||||
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(otherPage); // wait for other page
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo); // assert no changes in the sibling frame
|
||||
|
||||
await driver.navBack(); // other page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // other page back navigation
|
||||
} else {
|
||||
await screen.goBackFromOtherPage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -216,7 +243,7 @@ describe("layout-root:", () => {
|
||||
|
||||
await screen.loadedTeamsList();
|
||||
await screen.loadedPlayerDetails(playerTwo); // assert no changes in the sibling frame
|
||||
|
||||
|
||||
await shared[`testOtherPageNavigated${transition}`](screen);
|
||||
|
||||
if (appSuspendResume) {
|
||||
@@ -232,10 +259,15 @@ describe("layout-root:", () => {
|
||||
}
|
||||
|
||||
await screen.loadedOtherPage(); // assert no changes in the sibling frame
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
await screen.loadedPlayerDetails(playerTwo);
|
||||
|
||||
|
||||
await screen.goBackToPlayersList();
|
||||
await screen.loadedPlayersList();
|
||||
|
||||
@@ -243,7 +275,7 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(playerOne.name); // wait for players list
|
||||
}
|
||||
|
||||
|
||||
await screen.goBackFromOtherPage();
|
||||
|
||||
if (appSuspendResume) {
|
||||
@@ -269,7 +301,7 @@ describe("layout-root:", () => {
|
||||
await screen.navigateToLayoutWithFrame();
|
||||
await screen.loadedLayoutWithFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
@@ -282,7 +314,7 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(playerTwo.name); // wait for player
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it("navigate parent frame and go back", async () => {
|
||||
await shared.testSomePageNavigatedDefault(screen);
|
||||
|
||||
@@ -290,8 +322,12 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -324,7 +360,7 @@ describe("layout-root:", () => {
|
||||
await screen.navigateToLayoutWithFrame();
|
||||
await screen.loadedLayoutWithFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
@@ -337,7 +373,7 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(playerTwo.name); // wait for player
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it("navigate parent frame and go back", async () => {
|
||||
await shared.testSomePageNavigatedNone(screen);
|
||||
|
||||
@@ -345,8 +381,12 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -379,7 +419,7 @@ describe("layout-root:", () => {
|
||||
await screen.navigateToLayoutWithFrame();
|
||||
await screen.loadedLayoutWithFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
@@ -392,7 +432,7 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(playerTwo.name); // wait for player
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it("navigate parent frame and go back", async () => {
|
||||
await shared.testSomePageNavigatedDefault(screen);
|
||||
|
||||
@@ -400,8 +440,12 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
@@ -434,7 +478,7 @@ describe("layout-root:", () => {
|
||||
await screen.navigateToLayoutWithFrame();
|
||||
await screen.loadedLayoutWithFrame();
|
||||
});
|
||||
|
||||
|
||||
it("loaded players list", async () => {
|
||||
await screen.loadedPlayersList();
|
||||
});
|
||||
@@ -447,7 +491,7 @@ describe("layout-root:", () => {
|
||||
await driver.waitForElement(playerTwo.name); // wait for player
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
it("navigate parent frame and go back", async () => {
|
||||
await shared.testSomePageNavigatedNone(screen);
|
||||
|
||||
@@ -455,8 +499,12 @@ describe("layout-root:", () => {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
await driver.waitForElement(somePage); // wait for some page
|
||||
}
|
||||
|
||||
await driver.navBack(); // some page back navigation
|
||||
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack(); // some page back navigation
|
||||
} else {
|
||||
await screen.goBackFromSomePage();
|
||||
}
|
||||
|
||||
if (appSuspendResume) {
|
||||
await driver.backgroundApp(suspendTime);
|
||||
|
||||
@@ -36,6 +36,7 @@ const tabTopBack = "tabTopBack";
|
||||
const tabBottomBack = "tabBottomBack";
|
||||
const resetApp = "reset app";
|
||||
|
||||
export const driverDefaultWaitTime = 10000;
|
||||
export const home = "Home";
|
||||
export const somePage = "some page";
|
||||
export const otherPage = "other page";
|
||||
@@ -213,7 +214,7 @@ export class Screen {
|
||||
};
|
||||
|
||||
resetToHome = async () => {
|
||||
const btnReset = await this._driver.findElementByAutomationText(resetApp);
|
||||
const btnReset = await this._driver.waitForElement(resetApp);
|
||||
await btnReset.tap();
|
||||
};
|
||||
|
||||
@@ -246,18 +247,18 @@ export class Screen {
|
||||
}
|
||||
|
||||
togglePlayersTab = async () => {
|
||||
const lblPlayers = await this._driver.findElementByAutomationText(players);
|
||||
const lblPlayers = await this._driver.waitForElement(players);
|
||||
await lblPlayers.tap();
|
||||
}
|
||||
|
||||
toggleTeamsTab = async () => {
|
||||
const lblTeams = await this._driver.findElementByAutomationText(teams);
|
||||
const lblTeams = await this._driver.waitForElement(teams);
|
||||
await lblTeams.tap();
|
||||
}
|
||||
|
||||
loadedHome = async () => {
|
||||
const lblHome = await this._driver.findElementByAutomationText(home);
|
||||
assert.isTrue(await lblHome.isDisplayed());
|
||||
const lblHome = await this._driver.waitForElement(home);
|
||||
assert.isNotNull(lblHome);
|
||||
console.log(home + " loaded!");
|
||||
};
|
||||
|
||||
@@ -303,8 +304,8 @@ export class Screen {
|
||||
}
|
||||
|
||||
loadedPlayersList = async () => {
|
||||
const lblPlayerOne = await this._driver.findElementByAutomationText(playersData["playerOneDefault"].name);
|
||||
assert.isTrue(await lblPlayerOne.isDisplayed());
|
||||
const lblPlayerOne = await this._driver.waitForElement(playersData["playerOneDefault"].name);
|
||||
assert.isNotNull(lblPlayerOne);
|
||||
console.log(players + " loaded!");
|
||||
}
|
||||
|
||||
@@ -313,8 +314,8 @@ export class Screen {
|
||||
}
|
||||
|
||||
loadedTeamsList = async () => {
|
||||
const lblTeamOne = await this._driver.findElementByAutomationText(teamsData["teamOneDefault"].name);
|
||||
assert.isTrue(await lblTeamOne.isDisplayed());
|
||||
const lblTeamOne = await this._driver.waitForElement(teamsData["teamOneDefault"].name);
|
||||
assert.isNotNull(lblTeamOne);
|
||||
console.log(teams + " loaded!");
|
||||
}
|
||||
|
||||
@@ -323,33 +324,33 @@ export class Screen {
|
||||
}
|
||||
|
||||
private navigateToPage = async (page: string) => {
|
||||
const btnPage = await this._driver.findElementByAutomationText(page);
|
||||
const btnPage = await this._driver.waitForElement(page);
|
||||
await btnPage.tap();
|
||||
};
|
||||
|
||||
private loadedPage = async (page: string) => {
|
||||
const lblPage = await this._driver.findElementByAutomationText(page);
|
||||
assert.isTrue(await lblPage.isDisplayed());
|
||||
const lblPage = await this._driver.waitForElement(page);
|
||||
assert.isNotNull(lblPage);
|
||||
console.log(page + " loaded!");
|
||||
};
|
||||
|
||||
private navigateToItem = async (item: Item) => {
|
||||
const lblItem = await this._driver.findElementByAutomationText(item.name);
|
||||
const lblItem = await this._driver.waitForElement(item.name);
|
||||
await lblItem.tap();
|
||||
}
|
||||
|
||||
private loadedItem = async (item: Item) => {
|
||||
const lblItemName = await this._driver.findElementByAutomationText(item.name);
|
||||
assert.isTrue(await lblItemName.isDisplayed());
|
||||
const lblItemName = await this._driver.waitForElement(item.name);
|
||||
assert.isNotNull(lblItemName);
|
||||
|
||||
const lblItemDescription = await this._driver.findElementByAutomationText(item.description);
|
||||
assert.isTrue(await lblItemDescription.isDisplayed());
|
||||
const lblItemDescription = await this._driver.waitForElement(item.description);
|
||||
assert.isNotNull(lblItemDescription);
|
||||
|
||||
console.log(item.name + " loaded!");
|
||||
}
|
||||
|
||||
private goBack = async (accessibilityId: string) => {
|
||||
const btnBack = await this._driver.findElementByAccessibilityId(accessibilityId);
|
||||
const btnBack = await this._driver.waitForElement(accessibilityId);
|
||||
await btnBack.tap();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
import { Screen, Item } from "./screen";
|
||||
import { AppiumDriver } from "nativescript-dev-appium";
|
||||
|
||||
import { Screen, Item } from "./screen";
|
||||
|
||||
export async function testPlayerNavigated(player: Item, screen: Screen) {
|
||||
await screen.navigateToPlayerDetails(player);
|
||||
await screen.loadedPlayerDetails(player);
|
||||
}
|
||||
|
||||
export async function testPlayerNavigatedBack(screen: Screen, driver: AppiumDriver) {
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackToPlayersList();
|
||||
}
|
||||
|
||||
await screen.loadedPlayersList();
|
||||
}
|
||||
|
||||
@@ -37,7 +43,12 @@ export async function testTeamNavigated(team: Item, screen: Screen) {
|
||||
}
|
||||
|
||||
export async function testTeamNavigatedBack(screen: Screen, driver: AppiumDriver) {
|
||||
await driver.navBack();
|
||||
if (driver.isAndroid) {
|
||||
await driver.navBack();
|
||||
} else {
|
||||
await screen.goBackToTeamsList();
|
||||
}
|
||||
|
||||
await screen.loadedTeamsList();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { AppiumDriver, createDriver } from "nativescript-dev-appium";
|
||||
|
||||
import { Screen, playersData, teamsData } from "./screen";
|
||||
import * as shared from "./shared.e2e-spec";
|
||||
import { suspendTime, appSuspendResume, dontKeepActivities, transitions } from "./config";
|
||||
|
||||
// NOTE: TabTop is Android only scenario (for iOS we will essentially execute 2x TabBottom)
|
||||
const roots = ["TabTop", "TabBottom"];
|
||||
|
||||
function hyphenate(s: string) {
|
||||
@@ -19,6 +21,8 @@ describe("tab-root:", () => {
|
||||
if (dontKeepActivities) {
|
||||
await driver.setDontKeepActivities(true);
|
||||
}
|
||||
|
||||
driver.defaultWaitTime = 8000;
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
|
||||
@@ -33,4 +33,4 @@
|
||||
"e2e-watch": "tsc -p e2e --watch",
|
||||
"clean-e2e": "rimraf 'e2e/**/*.js' 'e2e/**/*.js.map' 'e2e/**/*.map'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"time-grunt": "1.3.0",
|
||||
"tslib": "^1.9.3",
|
||||
"tslint": "^5.4.3",
|
||||
"typedoc": "^0.5.10",
|
||||
"typedoc": "^0.13.0",
|
||||
"typedoc-plugin-external-module-name": "git://github.com/PanayotCankov/typedoc-plugin-external-module-name.git#with-js",
|
||||
"typescript": "^3.1.6"
|
||||
},
|
||||
|
||||
3
tests/app/app/app-new.css
Normal file
3
tests/app/app/app-new.css
Normal file
@@ -0,0 +1,3 @@
|
||||
Button, Label {
|
||||
color: green;
|
||||
}
|
||||
3
tests/app/app/app-new.scss
Normal file
3
tests/app/app/app-new.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
Button, Label {
|
||||
color: green;
|
||||
}
|
||||
@@ -90,6 +90,12 @@ application.on(application.uncaughtErrorEvent, function (args: application.Unhan
|
||||
console.log((<any>args.error).stackTrace || (<any>args.error).stack);
|
||||
});
|
||||
|
||||
application.on(application.discardedErrorEvent, function (args: application.DiscardedErrorEventData) {
|
||||
console.log("[Discarded] NativeScriptError: " + args.error);
|
||||
console.log((<any>args.error).nativeException || (<any>args.error).nativeError);
|
||||
console.log((<any>args.error).stackTrace || (<any>args.error).stack);
|
||||
});
|
||||
|
||||
// Android activity events
|
||||
if (application.android) {
|
||||
application.android.on(application.AndroidApplication.activityCreatedEvent, function (args: application.AndroidActivityBundleEventData) {
|
||||
|
||||
3
tests/app/app/application.css
Normal file
3
tests/app/app/application.css
Normal file
@@ -0,0 +1,3 @@
|
||||
Button, Label {
|
||||
color: black;
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
import * as trace from "tns-core-modules/trace";
|
||||
import * as tests from "../testRunner";
|
||||
|
||||
let executeTests = true;
|
||||
|
||||
trace.enable();
|
||||
trace.addCategories(trace.categories.Test + "," + trace.categories.Error);
|
||||
|
||||
@@ -21,6 +23,8 @@ function runTests() {
|
||||
|
||||
export function onNavigatedTo(args) {
|
||||
args.object.off(Page.loadedEvent, onNavigatedTo);
|
||||
|
||||
runTests();
|
||||
if (executeTests) {
|
||||
executeTests = false;
|
||||
runTests();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<Page navigatedTo="onNavigatedTo">
|
||||
<Label text="Running non-UI tests..." />
|
||||
<Label id="label" text="Running non-UI tests..." />
|
||||
</Page>
|
||||
|
||||
113
tests/app/livesync/livesync-tests.ts
Normal file
113
tests/app/livesync/livesync-tests.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import * as app from "tns-core-modules/application/application";
|
||||
import * as frame from "tns-core-modules/ui/frame";
|
||||
import * as helper from "../ui/helper";
|
||||
import * as TKUnit from "../TKUnit";
|
||||
import { Color } from "tns-core-modules/color";
|
||||
import { parse } from "tns-core-modules/ui/builder";
|
||||
import { Page } from "tns-core-modules/ui/page";
|
||||
|
||||
const appCssFileName = "./app/application.css";
|
||||
const appNewCssFileName = "./app/app-new.css";
|
||||
const appNewScssFileName = "./app/app-new.scss";
|
||||
const appJsFileName = "./app/app.js";
|
||||
const appTsFileName = "./app/app.ts";
|
||||
const mainPageCssFileName = "./app/main-page.css";
|
||||
const mainPageHtmlFileName = "./app/main-page.html";
|
||||
const mainPageXmlFileName = "./app/main-page.xml";
|
||||
|
||||
const green = new Color("green");
|
||||
|
||||
const mainPageTemplate = `
|
||||
<Page>
|
||||
<StackLayout>
|
||||
<Label id="label" text="label"></Label>
|
||||
</StackLayout>
|
||||
</Page>`;
|
||||
|
||||
const pageTemplate = `
|
||||
<Page>
|
||||
<StackLayout>
|
||||
<Button id="button" text="button"></Button>
|
||||
</StackLayout>
|
||||
</Page>`;
|
||||
|
||||
export function test_onLiveSync_HmrContext_AppStyle_AppNewCss() {
|
||||
_test_onLiveSync_HmrContext_AppStyle(appNewCssFileName);
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_AppStyle_AppNewScss() {
|
||||
_test_onLiveSync_HmrContext_AppStyle(appNewScssFileName);
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_ContextUndefined() {
|
||||
_test_onLiveSync_HmrContext({ type: undefined, module: undefined });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_ModuleUndefined() {
|
||||
_test_onLiveSync_HmrContext({ type: "script", module: undefined });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_Script_AppJs() {
|
||||
_test_onLiveSync_HmrContext({ type: "script", module: appJsFileName });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_Script_AppTs() {
|
||||
_test_onLiveSync_HmrContext({ type: "script", module: appTsFileName });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_Style_MainPageCss() {
|
||||
_test_onLiveSync_HmrContext({ type: "style", module: mainPageCssFileName });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_Markup_MainPageHtml() {
|
||||
_test_onLiveSync_HmrContext({ type: "markup", module: mainPageHtmlFileName });
|
||||
}
|
||||
|
||||
export function test_onLiveSync_HmrContext_Markup_MainPageXml() {
|
||||
_test_onLiveSync_HmrContext({ type: "markup", module: mainPageXmlFileName });
|
||||
}
|
||||
|
||||
export function setUpModule() {
|
||||
const mainPage = <Page>parse(mainPageTemplate);
|
||||
helper.navigate(() => mainPage);
|
||||
}
|
||||
|
||||
export function tearDown() {
|
||||
app.setCssFileName(appCssFileName);
|
||||
}
|
||||
|
||||
function _test_onLiveSync_HmrContext_AppStyle(styleFileName: string) {
|
||||
const pageBeforeNavigation = helper.getCurrentPage();
|
||||
|
||||
const page = <Page>parse(pageTemplate);
|
||||
helper.navigateWithHistory(() => page);
|
||||
app.setCssFileName(styleFileName);
|
||||
|
||||
const pageBeforeLiveSync = helper.getCurrentPage();
|
||||
global.__onLiveSync({ type: "style", module: styleFileName });
|
||||
|
||||
const pageAfterLiveSync = helper.getCurrentPage();
|
||||
TKUnit.waitUntilReady(() => pageAfterLiveSync.getViewById("button").style.color.toString() === green.toString());
|
||||
|
||||
TKUnit.assertTrue(pageAfterLiveSync.frame.canGoBack(), "App styles NOT applied - livesync navigation executed!");
|
||||
TKUnit.assertEqual(pageAfterLiveSync, pageBeforeLiveSync, "Pages are different - livesync navigation executed!");
|
||||
TKUnit.assertTrue(pageAfterLiveSync._cssState.isSelectorsLatestVersionApplied(), "Latest selectors version NOT applied!");
|
||||
|
||||
helper.goBack();
|
||||
|
||||
const pageAfterNavigationBack = helper.getCurrentPage();
|
||||
TKUnit.assertEqual(pageAfterNavigationBack.getViewById("label").style.color, green, "App styles NOT applied on back navigation!");
|
||||
TKUnit.assertEqual(pageBeforeNavigation, pageAfterNavigationBack, "Pages are different - livesync navigation executed!");
|
||||
TKUnit.assertTrue(pageAfterNavigationBack._cssState.isSelectorsLatestVersionApplied(), "Latest selectors version is NOT applied!");
|
||||
}
|
||||
|
||||
function _test_onLiveSync_HmrContext(context: { type, module }) {
|
||||
const page = <Page>parse(pageTemplate);
|
||||
helper.navigateWithHistory(() => page);
|
||||
global.__onLiveSync({ type: context.type, module: context.module });
|
||||
|
||||
TKUnit.waitUntilReady(() => !!frame.topmost());
|
||||
const topmostFrame = frame.topmost();
|
||||
TKUnit.waitUntilReady(() => topmostFrame.currentPage && topmostFrame.currentPage.isLoaded && !topmostFrame.canGoBack());
|
||||
TKUnit.assertTrue(topmostFrame.currentPage.getViewById("label").isLoaded);
|
||||
}
|
||||
@@ -153,9 +153,6 @@ allTests["STYLE-PROPERTIES"] = stylePropertiesTests;
|
||||
import * as frameTests from "./ui/frame/frame-tests";
|
||||
allTests["FRAME"] = frameTests;
|
||||
|
||||
import * as tabViewRootTests from "./ui/tab-view/tab-view-root-tests";
|
||||
allTests["TAB-VIEW-ROOT"] = tabViewRootTests;
|
||||
|
||||
import * as viewTests from "./ui/view/view-tests";
|
||||
allTests["VIEW"] = viewTests;
|
||||
|
||||
@@ -255,6 +252,12 @@ allTests["SEARCH-BAR"] = searchBarTests;
|
||||
import * as navigationTests from "./navigation/navigation-tests";
|
||||
allTests["NAVIGATION"] = navigationTests;
|
||||
|
||||
import * as livesyncTests from "./livesync/livesync-tests";
|
||||
allTests["LIVESYNC"] = livesyncTests;
|
||||
|
||||
import * as tabViewRootTests from "./ui/tab-view/tab-view-root-tests";
|
||||
allTests["TAB-VIEW-ROOT"] = tabViewRootTests;
|
||||
|
||||
import * as resetRootViewTests from "./ui/root-view/reset-root-view-tests";
|
||||
allTests["RESET-ROOT-VIEW"] = resetRootViewTests;
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2015-2018 Telerik AD
|
||||
Copyright (c) 2015-2019 Progress Software Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -198,4 +198,4 @@
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
limitations under the License.
|
||||
|
||||
@@ -32,9 +32,17 @@ export function hasLaunched(): boolean {
|
||||
|
||||
export { Observable };
|
||||
|
||||
import { UnhandledErrorEventData, iOSApplication, AndroidApplication, CssChangedEventData, LoadAppCSSEventData } from ".";
|
||||
import {
|
||||
AndroidApplication,
|
||||
CssChangedEventData,
|
||||
getRootView,
|
||||
iOSApplication,
|
||||
LoadAppCSSEventData,
|
||||
UnhandledErrorEventData,
|
||||
DiscardedErrorEventData
|
||||
} from "./application";
|
||||
|
||||
export { UnhandledErrorEventData, CssChangedEventData, LoadAppCSSEventData };
|
||||
export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData };
|
||||
|
||||
export const launchEvent = "launch";
|
||||
export const suspendEvent = "suspend";
|
||||
@@ -43,6 +51,7 @@ export const resumeEvent = "resume";
|
||||
export const exitEvent = "exit";
|
||||
export const lowMemoryEvent = "lowMemory";
|
||||
export const uncaughtErrorEvent = "uncaughtError";
|
||||
export const discardedErrorEvent = "discardedError";
|
||||
export const orientationChangedEvent = "orientationChanged";
|
||||
|
||||
let cssFile: string = "./app.css";
|
||||
@@ -70,10 +79,22 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v
|
||||
app = instance;
|
||||
}
|
||||
|
||||
export function livesync() {
|
||||
export function livesync(context?: HmrContext) {
|
||||
events.notify(<EventData>{ eventName: "livesync", object: app });
|
||||
const liveSyncCore = global.__onLiveSyncCore;
|
||||
if (liveSyncCore) {
|
||||
let reapplyAppCss = false
|
||||
|
||||
if (context) {
|
||||
const fullFileName = getCssFileName();
|
||||
const fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".") + 1);
|
||||
const extensions = ["css", "scss"];
|
||||
reapplyAppCss = extensions.some(ext => context.module === fileName.concat(ext));
|
||||
}
|
||||
|
||||
const rootView = getRootView();
|
||||
if (reapplyAppCss && rootView) {
|
||||
rootView._onCssStateChange();
|
||||
} else if (liveSyncCore) {
|
||||
liveSyncCore();
|
||||
}
|
||||
}
|
||||
@@ -92,7 +113,7 @@ export function loadAppCss(): void {
|
||||
events.notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: app, cssFile: getCssFileName() });
|
||||
} catch (e) {
|
||||
throw new Error(`The file ${getCssFileName()} couldn't be loaded! ` +
|
||||
`You may need to register it inside ./app/vendor.ts.`);
|
||||
`You may need to register it inside ./app/vendor.ts.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,3 +124,7 @@ export function addCss(cssText: string): void {
|
||||
global.__onUncaughtError = function (error: NativeScriptError) {
|
||||
events.notify(<UnhandledErrorEventData>{ eventName: uncaughtErrorEvent, object: app, android: error, ios: error, error: error });
|
||||
}
|
||||
|
||||
global.__onDiscardedError = function (error: NativeScriptError) {
|
||||
events.notify(<DiscardedErrorEventData>{ eventName: discardedErrorEvent, object: app, error: error });
|
||||
}
|
||||
|
||||
@@ -212,12 +212,12 @@ export function getNativeApplication(): android.app.Application {
|
||||
return nativeApp;
|
||||
}
|
||||
|
||||
global.__onLiveSync = function () {
|
||||
global.__onLiveSync = function __onLiveSync(context?: HmrContext) {
|
||||
if (androidApp && androidApp.paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
livesync();
|
||||
livesync(context);
|
||||
};
|
||||
|
||||
function initLifecycleCallbacks() {
|
||||
@@ -290,15 +290,10 @@ function initLifecycleCallbacks() {
|
||||
onActivityResumed: profile("onActivityResumed", function (activity: android.support.v7.app.AppCompatActivity) {
|
||||
androidApp.foregroundActivity = activity;
|
||||
|
||||
if ((<any>activity).isNativeScriptActivity) {
|
||||
notify(<ApplicationEventData>{ eventName: resumeEvent, object: androidApp, android: activity });
|
||||
androidApp.paused = false;
|
||||
}
|
||||
|
||||
androidApp.notify(<AndroidActivityEventData>{ eventName: ActivityResumed, object: androidApp, activity: activity });
|
||||
}),
|
||||
|
||||
onActivitySaveInstanceState: profile("onActivityResumed", function (activity: android.support.v7.app.AppCompatActivity, outState: android.os.Bundle) {
|
||||
onActivitySaveInstanceState: profile("onActivitySaveInstanceState", function (activity: android.support.v7.app.AppCompatActivity, outState: android.os.Bundle) {
|
||||
androidApp.notify(<AndroidActivityBundleEventData>{ eventName: SaveActivityState, object: androidApp, activity: activity, bundle: outState });
|
||||
}),
|
||||
|
||||
|
||||
29
tns-core-modules/application/application.d.ts
vendored
29
tns-core-modules/application/application.d.ts
vendored
@@ -21,6 +21,11 @@ export var displayedEvent: string;
|
||||
*/
|
||||
export var uncaughtErrorEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to discardedError event.
|
||||
*/
|
||||
export var discardedErrorEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to suspend event.
|
||||
*/
|
||||
@@ -103,6 +108,13 @@ export interface UnhandledErrorEventData extends ApplicationEventData {
|
||||
error: NativeScriptError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event data containing information about discarded application errors.
|
||||
*/
|
||||
export interface DiscardedErrorEventData extends ApplicationEventData {
|
||||
error: NativeScriptError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event data containing information about application css change.
|
||||
*/
|
||||
@@ -137,7 +149,7 @@ export function setResources(res: any): void;
|
||||
export function setResources(resources: any);
|
||||
|
||||
/**
|
||||
* Sets css file name for the application.
|
||||
* Sets css file name for the application.
|
||||
*/
|
||||
export function setCssFileName(cssFile: string): void;
|
||||
|
||||
@@ -199,7 +211,7 @@ export function shouldCreateRootFrame(): boolean;
|
||||
|
||||
/**
|
||||
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
|
||||
* @param eventNames - String corresponding to events (e.g. "onLaunch"). Optionally could be used more events separated by `,` (e.g. "onLaunch", "onSuspend").
|
||||
* @param eventNames - String corresponding to events (e.g. "onLaunch"). Optionally could be used more events separated by `,` (e.g. "onLaunch", "onSuspend").
|
||||
* @param callback - Callback function which will be executed when event is raised.
|
||||
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
||||
*/
|
||||
@@ -262,6 +274,11 @@ export function on(event: "lowMemory", callback: (args: ApplicationEventData) =>
|
||||
*/
|
||||
export function on(event: "uncaughtError", callback: (args: UnhandledErrorEventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* This event is raised when an discarded error occurs while the application is running.
|
||||
*/
|
||||
export function on(event: "discardedError", callback: (args: DiscardedErrorEventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* This event is raised the orientation of the current device has changed.
|
||||
*/
|
||||
@@ -403,13 +420,13 @@ export class AndroidApplication extends Observable {
|
||||
/**
|
||||
* Initialized the android-specific application object with the native android.app.Application instance.
|
||||
* This is useful when creating custom application types.
|
||||
* @param nativeApp - the android.app.Application instance that started the app.
|
||||
* @param nativeApp - the android.app.Application instance that started the app.
|
||||
*/
|
||||
init: (nativeApp) => void;
|
||||
|
||||
/**
|
||||
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
|
||||
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
|
||||
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
|
||||
* @param callback - Callback function which will be executed when event is raised.
|
||||
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
||||
*/
|
||||
@@ -516,7 +533,7 @@ export class AndroidApplication extends Observable {
|
||||
public static activityRequestPermissionsEvent: string;
|
||||
|
||||
/**
|
||||
* Register a BroadcastReceiver to be run in the main activity thread. The receiver will be called with any broadcast Intent that matches filter, in the main application thread.
|
||||
* Register a BroadcastReceiver to be run in the main activity thread. The receiver will be called with any broadcast Intent that matches filter, in the main application thread.
|
||||
* For more information, please visit 'http://developer.android.com/reference/android/content/Context.html#registerReceiver%28android.content.BroadcastReceiver,%20android.content.IntentFilter%29'
|
||||
* @param intentFilter A string containing the intent filter.
|
||||
* @param onReceiveCallback A callback function that will be called each time the receiver receives a broadcast.
|
||||
@@ -524,7 +541,7 @@ export class AndroidApplication extends Observable {
|
||||
registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: any /* android.content.Context */, intent: any /* android.content.Intent */) => void): void;
|
||||
|
||||
/**
|
||||
* Unregister a previously registered BroadcastReceiver.
|
||||
* Unregister a previously registered BroadcastReceiver.
|
||||
* For more information, please visit 'http://developer.android.com/reference/android/content/Context.html#unregisterReceiver(android.content.BroadcastReceiver)'
|
||||
* @param intentFilter A string containing the intent filter with which the receiver was originally registered.
|
||||
*/
|
||||
|
||||
@@ -161,7 +161,7 @@ class IOSApplication implements IOSApplicationDefinition {
|
||||
this.setWindowContent(args.root);
|
||||
} else {
|
||||
this._window = UIApplication.sharedApplication.delegate.window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
@@ -373,10 +373,10 @@ function setViewControllerView(view: View): void {
|
||||
}
|
||||
}
|
||||
|
||||
global.__onLiveSync = function () {
|
||||
global.__onLiveSync = function __onLiveSync(context?: HmrContext) {
|
||||
if (!started) {
|
||||
return;
|
||||
}
|
||||
|
||||
livesync();
|
||||
}
|
||||
livesync(context);
|
||||
}
|
||||
@@ -52,7 +52,10 @@ function ensureCompleteCallback() {
|
||||
onComplete: function (result: any, context: any) {
|
||||
// as a context we will receive the id of the request
|
||||
onRequestComplete(context, result);
|
||||
}
|
||||
},
|
||||
onError: function (error: string, context: any) {
|
||||
onRequestError(error, context);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -148,6 +151,14 @@ function onRequestComplete(requestId: number, result: org.nativescript.widgets.A
|
||||
});
|
||||
}
|
||||
|
||||
function onRequestError(error: string, requestId: number) {
|
||||
var callbacks = pendingRequests[requestId];
|
||||
delete pendingRequests[requestId];
|
||||
if (callbacks) {
|
||||
callbacks.rejectCallback(new Error(error));
|
||||
}
|
||||
}
|
||||
|
||||
function buildJavaOptions(options: http.HttpRequestOptions) {
|
||||
if (typeof options.url !== "string") {
|
||||
throw new Error("Http request must provide a valid url.");
|
||||
|
||||
28
tns-core-modules/module.d.ts
vendored
28
tns-core-modules/module.d.ts
vendored
@@ -3,7 +3,7 @@ declare var global: NodeJS.Global;
|
||||
interface ModuleResolver {
|
||||
/**
|
||||
* A function used to resolve the exports for a module.
|
||||
* @param uri The name of the module to be resolved.
|
||||
* @param uri The name of the module to be resolved.
|
||||
*/
|
||||
(uri: string): any;
|
||||
}
|
||||
@@ -18,7 +18,7 @@ declare namespace NodeJS {
|
||||
* Register all modules from a webpack context.
|
||||
* The context is one created using the following webpack utility:
|
||||
* https://webpack.github.io/docs/context.html
|
||||
*
|
||||
*
|
||||
* The extension map is optional, modules in the webpack context will have their original file extension (e.g. may be ".ts" or ".scss" etc.),
|
||||
* while the built-in module builders in {N} will look for ".js", ".css" or ".xml" files. Adding a map such as:
|
||||
* ```
|
||||
@@ -51,9 +51,10 @@ declare namespace NodeJS {
|
||||
__native?: any;
|
||||
__inspector?: any;
|
||||
__extends: any;
|
||||
__onLiveSync: () => void;
|
||||
__onLiveSync: (context?: { type: string, module: string }) => void;
|
||||
__onLiveSyncCore: () => void;
|
||||
__onUncaughtError: (error: NativeScriptError) => void;
|
||||
__onDiscardedError: (error: NativeScriptError) => void;
|
||||
TNS_WEBPACK?: boolean;
|
||||
__requireOverride?: (name: string, dir: string) => any;
|
||||
}
|
||||
@@ -64,6 +65,27 @@ declare function clearTimeout(timeoutId: number): void;
|
||||
declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): number;
|
||||
declare function clearInterval(intervalId: number): void;
|
||||
|
||||
declare enum HmrType {
|
||||
markup = "markup",
|
||||
script = "script",
|
||||
style = "style"
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a context for Hot Module Replacement.
|
||||
*/
|
||||
interface HmrContext {
|
||||
/**
|
||||
* The type of module for replacement.
|
||||
*/
|
||||
type: HmrType;
|
||||
|
||||
/**
|
||||
* The module for replacement.
|
||||
*/
|
||||
module: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An extended JavaScript Error which will have the nativeError property initialized in case the error is caused by executing platform-specific code.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tns-core-modules",
|
||||
"description": "Telerik NativeScript Core Modules",
|
||||
"version": "5.1.2",
|
||||
"version": "5.2.0",
|
||||
"homepage": "https://www.nativescript.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -26,7 +26,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"typings": "tns-core-modules.d.ts",
|
||||
"dependencies": {
|
||||
"tns-core-modules-widgets": "5.1.2",
|
||||
"tns-core-modules-widgets": "next",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -38,8 +38,8 @@
|
||||
},
|
||||
"nativescript": {
|
||||
"platforms": {
|
||||
"ios": "5.0.0",
|
||||
"android": "5.0.0"
|
||||
"ios": "4.0.0",
|
||||
"android": "4.0.0"
|
||||
}
|
||||
},
|
||||
"snapshot": {
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
layout, Color, traceMissingIcon } from "./action-bar-common";
|
||||
import { fromFileOrResource } from "../../image-source";
|
||||
import { ios as iosUtils } from "../../utils/utils";
|
||||
import { write as traceWrite, categories, messageType } from "../../trace";
|
||||
|
||||
export * from "./action-bar-common";
|
||||
|
||||
|
||||
@@ -81,6 +81,12 @@ export interface ShowModalOptions {
|
||||
*/
|
||||
presentationStyle: any /* UIModalPresentationStyle */
|
||||
}
|
||||
android?: {
|
||||
/**
|
||||
* An optional parameter specifying whether the modal view can be dismissed when not in full-screen mode.
|
||||
*/
|
||||
cancelable?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class ViewBase extends Observable {
|
||||
|
||||
@@ -37,6 +37,7 @@ interface DialogOptions {
|
||||
owner: View;
|
||||
fullscreen: boolean;
|
||||
stretched: boolean;
|
||||
cancelable: boolean;
|
||||
shownCallback: () => void;
|
||||
dismissCallback: () => void;
|
||||
}
|
||||
@@ -117,6 +118,7 @@ function initializeDialogFragment() {
|
||||
public owner: View;
|
||||
private _fullscreen: boolean;
|
||||
private _stretched: boolean;
|
||||
private _cancelable: boolean;
|
||||
private _shownCallback: () => void;
|
||||
private _dismissCallback: () => void;
|
||||
|
||||
@@ -130,13 +132,20 @@ function initializeDialogFragment() {
|
||||
const options = getModalOptions(ownerId);
|
||||
this.owner = options.owner;
|
||||
this._fullscreen = options.fullscreen;
|
||||
this._cancelable = options.cancelable;
|
||||
this._stretched = options.stretched;
|
||||
this._dismissCallback = options.dismissCallback;
|
||||
this._shownCallback = options.shownCallback;
|
||||
this.owner._dialogFragment = this;
|
||||
this.setStyle(android.support.v4.app.DialogFragment.STYLE_NO_TITLE, 0);
|
||||
|
||||
let theme = this.getTheme();
|
||||
if (this._fullscreen) {
|
||||
// In fullscreen mode, get the application's theme.
|
||||
theme = this.getActivity().getApplicationInfo().theme;
|
||||
}
|
||||
|
||||
const dialog = new DialogImpl(this, this.getActivity(), this.getTheme());
|
||||
const dialog = new DialogImpl(this, this.getActivity(), theme);
|
||||
|
||||
// do not override alignment unless fullscreen modal will be shown;
|
||||
// otherwise we might break component-level layout:
|
||||
@@ -149,6 +158,7 @@ function initializeDialogFragment() {
|
||||
this.owner.verticalAlignment = "stretch";
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(this._cancelable);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@@ -195,8 +205,17 @@ function initializeDialogFragment() {
|
||||
public onDestroy(): void {
|
||||
super.onDestroy();
|
||||
const owner = this.owner;
|
||||
owner._isAddedToNativeVisualTree = false;
|
||||
owner._tearDownUI(true);
|
||||
|
||||
if (owner) {
|
||||
// Android calls onDestroy before onDismiss.
|
||||
// Make sure we unload first and then call _tearDownUI.
|
||||
if (owner.isLoaded) {
|
||||
owner.callUnloaded();
|
||||
}
|
||||
|
||||
owner._isAddedToNativeVisualTree = false;
|
||||
owner._tearDownUI(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +405,7 @@ export class View extends ViewCommon {
|
||||
if (!this.nativeViewProtected || !this.hasGestureObservers()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// do not set noop listener that handles the event (disabled listener) if IsUserInteractionEnabled is
|
||||
// false as we might need the ability for the event to pass through to a parent view
|
||||
initializeTouchListener();
|
||||
@@ -574,7 +593,7 @@ export class View extends ViewCommon {
|
||||
|
||||
return result | (childMeasuredState & layout.MEASURED_STATE_MASK);
|
||||
}
|
||||
protected _showNativeModalView(parent: View, options: ShowModalOptions) { //context: any, closeCallback: Function, fullscreen?: boolean, animated?: boolean, stretched?: boolean, iosOpts?: any) {
|
||||
protected _showNativeModalView(parent: View, options: ShowModalOptions) {
|
||||
super._showNativeModalView(parent, options);
|
||||
if (!this.backgroundColor) {
|
||||
this.backgroundColor = new Color("White");
|
||||
@@ -591,6 +610,7 @@ export class View extends ViewCommon {
|
||||
owner: this,
|
||||
fullscreen: !!options.fullscreen,
|
||||
stretched: !!options.stretched,
|
||||
cancelable: options.android ? !!options.android.cancelable : true,
|
||||
shownCallback: () => this._raiseShownModallyEvent(),
|
||||
dismissCallback: () => this.closeModal()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Definitions.
|
||||
import { Point, View as ViewDefinition, dip } from ".";
|
||||
import { ViewBase } from "../view-base";
|
||||
import { booleanConverter, Property } from "../view";
|
||||
|
||||
import {
|
||||
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
|
||||
@@ -371,7 +370,7 @@ export class View extends ViewCommon {
|
||||
return this._suspendCATransaction || this._suspendNativeUpdatesCount;
|
||||
}
|
||||
|
||||
protected _showNativeModalView(parent: View, options: ShowModalOptions) { //context: any, closeCallback: Function, fullscreen?: boolean, animated?: boolean, stretched?: boolean, iosOpts?: any) {
|
||||
protected _showNativeModalView(parent: View, options: ShowModalOptions) {
|
||||
const parentWithController = ios.getParentWithViewController(parent);
|
||||
if (!parentWithController) {
|
||||
traceWrite(`Could not find parent with viewController for ${parent} while showing modal view.`,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* iOS specific dialogs functions implementation.
|
||||
*/
|
||||
import { View, ios as iosView } from "../core/view";
|
||||
import { ios as iosView } from "../core/view";
|
||||
import { ConfirmOptions, PromptOptions, PromptResult, LoginOptions, LoginResult, ActionOptions } from ".";
|
||||
import { getCurrentPage, getLabelColor, getButtonColors, getTextFieldColor, isDialogOptions, inputType, capitalizationType, ALERT, OK, CONFIRM, CANCEL, PROMPT, parseLoginOptions } from "./dialogs-common";
|
||||
import { isString, isDefined, isFunction } from "../../utils/types";
|
||||
|
||||
@@ -50,6 +50,10 @@ class NativeScriptActivity extends android.support.v7.app.AppCompatActivity {
|
||||
this._callbacks.onDestroy(this, super.onDestroy);
|
||||
}
|
||||
|
||||
public onPostResume(): void {
|
||||
this._callbacks.onPostResume(this, super.onPostResume);
|
||||
}
|
||||
|
||||
public onBackPressed(): void {
|
||||
this._callbacks.onBackPressed(this, super.onBackPressed);
|
||||
}
|
||||
|
||||
@@ -85,10 +85,14 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
|
||||
export function reloadPage(): void {
|
||||
const activity = application.android.foregroundActivity;
|
||||
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
|
||||
const rootView: View = callbacks.getRootView();
|
||||
if (callbacks) {
|
||||
const rootView: View = callbacks.getRootView();
|
||||
|
||||
if (!rootView || !rootView._onLivesync()) {
|
||||
callbacks.resetActivityContent(activity);
|
||||
if (!rootView || !rootView._onLivesync()) {
|
||||
callbacks.resetActivityContent(activity);
|
||||
}
|
||||
} else {
|
||||
traceError(`${activity}[CALLBACKS] is null or undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,19 +473,19 @@ export class Frame extends FrameBase {
|
||||
switch (this.actionBarVisibility) {
|
||||
case "never":
|
||||
return false;
|
||||
|
||||
|
||||
case "always":
|
||||
return true;
|
||||
|
||||
|
||||
default:
|
||||
if (page.actionBarHidden !== undefined) {
|
||||
return !page.actionBarHidden;
|
||||
}
|
||||
|
||||
|
||||
if (this._android && this._android.showActionBar !== undefined) {
|
||||
return this._android.showActionBar;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -530,7 +534,7 @@ function restoreAnimatorState(entry: BackstackEntry, snapshot: AnimatorState): v
|
||||
if (snapshot.enterAnimator) {
|
||||
expandedEntry.enterAnimator = snapshot.enterAnimator;
|
||||
}
|
||||
|
||||
|
||||
if (snapshot.exitAnimator) {
|
||||
expandedEntry.exitAnimator = snapshot.exitAnimator;
|
||||
}
|
||||
@@ -538,7 +542,7 @@ function restoreAnimatorState(entry: BackstackEntry, snapshot: AnimatorState): v
|
||||
if (snapshot.popEnterAnimator) {
|
||||
expandedEntry.popEnterAnimator = snapshot.popEnterAnimator;
|
||||
}
|
||||
|
||||
|
||||
if (snapshot.popExitAnimator) {
|
||||
expandedEntry.popExitAnimator = snapshot.popExitAnimator;
|
||||
}
|
||||
@@ -858,14 +862,14 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
|
||||
// parent while its supposed parent believes it properly removed its children; in order to "force" the child to
|
||||
// lose its parent we temporarily add it to the parent, and then remove it (addViewInLayout doesn't trigger layout pass)
|
||||
const nativeView = page.nativeViewProtected;
|
||||
if (nativeView != null) {
|
||||
const parentView = nativeView.getParent();
|
||||
if (nativeView != null) {
|
||||
const parentView = nativeView.getParent();
|
||||
if (parentView instanceof android.view.ViewGroup) {
|
||||
if (parentView.getChildCount() === 0) {
|
||||
parentView.addViewInLayout(nativeView, -1, new org.nativescript.widgets.CommonLayoutParams());
|
||||
}
|
||||
|
||||
parentView.removeView(nativeView);
|
||||
parentView.removeView(nativeView);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1006,6 +1010,30 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public onPostResume(activity: any, superFunc: Function): void {
|
||||
superFunc.call(activity);
|
||||
|
||||
if (traceEnabled()) {
|
||||
traceWrite("NativeScriptActivity.onPostResume();", traceCategories.NativeLifecycle);
|
||||
}
|
||||
|
||||
// NOTE: activity.onPostResume() is called when activity resume is complete and we can
|
||||
// safely raise the application resume event;
|
||||
// onActivityResumed(...) lifecycle callback registered in application is called too early
|
||||
// and raising the application resume event there causes issues like
|
||||
// https://github.com/NativeScript/NativeScript/issues/6708
|
||||
if ((<any>activity).isNativeScriptActivity) {
|
||||
const args = <application.ApplicationEventData>{
|
||||
eventName: application.resumeEvent,
|
||||
object: application.android,
|
||||
android: activity
|
||||
};
|
||||
application.notify(args);
|
||||
application.android.paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public onDestroy(activity: any, superFunc: Function): void {
|
||||
if (traceEnabled()) {
|
||||
@@ -1216,4 +1244,4 @@ export function setActivityCallbacks(activity: android.support.v7.app.AppCompatA
|
||||
|
||||
export function setFragmentCallbacks(fragment: android.support.v4.app.Fragment): void {
|
||||
fragment[CALLBACKS] = new FragmentCallbacksImplementation();
|
||||
}
|
||||
}
|
||||
1
tns-core-modules/ui/frame/frame.d.ts
vendored
1
tns-core-modules/ui/frame/frame.d.ts
vendored
@@ -415,6 +415,7 @@ export interface AndroidActivityCallbacks {
|
||||
onSaveInstanceState(activity: any, outState: any, superFunc: Function): void;
|
||||
onStart(activity: any, superFunc: Function): void;
|
||||
onStop(activity: any, superFunc: Function): void;
|
||||
onPostResume(activity: any, superFunc: Function): void;
|
||||
onDestroy(activity: any, superFunc: Function): void;
|
||||
onBackPressed(activity: any, superFunc: Function): void;
|
||||
onRequestPermissionsResult(activity: any, requestCode: number, permissions: Array<String>, grantResults: Array<number>, superFunc: Function): void;
|
||||
|
||||
@@ -6,10 +6,12 @@ export interface DownloadRequest {
|
||||
url: string;
|
||||
key: string;
|
||||
completed?: (image: any, key: string) => void;
|
||||
error?: (key: string) => void;
|
||||
}
|
||||
|
||||
export class Cache extends observable.Observable implements definition.Cache {
|
||||
public static downloadedEvent = "downloaded";
|
||||
public static downloadErrorEvent = "downloadError";
|
||||
|
||||
public placeholder: imageSource.ImageSource;
|
||||
public maxRequests = 5;
|
||||
@@ -93,6 +95,20 @@ export class Cache extends observable.Observable implements definition.Cache {
|
||||
else {
|
||||
existingRequest.completed = newRequest.completed;
|
||||
}
|
||||
if (existingRequest.error) {
|
||||
if (newRequest.error) {
|
||||
var existingError = existingRequest.error;
|
||||
var stackError = function (key: string) {
|
||||
existingError(key);
|
||||
newRequest.error(key);
|
||||
}
|
||||
|
||||
existingRequest.error = stackError;
|
||||
}
|
||||
}
|
||||
else {
|
||||
existingRequest.error = newRequest.error;
|
||||
}
|
||||
}
|
||||
|
||||
public get(key: string): any {
|
||||
@@ -125,10 +141,7 @@ export class Cache extends observable.Observable implements definition.Cache {
|
||||
public _onDownloadCompleted(key: string, image: any) {
|
||||
var request = <DownloadRequest>this._pendingDownloads[key];
|
||||
|
||||
if (request.key && image) {
|
||||
this.set(request.key, image);
|
||||
}
|
||||
|
||||
this.set(request.key, image);
|
||||
this._currentDownloads--;
|
||||
|
||||
if (request.completed) {
|
||||
@@ -140,7 +153,29 @@ export class Cache extends observable.Observable implements definition.Cache {
|
||||
eventName: Cache.downloadedEvent,
|
||||
object: this,
|
||||
key: key,
|
||||
image: image
|
||||
image: image
|
||||
});
|
||||
}
|
||||
|
||||
delete this._pendingDownloads[request.key];
|
||||
|
||||
this._updateQueue();
|
||||
}
|
||||
|
||||
public _onDownloadError(key: string, err: Error) {
|
||||
var request = <DownloadRequest>this._pendingDownloads[key];
|
||||
this._currentDownloads--;
|
||||
|
||||
if (request.error) {
|
||||
request.error(request.key);
|
||||
}
|
||||
|
||||
if (this.hasListeners(Cache.downloadErrorEvent)) {
|
||||
this.notify({
|
||||
eventName: Cache.downloadErrorEvent,
|
||||
object: this,
|
||||
key: key,
|
||||
error: err
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,6 +220,7 @@ export class Cache extends observable.Observable implements definition.Cache {
|
||||
}
|
||||
}
|
||||
export interface Cache {
|
||||
on(eventNames: string, callback: (args: observable.EventData) => void , thisArg?: any);
|
||||
on(event: "downloaded", callback: (args: definition.DownloadedData) => void , thisArg?: any);
|
||||
on(eventNames: string, callback: (args: observable.EventData) => void, thisArg?: any);
|
||||
on(event: "downloaded", callback: (args: definition.DownloadedData) => void, thisArg?: any);
|
||||
on(event: "downloadError", callback: (args: definition.DownloadError) => void, thisArg?: any);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as common from "./image-cache-common";
|
||||
import * as trace from "../../trace";
|
||||
|
||||
var LruBitmapCacheClass;
|
||||
function ensureLruBitmapCacheClass() {
|
||||
@@ -45,7 +46,17 @@ export class Cache extends common.Cache {
|
||||
onComplete: function (result: any, context: any) {
|
||||
var instance = that.get();
|
||||
if (instance) {
|
||||
instance._onDownloadCompleted(context, result)
|
||||
if (result) {
|
||||
instance._onDownloadCompleted(context, result);
|
||||
} else {
|
||||
instance._onDownloadError(context, new Error("No result in CompletionCallback"));
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: function (err: string, context: any) {
|
||||
var instance = that.get();
|
||||
if (instance) {
|
||||
instance._onDownloadError(context, new Error(err));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -61,7 +72,13 @@ export class Cache extends common.Cache {
|
||||
}
|
||||
|
||||
public set(key: string, image: any): void {
|
||||
this._cache.put(key, image);
|
||||
try {
|
||||
if (key && image) {
|
||||
this._cache.put(key, image);
|
||||
}
|
||||
} catch (err) {
|
||||
trace.write("Cache set error: " + err, trace.categories.Error, trace.messageType.error);
|
||||
}
|
||||
}
|
||||
|
||||
public remove(key: string): void {
|
||||
|
||||
36
tns-core-modules/ui/image-cache/image-cache.d.ts
vendored
36
tns-core-modules/ui/image-cache/image-cache.d.ts
vendored
@@ -22,6 +22,10 @@ export interface DownloadRequest {
|
||||
* An optional function to be called when the download is complete.
|
||||
*/
|
||||
completed?: (image: any, key: string) => void;
|
||||
/**
|
||||
* An optional function to be called if the download errors.
|
||||
*/
|
||||
error?: (key: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,6 +36,10 @@ export class Cache extends observable.Observable {
|
||||
* String value used when hooking to downloaded event.
|
||||
*/
|
||||
public static downloadedEvent: string;
|
||||
/**
|
||||
* String value used when hooking to download error event.
|
||||
*/
|
||||
public static downloadErrorEvent: string;
|
||||
/**
|
||||
* The image to be used to notify for a pending download request - e.g. loading indicator.
|
||||
*/
|
||||
@@ -82,12 +90,17 @@ export class Cache extends observable.Observable {
|
||||
* @param callback - Callback function which will be executed when event is raised.
|
||||
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
||||
*/
|
||||
on(eventNames: string, callback: (args: observable.EventData) => void , thisArg?: any);
|
||||
on(eventNames: string, callback: (args: observable.EventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Raised when the image has been downloaded.
|
||||
*/
|
||||
on(event: "downloaded", callback: (args: DownloadedData) => void , thisArg?: any);
|
||||
on(event: "downloaded", callback: (args: DownloadedData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Raised if the image download errors.
|
||||
*/
|
||||
on(event: "downloadError", callback: (args: DownloadError) => void, thisArg?: any);
|
||||
|
||||
//@private
|
||||
/**
|
||||
@@ -99,6 +112,11 @@ export class Cache extends observable.Observable {
|
||||
*/
|
||||
_onDownloadCompleted(key: string, image: any);
|
||||
//@endprivate
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onDownloadError(key: string, err: Error);
|
||||
//@endprivate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,3 +132,17 @@ export interface DownloadedData extends observable.EventData {
|
||||
*/
|
||||
image: imageSource.ImageSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides data for download error.
|
||||
*/
|
||||
export interface DownloadError extends observable.EventData {
|
||||
/**
|
||||
* A string indentifier of the cached image.
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* Gets the error.
|
||||
*/
|
||||
error: Error;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export class Cache extends common.Cache {
|
||||
super();
|
||||
|
||||
this._cache = new NSCache<any, any>();
|
||||
|
||||
|
||||
//this._delegate = NSCacheDelegateImpl.new();
|
||||
//this._cache.delegate = this._delegate;
|
||||
|
||||
@@ -83,11 +83,16 @@ export class Cache extends common.Cache {
|
||||
public _downloadCore(request: common.DownloadRequest) {
|
||||
ensureHttpRequest();
|
||||
|
||||
var that = this;
|
||||
httpRequest.request({ url: request.url, method: "GET" })
|
||||
.then(response => {
|
||||
var image = UIImage.alloc().initWithData(response.content.raw);
|
||||
that._onDownloadCompleted(request.key, image);
|
||||
.then((response) => {
|
||||
try {
|
||||
var image = UIImage.alloc().initWithData(response.content.raw);
|
||||
this._onDownloadCompleted(request.key, image);
|
||||
} catch (err) {
|
||||
this._onDownloadError(request.key, err);
|
||||
}
|
||||
}, (err) => {
|
||||
this._onDownloadError(request.key, err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ListView as ListViewDefinition, ItemsSource, ItemEventData, TemplatedItemsView } from ".";
|
||||
import { CoercibleProperty, CssProperty, Style, View, ViewBase, ContainerView, Template, KeyedTemplate, Length, Property, Color, Observable, EventData, CSSType } from "../core/view";
|
||||
import { CoercibleProperty, CssProperty, Style, View, ContainerView, Template, KeyedTemplate, Length, Property, Color, Observable, EventData, CSSType } from "../core/view";
|
||||
import { parse, parseMultipleTemplates } from "../builder";
|
||||
import { Label } from "../label";
|
||||
import { ObservableArray, ChangedData } from "../../data/observable-array";
|
||||
|
||||
@@ -7,7 +7,6 @@ import { StackLayout } from "../layouts/stack-layout";
|
||||
import { ProxyViewContainer } from "../proxy-view-container";
|
||||
import { profile } from "../../profiling";
|
||||
import * as trace from "../../trace";
|
||||
import { ios as iosUtils } from "../../utils/utils";
|
||||
|
||||
export * from "./list-view-common";
|
||||
|
||||
@@ -23,7 +22,6 @@ interface ViewItemIndex {
|
||||
}
|
||||
|
||||
type ItemView = View & ViewItemIndex;
|
||||
const majorVersion = iosUtils.MajorVersion;
|
||||
|
||||
class ListViewCell extends UITableViewCell {
|
||||
public static initWithEmptyBackground(): ListViewCell {
|
||||
|
||||
@@ -17,17 +17,17 @@ export class PageBase extends ContentView implements PageDefinition {
|
||||
public static navigatedToEvent = "navigatedTo";
|
||||
public static navigatingFromEvent = "navigatingFrom";
|
||||
public static navigatedFromEvent = "navigatedFrom";
|
||||
|
||||
|
||||
private _navigationContext: any;
|
||||
private _actionBar: ActionBar;
|
||||
|
||||
public _frame: Frame;
|
||||
|
||||
|
||||
public actionBarHidden: boolean;
|
||||
public enableSwipeBackNavigation: boolean;
|
||||
public backgroundSpanUnderStatusBar: boolean;
|
||||
public hasActionBar: boolean;
|
||||
|
||||
|
||||
get navigationContext(): any {
|
||||
return this._navigationContext;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export class PageBase extends ContentView implements PageDefinition {
|
||||
const frame = this.parent;
|
||||
return frame instanceof Frame ? frame : undefined;
|
||||
}
|
||||
|
||||
|
||||
private createNavigatedData(eventName: string, isBackNavigation: boolean): NavigatedData {
|
||||
return {
|
||||
eventName: eventName,
|
||||
@@ -103,6 +103,13 @@ export class PageBase extends ContentView implements PageDefinition {
|
||||
public onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any) {
|
||||
this._navigationContext = context;
|
||||
|
||||
if (isBackNavigation && this._styleScope) {
|
||||
this._styleScope.ensureSelectors();
|
||||
if (!this._cssState.isSelectorsLatestVersionApplied()) {
|
||||
this._onCssStateChange();
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/NativeScript/NativeScript/issues/731
|
||||
if (!isBackNavigation && bindingContext !== undefined && bindingContext !== null) {
|
||||
this.bindingContext = bindingContext;
|
||||
|
||||
@@ -3,9 +3,6 @@ import {
|
||||
View, layout, ScrollViewBase, scrollBarIndicatorVisibleProperty, isScrollEnabledProperty
|
||||
} from "./scroll-view-common";
|
||||
import { ios as iosUtils } from "../../utils/utils";
|
||||
// HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to
|
||||
// kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism.
|
||||
import * as uiUtils from "tns-core-modules/ui/utils";
|
||||
|
||||
export * from "./scroll-view-common";
|
||||
|
||||
@@ -193,18 +190,4 @@ export class ScrollView extends ScrollViewBase {
|
||||
}
|
||||
}
|
||||
|
||||
function getTabBarHeight(scrollView: ScrollView): number {
|
||||
let parent = scrollView.parent;
|
||||
while (parent) {
|
||||
const controller = parent.viewController;
|
||||
if (controller instanceof UITabBarController) {
|
||||
return uiUtils.ios.getActualHeight(controller.tabBar);
|
||||
}
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScrollView.prototype.recycleNativeView = "auto";
|
||||
|
||||
8
tns-core-modules/ui/styling/style-scope.d.ts
vendored
8
tns-core-modules/ui/styling/style-scope.d.ts
vendored
@@ -19,6 +19,11 @@ export class CssState {
|
||||
* Gets the static selectors that match the view and the dynamic selectors that may potentially match the view.
|
||||
*/
|
||||
public changeMap: ChangeMap<ViewBase>;
|
||||
|
||||
/**
|
||||
* Checks whether style scope and CSS state selectors are in sync.
|
||||
*/
|
||||
public isSelectorsLatestVersionApplied(): boolean
|
||||
}
|
||||
|
||||
export class StyleScope {
|
||||
@@ -29,6 +34,9 @@ export class StyleScope {
|
||||
public static createSelectorsFromImports(tree: SyntaxTree, keyframes: Object): RuleSet[];
|
||||
public ensureSelectors(): number;
|
||||
|
||||
public isApplicationCssSelectorsLatestVersionApplied(): boolean;
|
||||
public isLocalCssSelectorsLatestVersionApplied(): boolean;
|
||||
|
||||
public applySelectors(view: ViewBase): void
|
||||
public query(options: Node): SelectorCore[];
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ export function removeTaggedAdditionalCSS(tag: String | Number): Boolean {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) { mergeCssSelectors(); }
|
||||
if (changed) { mergeCssSelectors(); }
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -343,6 +343,7 @@ export class CssState {
|
||||
_appliedChangeMap: Readonly<ChangeMap<ViewBase>>;
|
||||
_appliedPropertyValues: Readonly<{}>;
|
||||
_appliedAnimations: ReadonlyArray<kam.KeyframeAnimation>;
|
||||
_appliedSelectorsVersion: number;
|
||||
|
||||
_match: SelectorsMatch<ViewBase>;
|
||||
_matchInvalid: boolean;
|
||||
@@ -367,6 +368,10 @@ export class CssState {
|
||||
}
|
||||
}
|
||||
|
||||
public isSelectorsLatestVersionApplied(): boolean {
|
||||
return this.view._styleScope._getSelectorsVersion() === this._appliedSelectorsVersion;
|
||||
}
|
||||
|
||||
public onLoaded(): void {
|
||||
if (this._matchInvalid) {
|
||||
this.updateMatch();
|
||||
@@ -381,7 +386,12 @@ export class CssState {
|
||||
|
||||
@profile
|
||||
private updateMatch() {
|
||||
this._match = this.view._styleScope ? this.view._styleScope.matchSelectors(this.view) : CssState.emptyMatch;
|
||||
if (this.view._styleScope) {
|
||||
this._appliedSelectorsVersion = this.view._styleScope._getSelectorsVersion();
|
||||
this._match = this.view._styleScope.matchSelectors(this.view);
|
||||
} else {
|
||||
this._match = CssState.emptyMatch;
|
||||
}
|
||||
this._matchInvalid = false;
|
||||
}
|
||||
|
||||
@@ -597,8 +607,8 @@ export class StyleScope {
|
||||
}
|
||||
|
||||
public ensureSelectors(): number {
|
||||
if (this._applicationCssSelectorsAppliedVersion !== applicationCssSelectorVersion ||
|
||||
this._localCssSelectorVersion !== this._localCssSelectorsAppliedVersion ||
|
||||
if (!this.isApplicationCssSelectorsLatestVersionApplied() ||
|
||||
!this.isLocalCssSelectorsLatestVersionApplied() ||
|
||||
!this._mergedCssSelectors) {
|
||||
|
||||
this._createSelectors();
|
||||
@@ -607,6 +617,14 @@ export class StyleScope {
|
||||
return this._getSelectorsVersion();
|
||||
}
|
||||
|
||||
public isApplicationCssSelectorsLatestVersionApplied(): boolean {
|
||||
return this._applicationCssSelectorsAppliedVersion === applicationCssSelectorVersion;
|
||||
}
|
||||
|
||||
public isLocalCssSelectorsLatestVersionApplied(): boolean {
|
||||
return this._localCssSelectorsAppliedVersion === this._localCssSelectorVersion;
|
||||
}
|
||||
|
||||
@profile
|
||||
private _createSelectors() {
|
||||
let toMerge: RuleSet[][] = [];
|
||||
|
||||
@@ -127,7 +127,6 @@ export module ios {
|
||||
}
|
||||
|
||||
if (rootViewController.isKindOfClass(UITabBarController.class())) {
|
||||
let selectedTab = (<UITabBarController>rootViewController).selectedViewController;
|
||||
return getVisibleViewController(<UITabBarController>rootViewController);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
export class CompleteCallback {
|
||||
constructor(implementation: ICompleteCallback);
|
||||
onComplete(result: Object, context: Object): void;
|
||||
onError(error: string, context: Object): void;
|
||||
}
|
||||
|
||||
export interface ICompleteCallback {
|
||||
onComplete(result: Object, context: Object): void;
|
||||
onError(error: string, context: Object): void;
|
||||
}
|
||||
|
||||
export module Image {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tns-platform-declarations",
|
||||
"version": "5.1.2",
|
||||
"version": "5.2.0",
|
||||
"description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
|
||||
"main": "",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user