Merge branch 'master' into myankov/merge-release-master

This commit is contained in:
Martin Yankov
2019-03-01 11:19:19 +02:00
committed by GitHub
24 changed files with 202 additions and 119 deletions

View File

@ -205,7 +205,7 @@ let b = {"good": "code"
## Equality operator ## Equality operator
Use the [strict comparison operators][comparisonoperators]. The triple equality operator helps to maintain data type integrity throughout code. Use the [strict comparison operators][comparisonoperators]. The triple equality operator helps to maintain data type integrity throughout the code.
*Right:* *Right:*
@ -341,8 +341,8 @@ the last row of a big room can comfortably read. So don't count on them having
perfect vision and limit yourself to 1/2 of your screen height per function (no screen rotation :). perfect vision and limit yourself to 1/2 of your screen height per function (no screen rotation :).
## Return statements ## Return statements
There are few important considerations here: There are a few important considerations here:
+ To avoid deep nesting of if-statements, always return a functions value as early + To avoid deep nesting of if-statements, always return a function's value as early
as possible. In certain routines, once you know the answer, you want to return it to the calling routine immediately. If the routine is defined in such a way that it doesn't require any cleanup, not returning immediately means that you have to write more code. as possible. In certain routines, once you know the answer, you want to return it to the calling routine immediately. If the routine is defined in such a way that it doesn't require any cleanup, not returning immediately means that you have to write more code.
+ Minimize the number of returns in each routine. It's harder to understand a routine if, reading it at the bottom, you're unaware of the possibility that it *return*ed somewhere above. + Minimize the number of returns in each routine. It's harder to understand a routine if, reading it at the bottom, you're unaware of the possibility that it *return*ed somewhere above.
@ -396,7 +396,7 @@ function getSomething(val) {
## Arrow Functions ## Arrow Functions
Use arrow functions over anonymous function expressions. Typescript will take care for `this`. Use arrow functions over anonymous function expressions. Typescript will take care of `this`.
*Right:* *Right:*
@ -423,7 +423,7 @@ req.on("end", function () {
Use the [JSDoc][JSDOC] convention for comments. When writing a comment always think how understandable will be for somebody who is new to this code. Even if it may look simple to you think how a guy that just joined will understand it. Always comment in the following cases: Use the [JSDoc][JSDOC] convention for comments. When writing a comment always think how understandable will be for somebody who is new to this code. Even if it may look simple to you think how a guy that just joined will understand it. Always comment in the following cases:
+ When there is some non-trivial logic. + When there is some non-trivial logic.
+ Some "external" knowledge is needed which is missing in the context - workaround for driver, module bug, special 'hack' because of a bug and so on; + Some "external" knowledge is needed which is missing in the context - workaround for a driver, module bug, special 'hack' because of a bug and so on;
+ When you are creating a new class + When you are creating a new class
+ Public methods - include all the arguments and if possible the types {String}, {Number}. Optional arguments should be marked too. Check the [@param tag][param] + Public methods - include all the arguments and if possible the types {String}, {Number}. Optional arguments should be marked too. Check the [@param tag][param]
@ -432,7 +432,7 @@ Use the [JSDoc][JSDOC] convention for comments. When writing a comment always th
## File/module structure ## File/module structure
Typical module should have the following structure: A typical module should have the following structure:
1. required dependencies 1. required dependencies
2. module-private declarations - variables, functions, classes, etc. 2. module-private declarations - variables, functions, classes, etc.
@ -442,7 +442,7 @@ Typical module should have the following structure:
For more information see [this file](https://github.com/telerik/xPlatCore/blob/master/JS/BCL/CreateNewModule.md) For more information see [this file](https://github.com/telerik/xPlatCore/blob/master/JS/BCL/CreateNewModule.md)
## File naming ## File naming
Use lower case for file names. Use dash to separate different words. Use lower case for file names. Use a dash to separate different words.
*Right:* *Right:*
file-system file-system
@ -451,7 +451,7 @@ file-system
FileSystem, fileSystem, file_system FileSystem, fileSystem, file_system
## This, that, self ## This, that, self
When you **need** to keep reference to **this** use **that** as the name of the variable. Additionally, if you use the TypeScript lambda support, the compiler will take care of this automatically. When you **need** to keep a reference to **this** use **that** as the name of the variable. Additionally, if you use the TypeScript lambda support, the compiler will take care of this automatically.
*Right:* *Right:*
```TypeScript ```TypeScript
@ -470,7 +470,7 @@ doSomething(function(){
``` ```
## Private (hidden) variables and methods ## Private (hidden) variables and methods
Although there is the **private** keyword in TypeScript, it is only a syntax sugar. There is no such notation in JavaScript and everything is available to the users. Hence, always use underscore (**_**) to prefix private variables and methods. There are also methods which have the **public** visibility but they are meant to be used within our code ONLY. Such methods should also be prefixed with underscore. Although there is the **private** keyword in TypeScript, it is only a syntax sugar. There is no such notation in JavaScript and everything is available to the users. Hence, always use underscore (**_**) to prefix private variables and methods. There are also methods which have the **public** visibility but they are meant to be used within our code ONLY. Such methods should also be prefixed with an underscore.
*Right:* *Right:*
```TypeScript ```TypeScript

View File

@ -1,7 +1,7 @@
# Writing Unit Tests for NativeScript Core Modules # Writing Unit Tests for NativeScript Core Modules
Unit tests for NativeScript Modules are written and executed with a custom lightweight test-runner and assertion framework. Unit tests for NativeScript Modules are written and executed with a custom lightweight test-runner and assertion framework.
The purpose of this document is to get you familiar with it, so that you can unit-test your contributions to the NativeScript framework. The purpose of this document is to get you familiar with it so that you can unit-test your contributions to the NativeScript framework.
# Run Unit Tests Project # Run Unit Tests Project
@ -19,7 +19,7 @@ tns run ios
# Test Modules # Test Modules
All unit tests are organized into test modules(bundles). All unit tests are organized into test modules(bundles).
By default the test app will run all the tests from all registered test modules. This happens in [`runTests()`](/tests/app/app/mainPage.ts#L26-L28) method in the main page of the test-app. By modifying this method, you can configure the app to: By default, the test app will run all the tests from all registered test modules. This happens in [`runTests()`](/tests/app/app/mainPage.ts#L26-L28) method in the main page of the test-app. By modifying this method, you can configure the app to:
* **Execute only the tests from a specific test module**: * **Execute only the tests from a specific test module**:
@ -50,8 +50,8 @@ The test modules are actually TypeScript modules which export unit tests and hoo
* All exported functions with a `test` prefix are unit-tests. * All exported functions with a `test` prefix are unit-tests.
* The `setUpModule()` hook is called once - before all the tests in the module. * The `setUpModule()` hook is called once - before all the tests in the module.
* The `setUp()` hook is called before each tests. * The `setUp()` hook is called before each test.
* The `tearDown()` hook called after each tests. * The `tearDown()` hook called after each test.
* The `tearDownModule()` hook is called once - after all the tests in the module. * The `tearDownModule()` hook is called once - after all the tests in the module.
# Asserting # Asserting
@ -85,4 +85,4 @@ export function test_getJSON(done) {
# Misc # Misc
When looking into the code of the existing tests, you might encounter strange comments looking like this `// >> animation-chaining`. These are markers for code snippets generated in the docs documetation. They are not related to testing so you don't need to add any of those in your tests. When looking into the code of the existing tests, you might encounter strange comments looking like this `// >> animation-chaining`. These are markers for code snippets generated in the docs documentation. They are not related to testing so you don't need to add any of those in your tests.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 296 KiB

View File

@ -674,6 +674,23 @@ export function test_CSS_isAppliedOnPage_From_addCssFile() {
}); });
} }
export function test_CSS_isAppliedOnPage_From_changeCssFile() {
const testButton = new buttonModule.Button();
testButton.text = "Test";
const testCss = "button { color: blue; }";
const testFunc = function (views: Array<viewModule.View>) {
helper.assertViewColor(testButton, "#0000FF");
const page: pageModule.Page = <pageModule.Page>views[1];
page.changeCssFile("~/ui/styling/test.css");
helper.assertViewBackgroundColor(page, "#FF0000");
TKUnit.assert(testButton.style.color === undefined, "Color should not have a value");
}
helper.buildUIAndRunTest(testButton, testFunc, { pageCss: testCss });
}
const invalidCSS = ".invalid { " + const invalidCSS = ".invalid { " +
"color: invalidValue; " + "color: invalidValue; " +
"background-color: invalidValue; " + "background-color: invalidValue; " +

View File

@ -39,7 +39,7 @@ import {
iOSApplication, iOSApplication,
LoadAppCSSEventData, LoadAppCSSEventData,
UnhandledErrorEventData, UnhandledErrorEventData,
DiscardedErrorEventData DiscardedErrorEventData,
} from "./application"; } from "./application";
export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData }; export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData };
@ -82,19 +82,23 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v
export function livesync(rootView: View, context?: ModuleContext) { export function livesync(rootView: View, context?: ModuleContext) {
events.notify(<EventData>{ eventName: "livesync", object: app }); events.notify(<EventData>{ eventName: "livesync", object: app });
const liveSyncCore = global.__onLiveSyncCore; const liveSyncCore = global.__onLiveSyncCore;
let reapplyAppCss = false; let reapplyAppStyles = false;
let reapplyLocalStyles = false;
if (context) { if (context && context.path) {
const fullFileName = getCssFileName();
const fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".") + 1);
const extensions = ["css", "scss"]; const extensions = ["css", "scss"];
reapplyAppCss = extensions.some(ext => context.path === fileName.concat(ext)); const appStylesFullFileName = getCssFileName();
const appStylesFileName = appStylesFullFileName.substring(0, appStylesFullFileName.lastIndexOf(".") + 1);
reapplyAppStyles = extensions.some(ext => context.path === appStylesFileName.concat(ext));
if (!reapplyAppStyles) {
reapplyLocalStyles = extensions.some(ext => context.path.endsWith(ext));
}
} }
if (reapplyAppCss && rootView) { if (reapplyAppStyles && rootView) {
rootView._onCssStateChange(); rootView._onCssStateChange();
} else if (liveSyncCore) { } else if (liveSyncCore) {
liveSyncCore(); reapplyLocalStyles ? liveSyncCore(context) : liveSyncCore();
} }
} }

View File

@ -3,7 +3,9 @@
* @module "application" * @module "application"
*/ /** */ */ /** */
///<reference path="../tns-core-modules.d.ts" /> Include global typings /// <reference path="../nativescript-error.d.ts" />
/// <reference path="../tns-core-modules.d.ts" />
import { NavigationEntry, View, Observable, EventData } from "../ui/frame"; import { NavigationEntry, View, Observable, EventData } from "../ui/frame";
/** /**
@ -607,4 +609,4 @@ export function hasLaunched(): boolean;
export interface LoadAppCSSEventData extends EventData { export interface LoadAppCSSEventData extends EventData {
cssFile: string; cssFile: string;
} }

View File

@ -225,9 +225,9 @@ class IOSApplication implements IOSApplicationDefinition {
} }
} }
public _onLivesync(): void { public _onLivesync(context?: ModuleContext): void {
// If view can't handle livesync set window controller. // If view can't handle livesync set window controller.
if (this._rootView && !this._rootView._onLivesync()) { if (this._rootView && !this._rootView._onLivesync(context)) {
this.setWindowContent(); this.setWindowContent();
} }
} }
@ -264,8 +264,8 @@ exports.ios = iosApp;
setApplication(iosApp); setApplication(iosApp);
// attach on global, so it can be overwritten in NativeScript Angular // attach on global, so it can be overwritten in NativeScript Angular
(<any>global).__onLiveSyncCore = function () { (<any>global).__onLiveSyncCore = function (context?: ModuleContext) {
iosApp._onLivesync(); iosApp._onLivesync(context);
} }
let mainEntry: NavigationEntry; let mainEntry: NavigationEntry;

View File

@ -18,6 +18,10 @@ export class CSSDomainDebugger implements inspectorCommandTypes.CSSDomain.CSSDom
this.commands = {}; this.commands = {};
attachCSSInspectorCommandCallbacks(this.commands); attachCSSInspectorCommandCallbacks(this.commands);
// By default start enabled because we can miss the "enable" event when
// running with `--debug-brk` -- the frontend will send it before we've been created
this.enable();
} }
get enabled(): boolean { get enabled(): boolean {

View File

@ -20,6 +20,10 @@ export class DOMDomainDebugger implements inspectorCommandTypes.DOMDomain.DOMDom
attachDOMInspectorEventCallbacks(this.events); attachDOMInspectorEventCallbacks(this.events);
attachDOMInspectorCommandCallbacks(this.commands); attachDOMInspectorCommandCallbacks(this.commands);
// By default start enabled because we can miss the "enable event when
// running with `--debug-brk` -- the frontend will send it before we've been created
this.enable();
} }
get enabled(): boolean { get enabled(): boolean {

View File

@ -64,7 +64,7 @@ export class Request {
this._resourceType = "Other"; this._resourceType = "Other";
return; return;
} }
this._mimeType = value; this._mimeType = value;
var resourceType = "Other"; var resourceType = "Other";
@ -112,19 +112,19 @@ export class Request {
this._resourceType = value; this._resourceType = value;
} }
} }
public responseReceived(response: inspectorCommandTypes.NetworkDomain.Response): void { public responseReceived(response: inspectorCommandTypes.NetworkDomain.Response): void {
if (this._networkDomainDebugger.enabled) { if (this._networkDomainDebugger.enabled) {
this._networkDomainDebugger.events.responseReceived(this.requestID, frameId, loaderId, __inspectorTimestamp(), <any>this.resourceType, response); this._networkDomainDebugger.events.responseReceived(this.requestID, frameId, loaderId, __inspectorTimestamp(), <any>this.resourceType, response);
} }
} }
public loadingFinished(): void { public loadingFinished(): void {
if (this._networkDomainDebugger.enabled) { if (this._networkDomainDebugger.enabled) {
this._networkDomainDebugger.events.loadingFinished(this.requestID, __inspectorTimestamp()); this._networkDomainDebugger.events.loadingFinished(this.requestID, __inspectorTimestamp());
} }
} }
public requestWillBeSent(request: inspectorCommandTypes.NetworkDomain.Request): void { public requestWillBeSent(request: inspectorCommandTypes.NetworkDomain.Request): void {
if (this._networkDomainDebugger.enabled) { if (this._networkDomainDebugger.enabled) {
this._networkDomainDebugger.events.requestWillBeSent(this.requestID, frameId, loaderId, request.url, request, __inspectorTimestamp(), { type: "Script" }); this._networkDomainDebugger.events.requestWillBeSent(this.requestID, frameId, loaderId, request.url, request, __inspectorTimestamp(), { type: "Script" });
@ -136,9 +136,13 @@ export class Request {
export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomain.NetworkDomainDispatcher { export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomain.NetworkDomainDispatcher {
private _enabled: boolean; private _enabled: boolean;
public events: inspectorCommandTypes.NetworkDomain.NetworkFrontend; public events: inspectorCommandTypes.NetworkDomain.NetworkFrontend;
constructor() { constructor() {
this.events = new inspectorCommands.NetworkDomain.NetworkFrontend(); this.events = new inspectorCommands.NetworkDomain.NetworkFrontend();
// By default start enabled because we can miss the "enable" event when
// running with `--debug-brk` -- the frontend will send it before we've been created
this.enable();
} }
get enabled(): boolean { get enabled(): boolean {
@ -156,7 +160,7 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
} }
this._enabled = true; this._enabled = true;
} }
/** /**
* Disables network tracking, prevents network events from being sent to the client. * Disables network tracking, prevents network events from being sent to the client.
*/ */
@ -166,14 +170,14 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
} }
this._enabled = false; this._enabled = false;
} }
/** /**
* Specifies whether to always send extra HTTP headers with the requests from this page. * Specifies whether to always send extra HTTP headers with the requests from this page.
*/ */
setExtraHTTPHeaders(params: inspectorCommandTypes.NetworkDomain.SetExtraHTTPHeadersMethodArguments): void { setExtraHTTPHeaders(params: inspectorCommandTypes.NetworkDomain.SetExtraHTTPHeadersMethodArguments): void {
// //
} }
/** /**
* Returns content served for the given request. * Returns content served for the given request.
*/ */
@ -187,9 +191,9 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
body: body, body: body,
base64Encoded: !resource_data.hasTextContent base64Encoded: !resource_data.hasTextContent
}; };
} }
} }
/** /**
* Tells whether clearing browser cache is supported. * Tells whether clearing browser cache is supported.
*/ */
@ -198,14 +202,14 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
result: false result: false
}; };
} }
/** /**
* Clears browser cache. * Clears browser cache.
*/ */
clearBrowserCache(): void { clearBrowserCache(): void {
// //
} }
/** /**
* Tells whether clearing browser cookies is supported. * Tells whether clearing browser cookies is supported.
*/ */
@ -214,21 +218,21 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
result: false result: false
}; };
} }
/** /**
* Clears browser cookies. * Clears browser cookies.
*/ */
clearBrowserCookies(): void { clearBrowserCookies(): void {
// //
} }
/** /**
* Toggles ignoring cache for each request. If <code>true</code>, cache will not be used. * Toggles ignoring cache for each request. If <code>true</code>, cache will not be used.
*/ */
setCacheDisabled(params: inspectorCommandTypes.NetworkDomain.SetCacheDisabledMethodArguments): void { setCacheDisabled(params: inspectorCommandTypes.NetworkDomain.SetCacheDisabledMethodArguments): void {
// //
} }
/** /**
* Loads a resource in the context of a frame on the inspected page without cross origin checks. * Loads a resource in the context of a frame on the inspected page without cross origin checks.
*/ */
@ -245,7 +249,7 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
status: 200 status: 200
} }
} }
public static idSequence: number = 0; public static idSequence: number = 0;
create(): Request { create(): Request {
let id = (++NetworkDomainDebugger.idSequence).toString(); let id = (++NetworkDomainDebugger.idSequence).toString();
@ -264,4 +268,4 @@ export class RuntimeDomainDebugger {
compileScript(): { scriptId?: string, exceptionDetails?: Object } { compileScript(): { scriptId?: string, exceptionDetails?: Object } {
return {}; return {};
} }
} }

View File

@ -1,3 +1,4 @@
/// <reference path="./nativescript-error.d.ts" />
declare var global: NodeJS.Global; declare var global: NodeJS.Global;
interface ModuleResolver { interface ModuleResolver {
@ -52,7 +53,7 @@ declare namespace NodeJS {
__inspector?: any; __inspector?: any;
__extends: any; __extends: any;
__onLiveSync: (context?: { type: string, path: string }) => void; __onLiveSync: (context?: { type: string, path: string }) => void;
__onLiveSyncCore: () => void; __onLiveSyncCore: (context?: { type: string, path: string }) => void;
__onUncaughtError: (error: NativeScriptError) => void; __onUncaughtError: (error: NativeScriptError) => void;
__onDiscardedError: (error: NativeScriptError) => void; __onDiscardedError: (error: NativeScriptError) => void;
TNS_WEBPACK?: boolean; TNS_WEBPACK?: boolean;
@ -86,16 +87,6 @@ interface ModuleContext {
path: string; path: string;
} }
/**
* An extended JavaScript Error which will have the nativeError property initialized in case the error is caused by executing platform-specific code.
*/
interface NativeScriptError extends Error {
/**
* Represents the native error object.
*/
nativeError: any;
}
// Define a minimal subset of NodeRequire and NodeModule so user apps can compile without // Define a minimal subset of NodeRequire and NodeModule so user apps can compile without
// installing @types/node // installing @types/node

View File

@ -0,0 +1,9 @@
/**
* An extended JavaScript Error which will have the nativeError property initialized in case the error is caused by executing platform-specific code.
*/
declare interface NativeScriptError extends Error {
/**
* Represents the native error object.
*/
nativeError: any;
}

View File

@ -1,7 +1,7 @@
{ {
"name": "tns-core-modules", "name": "tns-core-modules",
"description": "Telerik NativeScript Core Modules", "description": "Telerik NativeScript Core Modules",
"version": "5.2.2", "version": "5.3.0",
"homepage": "https://www.nativescript.org", "homepage": "https://www.nativescript.org",
"repository": { "repository": {
"type": "git", "type": "git",
@ -26,7 +26,7 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"typings": "tns-core-modules.d.ts", "typings": "tns-core-modules.d.ts",
"dependencies": { "dependencies": {
"tns-core-modules-widgets": "5.2.0", "tns-core-modules-widgets": "next",
"tslib": "^1.9.3" "tslib": "^1.9.3"
}, },
"devDependencies": { "devDependencies": {

View File

@ -22,12 +22,15 @@ declare var console: Console;
declare var require: NodeRequire; declare var require: NodeRequire;
// Extend NodeRequire with the webpack's require context extension. // Extend NodeRequire with the webpack's require context extension.
interface RequireContext {
keys(): string[];
(id: string): any;
<T>(id: string): T;
resolve(id: string): string;
}
interface NodeRequire { interface NodeRequire {
context(root: string, recursive: boolean, filter: RegExp): { context(path: string, deep?: boolean, filter?: RegExp): RequireContext;
(module: string): any;
id: number;
keys(): string[];
}
} }
declare var __dirname: string; declare var __dirname: string;

View File

@ -105,6 +105,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
this._updateStyleScope(cssFileName); this._updateStyleScope(cssFileName);
} }
public changeCssFile(cssFileName: string): void {
const scope = this._styleScope;
if (scope && cssFileName) {
scope.changeCssFile(cssFileName);
this._onCssStateChange();
}
}
public _updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void { public _updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void {
let scope = this._styleScope; let scope = this._styleScope;
if (!scope) { if (!scope) {

View File

@ -2,7 +2,8 @@
* @module "ui/core/view" * @module "ui/core/view"
*/ /** */ */ /** */
///<reference path="../../../tns-core-modules.d.ts" /> Include global typings /// <reference path="../../../tns-core-modules.d.ts" />
import { ViewBase, Property, InheritedProperty, EventData, Color } from "../view-base"; import { ViewBase, Property, InheritedProperty, EventData, Color } from "../view-base";
import { Animation, AnimationDefinition, AnimationPromise } from "../../animation"; import { Animation, AnimationDefinition, AnimationPromise } from "../../animation";
import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties"; import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties";
@ -18,14 +19,14 @@ export function PseudoClassHandler(...pseudoClasses: string[]): MethodDecorator;
/** /**
* Specifies the type name for the instances of this View class, * Specifies the type name for the instances of this View class,
* that is used when matching CSS type selectors. * that is used when matching CSS type selectors.
* *
* Usage: * Usage:
* ``` * ```
* @CSSType("Button") * @CSSType("Button")
* class Button extends View { * class Button extends View {
* } * }
* ``` * ```
* *
* Internally the decorator set `Button.prototype.cssType = "Button"`. * Internally the decorator set `Button.prototype.cssType = "Button"`.
* @param type The type name, e. g. "Button", "Label", etc. * @param type The type name, e. g. "Button", "Label", etc.
*/ */
@ -50,8 +51,8 @@ export type px = number;
export type percent = number; export type percent = number;
/** /**
* The Point interface describes a two dimensional location. * The Point interface describes a two dimensional location.
* It has two properties x and y, representing the x and y coordinate of the location. * It has two properties x and y, representing the x and y coordinate of the location.
*/ */
export interface Point { export interface Point {
/** /**
@ -66,8 +67,8 @@ export interface Point {
} }
/** /**
* The Size interface describes abstract dimensions in two dimensional space. * The Size interface describes abstract dimensions in two dimensional space.
* It has two properties width and height, representing the width and height values of the size. * It has two properties width and height, representing the width and height values of the size.
*/ */
export interface Size { export interface Size {
/** /**
@ -99,8 +100,8 @@ export interface ShownModallyData extends EventData {
} }
/** /**
* This class is the base class for all UI components. * This class is the base class for all UI components.
* A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within. * A View occupies a rectangular area on the screen and is responsible for drawing and layouting of all UI components within.
*/ */
export abstract class View extends ViewBase { export abstract class View extends ViewBase {
/** /**
@ -475,13 +476,13 @@ export abstract class View extends ViewBase {
* [Deprecated. Please use the on() instead.] Adds a gesture observer. * [Deprecated. Please use the on() instead.] Adds a gesture observer.
* @param type - Type of the gesture. * @param type - Type of the gesture.
* @param callback - A function that will be executed when gesture is received. * @param callback - A function that will be executed when gesture is received.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution. * @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/ */
observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any); observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any);
/** /**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method). * 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") or you can use gesture types. * @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change") or you can use gesture types.
* @param callback - Callback function which will be executed when event is raised. * @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. * @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/ */
@ -527,12 +528,12 @@ export abstract class View extends ViewBase {
modal: View; modal: View;
/** /**
* Animates one or more properties of the view based on the supplied options. * Animates one or more properties of the view based on the supplied options.
*/ */
public animate(options: AnimationDefinition): AnimationPromise; public animate(options: AnimationDefinition): AnimationPromise;
/** /**
* Creates an Animation object based on the supplied options. * Creates an Animation object based on the supplied options.
*/ */
public createAnimation(options: AnimationDefinition): Animation; public createAnimation(options: AnimationDefinition): Animation;
@ -562,7 +563,7 @@ export abstract class View extends ViewBase {
public getActualSize(): Size; public getActualSize(): Size;
/** /**
* Derived classes can override this method to handle Android back button press. * Derived classes can override this method to handle Android back button press.
*/ */
onBackPressed(): boolean; onBackPressed(): boolean;
@ -575,7 +576,7 @@ export abstract class View extends ViewBase {
/** /**
* @private * @private
* Adds a new values to current css. * Adds a new values to current css.
* @param cssString - A valid css which will be added to current css. * @param cssString - A valid css which will be added to current css.
*/ */
addCss(cssString: string): void; addCss(cssString: string): void;
@ -586,13 +587,20 @@ export abstract class View extends ViewBase {
*/ */
addCssFile(cssFileName: string): void; addCssFile(cssFileName: string): void;
/**
* @private
* Changes the current css to the content of the file.
* @param cssFileName - A valid file name (from the application root) which contains a valid css.
*/
changeCssFile(cssFileName: string): void;
// Lifecycle events // Lifecycle events
_getNativeViewsCount(): number; _getNativeViewsCount(): number;
_eachLayoutView(callback: (View) => void): void; _eachLayoutView(callback: (View) => void): void;
/** /**
* Iterates over children of type View. * Iterates over children of type View.
* @param callback Called for each child of type View. Iteration stops if this method returns falsy value. * @param callback Called for each child of type View. Iteration stops if this method returns falsy value.
*/ */
public eachChildView(callback: (view: View) => boolean): void; public eachChildView(callback: (view: View) => boolean): void;
@ -673,7 +681,7 @@ export abstract class View extends ViewBase {
/** /**
* @private * @private
*/ */
_onLivesync(): boolean; _onLivesync(context?: { type: string, path: string }): boolean;
/** /**
* @private * @private
*/ */
@ -681,9 +689,9 @@ export abstract class View extends ViewBase {
/** /**
* Updates styleScope or create new styleScope. * Updates styleScope or create new styleScope.
* @param cssFileName * @param cssFileName
* @param cssString * @param cssString
* @param css * @param css
*/ */
_updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void; _updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void;
@ -715,7 +723,7 @@ export abstract class View extends ViewBase {
} }
/** /**
* Base class for all UI components that are containers. * Base class for all UI components that are containers.
*/ */
export class ContainerView extends View { export class ContainerView extends View {
/** /**
@ -725,7 +733,7 @@ export class ContainerView extends View {
} }
/** /**
* Base class for all UI components that implement custom layouts. * Base class for all UI components that implement custom layouts.
*/ */
export class CustomLayoutView extends ContainerView { export class CustomLayoutView extends ContainerView {
//@private //@private

View File

@ -76,7 +76,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
if (backstackIndex !== -1) { if (backstackIndex !== -1) {
backstack = backstackIndex; backstack = backstackIndex;
} else { } else {
// NOTE: We don't search for entries in navigationQueue because there is no way for // NOTE: We don't search for entries in navigationQueue because there is no way for
// developer to get reference to BackstackEntry unless transition is completed. // developer to get reference to BackstackEntry unless transition is completed.
// At that point the entry is put in the backstack array. // At that point the entry is put in the backstack array.
// If we start to return Backstack entry from navigate method then // If we start to return Backstack entry from navigate method then
@ -153,7 +153,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
// } // }
// let currentPage = this._currentEntry.resolvedPage; // let currentPage = this._currentEntry.resolvedPage;
// let currentNavigationEntry = this._currentEntry.entry; // let currentNavigationEntry = this._currentEntry.entry;
// if (currentPage["isBiOrientational"] && currentNavigationEntry.moduleName) { // if (currentPage["isBiOrientational"] && currentNavigationEntry.moduleName) {
// if (this.canGoBack()){ // if (this.canGoBack()){
// this.goBack(); // this.goBack();
@ -162,7 +162,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
// currentNavigationEntry.backstackVisible = false; // currentNavigationEntry.backstackVisible = false;
// } // }
// // Re-navigate to the same page so the other (.port or .land) xml is loaded. // // Re-navigate to the same page so the other (.port or .land) xml is loaded.
// this.navigate(currentNavigationEntry); // this.navigate(currentNavigationEntry);
// } // }
// } // }
@ -224,7 +224,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
newPage.onNavigatedTo(isBack); newPage.onNavigatedTo(isBack);
// Reset executing entry after NavigatedTo is raised; // Reset executing entry after NavigatedTo is raised;
// we do not want to execute two navigations in parallel in case // we do not want to execute two navigations in parallel in case
// additional navigation is triggered from the NavigatedTo handler. // additional navigation is triggered from the NavigatedTo handler.
this._executingEntry = null; this._executingEntry = null;
} }
@ -259,7 +259,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
return true; return true;
} }
} }
return false; return false;
} }
@ -563,7 +563,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
return result; return result;
} }
public _onLivesync(): boolean { public _onLivesync(context?: ModuleContext): boolean {
super._onLivesync(); super._onLivesync();
if (!this._currentEntry || !this._currentEntry.entry) { if (!this._currentEntry || !this._currentEntry.entry) {
@ -571,6 +571,17 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
} }
const currentEntry = this._currentEntry.entry; const currentEntry = this._currentEntry.entry;
if (context && context.path) {
// Use topmost instead of this to cover nested frames scenario
const topmostFrame = topmost();
const moduleName = topmostFrame.currentEntry.moduleName;
const reapplyStyles = context.path.includes(moduleName);
if (reapplyStyles && moduleName) {
topmostFrame.currentPage.changeCssFile(context.path);
return true;
}
}
const newEntry: NavigationEntry = { const newEntry: NavigationEntry = {
animated: false, animated: false,
clearHistory: true, clearHistory: true,

View File

@ -82,13 +82,13 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
return attachStateChangeListener; return attachStateChangeListener;
} }
export function reloadPage(): void { export function reloadPage(context?: ModuleContext): void {
const activity = application.android.foregroundActivity; const activity = application.android.foregroundActivity;
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS]; const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
if (callbacks) { if (callbacks) {
const rootView: View = callbacks.getRootView(); const rootView: View = callbacks.getRootView();
if (!rootView || !rootView._onLivesync()) { if (!rootView || !rootView._onLivesync(context)) {
callbacks.resetActivityContent(activity); callbacks.resetActivityContent(activity);
} }
} else { } else {
@ -153,7 +153,7 @@ export class Frame extends FrameBase {
// In case activity was destroyed because of back button pressed (e.g. app exit) // In case activity was destroyed because of back button pressed (e.g. app exit)
// and application is restored from recent apps, current fragment isn't recreated. // and application is restored from recent apps, current fragment isn't recreated.
// In this case call _navigateCore in order to recreate the current fragment. // In this case call _navigateCore in order to recreate the current fragment.
// Don't call navigate because it will fire navigation events. // Don't call navigate because it will fire navigation events.
// As JS instances are alive it is already done for the current page. // As JS instances are alive it is already done for the current page.
if (!this.isLoaded || this._executingEntry || !this._attachedToWindow) { if (!this.isLoaded || this._executingEntry || !this._attachedToWindow) {
return; return;
@ -183,13 +183,13 @@ export class Frame extends FrameBase {
const entry = this._currentEntry; const entry = this._currentEntry;
if (entry && manager && !manager.findFragmentByTag(entry.fragmentTag)) { if (entry && manager && !manager.findFragmentByTag(entry.fragmentTag)) {
// Simulate first navigation (e.g. no animations or transitions) // Simulate first navigation (e.g. no animations or transitions)
// we need to cache the original animation settings so we can restore them later; otherwise as the // we need to cache the original animation settings so we can restore them later; otherwise as the
// simulated first navigation is not animated (it is actually a zero duration animator) the "popExit" animation // simulated first navigation is not animated (it is actually a zero duration animator) the "popExit" animation
// is broken when transaction.setCustomAnimations(...) is used in a scenario with: // is broken when transaction.setCustomAnimations(...) is used in a scenario with:
// 1) forward navigation // 1) forward navigation
// 2) suspend / resume app // 2) suspend / resume app
// 3) back navigation -- the exiting fragment is erroneously animated with the exit animator from the // 3) back navigation -- the exiting fragment is erroneously animated with the exit animator from the
// simulated navigation (NoTransition, zero duration animator) and thus the fragment immediately disappears; // simulated navigation (NoTransition, zero duration animator) and thus the fragment immediately disappears;
// the user only sees the animation of the entering fragment as per its specific enter animation settings. // the user only sees the animation of the entering fragment as per its specific enter animation settings.
// NOTE: we are restoring the animation settings in Frame.setCurrent(...) as navigation completes asynchronously // NOTE: we are restoring the animation settings in Frame.setCurrent(...) as navigation completes asynchronously
this._cachedAnimatorState = getAnimatorState(this._currentEntry); this._cachedAnimatorState = getAnimatorState(this._currentEntry);
@ -727,7 +727,7 @@ function ensureFragmentClass() {
return; return;
} }
// this require will apply the FragmentClass implementation // this require will apply the FragmentClass implementation
require("ui/frame/fragment"); require("ui/frame/fragment");
if (!fragmentClass) { if (!fragmentClass) {
@ -855,11 +855,11 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
entry.viewSavedState = null; entry.viewSavedState = null;
} }
// fixes 'java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first'. // fixes 'java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first'.
// on app resume in nested frame scenarios with support library version greater than 26.0.0 // on app resume in nested frame scenarios with support library version greater than 26.0.0
// HACK: this whole code block shouldn't be necessary as the native view is supposedly removed from its parent // HACK: this whole code block shouldn't be necessary as the native view is supposedly removed from its parent
// right after onDestroyView(...) is called but for some reason the fragment view (page) still thinks it has a // right after onDestroyView(...) is called but for some reason the fragment view (page) still thinks it has a
// parent while its supposed parent believes it properly removed its children; in order to "force" the child to // 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) // lose its parent we temporarily add it to the parent, and then remove it (addViewInLayout doesn't trigger layout pass)
const nativeView = page.nativeViewProtected; const nativeView = page.nativeViewProtected;
if (nativeView != null) { if (nativeView != null) {
@ -908,8 +908,8 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
} }
// [nested frames / fragments] see https://github.com/NativeScript/NativeScript/issues/6629 // [nested frames / fragments] see https://github.com/NativeScript/NativeScript/issues/6629
// retaining reference to a destroyed fragment here somehow causes a cryptic // retaining reference to a destroyed fragment here somehow causes a cryptic
// "IllegalStateException: Failure saving state: active fragment has cleared index: -1" // "IllegalStateException: Failure saving state: active fragment has cleared index: -1"
// in a specific mixed parent / nested frame navigation scenario // in a specific mixed parent / nested frame navigation scenario
entry.fragment = null; entry.fragment = null;
@ -1019,15 +1019,15 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
} }
// NOTE: activity.onPostResume() is called when activity resume is complete and we can // NOTE: activity.onPostResume() is called when activity resume is complete and we can
// safely raise the application resume event; // safely raise the application resume event;
// onActivityResumed(...) lifecycle callback registered in application is called too early // onActivityResumed(...) lifecycle callback registered in application is called too early
// and raising the application resume event there causes issues like // and raising the application resume event there causes issues like
// https://github.com/NativeScript/NativeScript/issues/6708 // https://github.com/NativeScript/NativeScript/issues/6708
if ((<any>activity).isNativeScriptActivity) { if ((<any>activity).isNativeScriptActivity) {
const args = <application.ApplicationEventData>{ const args = <application.ApplicationEventData>{
eventName: application.resumeEvent, eventName: application.resumeEvent,
object: application.android, object: application.android,
android: activity android: activity
}; };
application.notify(args); application.notify(args);
application.android.paused = false; application.android.paused = false;
@ -1151,7 +1151,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
// Paths that go trough this method: // Paths that go trough this method:
// 1. Application initial start - there is no rootView in callbacks. // 1. Application initial start - there is no rootView in callbacks.
// 2. Application revived after Activity is destroyed. this._rootView should have been restored by id in onCreate. // 2. Application revived after Activity is destroyed. this._rootView should have been restored by id in onCreate.
// 3. Livesync if rootView has no custom _onLivesync. this._rootView should have been cleared upfront. Launch event should not fired // 3. Livesync if rootView has no custom _onLivesync. this._rootView should have been cleared upfront. Launch event should not fired
// 4. _resetRootView method. this._rootView should have been cleared upfront. Launch event should not fired // 4. _resetRootView method. this._rootView should have been cleared upfront. Launch event should not fired
private setActivityContent( private setActivityContent(

View File

@ -3,7 +3,8 @@
* @module "ui/page" * @module "ui/page"
*/ /** */ */ /** */
///<reference path="../../tns-core-modules.d.ts" /> Include global typings /// <reference path="../../tns-core-modules.d.ts" />
import { ShownModallyData } from "../core/view"; import { ShownModallyData } from "../core/view";
import { ContentView, EventData, Property, Color, CssProperty, Style } from "../content-view"; import { ContentView, EventData, Property, Color, CssProperty, Style } from "../content-view";
import { Frame } from "../frame"; import { Frame } from "../frame";
@ -106,7 +107,7 @@ export class Page extends ContentView {
/** /**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method). * 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 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. * @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/ */
@ -198,4 +199,4 @@ export const statusBarStyleProperty: CssProperty<Style, "light" | "dark">;
/** /**
* Property backing androidStatusBarBackground. * Property backing androidStatusBarBackground.
*/ */
export const androidStatusBarBackgroundProperty: CssProperty<Style, Color>; export const androidStatusBarBackgroundProperty: CssProperty<Style, Color>;

View File

@ -29,6 +29,7 @@ export class CssState {
export class StyleScope { export class StyleScope {
public css: string; public css: string;
public addCss(cssString: string, cssFileName: string): void; public addCss(cssString: string, cssFileName: string): void;
public changeCssFile(cssFileName: string): void;
public static createSelectorsFromCss(css: string, cssFileName: string, keyframes: Object): RuleSet[]; public static createSelectorsFromCss(css: string, cssFileName: string, keyframes: Object): RuleSet[];
public static createSelectorsFromImports(tree: SyntaxTree, keyframes: Object): RuleSet[]; public static createSelectorsFromImports(tree: SyntaxTree, keyframes: Object): RuleSet[];

View File

@ -569,6 +569,19 @@ export class StyleScope {
this.appendCss(null, cssFileName); this.appendCss(null, cssFileName);
} }
@profile
private changeCssFile(cssFileName: string): void {
if (!cssFileName) {
return;
}
const cssSelectors = CSSSource.fromURI(cssFileName, this._keyframes);
this._css = cssSelectors.source;
this._localCssSelectors = cssSelectors.selectors;
this._localCssSelectorVersion++;
this.ensureSelectors();
}
@profile @profile
private setCss(cssString: string, cssFileName?): void { private setCss(cssString: string, cssFileName?): void {
this._css = cssString; this._css = cssString;

View File

@ -643,11 +643,13 @@ export class TabView extends TabViewBase {
} }
[selectedIndexProperty.setNative](value: number) { [selectedIndexProperty.setNative](value: number) {
const smoothScroll = this.androidTabsPosition === "top";
if (traceEnabled()) { if (traceEnabled()) {
traceWrite("TabView this._viewPager.setCurrentItem(" + value + ", true);", traceCategory); traceWrite("TabView this._viewPager.setCurrentItem(" + value + ", " + smoothScroll + ");", traceCategory);
} }
this._viewPager.setCurrentItem(value, true); this._viewPager.setCurrentItem(value, smoothScroll);
} }
[itemsProperty.getDefault](): TabViewItem[] { [itemsProperty.getDefault](): TabViewItem[] {

View File

@ -131,7 +131,8 @@ export class WebView extends WebViewBase {
public _loadUrl(src: string) { public _loadUrl(src: string) {
if (src.startsWith("file:///")) { if (src.startsWith("file:///")) {
this.ios.loadFileURLAllowingReadAccessToURL(NSURL.URLWithString(src), NSURL.URLWithString(src)); var cachePath = src.substring(0, src.lastIndexOf("/"));
this.ios.loadFileURLAllowingReadAccessToURL(NSURL.URLWithString(src), NSURL.URLWithString(cachePath));
} else { } else {
this.ios.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(src))); this.ios.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(src)));
} }
@ -160,4 +161,4 @@ export class WebView extends WebViewBase {
public reload() { public reload() {
this.ios.reload(); this.ios.reload();
} }
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "tns-platform-declarations", "name": "tns-platform-declarations",
"version": "5.2.2", "version": "5.3.0",
"description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects", "description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
"main": "", "main": "",
"scripts": { "scripts": {