Merge pull request #6584 from NativeScript/release-5.0.3

docs: cut the 5.0.3 release
This commit is contained in:
Svetoslav
2018-11-20 16:12:46 +02:00
committed by SvetoslavTsenov
35 changed files with 661 additions and 60 deletions

View File

@ -1,5 +1,29 @@
Cross Platform Modules Changelog
==============================
<a name="5.0.3"></a>
## [5.0.3](https://github.com/NativeScript/NativeScript/compare/5.0.2...5.0.3) (2018-11-20)
### Bug Fixes
* crash on Android Tab-View [#6466](https://github.com/NativeScript/NativeScript/issues/6466) ([#6467](https://github.com/NativeScript/NativeScript/issues/6467)) ([db33cf3](https://github.com/NativeScript/NativeScript/commit/db33cf3)), closes [ac04ede#diff-f1459d509d1432b432c29bcd30e462fbL97](https://github.com/ac04ede/issues/diff-f1459d509d1432b432c29bcd30e462fbL97)
* doc of transitionAndroid property of NavigationEntry interface ([#6563](https://github.com/NativeScript/NativeScript/issues/6563)) ([efe3318](https://github.com/NativeScript/NativeScript/commit/efe3318))
* layoutChanged event in landscape ([#6520](https://github.com/NativeScript/NativeScript/issues/6520)) ([7fbdc7a](https://github.com/NativeScript/NativeScript/commit/7fbdc7a))
* nested frames order with tabs & suspend/resume ([#6528](https://github.com/NativeScript/NativeScript/issues/6528)) ([7df8038](https://github.com/NativeScript/NativeScript/commit/7df8038))
* Resolve incorrect name of listener when unsubscribing ([#6487](https://github.com/NativeScript/NativeScript/issues/6487)) ([af5eb73](https://github.com/NativeScript/NativeScript/commit/af5eb73))
* Resolve incorrect name of listener when unsubscribing ([#6487](https://github.com/NativeScript/NativeScript/issues/6487)) ([2933a9a](https://github.com/NativeScript/NativeScript/commit/2933a9a))
* **image:** uncaught error in promise with image handling ([#6453](https://github.com/NativeScript/NativeScript/issues/6453)) ([950fdcf](https://github.com/NativeScript/NativeScript/commit/950fdcf))
* **android:** back navigation on app suspend/resume ([#6489](https://github.com/NativeScript/NativeScript/issues/6489)) ([999e378](https://github.com/NativeScript/NativeScript/commit/999e378))
* **android:** back navigation on app suspend/resume ([#6489](https://github.com/NativeScript/NativeScript/issues/6489)) ([fac970e](https://github.com/NativeScript/NativeScript/commit/fac970e))
* **android:** IllegalStateException with tabview&nested frames ([#6495](https://github.com/NativeScript/NativeScript/issues/6495)) ([7d21b5c](https://github.com/NativeScript/NativeScript/commit/7d21b5c))
* **android:** IllegalStateException with tabview&nested frames ([#6495](https://github.com/NativeScript/NativeScript/issues/6495)) ([41ba93d](https://github.com/NativeScript/NativeScript/commit/41ba93d))
* **ios:** safe area handling in scrollview ([#6561](https://github.com/NativeScript/NativeScript/issues/6561)) ([51a191f](https://github.com/NativeScript/NativeScript/commit/51a191f))
* **ios:** scrollview safe area when no scroll ([#6568](https://github.com/NativeScript/NativeScript/issues/6568)) ([f90995f](https://github.com/NativeScript/NativeScript/commit/f90995f))
### Features
* add number and phone input types for prompt dialog ([#6365](https://github.com/NativeScript/NativeScript/issues/6365)) ([7e7c050](https://github.com/NativeScript/NativeScript/commit/7e7c050))
<a name="5.0.2"></a>
## [5.0.2](https://github.com/NativeScript/NativeScript/compare/5.0.1...5.0.2) (2018-11-07)

View File

@ -7,7 +7,9 @@
<Button text="login" tap="{{ loginName }}" />
<Button text="promptText" tap="{{ promptText }}" />
<Button text="promptPass" tap="{{ promptPass }}" />
<Button text="promptEmail" tap="{{ promptEmail }}" />
<Button text="promptEmail" tap="{{ promptEmail }}" />
<Button text="promptNumber" tap="{{ promptNumber }}" />
<Button text="promptPhone" tap="{{ promptPhone }}" />
<Button text="promptCapitalizationNone" tap="{{ promptCapitalizationNone }}" />
<Button text="promptCapitalizationAll" tap="{{ promptCapitalizationAll }}" />
<Button text="promptCapitalizationSentences" tap="{{ promptCapitalizationSentences }}" />

View File

@ -138,6 +138,46 @@ export class SettingsViewModel extends observable.Observable {
});
}
public promptNumber(args: observable.EventData) {
dialogs.prompt({
title: "Name",
message: "Enter a number:",
cancelButtonText: "Cancel",
neutralButtonText: "Ignore",
okButtonText: "OK",
defaultText: "1234",
inputType: dialogs.inputType.number
}).then((promptResult) => {
console.log("### Result: " + promptResult.result + ", Text: " + promptResult.text);
if (promptResult.result) {
this.set("name", promptResult.text);
}
else {
this.set("name", "1234");
}
});
}
public promptPhone(args: observable.EventData) {
dialogs.prompt({
title: "Name",
message: "Enter a phone:",
cancelButtonText: "Cancel",
neutralButtonText: "Ignore",
okButtonText: "OK",
defaultText: "1234",
inputType: dialogs.inputType.phone
}).then((promptResult) => {
console.log("### Result: " + promptResult.result + ", Text: " + promptResult.text);
if (promptResult.result) {
this.set("name", promptResult.text);
}
else {
this.set("name", "1234");
}
});
}
public promptCapitalizationNone(args: observable.EventData) {
dialogs.prompt({
title: "Name",

View File

@ -0,0 +1,8 @@
.hr-light {
height: 1;
background-color: gray;
}
.title {
height: 200;
}

View File

@ -0,0 +1,38 @@
<Page>
<ActionBar title="issue-6439"></ActionBar>
<GridLayout>
<ScrollView>
<StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
<StackLayout>
<Label text="Play with NativeScript!" textWrap="true" class="title" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
</GridLayout>
</Page>

View File

@ -0,0 +1,35 @@
.page {
padding: 20;
}
.title {
font-weight: bold;
}
.list-items {
border-radius: 10;
background-repeat: no-repeat;
background-size: cover;
background-position: center top;
background-color: black;
margin-top: 20;
}
.item-title {
color: white;
vertical-align: bottom;
font-size: 30;
padding: 180 20 20;
font-weight: 600;
}
.list-item__row {
padding-left: 20;
}
.list-item {
border-radius: 4;
background-color: white;
margin: 0 10 20 0;
padding: 5 10;
}

View File

@ -0,0 +1,109 @@
<Page>
<ActionBar title="issue-ng-repo-1599"></ActionBar>
<ScrollView>
<GridLayout rows="auto, *" columns="*" class="page page-content">
<!-- Banner -->
<StackLayout row="0" orientation="vertical">
<StackLayout>
<Label textWrap="true" text="My shopping lists" class="title"></Label>
</StackLayout>
</StackLayout>
<!-- Offer categories -->
<StackLayout row="1">
<!-- Shopping list 1 -->
<StackLayout class="list-items" backgroundImage="~/ui-tests-app/resources/images/woods.jpg">
<Label text="Shopping list 1" class="item-title" textWrap="true"></Label>
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="list-item__row">
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
<!-- Shopping list 2 -->
<StackLayout class="list-items" backgroundImage="~/ui-tests-app/resources/images/woods.jpg">
<Label text="Shopping list 2" class="item-title" textWrap="true"></Label>
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="list-item__row">
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
<!-- Shopping list 3 -->
<StackLayout class="list-items" backgroundImage="~/ui-tests-app/resources/images/woods.jpg">
<Label text="Shopping list 3" class="item-title" textWrap="true"></Label>
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="list-item__row">
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
<!-- Shopping list 4 -->
<StackLayout class="list-items" backgroundImage="~/ui-tests-app/resources/images/woods.jpg">
<Label text="Shopping list 4" class="item-title" textWrap="true"></Label>
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="list-item__row">
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
<StackLayout class="list-item">
<Label text="Shop Item" textWrap="true" />
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
</StackLayout>
</GridLayout>
</ScrollView>
</Page>

View File

@ -27,6 +27,8 @@ export function loadExamples() {
examples.set("3354-ios", "issues/issue-3354");
examples.set("4450", "issues/issue-4450");
examples.set("5274", "issues/issue-5274");
examples.set("ng-repo-1599", "issues/issue-ng-repo-1599");
examples.set("6439", "issues/issue-6439");
return examples;
}

View File

@ -6,7 +6,7 @@
</Page.actionBar>
<ScrollView>
<StackLayout>
<StackLayout backgroundColor="teal">
<GridLayout height="30" backgroundColor="red" />
<GridLayout height="30" backgroundColor="yellow" />
<GridLayout height="30" backgroundColor="green" />

View File

@ -6,8 +6,8 @@
</Page.actionBar>
<GridLayout>
<ScrollView height="50" verticalAlignment="top">
<StackLayout>
<ScrollView>
<StackLayout backgroundColor="teal">
<GridLayout height="30" backgroundColor="red" />
<GridLayout height="30" backgroundColor="yellow" />
<GridLayout height="30" backgroundColor="green" />

View File

@ -20,8 +20,8 @@
"babel-types": "6.11.1",
"babylon": "6.8.3",
"lazy": "1.0.11",
"nativescript-dev-typescript": "^0.7.1",
"nativescript-dev-typescript": "next",
"tns-platform-declarations": "*",
"typescript": "^2.7.2"
"typescript": "^3.1.6"
}
}

View File

@ -27,7 +27,7 @@
"nativescript-dev-typescript": "next",
"nativescript-dev-webpack": "next",
"rimraf": "^2.6.2",
"typescript": "^3.1.1"
"typescript": "^3.1.6"
},
"scripts": {
"e2e": "npm run clean-e2e && tsc -p e2e && mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json",

View File

@ -43,7 +43,7 @@
"tslint": "^5.4.3",
"typedoc": "^0.5.10",
"typedoc-plugin-external-module-name": "git://github.com/PanayotCankov/typedoc-plugin-external-module-name.git#with-js",
"typescript": "^2.6.1"
"typescript": "^3.1.6"
},
"scripts": {
"setup": "npm run dev-link-tns-platform-declarations && npm run dev-link-tns-core-modules && npm run dev-link-tests && npm run dev-link-apps && npm run dev-link-e2e-modal",

View File

@ -136,11 +136,15 @@ allTests["FLEXBOXLAYOUT"] = flexBoxLayoutTests;
import * as safeAreaLayoutTests from "./ui/layouts/safe-area-tests";
import * as safeAreaListViewtTests from "./ui/list-view/list-view-safe-area-tests";
import * as scrollViewSafeAreaTests from "./ui/scroll-view/scroll-view-safe-area-tests";
import * as repeaterSafeAreaTests from "./ui/repeater/repeater-safe-area-tests";
import * as webViewSafeAreaTests from "./ui/web-view/web-view-safe-area-tests";
if (platform.isIOS && ios.MajorVersion > 10) {
allTests["SAFEAREALAYOUT"] = safeAreaLayoutTests;
allTests["SAFEAREA-LISTVIEW"] = safeAreaListViewtTests;
allTests["SAFEAREA-SCROLL-VIEW"] = scrollViewSafeAreaTests;
allTests["SAFEAREA-REPEATER"] = repeaterSafeAreaTests;
allTests["SAFEAREA-WEBVIEW"] = webViewSafeAreaTests;
}
import * as stylePropertiesTests from "./ui/styling/style-properties-tests";

View File

@ -209,8 +209,8 @@ export function waitUntilNavigatedTo(page: Page, action: Function) {
TKUnit.waitUntilReady(() => completed, 5);
}
export function waitUntilNavigatedFrom(action: Function) {
const currentPage = frame.topmost().currentPage;
export function waitUntilNavigatedFrom(action: Function, topFrame?: frame.Frame) {
const currentPage = topFrame ? topFrame.currentPage : frame.topmost().currentPage;
let completed = false;
function navigatedFrom(args) {
args.object.page.off("navigatedFrom", navigatedFrom);
@ -226,19 +226,19 @@ export function waitUntilLayoutReady(view: View): void {
TKUnit.waitUntilReady(() => view.isLayoutValid);
}
export function navigateWithEntry(entry: frame.NavigationEntry): Page {
export function navigateWithEntry(entry: frame.NavigationEntry, topFrame?: frame.Frame): Page {
const page = createViewFromEntry(entry) as Page;
entry.moduleName = null;
entry.create = function () {
return page;
};
waitUntilNavigatedFrom(() => frame.topmost().navigate(entry));
waitUntilNavigatedFrom(() => topFrame ? topFrame.navigate(entry) : frame.topmost().navigate(entry));
return page;
}
export function goBack() {
waitUntilNavigatedFrom(() => frame.topmost().goBack());
export function goBack(topFrame?: frame.Frame) {
waitUntilNavigatedFrom(() => topFrame ? topFrame.goBack() : frame.topmost().goBack());
}
export function assertAreClose(actual: number, expected: number, message: string): void {

View File

@ -6,6 +6,8 @@ import * as platform from "tns-core-modules/platform";
import { ios as iosUtils } from "tns-core-modules/utils/utils";
import * as helper from "../helper";
import { parse } from "tns-core-modules/ui/builder";
import { Page } from "tns-core-modules/ui/page";
import { Label } from "tns-core-modules/ui/label";
import {
dipToDp, left, top, right, bottom, height, width,
equal, closeEnough, lessOrCloseEnough, greaterOrCloseEnough, check,
@ -37,6 +39,30 @@ export class SafeAreaTests extends testModule.UITest<any> {
// no operation
};
public test_layout_changed_event_count() {
const page = <Page>parse(`
<Page>
<GridLayout id="grid" backgroundColor="Crimson">
<Label id="label" text="label1" backgroundColor="Gold"></Label>
</GridLayout>
</Page>
`);
let gridLayoutChangedCounter = 0;
let labelLayoutChangedCounter = 0;
const grid = page.getViewById("grid");
grid.on(view.View.layoutChangedEvent, () => {
gridLayoutChangedCounter++;
});
const label = <Label>page.getViewById("label");
label.on(view.View.layoutChangedEvent, () => {
labelLayoutChangedCounter++;
});
helper.navigate(() => page);
label.height = 100;
TKUnit.waitUntilReady(() => labelLayoutChangedCounter === 2);
TKUnit.assert(gridLayoutChangedCounter === 1, `${grid} layoutChanged event count - actual:${gridLayoutChangedCounter}; expected: 1`)
}
// Common
private getViews(template: string) {
let root = parse(template);

View File

@ -759,17 +759,6 @@ export class ListViewTest extends UITest<ListView> {
TKUnit.assertEqual(lastNativeElementVisible, false, "Last element is not visible");
}
public test_scrollToIndex_should_coerce_negative_index_to_zero_index() {
var listView = this.testView;
listView.items = MANY_ITEMS;
listView.scrollToIndex(-1);
TKUnit.wait(0.1);
var firstNativeElementVisible = this.checkItemVisibleAtIndex(listView, 0);
TKUnit.assertEqual(firstNativeElementVisible, true, "first element is visible");
}
public test_scrollToIndex_should_coerce_larger_index_to_last_item_index() {
var listView = this.testView;

View File

@ -0,0 +1,95 @@
import * as helper from "../helper";
import * as TKUnit from "../../TKUnit";
import { parse } from "tns-core-modules/ui/builder";
import * as view from "tns-core-modules/ui/core/view";
import * as platform from "tns-core-modules/platform";
import { Repeater } from "tns-core-modules/ui/repeater";
import { ios as iosUtils } from "tns-core-modules/utils/utils";
import { UITest } from "../../ui-test";
import {
dipToDp, left, top, right, bottom, height, width,
equal, check, lessOrCloseEnough, greaterOrCloseEnough,
isLeftAlignedWith, isRightAlignedWith, isTopAlignedWith
} from "../layouts/layout-tests-helper";
export class RepeaterSafeAreaTest extends UITest<Repeater> {
private executeSnippet<U extends { root: view.View }>(ui: U, setup: (ui: U) => void, test: (ui: U) => void, pageOptions?: helper.PageOptions): void {
function waitUntilTestElementLayoutIsValid(view: view.View, timeoutSec?: number): void {
TKUnit.waitUntilReady(() => {
return view.isLayoutValid;
}, timeoutSec || 1);
}
setup(ui);
helper.buildUIAndRunTest(ui.root, () => {
waitUntilTestElementLayoutIsValid(ui.root);
test(ui);
}, pageOptions);
};
private noop() {
// no operation
};
private getViews(template: string) {
let root = parse(template);
return {
root,
list: root.getViewById("repeater") as Repeater
};
};
private repeater_in_full_screen(repeater: Repeater, pageOptions?: helper.PageOptions) {
let expectedTop = 0;
if (pageOptions && pageOptions.actionBarFlat) {
const actionBarHeight = round(dipToDp(repeater.page.actionBar.nativeViewProtected.frame.size.height));
const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication);
const statusBarHeight = round(dipToDp(app.statusBarFrame.size.height));
expectedTop = actionBarHeight + statusBarHeight;
}
const l = left(repeater);
const t = top(repeater);
const r = right(repeater);
const b = bottom(repeater);
equal(l, 0, `${repeater}.left - actual:${l}; expected: ${0}`);
equal(t, expectedTop, `${repeater}.top - actual:${t}; expected: ${expectedTop}`);
equal(r, platform.screen.mainScreen.widthPixels, `${repeater}.right - actual:${r}; expected: ${platform.screen.mainScreen.widthPixels}`);
equal(b, platform.screen.mainScreen.heightPixels, `${repeater}.bottom - actual:${b}; expected: ${platform.screen.mainScreen.heightPixels}`);
}
private repeater_in_full_screen_test(pageOptions?: helper.PageOptions) {
const snippet = `
<Repeater id="repeater" loaded="onLoaded" backgroundColor="Crimson"></Repeater>
`;
this.executeSnippet(
this.getViews(snippet),
this.noop,
({ list }) => {
this.repeater_in_full_screen(list, pageOptions);
},
pageOptions
);
}
public test_repeater_in_full_screen_action_bar() {
this.repeater_in_full_screen_test({ actionBar: true });
}
public test_repeater_in_full_screen_action_bar_hidden() {
this.repeater_in_full_screen_test({ actionBarHidden: true });
}
public test_repeater_in_full_screen_action_bar_flat() {
this.repeater_in_full_screen_test({ actionBarFlat: true });
}
public test_repeater_in_full_screen_tab_bar() {
this.repeater_in_full_screen_test({ tabBar: true });
}
}
export function createTestCase(): RepeaterSafeAreaTest {
return new RepeaterSafeAreaTest();
}

View File

@ -4,7 +4,7 @@ import { isIOS, isAndroid } from "tns-core-modules/platform";
import { Label } from "tns-core-modules/ui/label";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
import * as frameModule from "tns-core-modules/ui/frame";
import { Page } from "tns-core-modules/ui/page";
import { Page, NavigatedData } from "tns-core-modules/ui/page";
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view";
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";
import { Button } from "tns-core-modules/ui/button";
@ -68,6 +68,56 @@ function _clickHandlerFactory(index: number) {
}
}
function _createFrameView(): frameModule.Frame {
const frame = new frameModule.Frame();
frame.navigate({ create: () => new Page() });
return frame;
}
export function testBackNavigationToTabViewWithNestedFramesShouldWork() {
// https://github.com/NativeScript/NativeScript/issues/6490
const topFrame = frameModule.topmost();
let tabViewPage: Page;
let tabView: TabView;
const pageFactory = function (): Page {
tabView = _createTabView();
let items = Array<TabViewItem>();
let tabViewitem = new TabViewItem();
tabViewitem.title = "Item1";
tabViewitem.view = _createFrameView();
items.push(tabViewitem);
let tabViewitem2 = new TabViewItem();
tabViewitem2.title = "Item2";
tabViewitem2.view = _createFrameView();
items.push(tabViewitem2);
tabView.items = items;
tabViewPage = new Page();
tabViewPage.id = "tab-view-page";
tabViewPage.content = tabView;
return tabViewPage;
}
helper.waitUntilNavigatedFrom(() => topFrame.navigate(pageFactory), topFrame);
TKUnit.waitUntilReady(() => topFrame.currentPage === tabViewPage);
TKUnit.waitUntilReady(() => tabViewIsFullyLoaded(tabView));
// navigate to a different page
helper.waitUntilNavigatedFrom(() => topFrame.navigate({ create: () => new Page(), animated: false }), topFrame);
// navigate back to the page that hold the tabview with nested frames
topFrame.goBack();
// make sure the app did not crash
TKUnit.waitUntilReady(() => topFrame.navigationQueueIsEmpty());
}
export function testWhenNavigatingBackToANonCachedPageContainingATabViewWithAListViewTheListViewIsThere() {
var topFrame = frameModule.topmost();

View File

@ -0,0 +1,95 @@
import * as helper from "../helper";
import * as TKUnit from "../../TKUnit";
import { parse } from "tns-core-modules/ui/builder";
import * as view from "tns-core-modules/ui/core/view";
import * as platform from "tns-core-modules/platform";
import { WebView } from "tns-core-modules/ui/web-view";
import { ios as iosUtils } from "tns-core-modules/utils/utils";
import { UITest } from "../../ui-test";
import {
dipToDp, left, top, right, bottom, height, width,
equal, check, lessOrCloseEnough, greaterOrCloseEnough,
isLeftAlignedWith, isRightAlignedWith, isTopAlignedWith
} from "../layouts/layout-tests-helper";
export class WebViewSafeAreaTest extends UITest<WebView> {
private executeSnippet<U extends { root: view.View }>(ui: U, setup: (ui: U) => void, test: (ui: U) => void, pageOptions?: helper.PageOptions): void {
function waitUntilTestElementLayoutIsValid(view: view.View, timeoutSec?: number): void {
TKUnit.waitUntilReady(() => {
return view.isLayoutValid;
}, timeoutSec || 1);
}
setup(ui);
helper.buildUIAndRunTest(ui.root, () => {
waitUntilTestElementLayoutIsValid(ui.root);
test(ui);
}, pageOptions);
};
private noop() {
// no operation
};
private getViews(template: string) {
let root = parse(template);
return {
root,
list: root.getViewById("webview") as WebView
};
};
private webview_in_full_screen(webView: WebView, pageOptions?: helper.PageOptions) {
let expectedTop = 0;
if (pageOptions && pageOptions.actionBarFlat) {
const actionBarHeight = round(dipToDp(webView.page.actionBar.nativeViewProtected.frame.size.height));
const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication);
const statusBarHeight = round(dipToDp(app.statusBarFrame.size.height));
expectedTop = actionBarHeight + statusBarHeight;
}
const l = left(webView);
const t = top(webView);
const r = right(webView);
const b = bottom(webView);
equal(l, 0, `${webView}.left - actual:${l}; expected: ${0}`);
equal(t, expectedTop, `${webView}.top - actual:${t}; expected: ${expectedTop}`);
equal(r, platform.screen.mainScreen.widthPixels, `${webView}.right - actual:${r}; expected: ${platform.screen.mainScreen.widthPixels}`);
equal(b, platform.screen.mainScreen.heightPixels, `${webView}.bottom - actual:${b}; expected: ${platform.screen.mainScreen.heightPixels}`);
}
private webview_in_full_screen_test(pageOptions?: helper.PageOptions) {
const snippet = `
<WebView id="webview" loaded="onLoaded" backgroundColor="Crimson"></WebView>
`;
this.executeSnippet(
this.getViews(snippet),
this.noop,
({ list }) => {
this.webview_in_full_screen(list, pageOptions);
},
pageOptions
);
}
public test_webview_in_full_screen_action_bar() {
this.webview_in_full_screen_test({ actionBar: true });
}
public test_webview_in_full_screen_action_bar_hidden() {
this.webview_in_full_screen_test({ actionBarHidden: true });
}
public test_webview_in_full_screen_action_bar_flat() {
this.webview_in_full_screen_test({ actionBarFlat: true });
}
public test_webview_in_full_screen_tab_bar() {
this.webview_in_full_screen_test({ tabBar: true });
}
}
export function createTestCase(): WebViewSafeAreaTest {
return new WebViewSafeAreaTest();
}

View File

@ -6,10 +6,10 @@
"nativescript": {
"id": "org.nativescript.UnitTestApp",
"tns-ios": {
"version": "4.2.0"
"version": "5.0.0"
},
"tns-android": {
"version": "4.2.0"
"version": "5.0.0"
}
},
"dependencies": {
@ -23,6 +23,6 @@
"filewalker": "0.1.2",
"lazy": "1.0.11",
"tns-platform-declarations": "*",
"typescript": "^2.6.1"
"typescript": "^3.1.6"
}
}

View File

@ -69,6 +69,11 @@ function ensureImageSource() {
export function request(options: http.HttpRequestOptions): Promise<http.HttpResponse> {
return new Promise<http.HttpResponse>((resolve, reject) => {
if (!options.url) {
reject(new Error("Request url was empty."));
return;
}
try {
var network = domainDebugger.getNetwork();
var debugRequest = network && network.create();

View File

@ -31,9 +31,18 @@ export function getJSON<T>(arg: any): Promise<T> {
}
export function getImage(arg: any): Promise<ImageSource> {
return httpRequest
.request(typeof arg === "string" ? { url: arg, method: "GET" } : arg)
.then(response => response.content.toImage());
return new Promise<any>((resolve, reject) => {
httpRequest.request(typeof arg === "string" ? { url: arg, method: "GET" } : arg)
.then(r => {
try {
resolve(r.content.toImage());
} catch (err) {
reject(err);
}
}, err => {
reject(err);
});
});
}
export function getFile(arg: any, destinationFilePath?: string): Promise<any> {

View File

@ -1,7 +1,7 @@
{
"name": "tns-core-modules",
"description": "Telerik NativeScript Core Modules",
"version": "5.0.2",
"version": "5.1.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.0.1",
"tns-core-modules-widgets": "next",
"tslib": "^1.9.3"
},
"devDependencies": {

View File

@ -190,6 +190,9 @@ export class View extends ViewCommon {
} else if (!this._isLaidOut) {
// Rects could be equal on the first layout and an event should be raised.
this._raiseLayoutChangedEvent();
// But make sure event is raised only once if rects are equal on the first layout as
// this method is called twice with equal rects in landscape mode (vs only once in portrait)
this._isLaidOut = true;
}
}
@ -795,11 +798,11 @@ export namespace ios {
}
if (inWindowRight < fullscreenPosition.right && inWindowRight >= safeAreaPosition.right + fullscreenPosition.left) {
adjustedPosition.right = fullscreenPosition.right - fullscreenPosition.left;
adjustedPosition.right += fullscreenPosition.right - inWindowRight;
}
if (inWindowBottom < fullscreenPosition.bottom && inWindowBottom >= safeAreaPosition.bottom + fullscreenPosition.top) {
adjustedPosition.bottom = fullscreenPosition.bottom - fullscreenPosition.top;
adjustedPosition.bottom += fullscreenPosition.bottom - inWindowBottom;
}
const adjustedFrame = CGRectMake(layout.toDeviceIndependentPixels(adjustedPosition.left), layout.toDeviceIndependentPixels(adjustedPosition.top), layout.toDeviceIndependentPixels(adjustedPosition.right - adjustedPosition.left), layout.toDeviceIndependentPixels(adjustedPosition.bottom - adjustedPosition.top));
@ -850,7 +853,8 @@ export namespace ios {
if (parent.nativeViewProtected instanceof UIScrollView) {
const nativeView = parent.nativeViewProtected;
safeArea = nativeView.safeAreaLayoutGuide.layoutFrame;
const insets = nativeView.safeAreaInsets;
safeArea = CGRectMake(insets.left, insets.top, nativeView.contentSize.width - insets.left - insets.right, nativeView.contentSize.height - insets.top - insets.bottom);
fullscreen = CGRectMake(0, 0, nativeView.contentSize.width, nativeView.contentSize.height);
} else if (parent.viewController) {
const nativeView = parent.viewController.view;

View File

@ -31,6 +31,16 @@ export module inputType {
* Email input type.
*/
export const email: string = "email";
/**
* Number input type
*/
export const number: string = "number";
/**
* Phone input type
*/
export const phone: string = "phone";
}
/**

View File

@ -184,6 +184,10 @@ export function prompt(arg: any): Promise<PromptResult> {
input.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD);
} else if (options.inputType === inputType.email) {
input.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
} else if (options.inputType === inputType.number) {
input.setInputType(android.text.InputType.TYPE_CLASS_NUMBER);
} else if (options.inputType === inputType.phone) {
input.setInputType(android.text.InputType.TYPE_CLASS_PHONE);
}
switch (options.capitalizationType) {

View File

@ -21,6 +21,16 @@ export module inputType {
* Email input type.
*/
export var email: string;
/**
* Number input type.
*/
export var number: string;
/**
* Phone input type.
*/
export var phone: string;
}
/**
@ -81,7 +91,7 @@ export function prompt(message: string, defaultText?: string): Promise<PromptRes
/**
* The prompt() method displays a dialog box that prompts the visitor for input.
* @param options The options for the dialog box.
* @param options The options for the dialog box.
*/
export function prompt(options: PromptOptions): Promise<PromptResult>;
@ -95,7 +105,7 @@ export function login(message: string, userName?: string, password?: string): Pr
/**
* The login() method displays a login dialog box that prompts the visitor for user name and password.
* @param options The options for the dialog box.
* @param options The options for the dialog box.
*/
export function login(options: LoginOptions): Promise<LoginResult>;
@ -109,7 +119,7 @@ export function action(message: string, cancelButtonText: string, actions: Array
/**
* The action() method displays a action box that prompts the visitor to choose some action.
* @param options The options for the dialog box.
* @param options The options for the dialog box.
*/
export function action(options: ActionOptions): Promise<string>;

View File

@ -104,6 +104,10 @@ export function prompt(arg: any): Promise<PromptResult> {
if (options && options.inputType === inputType.email) {
arg.keyboardType = UIKeyboardType.EmailAddress;
} else if (options && options.inputType === inputType.number) {
arg.keyboardType = UIKeyboardType.NumberPad;
} else if (options && options.inputType === inputType.phone) {
arg.keyboardType = UIKeyboardType.PhonePad;
}
let color = getTextFieldColor();

View File

@ -251,6 +251,18 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
}
}
private isNestedWithin(parentFrameCandidate: FrameBase): boolean {
let frameAncestor: FrameBase = this;
while (frameAncestor) {
frameAncestor = <FrameBase>getAncestor(frameAncestor, FrameBase);
if (frameAncestor === parentFrameCandidate) {
return true;
}
}
return false;
}
private raiseCurrentPageNavigatedEvents(isBack: boolean) {
const page = this.currentPage;
if (page) {
@ -410,6 +422,23 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
return null;
}
public _pushInFrameStackRecursive() {
this._pushInFrameStack();
// make sure nested frames order is kept intact i.e. the nested one should always be on top;
// see https://github.com/NativeScript/nativescript-angular/issues/1596 for more information
const framesToPush = [];
for (const frame of frameStack) {
if (frame.isNestedWithin(this)) {
framesToPush.push(frame);
}
}
for (const frame of framesToPush) {
frame._pushInFrameStack();
}
}
public _pushInFrameStack() {
_pushInFrameStack(this);
}

View File

@ -158,6 +158,10 @@ export class Frame extends View {
* @private
*/
_pushInFrameStack();
/**
* @private
*/
_pushInFrameStackRecursive();
/**
* @private
*/
@ -253,7 +257,7 @@ export interface NavigationEntry extends ViewEntry {
transitioniOS?: NavigationTransition;
/**
* Specifies an optional navigation transition for iOS. If not specified, the default platform transition will be used.
* Specifies an optional navigation transition for Android. If not specified, the default platform transition will be used.
*/
transitionAndroid?: NavigationTransition;

View File

@ -164,16 +164,14 @@ export class ScrollView extends ScrollViewBase {
nativeView.contentInsetAdjustmentBehavior = 2;
}
let scrollWidth = width;
let scrollHeight = height;
let scrollWidth = width + insets.left + insets.right;
let scrollHeight = height + insets.top + insets.bottom;
if (this.orientation === "horizontal") {
scrollWidth = Math.max(this._contentMeasuredWidth + insets.left + insets.right, width);
scrollHeight = height + insets.top + insets.bottom;
scrollWidth = Math.max(this._contentMeasuredWidth + insets.left + insets.right, scrollWidth);
width = Math.max(this._contentMeasuredWidth, width);
}
else {
scrollHeight = Math.max(this._contentMeasuredHeight + insets.top + insets.bottom, height);
scrollWidth = width + insets.left + insets.right;
scrollHeight = Math.max(this._contentMeasuredHeight + insets.top + insets.bottom, scrollHeight);
height = Math.max(this._contentMeasuredHeight, height);
}

View File

@ -200,10 +200,7 @@ function initializeNativeClasses() {
}
finishUpdate(container: android.view.ViewGroup): void {
if (this.mCurTransaction != null) {
(<any>this.mCurTransaction).commitNowAllowingStateLoss();
this.mCurTransaction = null;
}
this._commitCurrentTransaction();
}
isViewFromObject(view: android.view.View, object: java.lang.Object): boolean {
@ -211,6 +208,9 @@ function initializeNativeClasses() {
}
saveState(): android.os.Parcelable {
// Commit the current transaction on save to prevent "No view found for id 0xa" exception on restore.
// Related to: https://github.com/NativeScript/NativeScript/issues/6466
this._commitCurrentTransaction();
return null;
}
@ -221,8 +221,15 @@ function initializeNativeClasses() {
getItemId(position: number): number {
return position;
}
}
private _commitCurrentTransaction() {
if (this.mCurTransaction != null) {
this.mCurTransaction.commitNowAllowingStateLoss();
this.mCurTransaction = null;
}
}
}
PagerAdapter = FragmentPagerAdapter;
}
@ -506,7 +513,7 @@ export class TabView extends TabViewBase {
const newItem = items[newIndex];
const selectedView = newItem && newItem.view;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStack();
selectedView._pushInFrameStackRecursive();
}
toLoad.forEach(index => {
@ -713,4 +720,4 @@ function tryCloneDrawable(value: android.graphics.drawable.Drawable, resources:
}
return value;
}
}

View File

@ -261,7 +261,7 @@ export class TabView extends TabViewBase {
const selectedIndex = this.selectedIndex;
const selectedView = this.items && this.items[selectedIndex] && this.items[selectedIndex].view;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStack();
selectedView._pushInFrameStackRecursive();
}
this._ios.delegate = this._delegate;
@ -300,7 +300,7 @@ export class TabView extends TabViewBase {
if (newItem && this.isLoaded) {
const selectedView = items[newIndex].view;
if (selectedView instanceof Frame) {
selectedView._pushInFrameStack();
selectedView._pushInFrameStackRecursive();
}
newItem.loadView(newItem.view);

View File

@ -1,6 +1,6 @@
{
"name": "tns-platform-declarations",
"version": "5.0.2",
"version": "5.1.0",
"description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
"main": "",
"scripts": {
@ -32,6 +32,6 @@
},
"homepage": "https://github.com/NativeScript/NativeScript#readme",
"devDependencies": {
"typescript": "~2.6.1"
"typescript": "^3.1.6"
}
}