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
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:*
@ -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 :).
## Return statements
There are few important considerations here:
+ To avoid deep nesting of if-statements, always return a functions value as early
There are a few important considerations here:
+ 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.
+ 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
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:*
@ -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:
+ 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
+ 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
Typical module should have the following structure:
A typical module should have the following structure:
1. required dependencies
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)
## 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:*
file-system
@ -451,7 +451,7 @@ file-system
FileSystem, fileSystem, file_system
## 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:*
```TypeScript
@ -470,7 +470,7 @@ doSomething(function(){
```
## 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:*
```TypeScript

View File

@ -1,7 +1,7 @@
# 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.
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
@ -19,7 +19,7 @@ tns run ios
# Test Modules
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**:
@ -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.
* The `setUpModule()` hook is called once - before all the tests in the module.
* The `setUp()` hook is called before each tests.
* The `tearDown()` hook called after each tests.
* The `setUp()` hook is called before each test.
* The `tearDown()` hook called after each test.
* The `tearDownModule()` hook is called once - after all the tests in the module.
# Asserting
@ -85,4 +85,4 @@ export function test_getJSON(done) {
# 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 { " +
"color: invalidValue; " +
"background-color: invalidValue; " +

View File

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

View File

@ -3,7 +3,9 @@
* @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";
/**

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 (this._rootView && !this._rootView._onLivesync()) {
if (this._rootView && !this._rootView._onLivesync(context)) {
this.setWindowContent();
}
}
@ -264,8 +264,8 @@ exports.ios = iosApp;
setApplication(iosApp);
// attach on global, so it can be overwritten in NativeScript Angular
(<any>global).__onLiveSyncCore = function () {
iosApp._onLivesync();
(<any>global).__onLiveSyncCore = function (context?: ModuleContext) {
iosApp._onLivesync(context);
}
let mainEntry: NavigationEntry;

View File

@ -18,6 +18,10 @@ export class CSSDomainDebugger implements inspectorCommandTypes.CSSDomain.CSSDom
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 {

View File

@ -20,6 +20,10 @@ export class DOMDomainDebugger implements inspectorCommandTypes.DOMDomain.DOMDom
attachDOMInspectorEventCallbacks(this.events);
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 {

View File

@ -139,6 +139,10 @@ export class NetworkDomainDebugger implements inspectorCommandTypes.NetworkDomai
constructor() {
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 {

View File

@ -1,3 +1,4 @@
/// <reference path="./nativescript-error.d.ts" />
declare var global: NodeJS.Global;
interface ModuleResolver {
@ -52,7 +53,7 @@ declare namespace NodeJS {
__inspector?: any;
__extends: any;
__onLiveSync: (context?: { type: string, path: string }) => void;
__onLiveSyncCore: () => void;
__onLiveSyncCore: (context?: { type: string, path: string }) => void;
__onUncaughtError: (error: NativeScriptError) => void;
__onDiscardedError: (error: NativeScriptError) => void;
TNS_WEBPACK?: boolean;
@ -86,16 +87,6 @@ interface ModuleContext {
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
// 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",
"description": "Telerik NativeScript Core Modules",
"version": "5.2.2",
"version": "5.3.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.2.0",
"tns-core-modules-widgets": "next",
"tslib": "^1.9.3"
},
"devDependencies": {

View File

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

View File

@ -105,6 +105,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
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 {
let scope = this._styleScope;
if (!scope) {

View File

@ -2,7 +2,8 @@
* @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 { Animation, AnimationDefinition, AnimationPromise } from "../../animation";
import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties";
@ -586,6 +587,13 @@ export abstract class View extends ViewBase {
*/
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
_getNativeViewsCount(): number;
@ -673,7 +681,7 @@ export abstract class View extends ViewBase {
/**
* @private
*/
_onLivesync(): boolean;
_onLivesync(context?: { type: string, path: string }): boolean;
/**
* @private
*/

View File

@ -563,7 +563,7 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
return result;
}
public _onLivesync(): boolean {
public _onLivesync(context?: ModuleContext): boolean {
super._onLivesync();
if (!this._currentEntry || !this._currentEntry.entry) {
@ -571,6 +571,17 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
}
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 = {
animated: false,
clearHistory: true,

View File

@ -82,13 +82,13 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
return attachStateChangeListener;
}
export function reloadPage(): void {
export function reloadPage(context?: ModuleContext): void {
const activity = application.android.foregroundActivity;
const callbacks: AndroidActivityCallbacks = activity[CALLBACKS];
if (callbacks) {
const rootView: View = callbacks.getRootView();
if (!rootView || !rootView._onLivesync()) {
if (!rootView || !rootView._onLivesync(context)) {
callbacks.resetActivityContent(activity);
}
} else {

View File

@ -3,7 +3,8 @@
* @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 { ContentView, EventData, Property, Color, CssProperty, Style } from "../content-view";
import { Frame } from "../frame";

View File

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

View File

@ -569,6 +569,19 @@ export class StyleScope {
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
private setCss(cssString: string, cssFileName?): void {
this._css = cssString;

View File

@ -643,11 +643,13 @@ export class TabView extends TabViewBase {
}
[selectedIndexProperty.setNative](value: number) {
const smoothScroll = this.androidTabsPosition === "top";
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[] {

View File

@ -131,7 +131,8 @@ export class WebView extends WebViewBase {
public _loadUrl(src: string) {
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 {
this.ios.loadRequest(NSURLRequest.requestWithURL(NSURL.URLWithString(src)));
}

View File

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