From 43fbabb5e9d383244ce5fa9926ad6b45de5e8c68 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 10 Nov 2017 15:47:02 +0200 Subject: [PATCH] Fixed most module cyclic references. There is one left for ios and android: (#4978) - http -> http-request -> image-source that can't be fixed easily and will be removed once we delete image-source module because it is obsolete anyway. There is one more for android: - frame -> fragment that could be removed if we use global object. Updated madge bersion --- package.json | 6 +- .../application/application-common.ts | 10 +- .../file-name-resolver/file-name-resolver.ts | 6 +- .../file-system/file-system-access.ios.ts | 207 +++++++----------- tns-core-modules/http/http.ts | 6 +- .../image-source/image-source.d.ts | 1 + tns-core-modules/module.d.ts | 1 + tns-core-modules/ui/core/bindable/bindable.ts | 4 +- .../ui/core/view-base/view-base.ts | 18 +- tns-core-modules/ui/core/view/view-common.ts | 5 +- tns-core-modules/ui/core/view/view.ios.ts | 3 +- tns-core-modules/ui/frame/frame-common.ts | 26 +-- tns-core-modules/ui/frame/frame.android.ts | 3 +- tns-core-modules/ui/frame/frame.ios.ts | 49 +++-- .../ui/styling/style-properties.ts | 13 +- tns-core-modules/ui/styling/style-scope.ts | 24 +- tns-core-modules/utils/utils-common.ts | 26 +-- tns-core-modules/utils/utils.d.ts | 15 +- tns-core-modules/utils/utils.ios.ts | 40 +++- 19 files changed, 227 insertions(+), 236 deletions(-) diff --git a/package.json b/package.json index f6ff1aa26..112680f44 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "grunt-ts": "6.0.0-beta.11", "grunt-typedoc": "0.2.4", "http-server": "^0.9.0", - "madge": "^2.0.0", + "madge": "^2.2.0", "markdown-snippet-injector": "0.2.2", "mocha": "^3.5.0", "mocha-typescript": "^1.1.9", @@ -80,6 +80,8 @@ "test-tsc-es2016": "npm run tsc -- -p tsconfig.public.es2016.json", "tslint": "tslint --config build/tslint.json 'tns-core-modules/**/*.ts' 'tests/**/*.ts' 'apps/**/*.ts' -e '**/node_modules/**' -e '**/platforms/**'", "madge-ios": "tsc --skipLibCheck && tns prepare ios --path tests && madge --circular tests/platforms/ios/tests/app/tns_modules/tns-core-modules", - "madge-android": "tsc --skipLibCheck && tns prepare android --path tests && madge --circular tests/platforms/android/src/main/assets/app/tns_modules/tns-core-modules" + "madge-ios-image": "tsc --skipLibCheck && tns prepare ios --path tests && madge --image graph-tests-ios.svg tests/platforms/ios/tests/app/tns_modules/tns-core-modules", + "madge-android": "tsc --skipLibCheck && tns prepare android --path tests && madge --circular tests/platforms/android/src/main/assets/app/tns_modules/tns-core-modules", + "madge-android-image": "tsc --skipLibCheck && tns prepare android --path tests && madge --image graph-tests-android.svg tests/platforms/android/src/main/assets/app/tns_modules/tns-core-modules" } } diff --git a/tns-core-modules/application/application-common.ts b/tns-core-modules/application/application-common.ts index fe92b36aa..71149331c 100644 --- a/tns-core-modules/application/application-common.ts +++ b/tns-core-modules/application/application-common.ts @@ -19,6 +19,8 @@ export { Observable }; import { UnhandledErrorEventData, iOSApplication, AndroidApplication, CssChangedEventData, LoadAppCSSEventData } from "."; +export { UnhandledErrorEventData, CssChangedEventData, LoadAppCSSEventData }; + export const launchEvent = "launch"; export const suspendEvent = "suspend"; export const displayedEvent = "displayed"; @@ -54,7 +56,11 @@ export function setApplication(instance: iOSApplication | AndroidApplication): v } export function livesync() { - events.notify({ eventName: "livesync", object: app }); + events.notify({ eventName: "livesync", object: app }); + const liveSyncCore = global.__onLiveSyncCore; + if (liveSyncCore) { + liveSyncCore(); + } } export function setCssFileName(cssFileName: string) { @@ -76,4 +82,4 @@ export function addCss(cssText: string): void { global.__onUncaughtError = function (error: NativeScriptError) { events.notify({ eventName: uncaughtErrorEvent, object: app, android: error, ios: error, error: error }); -} +} \ No newline at end of file diff --git a/tns-core-modules/file-system/file-name-resolver/file-name-resolver.ts b/tns-core-modules/file-system/file-name-resolver/file-name-resolver.ts index e2271fe9d..c010f0b5d 100644 --- a/tns-core-modules/file-system/file-name-resolver/file-name-resolver.ts +++ b/tns-core-modules/file-system/file-name-resolver/file-name-resolver.ts @@ -2,7 +2,7 @@ import { PlatformContext, FileNameResolver as FileNameResolverDefinition } from import { screen, device } from "../../platform"; import { path as fsPath, Folder, File } from "../file-system"; import * as trace from "../../trace"; -import * as appModule from "../../application"; +import * as appCommonModule from "../../application/application-common"; const MIN_WH: string = "minWH"; const MIN_W: string = "minW"; @@ -234,5 +234,5 @@ export function resolveFileName(path: string, ext: string): string { return resolverInstance.resolveFileName(path, ext); } -appModule.on("cssChanged", args => resolverInstance = undefined); -appModule.on("livesync", args => resolverInstance && resolverInstance.clearCache()); +appCommonModule.on("cssChanged", args => resolverInstance = undefined); +appCommonModule.on("livesync", args => resolverInstance && resolverInstance.clearCache()); \ No newline at end of file diff --git a/tns-core-modules/file-system/file-system-access.ios.ts b/tns-core-modules/file-system/file-system-access.ios.ts index 836be6cc1..fbac86953 100644 --- a/tns-core-modules/file-system/file-system-access.ios.ts +++ b/tns-core-modules/file-system/file-system-access.ios.ts @@ -1,15 +1,13 @@ -import * as textModule from "../text"; -import * as utilsModule from "../utils/utils"; - -import * as utils from "../utils/utils"; +import { encoding as textEncoding } from "../text"; +import { ios } from "../utils/utils"; // TODO: Implement all the APIs receiving callback using async blocks // TODO: Check whether we need try/catch blocks for the iOS implementation export class FileSystemAccess { public getLastModified(path: string): Date { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var attributes = fileManager.attributesOfItemAtPathError(path); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const attributes = fileManager.attributesOfItemAtPathError(path); if (attributes) { return attributes.objectForKey("NSFileModificationDate"); @@ -20,18 +18,17 @@ export class FileSystemAccess { public getParent(path: string, onError?: (error: any) => any): { path: string; name: string } { try { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var nsString = NSString.stringWithString(path); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const nsString = NSString.stringWithString(path); - var parentPath = nsString.stringByDeletingLastPathComponent; - var name = fileManager.displayNameAtPath(parentPath); + const parentPath = nsString.stringByDeletingLastPathComponent; + const name = fileManager.displayNameAtPath(parentPath); return { path: parentPath.toString(), name: name }; - } - catch (exception) { + } catch (exception) { if (onError) { onError(exception); } @@ -42,13 +39,13 @@ export class FileSystemAccess { public getFile(path: string, onError?: (error: any) => any): { path: string; name: string; extension: string } { try { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var exists = fileManager.fileExistsAtPath(path); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const exists = fileManager.fileExistsAtPath(path); if (!exists) { - var parentPath = this.getParent(path, onError).path; - if (!fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(parentPath, true, null) || - !fileManager.createFileAtPathContentsAttributes(path, null, null)) { + const parentPath = this.getParent(path, onError).path; + if (!fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(parentPath, true, null) + || !fileManager.createFileAtPathContentsAttributes(path, null, null)) { if (onError) { onError(new Error("Failed to create file at path '" + path + "'")); } @@ -56,15 +53,14 @@ export class FileSystemAccess { } } - var fileName = fileManager.displayNameAtPath(path); + const fileName = fileManager.displayNameAtPath(path); return { path: path, name: fileName, extension: this.getFileExtension(path) }; - } - catch (exception) { + } catch (exception) { if (onError) { onError(exception); } @@ -75,8 +71,8 @@ export class FileSystemAccess { public getFolder(path: string, onError?: (error: any) => any): { path: string; name: string } { try { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var exists = this.folderExists(path); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const exists = this.folderExists(path); if (!exists) { try { @@ -91,14 +87,13 @@ export class FileSystemAccess { } } - var dirName = fileManager.displayNameAtPath(path); + const dirName = fileManager.displayNameAtPath(path); return { path: path, name: dirName }; - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to create folder at path '" + path + "'")); } @@ -107,29 +102,27 @@ export class FileSystemAccess { } } - public getExistingFolder(path: string, onError?: (error: any) => any): { path: string; name: string } { + public getExistingFolder(path: string, onError?: (error: any) => any): { path: string; name: string } { try { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var exists = this.folderExists(path); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const exists = this.folderExists(path); if (exists) { - var dirName = fileManager.displayNameAtPath(path); - + const dirName = fileManager.displayNameAtPath(path); return { path: path, name: dirName }; } return undefined; - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to get folder at path '" + path + "'")); } return undefined; } - } + } public eachEntity(path: string, onEntity: (file: { path: string; name: string; extension: string }) => any, onError?: (error: any) => any) { if (!onEntity) { @@ -140,15 +133,15 @@ export class FileSystemAccess { } public getEntities(path: string, onError?: (error: any) => any): Array<{ path: string; name: string; extension: string }> { - var fileInfos = new Array<{ path: string; name: string; extension: string }>(); + const fileInfos = new Array<{ path: string; name: string; extension: string }>(); - var onEntity = function (entity: { path: string; name: string; extension: string }): boolean { + const onEntity = function (entity: { path: string; name: string; extension: string }): boolean { fileInfos.push(entity); return true; } - var errorOccurred; - var localError = function (error: any) { + let errorOccurred; + const localError = function (error: any) { if (onError) { onError(error); } @@ -166,31 +159,25 @@ export class FileSystemAccess { } public fileExists(path: string): boolean { - var result = this.exists(path); + const result = this.exists(path); return result.exists; } public folderExists(path: string): boolean { - var result = this.exists(path); + const result = this.exists(path); return result.exists && result.isDirectory; } private exists(path: string): { exists: boolean, isDirectory: boolean } { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var isDirectory = new interop.Reference(interop.types.bool, false); - var exists = fileManager.fileExistsAtPathIsDirectory(path, isDirectory); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const isDirectory = new interop.Reference(interop.types.bool, false); + const exists = fileManager.fileExistsAtPathIsDirectory(path, isDirectory); return { exists: exists, isDirectory: isDirectory.value }; } public concatPath(left: string, right: string): string { - var utils: typeof utilsModule = require("utils/utils"); - - // TODO: This probably is not efficient, we may try concatenation with the "/" character - var nsArray = utils.ios.collections.jsArrayToNSArray([left, right]); - var nsString = NSString.pathWithComponents(nsArray); - - return nsString.toString(); + return NSString.pathWithComponents([left, right]).toString(); } public deleteFile(path: string, onError?: (error: any) => any) { @@ -202,15 +189,14 @@ export class FileSystemAccess { } public emptyFolder(path: string, onError?: (error: any) => any) { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var entities = this.getEntities(path, onError); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const entities = this.getEntities(path, onError); if (!entities) { return; } - var i; - for (i = 0; i < entities.length; i++) { + for (let i = 0; i < entities.length; i++) { try { fileManager.removeItemAtPathError(entities[i].path); } @@ -225,12 +211,11 @@ export class FileSystemAccess { } public rename(path: string, newPath: string, onError?: (error: any) => any) { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); try { fileManager.moveItemAtPathToPathError(path, newPath); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to rename '" + path + "' to '" + newPath + "': " + ex)); } @@ -238,8 +223,8 @@ export class FileSystemAccess { } public getLogicalRootPath(): string { - let mainBundlePath = utils.ios.getter(NSBundle, NSBundle.mainBundle).bundlePath; - let resolvedPath = NSString.stringWithString(mainBundlePath).stringByResolvingSymlinksInPath; + const mainBundlePath = ios.getter(NSBundle, NSBundle.mainBundle).bundlePath; + const resolvedPath = NSString.stringWithString(mainBundlePath).stringByResolvingSymlinksInPath; return resolvedPath; } @@ -250,32 +235,18 @@ export class FileSystemAccess { public getTempFolderPath(): string { return this.getKnownPath(NSSearchPathDirectory.CachesDirectory); } - - public getCurrentAppPath(): string { - const currentDir = __dirname; - const tnsModulesIndex = currentDir.indexOf("/tns_modules"); - // Module not hosted in ~/tns_modules when bundled. Use current dir. - let appPath = currentDir; - if (tnsModulesIndex !== -1) { - // Strip part after tns_modules to obtain app root - appPath = currentDir.substring(0, tnsModulesIndex); - } - - return appPath; + public getCurrentAppPath(): string { + return ios.getCurrentAppPath(); } public readText(path: string, onError?: (error: any) => any, encoding?: any) { - var actualEncoding = encoding; - if (!actualEncoding) { - actualEncoding = textModule.encoding.UTF_8; - } + const actualEncoding = encoding || textEncoding.UTF_8; try { - var nsString = NSString.stringWithContentsOfFileEncodingError(path, actualEncoding); + const nsString = NSString.stringWithContentsOfFileEncodingError(path, actualEncoding); return nsString.toString(); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to read file at path '" + path + "': " + ex)); } @@ -285,8 +256,7 @@ export class FileSystemAccess { public read(path: string, onError?: (error: any) => any): NSData { try { return NSData.dataWithContentsOfFile(path); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to read file at path '" + path + "': " + ex)); } @@ -294,18 +264,14 @@ export class FileSystemAccess { } public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) { - var nsString = NSString.stringWithString(content); + const nsString = NSString.stringWithString(content); - var actualEncoding = encoding; - if (!actualEncoding) { - actualEncoding = textModule.encoding.UTF_8; - } + const actualEncoding = encoding || textEncoding.UTF_8; // TODO: verify the useAuxiliaryFile parameter should be false try { nsString.writeToFileAtomicallyEncodingError(path, false, actualEncoding); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to write to file '" + path + "': " + ex)); } @@ -315,8 +281,7 @@ export class FileSystemAccess { public write(path: string, content: NSData, onError?: (error: any) => any) { try { content.writeToFileAtomically(path, true); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to write to file '" + path + "': " + ex)); } @@ -324,10 +289,10 @@ export class FileSystemAccess { } private getKnownPath(folderType: number): string { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); - var paths = fileManager.URLsForDirectoryInDomains(folderType, NSSearchPathDomainMask.UserDomainMask); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + const paths = fileManager.URLsForDirectoryInDomains(folderType, NSSearchPathDomainMask.UserDomainMask); - var url = paths.objectAtIndex(0); + const url = paths.objectAtIndex(0); return url.path; } @@ -335,15 +300,15 @@ export class FileSystemAccess { // Make it in a separate file / module so it can be reused from both implementations. private getFileExtension(path: string): string { // TODO [For Panata]: The definitions currently specify "any" as a return value of this method - //var nsString = Foundation.NSString.stringWithString(path); - //var extension = nsString.pathExtension(); + //const nsString = Foundation.NSString.stringWithString(path); + //const extension = nsString.pathExtension(); //if (extension && extension.length > 0) { // extension = extension.concat(".", extension); //} //return extension; - var dotIndex = path.lastIndexOf("."); + const dotIndex = path.lastIndexOf("."); if (dotIndex && dotIndex >= 0 && dotIndex < path.length) { return path.substring(dotIndex); } @@ -352,11 +317,10 @@ export class FileSystemAccess { } private deleteEntity(path: string, onError?: (error: any) => any) { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); try { fileManager.removeItemAtPathError(path); - } - catch (ex) { + } catch (ex) { if (onError) { onError(new Error("Failed to delete file at path '" + path + "': " + ex)); } @@ -365,11 +329,11 @@ export class FileSystemAccess { private enumEntities(path: string, callback: (entity: { path: string; name: string; extension: string }) => boolean, onError?: (error) => any) { try { - var fileManager = utils.ios.getter(NSFileManager, NSFileManager.defaultManager); + const fileManager = ios.getter(NSFileManager, NSFileManager.defaultManager); + let files: NSArray; try { - var files = fileManager.contentsOfDirectoryAtPathError(path); - } - catch (ex) { + files = fileManager.contentsOfDirectoryAtPathError(path); + } catch (ex) { if (onError) { onError(new Error("Failed to enum files for folder '" + path + "': " + ex)); } @@ -377,31 +341,26 @@ export class FileSystemAccess { return; } - var file; - var i; - var info; - var retVal; + for (let i = 0; i < files.count; i++) { + const file = files.objectAtIndex(i); - for (i = 0; i < files.count; i++) { - file = files.objectAtIndex(i); - - info = { + const info = { path: this.concatPath(path, file), - name: file + name: file, + extension: '' }; if (!this.folderExists(this.joinPath(path, file))) { info.extension = this.getFileExtension(info.path); } - retVal = callback(info); + const retVal = callback(info); if (retVal === false) { // the callback returned false meaning we should stop the iteration break; } } - } - catch (ex) { + } catch (ex) { if (onError) { onError(ex); } @@ -413,30 +372,18 @@ export class FileSystemAccess { } public normalizePath(path: string): string { - var nsString: NSString = NSString.stringWithString(path); - var normalized = nsString.stringByStandardizingPath; + const nsString: NSString = NSString.stringWithString(path); + const normalized = nsString.stringByStandardizingPath; return normalized; } public joinPath(left: string, right: string): string { - var nsString: NSString = NSString.stringWithString(left); + const nsString: NSString = NSString.stringWithString(left); return nsString.stringByAppendingPathComponent(right); } public joinPaths(paths: string[]): string { - if (!paths || paths.length === 0) { - return ""; - } - - var nsArray = NSMutableArray.alloc().initWithCapacity(paths.length); - - var i; - for (i = 0; i < paths.length; i++) { - nsArray.addObject(paths[i]); - } - - var nsString = NSString.stringWithString(NSString.pathWithComponents(nsArray)); - return nsString.stringByStandardizingPath; + return ios.joinPaths(...paths); } -} +} \ No newline at end of file diff --git a/tns-core-modules/http/http.ts b/tns-core-modules/http/http.ts index 7c7861255..e9f8d31eb 100644 --- a/tns-core-modules/http/http.ts +++ b/tns-core-modules/http/http.ts @@ -1,4 +1,4 @@ -import * as image from "../image-source"; +import { ImageSource } from "../image-source"; import * as httpRequest from "./http-request"; global.moduleMerge(httpRequest, exports); @@ -31,7 +31,7 @@ export function getJSON(arg: any): Promise { }); } -export function getImage(arg: any): Promise { +export function getImage(arg: any): Promise { return httpRequest .request(typeof arg === "string" ? { url: arg, method: "GET" } : arg) .then(responce => responce.content.toImage()); @@ -49,4 +49,4 @@ export function getFile(arg: any, destinationFilePath?: string): Promise { } }, e => reject(e)); }); -} +} \ No newline at end of file diff --git a/tns-core-modules/image-source/image-source.d.ts b/tns-core-modules/image-source/image-source.d.ts index d191e2c8c..23fd5bb59 100644 --- a/tns-core-modules/image-source/image-source.d.ts +++ b/tns-core-modules/image-source/image-source.d.ts @@ -148,6 +148,7 @@ export function fromBase64(source: string): ImageSource; export function fromNativeSource(source: any): ImageSource; /** + * Deprecated. Use http.getImage(url: string) instead. * Downloads the image from the provided Url and creates a new ImageSource instance from it. * @param url The link to the remote image object. This operation will download and decode the image. */ diff --git a/tns-core-modules/module.d.ts b/tns-core-modules/module.d.ts index c61a060af..c339fe8a5 100644 --- a/tns-core-modules/module.d.ts +++ b/tns-core-modules/module.d.ts @@ -38,6 +38,7 @@ declare namespace NodeJS { __inspector?: any; __extends: any; __onLiveSync: () => void; + __onLiveSyncCore: () => void; __onUncaughtError: (error: NativeScriptError) => void; TNS_WEBPACK?: boolean; __requireOverride?: (name: string, dir: string) => any; diff --git a/tns-core-modules/ui/core/bindable/bindable.ts b/tns-core-modules/ui/core/bindable/bindable.ts index 2b1552c43..df8800a03 100644 --- a/tns-core-modules/ui/core/bindable/bindable.ts +++ b/tns-core-modules/ui/core/bindable/bindable.ts @@ -9,7 +9,7 @@ import { escapeRegexSymbols } from "../../../utils/utils"; import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent, isCategorySet, messageType as traceMessageType } from "../../../trace"; import * as types from "../../../utils/types"; -import * as application from "../../../application"; +import * as applicationCommon from "../../../application/application-common"; import * as polymerExpressions from "../../../js-libs/polymer-expressions"; export { @@ -357,7 +357,7 @@ export class Binding { let context = this.source && this.source.get && this.source.get() || global; let model = {}; let addedProps = []; - const resources = application.getResources(); + const resources = applicationCommon.getResources(); for (let prop in resources) { if (resources.hasOwnProperty(prop) && !context.hasOwnProperty(prop)) { context[prop] = resources[prop]; diff --git a/tns-core-modules/ui/core/view-base/view-base.ts b/tns-core-modules/ui/core/view-base/view-base.ts index e7c13ef03..bdbdee00b 100644 --- a/tns-core-modules/ui/core/view-base/view-base.ts +++ b/tns-core-modules/ui/core/view-base/view-base.ts @@ -6,13 +6,12 @@ import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "../../la import { KeyframeAnimation } from "../../animation/keyframe-animation"; // Types. -import { Source } from "../../../utils/debug"; import { Property, CssProperty, CssAnimationProperty, InheritedProperty, Style, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, resetCSSProperties, initNativeView, resetNativeView } from "../properties"; +import { Source } from "../../../utils/debug"; import { Binding, BindingOptions, Observable, WrappedValue, PropertyChangeData, traceEnabled, traceWrite, traceCategories, traceNotifyEvent } from "../bindable"; import { isIOS, isAndroid } from "../../../platform"; import { layout } from "../../../utils/utils"; import { Length, paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from "../../styling/style-properties"; -import { DOMNode } from "../../../debugger/dom-node"; // TODO: Remove this import! import * as types from "../../../utils/types"; @@ -27,6 +26,16 @@ export * from "../properties"; import * as ssm from "../../styling/style-scope"; +// import { DOMNode } from "../../../debugger/dom-node"; +import * as dnm from "../../../debugger/dom-node"; +let domNodeModule: typeof dnm; + +function ensuredomNodeModule(): void { + if (!domNodeModule) { + domNodeModule = require("../../../debugger/dom-node"); + } +} + let styleScopeModule: typeof ssm; function ensureStyleScopeModule() { if (!styleScopeModule) { @@ -142,7 +151,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition private _visualState: string; private __nativeView: any; // private _disableNativeViewRecycling: boolean; - public domNode: DOMNode; + public domNode: dnm.DOMNode; public recycleNativeView: "always" | "never" | "auto"; public bindingContext: any; @@ -271,7 +280,8 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition public ensureDomNode() { if (!this.domNode) { - this.domNode = new DOMNode(this); + ensuredomNodeModule(); + this.domNode = new domNodeModule.DOMNode(this); } } diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts index 9d28e294e..33bde4650 100644 --- a/tns-core-modules/ui/core/view/view-common.ts +++ b/tns-core-modules/ui/core/view/view-common.ts @@ -1,12 +1,13 @@ // Definitions. import { View as ViewDefinition, Point, Size, Color, dip } from "."; -import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties"; import { ViewBase, Property, booleanConverter, EventData, layout, getEventOrGestureName, traceEnabled, traceWrite, traceCategories } from "../view-base"; +import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties"; + import { observe as gestureObserve, GesturesObserver, @@ -807,4 +808,4 @@ export const isEnabledProperty = new Property({ isEnabledProperty.register(ViewCommon); export const isUserInteractionEnabledProperty = new Property({ name: "isUserInteractionEnabled", defaultValue: true, valueConverter: booleanConverter }); -isUserInteractionEnabledProperty.register(ViewCommon); +isUserInteractionEnabledProperty.register(ViewCommon); \ No newline at end of file diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index 7b29b8833..810f18bd9 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -1,11 +1,12 @@ // Definitions. import { Point, View as ViewDefinition, dip } from "."; -import { ios, Background } from "../../styling/background"; import { ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, traceEnabled, traceWrite, traceCategories } from "./view-common"; + +import { ios, Background } from "../../styling/background"; import { Visibility, visibilityProperty, opacityProperty, diff --git a/tns-core-modules/ui/frame/frame-common.ts b/tns-core-modules/ui/frame/frame-common.ts index 236fbe342..a4a340779 100644 --- a/tns-core-modules/ui/frame/frame-common.ts +++ b/tns-core-modules/ui/frame/frame-common.ts @@ -7,34 +7,10 @@ import { View, CustomLayoutView, isIOS, isAndroid, traceEnabled, traceWrite, tra import { resolveFileName } from "../../file-system/file-name-resolver"; import { knownFolders, path } from "../../file-system"; import { parse, loadPage } from "../builder"; -import * as application from "../../application"; import { profile } from "../../profiling"; -export { application }; - export * from "../core/view"; -function onLivesync(args: EventData): void { - // give time to allow fileNameResolver & css to reload. - setTimeout(() => { - let g = global; - // Close the error page if available and remove the reference from global context. - if (g.errorPage) { - g.errorPage.closeModal(); - g.errorPage = undefined; - } - - try { - g.__onLiveSyncCore(); - } catch (ex) { - // Show the error as modal page, save reference to the page in global context. - g.errorPage = parse(``); - g.errorPage.showModal(); - } - }); -} -application.on("livesync", onLivesync); - let frameStack: Array = []; function buildEntryFromArgs(arg: any): NavigationEntry { @@ -626,4 +602,4 @@ export function goBack(): boolean { export function stack(): Array { return frameStack; -} +} \ No newline at end of file diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index ca1cda6c8..d039fae75 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -6,7 +6,8 @@ import { import { Page } from "../page"; // Types. -import { FrameBase, application, NavigationContext, stack, goBack, View, Observable, traceEnabled, traceWrite, traceCategories } from "./frame-common"; +import * as application from "../../application"; +import { FrameBase, NavigationContext, stack, goBack, View, Observable, traceEnabled, traceWrite, traceCategories } from "./frame-common"; import { DIALOG_FRAGMENT_TAG } from "../page/constants"; import { _setAndroidFragmentTransitions, _onFragmentCreateAnimator, diff --git a/tns-core-modules/ui/frame/frame.ios.ts b/tns-core-modules/ui/frame/frame.ios.ts index 38f0647e8..3a7ca3632 100644 --- a/tns-core-modules/ui/frame/frame.ios.ts +++ b/tns-core-modules/ui/frame/frame.ios.ts @@ -4,7 +4,7 @@ import { Page } from "../page"; import { profile } from "../../profiling"; //Types. -import { FrameBase, View, application, layout, traceEnabled, traceWrite, traceCategories, isCategorySet } from "./frame-common"; +import { FrameBase, View, topmost, layout, traceEnabled, traceWrite, traceCategories, isCategorySet } from "./frame-common"; import { _createIOSAnimatedTransitioning } from "./fragment.transitions"; // HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to // kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism. @@ -20,6 +20,39 @@ const DELEGATE = "_delegate"; let navDepth = -1; +class NotificationObserver2 extends NSObject { + private _onReceiveCallback: (notification: NSNotification) => void; + + public static initWithCallback(onReceiveCallback: (notification: NSNotification) => void): NotificationObserver2 { + const observer = super.new(); + observer._onReceiveCallback = onReceiveCallback; + return observer; + } + + public onReceive(notification: NSNotification): void { + this._onReceiveCallback(notification); + } + + public static ObjCExposedMethods = { + "onReceive": { returns: interop.types.void, params: [NSNotification] } + }; +} + +const observer = NotificationObserver2.initWithCallback(handleNotification); +const notificationCenter = utils.ios.getter(NSNotificationCenter, NSNotificationCenter.defaultCenter); +notificationCenter.addObserverSelectorNameObject(observer, "onReceive", UIApplicationDidChangeStatusBarFrameNotification, null); + +function handleNotification(notification: NSNotification): void { + // When there is a 40px high "in-call" status bar, nobody moves the navigationBar top from 20 to 40 and it remains underneath the status bar. + const frame = topmost() as Frame; + if (frame) { + frame._handleHigherInCallStatusBarIfNeeded(); + if (frame.currentPage) { + frame.currentPage.requestLayout(); + } + } +} + export class Frame extends FrameBase { private _ios: iOSFrame; private _paramToNavigate: any; @@ -37,18 +70,6 @@ export class Frame extends FrameBase { super(); this._ios = new iOSFrame(this); this.nativeViewProtected = this._ios.controller.view; - - // When there is a 40px high "in-call" status bar, nobody moves the navigationBar top from 20 to 40 and it remains underneath the status bar. - let frameRef = new WeakRef(this); - application.ios.addNotificationObserver(UIApplicationDidChangeStatusBarFrameNotification, (notification: NSNotification) => { - let frame = frameRef.get(); - if (frame) { - frame._handleHigherInCallStatusBarIfNeeded(); - if (frame.currentPage) { - frame.currentPage.requestLayout(); - } - } - }); } @profile @@ -730,4 +751,4 @@ class iOSFrame implements iOSFrameDefinition { public set navBarVisibility(value: "auto" | "never" | "always") { this._navBarVisibility = value; } -} +} \ No newline at end of file diff --git a/tns-core-modules/ui/styling/style-properties.ts b/tns-core-modules/ui/styling/style-properties.ts index b73f4141a..560f22b9d 100644 --- a/tns-core-modules/ui/styling/style-properties.ts +++ b/tns-core-modules/ui/styling/style-properties.ts @@ -1,4 +1,8 @@ // Types +import { unsetValue, Style, + CssProperty, CssAnimationProperty, + ShorthandProperty, InheritedCssProperty, + makeValidator, makeParser } from "../core/properties"; import { Transformation, TransformationValue, @@ -9,15 +13,10 @@ import { dip, px, percent } from "../core/view"; import { Color } from "../../color"; import { Font, parseFont, FontStyle, FontWeight } from "../../ui/styling/font"; -import { layout } from "../../utils/utils"; +import { layout, hasDuplicates } from "../../utils/utils"; import { Background } from "../../ui/styling/background"; import { isIOS } from "../../platform"; -import { Style } from "./style"; - -import { unsetValue, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty, makeValidator, makeParser } from "../core/properties"; - -import { hasDuplicates } from "../../utils/utils"; import { radiansToDegrees } from "../../utils/number-utils"; import { @@ -1038,4 +1037,4 @@ export const visibilityProperty = new CssProperty({ target.view.isCollapsed = (newValue === Visibility.COLLAPSE); } }); -visibilityProperty.register(Style); +visibilityProperty.register(Style); \ No newline at end of file diff --git a/tns-core-modules/ui/styling/style-scope.ts b/tns-core-modules/ui/styling/style-scope.ts index a8fa19575..40783fe69 100644 --- a/tns-core-modules/ui/styling/style-scope.ts +++ b/tns-core-modules/ui/styling/style-scope.ts @@ -28,7 +28,7 @@ import { messageType as traceMessageType, } from "../../trace"; import { File, knownFolders, path } from "../../file-system"; -import * as application from "../../application"; +import * as applicationCommon from "../../application/application-common"; import { profile } from "../../profiling"; import * as kam from "../animation/keyframe-animation"; @@ -216,7 +216,7 @@ class CSSSource { } } -const onCssChanged = profile('"style-scope".onCssChanged', (args: application.CssChangedEventData) => { +const onCssChanged = profile('"style-scope".onCssChanged', (args: applicationCommon.CssChangedEventData) => { if (args.cssText) { const parsed = CSSSource.fromSource(args.cssText, applicationKeyframes, args.cssFile).selectors; if (parsed) { @@ -228,8 +228,8 @@ const onCssChanged = profile('"style-scope".onCssChanged', (args: application.Cs } }); -function onLiveSync(args: application.CssChangedEventData): void { - loadCss(application.getCssFileName()); +function onLiveSync(args: applicationCommon.CssChangedEventData): void { + loadCss(applicationCommon.getCssFileName()); } const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => { @@ -244,18 +244,18 @@ const loadCss = profile(`"style-scope".loadCss`, (cssFile: string) => { } }); -application.on("cssChanged", onCssChanged); -application.on("livesync", onLiveSync); +applicationCommon.on("cssChanged", onCssChanged); +applicationCommon.on("livesync", onLiveSync); -export const loadAppCSS = profile('"style-scope".loadAppCSS', (args: application.LoadAppCSSEventData) => { +export const loadAppCSS = profile('"style-scope".loadAppCSS', (args: applicationCommon.LoadAppCSSEventData) => { loadCss(args.cssFile); - application.off("loadAppCss", loadAppCSS); + applicationCommon.off("loadAppCss", loadAppCSS); }); -if (application.hasLaunched()) { - loadAppCSS({ eventName: "loadAppCss", object: application, cssFile: application.getCssFileName() }); +if (applicationCommon.hasLaunched()) { + loadAppCSS({ eventName: "loadAppCss", object: applicationCommon, cssFile: applicationCommon.getCssFileName() }); } else { - application.on("loadAppCss", loadAppCSS); + applicationCommon.on("loadAppCss", loadAppCSS); } export class CssState { @@ -662,4 +662,4 @@ class InlineSelector implements SelectorCore { public dynamic: boolean = false; public ruleset: RuleSet; public match(node: Node): boolean { return true; } -} +} \ No newline at end of file diff --git a/tns-core-modules/utils/utils-common.ts b/tns-core-modules/utils/utils-common.ts index a31cb51d0..8b8ca0451 100644 --- a/tns-core-modules/utils/utils-common.ts +++ b/tns-core-modules/utils/utils-common.ts @@ -31,7 +31,6 @@ export function convertString(value: any): any { } export module layout { - const MODE_SHIFT = 30; const MODE_MASK = 0x3 << MODE_SHIFT; @@ -48,11 +47,8 @@ export module layout { switch (mode) { case layout.EXACTLY: return "Exact"; - case layout.AT_MOST: - return "AtMost"; - default: return "Unspecified"; } @@ -67,23 +63,17 @@ export module layout { } export function measureSpecToString(measureSpec: number): string { - let mode = getMeasureSpecMode(measureSpec); - let size = getMeasureSpecSize(measureSpec); + const mode = getMeasureSpecMode(measureSpec); + const size = getMeasureSpecSize(measureSpec); let text = "MeasureSpec: "; - if (mode === UNSPECIFIED) { text += "UNSPECIFIED "; - } - else if (mode === EXACTLY) { + } else if (mode === EXACTLY) { text += "EXACTLY "; - } - else if (mode === AT_MOST) { + } else if (mode === AT_MOST) { text += "AT_MOST "; } - else { - text += mode + " "; - } text += size; return text; @@ -126,9 +116,9 @@ export function mergeSort(arr, compareFunc) { return arr; } - let middle = arr.length / 2; - let left = arr.slice(0, middle); - let right = arr.slice(middle, arr.length); + const middle = arr.length / 2; + const left = arr.slice(0, middle); + const right = arr.slice(middle, arr.length); return merge(mergeSort(left, compareFunc), mergeSort(right, compareFunc), compareFunc); } @@ -160,4 +150,4 @@ export function hasDuplicates(arr: Array): boolean { export function eliminateDuplicates(arr: Array): Array { return Array.from(new Set(arr)); -} +} \ No newline at end of file diff --git a/tns-core-modules/utils/utils.d.ts b/tns-core-modules/utils/utils.d.ts index 383cb07ca..3cb7a8675 100644 --- a/tns-core-modules/utils/utils.d.ts +++ b/tns-core-modules/utils/utils.d.ts @@ -233,7 +233,20 @@ export module ios { * Opens file with associated application. * @param filePath The file path. */ - export function openFile(filePath: string): boolean + export function openFile(filePath: string): boolean; + + /** + * Joins an array of file paths. + * @param paths An array of paths. + * Returns the joined path. + */ + export function joinPaths(...paths: string[]): string; + + /** + * Gets the root folder for the current application. This Folder is private for the application and not accessible from Users/External apps. + * iOS - this folder is read-only and contains the app and all its resources. + */ + export function getCurrentAppPath(): string; } /** diff --git a/tns-core-modules/utils/utils.ios.ts b/tns-core-modules/utils/utils.ios.ts index 7800e5f72..7d684bb21 100644 --- a/tns-core-modules/utils/utils.ios.ts +++ b/tns-core-modules/utils/utils.ios.ts @@ -72,9 +72,9 @@ export module ios { } export function isLandscape(): boolean { - var device = getter(UIDevice, UIDevice.currentDevice); - var statusBarOrientation = getter(UIApplication, UIApplication.sharedApplication).statusBarOrientation; - var isStatusBarOrientationLandscape = isOrientationLandscape(statusBarOrientation); + const device = getter(UIDevice, UIDevice.currentDevice); + const statusBarOrientation = getter(UIApplication, UIApplication.sharedApplication).statusBarOrientation; + const isStatusBarOrientationLandscape = isOrientationLandscape(statusBarOrientation); return isOrientationLandscape(device.orientation) || isStatusBarOrientationLandscape; } @@ -82,10 +82,10 @@ export module ios { export function openFile(filePath: string): boolean { try { - var fs: typeof fsModule = require("file-system"); - var path = filePath.replace("~", fs.knownFolders.currentApp().path) + const appPath = getCurrentAppPath(); + const path = filePath.replace("~", appPath) - var controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path)); + const controller = UIDocumentInteractionController.interactionControllerWithURL(NSURL.fileURLWithPath(path)); controller.delegate = new UIDocumentInteractionControllerDelegateImpl(); return controller.presentPreviewAnimated(true); } @@ -94,6 +94,28 @@ export module ios { } return false; } + + export function getCurrentAppPath(): string { + const currentDir = __dirname; + const tnsModulesIndex = currentDir.indexOf("/tns_modules"); + + // Module not hosted in ~/tns_modules when bundled. Use current dir. + let appPath = currentDir; + if (tnsModulesIndex !== -1) { + // Strip part after tns_modules to obtain app root + appPath = currentDir.substring(0, tnsModulesIndex); + } + + return appPath; + } + + export function joinPaths(...paths: string[]): string { + if (!paths || paths.length === 0) { + return ""; + } + + return NSString.stringWithString(NSString.pathWithComponents(paths)).stringByStandardizingPath; + } } export function GC() { @@ -118,8 +140,8 @@ class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UI public static ObjCProtocols = [UIDocumentInteractionControllerDelegate]; public getViewController(): UIViewController { - var frame = require("ui/frame"); - return frame.topmost().currentPage.ios; + const app = ios.getter(UIApplication, UIApplication.sharedApplication); + return app.keyWindow.rootViewController; } public documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) { @@ -135,4 +157,4 @@ class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UI } } -mainScreenScale = ios.getter(UIScreen, UIScreen.mainScreen).scale; +mainScreenScale = ios.getter(UIScreen, UIScreen.mainScreen).scale; \ No newline at end of file