diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj index 6a6ffe7f0..0c7ef0322 100644 --- a/CrossPlatformModules.csproj +++ b/CrossPlatformModules.csproj @@ -981,6 +981,8 @@ utils.d.ts + + utils.d.ts @@ -2139,7 +2141,7 @@ True 0 / - http://localhost:3128/ + http://localhost:60276/ False False diff --git a/application-settings/application-settings-common.ts b/application-settings/application-settings-common.ts index 9517dc23b..77f4f291e 100644 --- a/application-settings/application-settings-common.ts +++ b/application-settings/application-settings-common.ts @@ -1,5 +1,4 @@ - -export var checkKey = function(key: string) : void { +export var checkKey = function(key: string) : void { if ("string" !== typeof key) { throw new Error("key: '" + key + "' must be a string"); } diff --git a/application-settings/application-settings.android.ts b/application-settings/application-settings.android.ts index c1a1dfcec..eb11ba117 100644 --- a/application-settings/application-settings.android.ts +++ b/application-settings/application-settings.android.ts @@ -1,16 +1,26 @@ -import Common = require("./application-settings-common"); +import common = require("./application-settings-common"); import utils = require("utils/utils"); -var sharedPreferences = utils.ad.getApplicationContext().getSharedPreferences("prefs.db", 0); +var sharedPreferences; +function ensureSharedPreferences() { + if (!sharedPreferences) { + sharedPreferences = utils.ad.getApplicationContext().getSharedPreferences("prefs.db", 0); + } +} + +function verify(key: string) { + common.checkKey(key); + ensureSharedPreferences(); +} export var hasKey = function (key: string): boolean { - Common.checkKey(key); + verify(key); return sharedPreferences.contains(key); } // getters export var getBoolean = function (key: string, defaultValue?: boolean): boolean { - Common.checkKey(key); + verify(key); if (hasKey(key)) { return sharedPreferences.getBoolean(key, false); } @@ -18,7 +28,7 @@ export var getBoolean = function (key: string, defaultValue?: boolean): boolean } export var getString = function (key: string, defaultValue?: string): string { - Common.checkKey(key); + verify(key); if (hasKey(key)) { return sharedPreferences.getString(key, ""); } @@ -26,7 +36,7 @@ export var getString = function (key: string, defaultValue?: string): string { } export var getNumber = function (key: string, defaultValue?: number): number { - Common.checkKey(key); + verify(key); if (hasKey(key)) { return sharedPreferences.getFloat(key, float(0.0)); } @@ -35,31 +45,31 @@ export var getNumber = function (key: string, defaultValue?: number): number { // setters export var setBoolean = function (key: string, value: boolean): void { - Common.checkKey(key); - Common.ensureValidValue(value, "boolean"); + verify(key); + common.ensureValidValue(value, "boolean"); var editor = sharedPreferences.edit(); editor.putBoolean(key, value); editor.commit(); } export var setString = function (key: string, value: string): void { - Common.checkKey(key); - Common.ensureValidValue(value, "string"); + verify(key); + common.ensureValidValue(value, "string"); var editor = sharedPreferences.edit(); editor.putString(key, value); editor.commit(); } export var setNumber = function (key: string, value: number): void { - Common.checkKey(key); - Common.ensureValidValue(value, "number"); + verify(key); + common.ensureValidValue(value, "number"); var editor = sharedPreferences.edit(); editor.putFloat(key, float(value)); editor.commit(); } export var remove = function (key: string): void { - Common.checkKey(key); + verify(key); var editor = sharedPreferences.edit(); editor.remove(key); editor.commit(); diff --git a/application/application.android.ts b/application/application.android.ts index 435d290a3..7c9cfbbe3 100644 --- a/application/application.android.ts +++ b/application/application.android.ts @@ -11,7 +11,7 @@ var typedExports: typeof definition = exports; // We are using the exports object for the common events since we merge the appModule with this module's exports, which is what users will receive when require("application") is called; // TODO: This is kind of hacky and is "pure JS in TypeScript" -var initEvents = function () { +function initEvents() { // TODO: Verify whether the logic for triggerring application-wide events based on Activity callbacks is working properly var lifecycleCallbacks = new android.app.Application.ActivityLifecycleCallbacks({ onActivityCreated: function (activity: any, bundle: any) { @@ -152,17 +152,6 @@ var initEvents = function () { return lifecycleCallbacks; } -app.init({ - getActivity: function (activity: android.app.Activity) { - var intent = activity.getIntent() - return androidApp.getActivity(intent); - }, - - onCreate: function () { - androidApp.init(this); - } -}); - export class AndroidApplication extends observable.Observable implements definition.AndroidApplication { public static activityCreatedEvent = "activityCreated"; public static activityDestroyedEvent = "activityDestroyed"; @@ -264,9 +253,10 @@ export class AndroidApplication extends observable.Observable implements definit } public registerBroadcastReceiver(intentFilter: string, onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) { + ensureBroadCastReceiverClass(); var that = this; var registerFunc = function (context: android.content.Context) { - var receiver = new BroadcastReceiver(onReceiveCallback); + var receiver = new BroadcastReceiverClass(onReceiveCallback); context.registerReceiver(receiver, new android.content.IntentFilter(intentFilter)); that._registeredReceivers[intentFilter] = receiver; } @@ -289,20 +279,29 @@ export class AndroidApplication extends observable.Observable implements definit } } -class BroadcastReceiver extends android.content.BroadcastReceiver { - private _onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void; - - constructor(onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) { - super(); - this._onReceiveCallback = onReceiveCallback; - return global.__native(this); +var BroadcastReceiverClass; +function ensureBroadCastReceiverClass() { + if (BroadcastReceiverClass) { + return; } - public onReceive(context: android.content.Context, intent: android.content.Intent) { - if (this._onReceiveCallback) { - this._onReceiveCallback(context, intent); + class BroadcastReceiver extends android.content.BroadcastReceiver { + private _onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void; + + constructor(onReceiveCallback: (context: android.content.Context, intent: android.content.Intent) => void) { + super(); + this._onReceiveCallback = onReceiveCallback; + return global.__native(this); + } + + public onReceive(context: android.content.Context, intent: android.content.Intent) { + if (this._onReceiveCallback) { + this._onReceiveCallback(context, intent); + } } } + + BroadcastReceiverClass = BroadcastReceiver; } global.__onUncaughtError = function (error: definition.NativeScriptError) { @@ -320,10 +319,29 @@ function loadCss() { typedExports.cssSelectorsCache = typedExports.loadCss(typedExports.cssFile); } -export function start(entry?: frame.NavigationEntry) { - if (entry) { +var started = false; +export function start (entry?: frame.NavigationEntry) { + if (started) { + throw new Error("Application is already started."); + } + + started = true; + + if (entry) { typedExports.mainEntry = entry; } + + // this should be the first call, to avoid issues when someone accesses the Application singleton prior to extending its onCreate method + app.init({ + getActivity: function (activity: android.app.Activity) { + var intent = activity.getIntent() + return androidApp.getActivity(intent); + }, + + onCreate: function () { + androidApp.init(this); + } + }); loadCss(); } diff --git a/file-system/file-name-resolver.ts b/file-system/file-name-resolver.ts index b9e7c785a..cb7a2867c 100644 --- a/file-system/file-name-resolver.ts +++ b/file-system/file-name-resolver.ts @@ -3,7 +3,7 @@ import fs = require("file-system"); import types = require("utils/types"); import trace = require("trace"); import platform = require("platform"); -import application = require("application"); +import * as appModule from "application"; var MIN_WH: string = "minWH"; var MIN_W: string = "minW"; @@ -225,7 +225,8 @@ var resolverInstance: FileNameResolver; export function resolveFileName(path: string, ext: string): string { if (!appEventAttached) { - application.on(application.orientationChangedEvent, (data) => { + var app: typeof appModule = require("application"); + app.on(app.orientationChangedEvent, (data) => { resolverInstance = undefined; }); appEventAttached = true; diff --git a/file-system/file-system-access.android.ts b/file-system/file-system-access.android.ts index 383553d99..d8ed46756 100644 --- a/file-system/file-system-access.android.ts +++ b/file-system/file-system-access.android.ts @@ -3,7 +3,7 @@ import utils = require("utils/utils"); import * as typesModule from "utils/types"; export class FileSystemAccess { - private _pathSeparator = java.io.File.separator.toString(); + private _pathSeparator = "/"; public getLastModified(path: string): Date { var javaFile = new java.io.File(path); diff --git a/file-system/file-system.ts b/file-system/file-system.ts index f1f27fb60..e5378b588 100644 --- a/file-system/file-system.ts +++ b/file-system/file-system.ts @@ -1,4 +1,5 @@ import file_access_module = require("file-system/file-system-access"); +import * as utilsModule from "utils/utils"; // The FileSystemAccess implementation, used through all the APIs. var fileAccess; @@ -442,17 +443,10 @@ export module knownFolders { export var currentApp = function (): Folder { if (!_app) { - 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); - } + var utils: typeof utilsModule = require("utils/utils"); + var filesDir = utils.ad.getApplicationContext().getFilesDir().getCanonicalPath(); _app = new Folder(); - _app[pathProperty] = appPath; + _app[pathProperty] = filesDir + "/app/"; _app[isKnownProperty] = true; } diff --git a/fps-meter/fps-meter.ts b/fps-meter/fps-meter.ts index 871153f48..e912c3861 100644 --- a/fps-meter/fps-meter.ts +++ b/fps-meter/fps-meter.ts @@ -29,7 +29,12 @@ function doFrame(currentTimeMillis: number) { } } -var native = new fpsNative.FPSCallback(doFrame); +var native; +function ensureNative() { + if (!native) { + native = new fpsNative.FPSCallback(doFrame); + } +} export function reset() { _minFps = 1000; @@ -38,6 +43,10 @@ export function reset() { } export function running(): boolean { + if (!native) { + return false; + } + return native.running; } @@ -46,10 +55,15 @@ export function minFps(): number { } export function start() { + ensureNative(); native.start(); } export function stop() { + if (!native) { + return; + } + native.stop(); reset(); } diff --git a/globals/globals.ts b/globals/globals.ts index 9a1038ce4..753c88778 100644 --- a/globals/globals.ts +++ b/globals/globals.ts @@ -28,7 +28,7 @@ global.loadModule = function(name: string): any { global.registerModule("timer", () => require("timer")); global.registerModule("ui/dialogs", () => require("ui/dialogs")); -global.registerModule("../xhr/xhr", () => require("../xhr/xhr")); +global.registerModule("xhr", () => require("xhr")); global.registerModule("fetch", () => require("fetch")); const __tnsGlobalMergedModules = new Map(); @@ -61,8 +61,8 @@ registerOnGlobalContext("clearInterval", "timer"); registerOnGlobalContext("alert", "ui/dialogs"); registerOnGlobalContext("confirm", "ui/dialogs"); registerOnGlobalContext("prompt", "ui/dialogs"); -registerOnGlobalContext("XMLHttpRequest", "../xhr/xhr"); -registerOnGlobalContext("FormData", "../xhr/xhr"); +registerOnGlobalContext("XMLHttpRequest", "xhr"); +registerOnGlobalContext("FormData", "xhr"); registerOnGlobalContext("fetch", "fetch"); import platform = require("platform"); diff --git a/http/http-request.android.ts b/http/http-request.android.ts index 2535fa2d6..da974bc3a 100644 --- a/http/http-request.android.ts +++ b/http/http-request.android.ts @@ -12,12 +12,19 @@ import http = require("http"); var requestIdCounter = 0; var pendingRequests = {}; -var completeCallback = new com.tns.Async.CompleteCallback({ - onComplete: function (result: any, context: any) { - // as a context we will receive the id of the request - onRequestComplete(context, result); +var completeCallback; +function ensureCompleteCallback() { + if (completeCallback) { + return; } -}); + + completeCallback = new com.tns.Async.CompleteCallback({ + onComplete: function (result: any, context: any) { + // as a context we will receive the id of the request + onRequestComplete(context, result); + } + }); +} function onRequestComplete(requestId: number, result: com.tns.Async.Http.RequestResult) { var callbacks = pendingRequests[requestId]; @@ -132,6 +139,7 @@ export function request(options: http.HttpRequestOptions): PromisepropertyAnimation.target.backgroundColor).argb) : java.lang.Integer.valueOf(-1); diff --git a/ui/dialogs/dialogs.android.ts b/ui/dialogs/dialogs.android.ts index 4b9ed1557..4a3808735 100644 --- a/ui/dialogs/dialogs.android.ts +++ b/ui/dialogs/dialogs.android.ts @@ -131,7 +131,7 @@ export function prompt(arg: any): Promise { title: dialogsCommon.PROMPT, okButtonText: dialogsCommon.OK, cancelButtonText: dialogsCommon.CANCEL, - inputType: dialogs.inputType.text, + inputType: dialogsCommon.inputType.text, }; if (arguments.length === 1) { @@ -155,7 +155,7 @@ export function prompt(arg: any): Promise { var input = new android.widget.EditText(appmodule.android.currentContext); - if (options && options.inputType === dialogs.inputType.password) { + if (options && options.inputType === dialogsCommon.inputType.password) { input.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD); } diff --git a/ui/editable-text-base/editable-text-base.android.ts b/ui/editable-text-base/editable-text-base.android.ts index 5c37deaae..958987b47 100644 --- a/ui/editable-text-base/editable-text-base.android.ts +++ b/ui/editable-text-base/editable-text-base.android.ts @@ -51,7 +51,7 @@ export class EditableTextBase extends common.EditableTextBase { owner._dirtyTextAccumulator = editable.toString(); break; case enums.UpdateTextTrigger.textChanged: - owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, editable.toString()); + owner._onPropertyChangedFromNative(EditableTextBase.textProperty, editable.toString()); break; default: throw new Error("Invalid updateTextTrigger: " + owner.updateTextTrigger); @@ -70,7 +70,7 @@ export class EditableTextBase extends common.EditableTextBase { if (!hasFocus) { if (owner._dirtyTextAccumulator) { - owner._onPropertyChangedFromNative(textBase.TextBase.textProperty, owner._dirtyTextAccumulator); + owner._onPropertyChangedFromNative(EditableTextBase.textProperty, owner._dirtyTextAccumulator); owner._dirtyTextAccumulator = undefined; } diff --git a/ui/frame/frame.android.ts b/ui/frame/frame.android.ts index e10b62b14..6e8585cf8 100644 --- a/ui/frame/frame.android.ts +++ b/ui/frame/frame.android.ts @@ -21,62 +21,69 @@ var activityInitialized = false; var navDepth = -1; -var PageFragmentBody = (android.app.Fragment).extend({ - - onCreate: function (savedInstanceState: android.os.Bundle) { - trace.write(`PageFragmentBody.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle); - this.super.onCreate(savedInstanceState); - this.super.setHasOptionsMenu(true); - }, - - onCreateView: function (inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { - var entry = this.entry; - var page = entry.resolvedPage; - trace.write(`PageFragmentBody.onCreateView(${inflater}, ${page}, ${savedInstanceState})`, trace.categories.NativeLifecycle); - if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) { - this.super.getFragmentManager().beginTransaction().hide(this).commit(); - page._onAttached(this.getActivity()); - } - else { - onFragmentShown(this); - } - return page._nativeView; - }, - - onHiddenChanged: function (hidden: boolean) { - trace.write(`PageFragmentBody.onHiddenChanged(${hidden})`, trace.categories.NativeLifecycle); - this.super.onHiddenChanged(hidden); - if (hidden) { - onFragmentHidden(this); - } - else { - onFragmentShown(this); - } - }, - - onSaveInstanceState: function (outState: android.os.Bundle) { - trace.write(`PageFragmentBody.onSaveInstanceState(${outState})`, trace.categories.NativeLifecycle); - this.super.onSaveInstanceState(outState); - if (this.isHidden()) { - outState.putBoolean(HIDDEN, true); - } - }, - - onDestroyView: function () { - trace.write(`PageFragmentBody.onDestroyView()`, trace.categories.NativeLifecycle); - this.super.onDestroyView(); - onFragmentHidden(this); - }, - - onDestroy: function () { - trace.write(`PageFragmentBody.onDestroy()`, trace.categories.NativeLifecycle); - this.super.onDestroy(); - - var utils: typeof utilsModule = require("utils/utils"); - - utils.GC(); +var FragmentClass; +function ensureFragmentClass() { + if (FragmentClass) { + return; } -}); + + FragmentClass = (android.app.Fragment).extend({ + + onCreate: function (savedInstanceState: android.os.Bundle) { + trace.write(`PageFragmentBody.onCreate(${savedInstanceState})`, trace.categories.NativeLifecycle); + this.super.onCreate(savedInstanceState); + this.super.setHasOptionsMenu(true); + }, + + onCreateView: function (inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { + var entry = this.entry; + var page = entry.resolvedPage; + trace.write(`PageFragmentBody.onCreateView(${inflater}, ${page}, ${savedInstanceState})`, trace.categories.NativeLifecycle); + if (savedInstanceState && savedInstanceState.getBoolean(HIDDEN, false)) { + this.super.getFragmentManager().beginTransaction().hide(this).commit(); + page._onAttached(this.getActivity()); + } + else { + onFragmentShown(this); + } + return page._nativeView; + }, + + onHiddenChanged: function (hidden: boolean) { + trace.write(`PageFragmentBody.onHiddenChanged(${hidden})`, trace.categories.NativeLifecycle); + this.super.onHiddenChanged(hidden); + if (hidden) { + onFragmentHidden(this); + } + else { + onFragmentShown(this); + } + }, + + onSaveInstanceState: function (outState: android.os.Bundle) { + trace.write(`PageFragmentBody.onSaveInstanceState(${outState})`, trace.categories.NativeLifecycle); + this.super.onSaveInstanceState(outState); + if (this.isHidden()) { + outState.putBoolean(HIDDEN, true); + } + }, + + onDestroyView: function () { + trace.write(`PageFragmentBody.onDestroyView()`, trace.categories.NativeLifecycle); + this.super.onDestroyView(); + onFragmentHidden(this); + }, + + onDestroy: function () { + trace.write(`PageFragmentBody.onDestroy()`, trace.categories.NativeLifecycle); + this.super.onDestroy(); + + var utils: typeof utilsModule = require("utils/utils"); + + utils.GC(); + } + }); +} function onFragmentShown(fragment) { trace.write(`onFragmentShown(${fragment.toString()})`, trace.categories.NativeLifecycle); @@ -215,7 +222,8 @@ export class Frame extends frameCommon.Frame { var fragmentTransaction = manager.beginTransaction(); var newFragmentTag = "fragment" + navDepth; - var newFragment = new PageFragmentBody(); + ensureFragmentClass(); + var newFragment = new FragmentClass(); newFragment.frame = this; newFragment.entry = backstackEntry; diff --git a/ui/gestures/gestures.android.ts b/ui/gestures/gestures.android.ts index abfe72b38..e838d8002 100644 --- a/ui/gestures/gestures.android.ts +++ b/ui/gestures/gestures.android.ts @@ -78,15 +78,18 @@ export class GesturesObserver extends common.GesturesObserver { this._detach(); if (type & definition.GestureTypes.tap || type & definition.GestureTypes.doubleTap || type & definition.GestureTypes.longPress) { - this._simpleGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new TapAndDoubleTapGestureListener(this, this.target, type)); + ensureTapAndDoubleTapGestureListenerClass(); + this._simpleGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new TapAndDoubleTapGestureListenerClass(this, this.target, type)); } if (type & definition.GestureTypes.pinch) { - this._scaleGestureDetector = new android.view.ScaleGestureDetector(target._context, new PinchGestureListener(this, this.target)); + ensurePinchGestureListenerClass(); + this._scaleGestureDetector = new android.view.ScaleGestureDetector(target._context, new PinchGestureListenerClass(this, this.target)); } if (type & definition.GestureTypes.swipe) { - this._swipeGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new SwipeGestureListener(this, this.target)); + ensureSwipeGestureListenerClass(); + this._swipeGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new SwipeGestureListenerClass(this, this.target)); } if (type & definition.GestureTypes.pan) { @@ -179,46 +182,55 @@ function _executeCallback(observer: GesturesObserver, args: definition.GestureEv } } -class TapAndDoubleTapGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { - private _observer: GesturesObserver; - private _target: view.View; - private _type: number; - - constructor(observer: GesturesObserver, target: view.View, type: number) { - super(); - - this._observer = observer; - this._target = target; - this._type = type; - return global.__native(this); +var TapAndDoubleTapGestureListenerClass; +function ensureTapAndDoubleTapGestureListenerClass() { + if (TapAndDoubleTapGestureListenerClass) { + return; } - public onSingleTapUp(motionEvent: android.view.MotionEvent): boolean { - if (this._type & definition.GestureTypes.tap) { - var args = _getArgs(definition.GestureTypes.tap, this._target, motionEvent); - _executeCallback(this._observer, args); + class TapAndDoubleTapGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { + private _observer: GesturesObserver; + private _target: view.View; + private _type: number; + + constructor(observer: GesturesObserver, target: view.View, type: number) { + super(); + + this._observer = observer; + this._target = target; + this._type = type; + return global.__native(this); } - return true; - } - public onDoubleTap(motionEvent: android.view.MotionEvent): boolean { - if (this._type & definition.GestureTypes.doubleTap) { - var args = _getArgs(definition.GestureTypes.doubleTap, this._target, motionEvent); - _executeCallback(this._observer, args); + public onSingleTapUp(motionEvent: android.view.MotionEvent): boolean { + if (this._type & definition.GestureTypes.tap) { + var args = _getArgs(definition.GestureTypes.tap, this._target, motionEvent); + _executeCallback(this._observer, args); + } + return true; } - return true; - } - public onDown(motionEvent: android.view.MotionEvent): boolean { - return true; - } + public onDoubleTap(motionEvent: android.view.MotionEvent): boolean { + if (this._type & definition.GestureTypes.doubleTap) { + var args = _getArgs(definition.GestureTypes.doubleTap, this._target, motionEvent); + _executeCallback(this._observer, args); + } + return true; + } - public onLongPress(motionEvent: android.view.MotionEvent): void { - if (this._type & definition.GestureTypes.longPress) { - var args = _getArgs(definition.GestureTypes.longPress, this._target, motionEvent); - _executeCallback(this._observer, args); + public onDown(motionEvent: android.view.MotionEvent): boolean { + return true; + } + + public onLongPress(motionEvent: android.view.MotionEvent): void { + if (this._type & definition.GestureTypes.longPress) { + var args = _getArgs(definition.GestureTypes.longPress, this._target, motionEvent); + _executeCallback(this._observer, args); + } } } + + TapAndDoubleTapGestureListenerClass = TapAndDoubleTapGestureListener; } class PinchGestureEventData implements definition.PinchGestureEventData { @@ -243,135 +255,153 @@ class PinchGestureEventData implements definition.PinchGestureEventData { } } -class PinchGestureListener extends android.view.ScaleGestureDetector.SimpleOnScaleGestureListener { - private _observer: GesturesObserver; - private _target: view.View; - private _scale: number; - private _density: number; - - constructor(observer: GesturesObserver, target: view.View) { - super(); - - this._observer = observer; - this._target = target; - this._density = utils.layout.getDisplayDensity(); - - return global.__native(this); +var PinchGestureListenerClass; +function ensurePinchGestureListenerClass() { + if (PinchGestureListenerClass) { + return; } - public onScaleBegin(detector: android.view.ScaleGestureDetector): boolean { - this._scale = detector.getScaleFactor(); + class PinchGestureListener extends android.view.ScaleGestureDetector.SimpleOnScaleGestureListener { + private _observer: GesturesObserver; + private _target: view.View; + private _scale: number; + private _density: number; - var args = new PinchGestureEventData( - this._target, - detector, - this._scale, - this._target, - common.GestureStateTypes.began); + constructor(observer: GesturesObserver, target: view.View) { + super(); - _executeCallback(this._observer, args); + this._observer = observer; + this._target = target; + this._density = utils.layout.getDisplayDensity(); - return true; - } - - public onScale(detector: android.view.ScaleGestureDetector): boolean { - this._scale *= detector.getScaleFactor(); - - var args = new PinchGestureEventData( - this._target, - detector, - this._scale, - this._target, - common.GestureStateTypes.changed); - - _executeCallback(this._observer, args); - return true; - } - - public onScaleEnd(detector: android.view.ScaleGestureDetector): void { - this._scale *= detector.getScaleFactor(); - - var args = new PinchGestureEventData( - this._target, - detector, - this._scale, - this._target, - common.GestureStateTypes.ended); - - _executeCallback(this._observer, args); - } -} - -class SwipeGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { - private _observer: GesturesObserver; - private _target: view.View; - - constructor(observer: GesturesObserver, target: view.View) { - super(); - - this._observer = observer; - this._target = target; - - return global.__native(this); - } - - public onDown(motionEvent: android.view.MotionEvent): boolean { - return true; - } - - public onFling(initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent, velocityX: number, velocityY: number): boolean { - var result = false; - var args: definition.SwipeGestureEventData; - try { - var deltaY = currentEvent.getY() - initialEvent.getY(); - var deltaX = currentEvent.getX() - initialEvent.getX(); - - if (Math.abs(deltaX) > Math.abs(deltaY)) { - - if (Math.abs(deltaX) > SWIPE_THRESHOLD - && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { - - if (deltaX > 0) { - - args = _getSwipeArgs(definition.SwipeDirection.right, this._target, initialEvent, currentEvent); - _executeCallback(this._observer, args); - - result = true; - } else { - - args = _getSwipeArgs(definition.SwipeDirection.left, this._target, initialEvent, currentEvent); - _executeCallback(this._observer, args); - - result = true; - } - } - - } else { - - if (Math.abs(deltaY) > SWIPE_THRESHOLD - && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { - - if (deltaY > 0) { - - args = _getSwipeArgs(definition.SwipeDirection.down, this._target, initialEvent, currentEvent); - _executeCallback(this._observer, args); - - result = true; - } else { - - args = _getSwipeArgs(definition.SwipeDirection.up, this._target, initialEvent, currentEvent); - _executeCallback(this._observer, args); - - result = true; - } - } - } - } catch (ex) { - // + return global.__native(this); } - return result; + public onScaleBegin(detector: android.view.ScaleGestureDetector): boolean { + this._scale = detector.getScaleFactor(); + + var args = new PinchGestureEventData( + this._target, + detector, + this._scale, + this._target, + common.GestureStateTypes.began); + + _executeCallback(this._observer, args); + + return true; + } + + public onScale(detector: android.view.ScaleGestureDetector): boolean { + this._scale *= detector.getScaleFactor(); + + var args = new PinchGestureEventData( + this._target, + detector, + this._scale, + this._target, + common.GestureStateTypes.changed); + + _executeCallback(this._observer, args); + return true; + } + + public onScaleEnd(detector: android.view.ScaleGestureDetector): void { + this._scale *= detector.getScaleFactor(); + + var args = new PinchGestureEventData( + this._target, + detector, + this._scale, + this._target, + common.GestureStateTypes.ended); + + _executeCallback(this._observer, args); + } } + + PinchGestureListenerClass = PinchGestureListener; +} + +var SwipeGestureListenerClass; +function ensureSwipeGestureListenerClass() { + if (SwipeGestureListenerClass) { + return; + } + + class SwipeGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { + private _observer: GesturesObserver; + private _target: view.View; + + constructor(observer: GesturesObserver, target: view.View) { + super(); + + this._observer = observer; + this._target = target; + + return global.__native(this); + } + + public onDown(motionEvent: android.view.MotionEvent): boolean { + return true; + } + + public onFling(initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent, velocityX: number, velocityY: number): boolean { + var result = false; + var args: definition.SwipeGestureEventData; + try { + var deltaY = currentEvent.getY() - initialEvent.getY(); + var deltaX = currentEvent.getX() - initialEvent.getX(); + + if (Math.abs(deltaX) > Math.abs(deltaY)) { + + if (Math.abs(deltaX) > SWIPE_THRESHOLD + && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { + + if (deltaX > 0) { + + args = _getSwipeArgs(definition.SwipeDirection.right, this._target, initialEvent, currentEvent); + _executeCallback(this._observer, args); + + result = true; + } else { + + args = _getSwipeArgs(definition.SwipeDirection.left, this._target, initialEvent, currentEvent); + _executeCallback(this._observer, args); + + result = true; + } + } + + } else { + + if (Math.abs(deltaY) > SWIPE_THRESHOLD + && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { + + if (deltaY > 0) { + + args = _getSwipeArgs(definition.SwipeDirection.down, this._target, initialEvent, currentEvent); + _executeCallback(this._observer, args); + + result = true; + } else { + + args = _getSwipeArgs(definition.SwipeDirection.up, this._target, initialEvent, currentEvent); + _executeCallback(this._observer, args); + + result = true; + } + } + } + } catch (ex) { + // + } + + return result; + } + } + + SwipeGestureListenerClass = SwipeGestureListener; } class CustomPanGestureDetector { diff --git a/ui/html-view/html-view.android.ts b/ui/html-view/html-view.android.ts index 9f7574308..a7d2fbb4a 100644 --- a/ui/html-view/html-view.android.ts +++ b/ui/html-view/html-view.android.ts @@ -42,7 +42,5 @@ export class HtmlView extends common.HtmlView { // This makes the html vwork this._android.setLinksClickable(true); this._android.setMovementMethod(android.text.method.LinkMovementMethod.getInstance()); - } - } diff --git a/ui/image-cache/image-cache.android.ts b/ui/image-cache/image-cache.android.ts index 145f5bcd2..0e3552ae8 100644 --- a/ui/image-cache/image-cache.android.ts +++ b/ui/image-cache/image-cache.android.ts @@ -1,35 +1,45 @@ import common = require("./image-cache-common"); -class LruBitmapCache extends android.util.LruCache { - constructor(cacheSize: number) { - super(cacheSize); - return global.__native(this); +var LruBitmapCacheClass; +function ensureLruBitmapCacheClass() { + if (LruBitmapCacheClass) { + return; } - protected sizeOf(key: string, bitmap: android.graphics.Bitmap): number { - // The cache size will be measured in kilobytes rather than - // number of items. - var result = Math.round(bitmap.getByteCount() / 1024); - //console.log("sizeOf key: " + result); - return result; - } + class LruBitmapCache extends android.util.LruCache { + constructor(cacheSize: number) { + super(cacheSize); + return global.__native(this); + } - //protected entryRemoved(evicted: boolean, key: string, oldValue: android.graphics.Bitmap, newValue: android.graphics.Bitmap): void { - // console.log("entryRemoved("+evicted+", "+key+", "+oldValue+", "+newValue+")"); - //} -}; + protected sizeOf(key: string, bitmap: android.graphics.Bitmap): number { + // The cache size will be measured in kilobytes rather than + // number of items. + var result = Math.round(bitmap.getByteCount() / 1024); + //console.log("sizeOf key: " + result); + return result; + } + + //protected entryRemoved(evicted: boolean, key: string, oldValue: android.graphics.Bitmap, newValue: android.graphics.Bitmap): void { + // console.log("entryRemoved("+evicted+", "+key+", "+oldValue+", "+newValue+")"); + //} + }; + + LruBitmapCacheClass = LruBitmapCache; +} export class Cache extends common.Cache { private _callback: any; - private _cache: LruBitmapCache; + private _cache; constructor() { super(); + ensureLruBitmapCacheClass(); var maxMemory = java.lang.Runtime.getRuntime().maxMemory() / 1024; var cacheSize = maxMemory / 8; //console.log("cacheSize: " + cacheSize); - this._cache = new LruBitmapCache(cacheSize); + this._cache = new LruBitmapCacheClass(cacheSize); var that = new WeakRef(this); this._callback = new (com).tns.Async.CompleteCallback({ diff --git a/ui/layouts/layout.android.ts b/ui/layouts/layout.android.ts index ab511b625..4390b5df2 100644 --- a/ui/layouts/layout.android.ts +++ b/ui/layouts/layout.android.ts @@ -6,17 +6,24 @@ import * as utilsModule from "utils/utils"; var OWNER = "_owner"; -var NativeViewGroup = (android.view.ViewGroup).extend({ - onMeasure: function (widthMeasureSpec, heightMeasureSpec) { - var owner: view.View = this[OWNER]; - owner.onMeasure(widthMeasureSpec, heightMeasureSpec); - this.setMeasuredDimension(owner.getMeasuredWidth(), owner.getMeasuredHeight()); - }, - onLayout: function (changed: boolean, left: number, top: number, right: number, bottom: number): void { - var owner: view.View = this[OWNER]; - owner.onLayout(left, top, right, bottom); +var NativeViewGroupClass; +function ensureNativeViewGroupClass() { + if (NativeViewGroupClass) { + return; } -}); + + NativeViewGroupClass = (android.view.ViewGroup).extend({ + onMeasure: function (widthMeasureSpec, heightMeasureSpec) { + var owner: view.View = this[OWNER]; + owner.onMeasure(widthMeasureSpec, heightMeasureSpec); + this.setMeasuredDimension(owner.getMeasuredWidth(), owner.getMeasuredHeight()); + }, + onLayout: function (changed: boolean, left: number, top: number, right: number, bottom: number): void { + var owner: view.View = this[OWNER]; + owner.onLayout(left, top, right, bottom); + } + }); +} export class Layout extends layoutBase.LayoutBase implements definition.Layout { private _viewGroup: android.view.ViewGroup; @@ -30,7 +37,8 @@ export class Layout extends layoutBase.LayoutBase implements definition.Layout { } public _createUI() { - this._viewGroup = new NativeViewGroup(this._context); + ensureNativeViewGroupClass(); + this._viewGroup = new NativeViewGroupClass(this._context); this._viewGroup[OWNER] = this; } diff --git a/ui/list-view/list-view.android.ts b/ui/list-view/list-view.android.ts index 9d7405cfd..241a39381 100644 --- a/ui/list-view/list-view.android.ts +++ b/ui/list-view/list-view.android.ts @@ -48,7 +48,8 @@ export class ListView extends common.ListView { } this._android.setId(this._androidViewId); - this.android.setAdapter(new ListViewAdapter(this)); + ensureListViewAdapterClass(); + this.android.setAdapter(new ListViewAdapterClass(this)); var that = new WeakRef(this); @@ -102,7 +103,7 @@ export class ListView extends common.ListView { return; } - (this.android.getAdapter()).notifyDataSetChanged(); + (this.android.getAdapter()).notifyDataSetChanged(); } public scrollToIndex(index: number) { @@ -158,83 +159,91 @@ export class ListView extends common.ListView { } } -class ListViewAdapter extends android.widget.BaseAdapter { - private _listView: ListView; - - constructor(listView: ListView) { - super(); - - this._listView = listView; - - return global.__native(this); +var ListViewAdapterClass; +function ensureListViewAdapterClass() { + if (ListViewAdapterClass) { + return; } - public getCount() { - return this._listView && this._listView.items ? this._listView.items.length : 0; - } + class ListViewAdapter extends android.widget.BaseAdapter { + private _listView: ListView; - public getItem(i: number) { - if (this._listView && this._listView.items && i < this._listView.items.length) { - return this._listView.items.getItem ? this._listView.items.getItem(i) : this._listView.items[i]; + constructor(listView: ListView) { + super(); + + this._listView = listView; + + return global.__native(this); } - return null; - } + public getCount() { + return this._listView && this._listView.items ? this._listView.items.length : 0; + } - public getItemId(i: number) { - return long(i); - } + public getItem(i: number) { + if (this._listView && this._listView.items && i < this._listView.items.length) { + return this._listView.items.getItem ? this._listView.items.getItem(i) : this._listView.items[i]; + } - public hasStableIds(): boolean { - return true; - } - - public getView(index: number, convertView: android.view.View, parent: android.view.ViewGroup): android.view.View { - if (!this._listView) { return null; } - var view = this._listView._getRealizedView(convertView, index); - var args = { - eventName: ITEMLOADING, object: this._listView, index: index, view: view, - android: parent, - ios: undefined - }; - this._listView.notify(args); - - if (!args.view) { - args.view = this._listView._getDefaultItemContent(index); + public getItemId(i: number) { + return long(i); } - if (args.view) { - if (this._listView.rowHeight > -1) { - args.view.height = this._listView.rowHeight; - } - else { - args.view.height = Number.NaN; - } - this._listView._prepareItem(args.view, index); - if (!args.view.parent) { - var layoutBase: typeof layoutBaseModule = require("ui/layouts/layout-base"); + public hasStableIds(): boolean { + return true; + } - if (args.view instanceof layoutBase.LayoutBase) { - this._listView._addView(args.view); - convertView = args.view.android; - } else { - var sp = new stackLayout.StackLayout(); - sp.addChild(args.view); - this._listView._addView(sp); + public getView(index: number, convertView: android.view.View, parent: android.view.ViewGroup): android.view.View { + if (!this._listView) { + return null; + } - convertView = sp.android; + var view = this._listView._getRealizedView(convertView, index); + var args = { + eventName: ITEMLOADING, object: this._listView, index: index, view: view, + android: parent, + ios: undefined + }; + this._listView.notify(args); + + if (!args.view) { + args.view = this._listView._getDefaultItemContent(index); + } + + if (args.view) { + if (this._listView.rowHeight > -1) { + args.view.height = this._listView.rowHeight; } + else { + args.view.height = Number.NaN; + } + this._listView._prepareItem(args.view, index); + if (!args.view.parent) { + var layoutBase: typeof layoutBaseModule = require("ui/layouts/layout-base"); + + if (args.view instanceof layoutBase.LayoutBase) { + this._listView._addView(args.view); + convertView = args.view.android; + } else { + var sp = new stackLayout.StackLayout(); + sp.addChild(args.view); + this._listView._addView(sp); + + convertView = sp.android; + } + } + + this._listView._realizedItems[convertView.hashCode()] = args.view; + // cache the realized index (used to raise the ItemLoading event upon scroll stop) + args.view[REALIZED_INDEX] = index; } - this._listView._realizedItems[convertView.hashCode()] = args.view; - // cache the realized index (used to raise the ItemLoading event upon scroll stop) - args.view[REALIZED_INDEX] = index; + return convertView; } - - return convertView; } -} + ListViewAdapterClass = ListViewAdapter; +} \ No newline at end of file diff --git a/ui/page/page.android.ts b/ui/page/page.android.ts index 8200fc1bf..7cdb27ef5 100644 --- a/ui/page/page.android.ts +++ b/ui/page/page.android.ts @@ -9,48 +9,57 @@ import * as colorModule from "color"; global.moduleMerge(pageCommon, exports); -class DialogFragmentClass extends android.app.DialogFragment { - private _owner: Page; - private _fullscreen: boolean; - private _dismissCallback: Function; - - constructor(owner: Page, fullscreen?: boolean, dismissCallback?: Function) { - super(); - - this._owner = owner; - this._fullscreen = fullscreen; - this._dismissCallback = dismissCallback; - return global.__native(this); +var DialogFragmentClass; +function ensureDialogFragmentClass() { + if (DialogFragmentClass) { + return; } - public onCreateDialog(savedInstanceState: android.os.Bundle): android.app.Dialog { - var dialog = new android.app.Dialog(this._owner._context); - dialog.requestWindowFeature(android.view.Window.FEATURE_NO_TITLE); + class DialogFragmentClassInner extends android.app.DialogFragment { + private _owner: Page; + private _fullscreen: boolean; + private _dismissCallback: Function; - // Hide actionBar and adjust alignment based on _fullscreen value. - this._owner.horizontalAlignment = this._fullscreen ? enums.HorizontalAlignment.stretch : enums.HorizontalAlignment.center; - this._owner.verticalAlignment = this._fullscreen ? enums.VerticalAlignment.stretch : enums.VerticalAlignment.center; - this._owner.actionBarHidden = true; + constructor(owner: Page, fullscreen?: boolean, dismissCallback?: Function) { + super(); - dialog.setContentView(this._owner._nativeView, this._owner._nativeView.getLayoutParams()); - - var window = dialog.getWindow(); - window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT)); - - if (this._fullscreen) { - window.setLayout(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT); + this._owner = owner; + this._fullscreen = fullscreen; + this._dismissCallback = dismissCallback; + return global.__native(this); } - - return dialog; - } - public onDismiss() { - if (typeof this._dismissCallback === "function") { - this._dismissCallback(); + public onCreateDialog(savedInstanceState: android.os.Bundle): android.app.Dialog { + var dialog = new android.app.Dialog(this._owner._context); + dialog.requestWindowFeature(android.view.Window.FEATURE_NO_TITLE); + + // Hide actionBar and adjust alignment based on _fullscreen value. + this._owner.horizontalAlignment = this._fullscreen ? enums.HorizontalAlignment.stretch : enums.HorizontalAlignment.center; + this._owner.verticalAlignment = this._fullscreen ? enums.VerticalAlignment.stretch : enums.VerticalAlignment.center; + this._owner.actionBarHidden = true; + + dialog.setContentView(this._owner._nativeView, this._owner._nativeView.getLayoutParams()); + + var window = dialog.getWindow(); + window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT)); + + if (this._fullscreen) { + window.setLayout(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT); + } + + return dialog; } - } -}; + public onDismiss() { + if (typeof this._dismissCallback === "function") { + this._dismissCallback(); + } + } + + }; + + DialogFragmentClass = DialogFragmentClassInner; +} export class Page extends pageCommon.Page { private _isBackNavigation = false; @@ -114,7 +123,7 @@ export class Page extends pageCommon.Page { } /* tslint:disable */ - private _dialogFragment: DialogFragmentClass; + private _dialogFragment; /* tslint:enable */ protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) { super._showNativeModalView(parent, context, closeCallback, fullscreen); @@ -128,6 +137,7 @@ export class Page extends pageCommon.Page { this._isAddedToNativeVisualTree = true; this.onLoaded(); + ensureDialogFragmentClass(); var that = this; this._dialogFragment = new DialogFragmentClass(this, fullscreen, function () { that.closeModal(); diff --git a/ui/scroll-view/scroll-view-common.ts b/ui/scroll-view/scroll-view-common.ts index f9074e34a..378ebf887 100644 --- a/ui/scroll-view/scroll-view-common.ts +++ b/ui/scroll-view/scroll-view-common.ts @@ -31,7 +31,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc public addEventListener(arg: string, callback: any, thisArg?: any) { super.addEventListener(arg, callback, thisArg); - if (arg === definition.ScrollView.scrollEvent) { + if (arg === ScrollView.scrollEvent) { this._scrollChangeCount++; this.attach(); } @@ -40,7 +40,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc public removeEventListener(arg: string, callback: any, thisArg?: any) { super.addEventListener(arg, callback, thisArg); - if (arg === definition.ScrollView.scrollEvent) { + if (arg === ScrollView.scrollEvent) { this._scrollChangeCount--; this.dettach(); } diff --git a/ui/scroll-view/scroll-view.android.ts b/ui/scroll-view/scroll-view.android.ts index e84972b8a..db2d03eeb 100644 --- a/ui/scroll-view/scroll-view.android.ts +++ b/ui/scroll-view/scroll-view.android.ts @@ -115,7 +115,7 @@ export class ScrollView extends common.ScrollView implements definition.ScrollVi if (rootScrollView && rootScrollView.android) { rootScrollView.notify({ object: rootScrollView, - eventName: definition.ScrollView.scrollEvent, + eventName: ScrollView.scrollEvent, scrollX: rootScrollView.android.getScrollX() / utils.layout.getDisplayDensity(), scrollY: rootScrollView.android.getScrollY() / utils.layout.getDisplayDensity() }); diff --git a/ui/segmented-bar/segmented-bar.android.ts b/ui/segmented-bar/segmented-bar.android.ts index 189268341..a705090f2 100644 --- a/ui/segmented-bar/segmented-bar.android.ts +++ b/ui/segmented-bar/segmented-bar.android.ts @@ -80,6 +80,7 @@ function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { var tabIndex: number; if (view.selectedBackgroundColor) { + ensureSegmentedBarColorDrawableClass(); for (tabIndex = 0; tabIndex < tabHost.getTabWidget().getTabCount(); tabIndex++) { var vg = tabHost.getTabWidget().getChildTabViewAt(tabIndex); @@ -87,7 +88,7 @@ function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { var arr = java.lang.reflect.Array.newInstance(java.lang.Integer.class.getField("TYPE").get(null), 1); arr[0] = R_ATTR_STATE_SELECTED; - var colorDrawable = new SegmentedBarColorDrawable(view.selectedBackgroundColor.android) + var colorDrawable = new SegmentedBarColorDrawableClass(view.selectedBackgroundColor.android) stateDrawable.addState(arr, colorDrawable); stateDrawable.setBounds(0, 15, vg.getRight(), vg.getBottom()); @@ -107,18 +108,25 @@ function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { } (common.SegmentedBar.itemsProperty.metadata).onSetNativeValue = onItemsPropertyChanged; -class SegmentedBarColorDrawable extends android.graphics.drawable.ColorDrawable { - constructor(arg: any) { - super(arg); - - return global.__native(this); +var SegmentedBarColorDrawableClass; +function ensureSegmentedBarColorDrawableClass() { + if (SegmentedBarColorDrawableClass) { + return; } - public draw(canvas: android.graphics.Canvas): void { - var p = new android.graphics.Paint(); - p.setColor(this.getColor()); - p.setStyle(android.graphics.Paint.Style.FILL); - canvas.drawRect(0, this.getBounds().height() - 15, this.getBounds().width(), this.getBounds().height(), p); + class SegmentedBarColorDrawable extends android.graphics.drawable.ColorDrawable { + constructor(arg: any) { + super(arg); + + return global.__native(this); + } + + public draw(canvas: android.graphics.Canvas): void { + var p = new android.graphics.Paint(); + p.setColor(this.getColor()); + p.setStyle(android.graphics.Paint.Style.FILL); + canvas.drawRect(0, this.getBounds().height() - 15, this.getBounds().width(), this.getBounds().height(), p); + } } } @@ -136,11 +144,12 @@ export class SegmentedBarItem extends common.SegmentedBarItem { } export class SegmentedBar extends common.SegmentedBar { - private _android: OurTabHost; + private _android; public _listener: android.widget.TabHost.OnTabChangeListener; public _createUI() { - this._android = new OurTabHost(this._context, null); + ensureTabHostClass(); + this._android = new TabHostClass(this._context, null); if (types.isNumber(this.selectedIndex) && this._android.getCurrentTab() !== this.selectedIndex) { this._android.setCurrentTab(this.selectedIndex); } @@ -177,16 +186,25 @@ export class SegmentedBar extends common.SegmentedBar { } } -class OurTabHost extends android.widget.TabHost { - constructor(context: any, attrs: any) { - super(context, attrs); - - return global.__native(this); +var TabHostClass; +function ensureTabHostClass() { + if (TabHostClass) { + return; } - protected onAttachedToWindow(): void { - // overriden to remove the code that will steal the focus from edit fields. + class OurTabHost extends android.widget.TabHost { + constructor(context: any, attrs: any) { + super(context, attrs); + + return global.__native(this); + } + + protected onAttachedToWindow(): void { + // overriden to remove the code that will steal the focus from edit fields. + } } + + TabHostClass = OurTabHost; } export class SegmentedBarStyler implements style.Styler { diff --git a/ui/styling/background-common.ts b/ui/styling/background-common.ts index c6541317b..b9ff61396 100644 --- a/ui/styling/background-common.ts +++ b/ui/styling/background-common.ts @@ -1,7 +1,7 @@ import imageSource = require("image-source"); import colorModule = require("color"); import enums = require("ui/enums"); -import dts = require("ui/styling/background"); +import definition = require("ui/styling/background"); import cssValue = require("css-value"); import * as typesModule from "utils/types"; @@ -12,7 +12,7 @@ interface CSSValue { value?: number; } -export class Background implements dts.Background { +export class Background implements definition.Background { public static default = new Background(undefined, undefined, undefined, undefined, undefined); color: colorModule.Color; @@ -55,12 +55,12 @@ export class Background implements dts.Background { return new Background(this.color, this.image, this.repeat, this.position, value); } - public getDrawParams(width: number, height: number): dts.BackgroundDrawParams { + public getDrawParams(width: number, height: number): definition.BackgroundDrawParams { if (!this.image) { return null; } - var res: dts.BackgroundDrawParams = { + var res: definition.BackgroundDrawParams = { repeatX: true, repeatY: true, posX: 0, diff --git a/ui/styling/background.android.ts b/ui/styling/background.android.ts index 24d5580f8..6bf4fea36 100644 --- a/ui/styling/background.android.ts +++ b/ui/styling/background.android.ts @@ -1,6 +1,6 @@ import utils = require("utils/utils"); import common = require("./background-common"); -import dts = require("ui/styling/background"); +import definition = require("ui/styling/background"); import view = require("ui/core/view"); import types = require("utils/types"); import * as styleModule from "./style"; @@ -12,130 +12,154 @@ global.moduleMerge(common, exports); // We are using "ad" here to avoid namespace collision with the global android object export module ad { - export class BorderDrawable extends android.graphics.drawable.ColorDrawable implements dts.ad.BorderDrawable { - private _density = utils.layout.getDisplayDensity(); - private _borderWidth: number; - private _cornerRadius: number; - private _borderColor: number; + Object.defineProperty(ad, "BorderDrawable", { + get: function () { + ensureBorderDrawable(); + return BorderDrawableClass; + }, + configurable: true + }); - constructor() { - super(); - return global.__native(this); + var BorderDrawableClass; + function ensureBorderDrawable() { + if (BorderDrawableClass) { + return; } - get borderWidth(): number { - return this._borderWidth; - } - set borderWidth(value: number) { - if (this._borderWidth !== value) { - this._borderWidth = value; - this.invalidateSelf(); + class BorderDrawable extends android.graphics.drawable.ColorDrawable implements definition.ad.BorderDrawable { + private _density = utils.layout.getDisplayDensity(); + private _borderWidth: number; + private _cornerRadius: number; + private _borderColor: number; + + constructor() { + super(); + return global.__native(this); } - } - get cornerRadius(): number { - return this._cornerRadius; - } - set cornerRadius(value: number) { - if (this._cornerRadius !== value) { - this._cornerRadius = value; - this.invalidateSelf(); + get borderWidth(): number { + return this._borderWidth; } - } - - get borderColor(): number { - return this._borderColor; - } - set borderColor(value: number) { - if (this._borderColor !== value) { - this._borderColor = value; - this.invalidateSelf(); + set borderWidth(value: number) { + if (this._borderWidth !== value) { + this._borderWidth = value; + this.invalidateSelf(); + } } - } - private _background: common.Background - get background(): common.Background { - return this._background; - } - set background(value: common.Background) { - if (this._background !== value) { - this._background = value; - this.invalidateSelf(); + get cornerRadius(): number { + return this._cornerRadius; + } + set cornerRadius(value: number) { + if (this._cornerRadius !== value) { + this._cornerRadius = value; + this.invalidateSelf(); + } } - } - public draw(canvas: android.graphics.Canvas): void { - var bounds = this.getBounds(); - var boundsF = new android.graphics.RectF(bounds); - var boundsWidth = bounds.width(); - var boundsHeight = bounds.height(); + get borderColor(): number { + return this._borderColor; + } + set borderColor(value: number) { + if (this._borderColor !== value) { + this._borderColor = value; + this.invalidateSelf(); + } + } - var radius = this._cornerRadius * this._density; - var stroke = this._borderWidth * this._density; + private _background: common.Background + get background(): common.Background { + return this._background; + } + set background(value: common.Background) { + if (this._background !== value) { + this._background = value; + this.invalidateSelf(); + } + } + + public draw(canvas: android.graphics.Canvas): void { + var bounds = this.getBounds(); + var boundsF = new android.graphics.RectF(bounds); + var boundsWidth = bounds.width(); + var boundsHeight = bounds.height(); + + var radius = this._cornerRadius * this._density; + var stroke = this._borderWidth * this._density; - // set clip first - if (radius > 0) { - var path = new android.graphics.Path(); - path.addRoundRect(boundsF, radius, radius, android.graphics.Path.Direction.CW); - canvas.clipPath(path); - } - - // draw background - if (this.background.color && this.background.color.android) { - let c = this.background.color; - canvas.drawARGB(c.a, c.r, c.g, c.b); - } - - // draw image - if (this.background.image) { - let bitmap = this.background.image.android; - let params = this.background.getDrawParams(boundsWidth, boundsHeight); - - var matrix = new android.graphics.Matrix(); - if (params.sizeX > 0 && params.sizeY > 0) { - var scaleX = params.sizeX / bitmap.getWidth(); - var scaleY = params.sizeY / bitmap.getHeight(); - matrix.setScale(scaleX, scaleY, 0, 0); + // set clip first + if (radius > 0) { + var path = new android.graphics.Path(); + path.addRoundRect(boundsF, radius, radius, android.graphics.Path.Direction.CW); + canvas.clipPath(path); } - else { - params.sizeX = bitmap.getWidth(); - params.sizeY = bitmap.getHeight(); + + // draw background + if (this.background.color && this.background.color.android) { + let c = this.background.color; + canvas.drawARGB(c.a, c.r, c.g, c.b); } - matrix.postTranslate(params.posX, params.posY); - if (!params.repeatX && !params.repeatY) { - canvas.drawBitmap(bitmap, matrix, undefined); + // draw image + if (this.background.image) { + let bitmap = this.background.image.android; + let params = this.background.getDrawParams(boundsWidth, boundsHeight); + + var matrix = new android.graphics.Matrix(); + if (params.sizeX > 0 && params.sizeY > 0) { + var scaleX = params.sizeX / bitmap.getWidth(); + var scaleY = params.sizeY / bitmap.getHeight(); + matrix.setScale(scaleX, scaleY, 0, 0); + } + else { + params.sizeX = bitmap.getWidth(); + params.sizeY = bitmap.getHeight(); + } + matrix.postTranslate(params.posX, params.posY); + + if (!params.repeatX && !params.repeatY) { + canvas.drawBitmap(bitmap, matrix, undefined); + } + else { + var shader = new android.graphics.BitmapShader(bitmap, android.graphics.Shader.TileMode.REPEAT, android.graphics.Shader.TileMode.REPEAT); + shader.setLocalMatrix(matrix); + var paint = new android.graphics.Paint(); + paint.setShader(shader); + + var w = params.repeatX ? bounds.width() : params.sizeX; + var h = params.repeatY ? bounds.height() : params.sizeY; + + params.posX = params.repeatX ? 0 : params.posX; + params.posY = params.repeatY ? 0 : params.posY; + + canvas.drawRect(params.posX, params.posY, params.posX + w, params.posY + h, paint); + } } - else { - var shader = new android.graphics.BitmapShader(bitmap, android.graphics.Shader.TileMode.REPEAT, android.graphics.Shader.TileMode.REPEAT); - shader.setLocalMatrix(matrix); - var paint = new android.graphics.Paint(); - paint.setShader(shader); - var w = params.repeatX ? bounds.width() : params.sizeX; - var h = params.repeatY ? bounds.height() : params.sizeY; + // draw border (topmost) + if (stroke > 0 && this._borderColor && this._borderColor) { + let borderPaint = new android.graphics.Paint(); + borderPaint.setStyle(android.graphics.Paint.Style.STROKE); + borderPaint.setColor(this._borderColor); - params.posX = params.repeatX ? 0 : params.posX; - params.posY = params.repeatY ? 0 : params.posY; - - canvas.drawRect(params.posX, params.posY, params.posX + w, params.posY + h, paint); + // Note: Double the stroke as the outer part will be clipped. + borderPaint.setStrokeWidth(stroke * 2); + canvas.drawRoundRect(boundsF, radius, radius, borderPaint) } } - - // draw border (topmost) - if (stroke > 0 && this._borderColor && this._borderColor) { - let borderPaint = new android.graphics.Paint(); - borderPaint.setStyle(android.graphics.Paint.Style.STROKE); - borderPaint.setColor(this._borderColor); - - // Note: Double the stroke as the outer part will be clipped. - borderPaint.setStrokeWidth(stroke * 2); - canvas.drawRoundRect(boundsF, radius, radius, borderPaint) - } } + + BorderDrawableClass = BorderDrawable; } - var SDK = android.os.Build.VERSION.SDK_INT; + var SDK: number; + function getSDK() { + if (!SDK) { + SDK = android.os.Build.VERSION.SDK_INT; + } + + return SDK; + } var _defaultBackgrounds = new Map(); @@ -164,8 +188,8 @@ export module ad { bkg.backgroundColor = backgroundColor; } else if (v.borderWidth !== 0 || v.borderRadius !== 0 || !backgroundValue.isEmpty()) { - if (!(bkg instanceof dts.ad.BorderDrawable)) { - bkg = new dts.ad.BorderDrawable(); + if (!(bkg instanceof BorderDrawableClass)) { + bkg = new BorderDrawableClass(); let viewClass = types.getClass(v); if (!(v instanceof btn.Button) && !_defaultBackgrounds.has(viewClass)) { _defaultBackgrounds.set(viewClass, nativeView.getBackground()); @@ -179,7 +203,7 @@ export module ad { bkg.borderColor = v.borderColor ? v.borderColor.android : android.graphics.Color.TRANSPARENT; bkg.background = backgroundValue; - if (SDK < 18) { + if (getSDK() < 18) { // Switch to software because of unsupported canvas methods if hardware acceleration is on: // http://developer.android.com/guide/topics/graphics/hardware-accel.html nativeView.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null); @@ -201,7 +225,7 @@ export module ad { } } - if (SDK < 18) { + if (getSDK() < 18) { // Reset layer type to hardware nativeView.setLayerType(android.view.View.LAYER_TYPE_HARDWARE, null); } diff --git a/ui/tab-view/tab-view.android.ts b/ui/tab-view/tab-view.android.ts index 37a6b6fa9..f412a405a 100644 --- a/ui/tab-view/tab-view.android.ts +++ b/ui/tab-view/tab-view.android.ts @@ -29,120 +29,138 @@ export class TabViewItem extends common.TabViewItem { } } -class PagerAdapterClass extends android.support.v4.view.PagerAdapter { - private owner: TabView; - private items: Array; - - constructor(owner: TabView, items: Array) { - super(); - - this.owner = owner; - this.items = items; - - return global.__native(this); +var PagerAdapterClass; +function ensurePagerAdapterClass() { + if (PagerAdapterClass) { + return; } - getCount() { - return this.items ? this.items.length : 0; - } + class PagerAdapterClassInner extends android.support.v4.view.PagerAdapter { + private owner: TabView; + private items: Array; - getPageTitle(index: number) { - if (index < 0 || index >= this.items.length) { - return ""; + constructor(owner: TabView, items: Array) { + super(); + + this.owner = owner; + this.items = items; + + return global.__native(this); } - return this.items[index].title; - } - - instantiateItem(container: android.view.ViewGroup, index: number) { - trace.write("TabView.PagerAdapter.instantiateItem; container: " + container + "; index: " + index, common.traceCategory); - - var item = this.items[index]; - if (item.view.parent !== this.owner) { - this.owner._addView(item.view); + getCount() { + return this.items ? this.items.length : 0; } - if (this[VIEWS_STATES]) { - trace.write("TabView.PagerAdapter.instantiateItem; restoreHierarchyState: " + item.view, common.traceCategory); - item.view.android.restoreHierarchyState(this[VIEWS_STATES]); - } - - container.addView(item.view.android); - return item.view.android; - } - - destroyItem(container: android.view.ViewGroup, index: number, _object: any) { - trace.write("TabView.PagerAdapter.destroyItem; container: " + container + "; index: " + index + "; _object: " + _object, common.traceCategory); - var item = this.items[index]; - var nativeView = item.view.android; - - if (nativeView.toString() !== _object.toString()) { - throw new Error("Expected " + nativeView.toString() + " to equal " + _object.toString()); - } - - if (!this[VIEWS_STATES]) { - this[VIEWS_STATES] = new android.util.SparseArray(); - } - nativeView.saveHierarchyState(this[VIEWS_STATES]); - - container.removeView(nativeView); - - // Note: this.owner._removeView will clear item.view.android. - // So call this after the native instance is removed form the container. - if (item.view.parent === this.owner) { - this.owner._removeView(item.view); - } - } - - isViewFromObject(view: android.view.View, _object: any) { - return view === _object; - } - - saveState(): android.os.Parcelable { - trace.write("TabView.PagerAdapter.saveState", common.traceCategory); - - var owner: TabView = this.owner; - if (!owner || owner._childrenCount === 0) { - return null; - } - - if (!this[VIEWS_STATES]) { - this[VIEWS_STATES] = new android.util.SparseArray(); - } - var viewStates = this[VIEWS_STATES]; - var childCallback = function (view: view.View): boolean { - var nativeView: android.view.View = view.android; - if (nativeView && nativeView.isSaveFromParentEnabled && nativeView.isSaveFromParentEnabled()) { - nativeView.saveHierarchyState(viewStates); + getPageTitle(index: number) { + if (index < 0 || index >= this.items.length) { + return ""; } - return true; + + return this.items[index].title; } - owner._eachChildView(childCallback); - var bundle = new android.os.Bundle(); - bundle.putSparseParcelableArray(VIEWS_STATES, viewStates); - return bundle; + instantiateItem(container: android.view.ViewGroup, index: number) { + trace.write("TabView.PagerAdapter.instantiateItem; container: " + container + "; index: " + index, common.traceCategory); + + var item = this.items[index]; + if (item.view.parent !== this.owner) { + this.owner._addView(item.view); + } + + if (this[VIEWS_STATES]) { + trace.write("TabView.PagerAdapter.instantiateItem; restoreHierarchyState: " + item.view, common.traceCategory); + item.view.android.restoreHierarchyState(this[VIEWS_STATES]); + } + + container.addView(item.view.android); + return item.view.android; + } + + destroyItem(container: android.view.ViewGroup, index: number, _object: any) { + trace.write("TabView.PagerAdapter.destroyItem; container: " + container + "; index: " + index + "; _object: " + _object, common.traceCategory); + var item = this.items[index]; + var nativeView = item.view.android; + + if (nativeView.toString() !== _object.toString()) { + throw new Error("Expected " + nativeView.toString() + " to equal " + _object.toString()); + } + + if (!this[VIEWS_STATES]) { + this[VIEWS_STATES] = new android.util.SparseArray(); + } + nativeView.saveHierarchyState(this[VIEWS_STATES]); + + container.removeView(nativeView); + + // Note: this.owner._removeView will clear item.view.android. + // So call this after the native instance is removed form the container. + if (item.view.parent === this.owner) { + this.owner._removeView(item.view); + } + } + + isViewFromObject(view: android.view.View, _object: any) { + return view === _object; + } + + saveState(): android.os.Parcelable { + trace.write("TabView.PagerAdapter.saveState", common.traceCategory); + + var owner: TabView = this.owner; + if (!owner || owner._childrenCount === 0) { + return null; + } + + if (!this[VIEWS_STATES]) { + this[VIEWS_STATES] = new android.util.SparseArray(); + } + var viewStates = this[VIEWS_STATES]; + var childCallback = function (view: view.View): boolean { + var nativeView: android.view.View = view.android; + if (nativeView && nativeView.isSaveFromParentEnabled && nativeView.isSaveFromParentEnabled()) { + nativeView.saveHierarchyState(viewStates); + } + return true; + } + owner._eachChildView(childCallback); + + var bundle = new android.os.Bundle(); + bundle.putSparseParcelableArray(VIEWS_STATES, viewStates); + return bundle; + } + + restoreState(state: android.os.Parcelable, loader: java.lang.ClassLoader) { + trace.write("TabView.PagerAdapter.restoreState", common.traceCategory); + var bundle: android.os.Bundle = state; + bundle.setClassLoader(loader); + this[VIEWS_STATES] = bundle.getSparseParcelableArray(VIEWS_STATES); + } + }; + + PagerAdapterClass = PagerAdapterClassInner; +} + +var PageChangedListenerClass; +function ensurePageChangedListenerClass() { + if (PageChangedListenerClass) { + return; } - restoreState(state: android.os.Parcelable, loader: java.lang.ClassLoader) { - trace.write("TabView.PagerAdapter.restoreState", common.traceCategory); - var bundle: android.os.Bundle = state; - bundle.setClassLoader(loader); - this[VIEWS_STATES] = bundle.getSparseParcelableArray(VIEWS_STATES); - } -}; + class PageChangedListener extends android.support.v4.view.ViewPager.SimpleOnPageChangeListener { + private _owner: TabView; + constructor(owner: TabView) { + super(); + this._owner = owner; + return global.__native(this); + } -class PageChangedListener extends android.support.v4.view.ViewPager.SimpleOnPageChangeListener { - private _owner: TabView; - constructor(owner: TabView) { - super(); - this._owner = owner; - return global.__native(this); + public onPageSelected(position: number) { + this._owner.selectedIndex = position; + } } - public onPageSelected(position: number) { - this._owner.selectedIndex = position; - } + PageChangedListenerClass = PageChangedListener; } function selectedColorPropertyChanged(data: dependencyObservable.PropertyChangeData) { @@ -168,7 +186,7 @@ export class TabView extends common.TabView { private _pagerAdapter: android.support.v4.view.PagerAdapter; private _androidViewId: number; - private _pageChagedListener: PageChangedListener; + private _pageChagedListener; get android(): android.view.View { return this._grid; @@ -207,7 +225,8 @@ export class TabView extends common.TabView { } this._grid.setId(this._androidViewId); - this._pageChagedListener = new PageChangedListener(this); + ensurePageChangedListenerClass(); + this._pageChagedListener = new PageChangedListenerClass(this); (this._viewPager).addOnPageChangeListener(this._pageChagedListener); } @@ -248,6 +267,7 @@ export class TabView extends common.TabView { tabItems.push(this.createTabItem(item)); }); + ensurePagerAdapterClass(); this._pagerAdapter = new PagerAdapterClass(this, data.newValue); this._viewPager.setAdapter(this._pagerAdapter); diff --git a/ui/web-view/web-view.android.ts b/ui/web-view/web-view.android.ts index 83f971846..9db1c93fd 100644 --- a/ui/web-view/web-view.android.ts +++ b/ui/web-view/web-view.android.ts @@ -4,68 +4,77 @@ import * as fileSystemModule from "file-system"; global.moduleMerge(common, exports); -export class WebViewClientClass extends android.webkit.WebViewClient { - private _view: common.WebView; - - constructor(view: common.WebView) { - super(); - - this._view = view; - return global.__native(this); +var WebViewClientClass; +function ensureWebViewClientClass() { + if (WebViewClientClass) { + return; } - public shouldOverrideUrlLoading(view: android.webkit.WebView, url: string) { - trace.write("WebViewClientClass.shouldOverrideUrlLoading(" + url + ")", trace.categories.Debug); - return false; - } + class WebViewClientClassInner extends android.webkit.WebViewClient { + private _view: common.WebView; - public onPageStarted(view: android.webkit.WebView, url: string, favicon: android.graphics.Bitmap) { - super.onPageStarted(view, url, favicon); + constructor(view: common.WebView) { + super(); - if (this._view) { - trace.write("WebViewClientClass.onPageStarted(" + url + ", " + favicon + ")", trace.categories.Debug); - this._view._onLoadStarted(url); + this._view = view; + return global.__native(this); } - } - public onPageFinished(view: android.webkit.WebView, url: string) { - super.onPageFinished(view, url); - - if (this._view) { - trace.write("WebViewClientClass.onPageFinished(" + url + ")", trace.categories.Debug); - this._view._onLoadFinished(url, undefined); + public shouldOverrideUrlLoading(view: android.webkit.WebView, url: string) { + trace.write("WebViewClientClass.shouldOverrideUrlLoading(" + url + ")", trace.categories.Debug); + return false; } - } - public onReceivedError() { - var view: android.webkit.WebView = arguments[0]; - - if (arguments.length === 4) { - - var errorCode: number = arguments[1]; - var description: string = arguments[2]; - var failingUrl: string = arguments[3]; - - super.onReceivedError(view, errorCode, description, failingUrl); + public onPageStarted(view: android.webkit.WebView, url: string, favicon: android.graphics.Bitmap) { + super.onPageStarted(view, url, favicon); if (this._view) { - trace.write("WebViewClientClass.onReceivedError(" + errorCode + ", " + description + ", " + failingUrl + ")", trace.categories.Debug); - this._view._onLoadFinished(failingUrl, description + "(" + errorCode + ")"); + trace.write("WebViewClientClass.onPageStarted(" + url + ", " + favicon + ")", trace.categories.Debug); + this._view._onLoadStarted(url); } - } else { + } - var request: any = arguments[1]; - var error: any = arguments[2]; - - super.onReceivedError(view, request, error); + public onPageFinished(view: android.webkit.WebView, url: string) { + super.onPageFinished(view, url); if (this._view) { - trace.write("WebViewClientClass.onReceivedError(" + error.getErrorCode() + ", " + error.getDescription() + ", " + (error.getUrl && error.getUrl()) + ")", trace.categories.Debug); - this._view._onLoadFinished(error.getUrl && error.getUrl(), error.getDescription() + "(" + error.getErrorCode() + ")"); + trace.write("WebViewClientClass.onPageFinished(" + url + ")", trace.categories.Debug); + this._view._onLoadFinished(url, undefined); } - } - } -}; + } + + public onReceivedError() { + var view: android.webkit.WebView = arguments[0]; + + if (arguments.length === 4) { + + var errorCode: number = arguments[1]; + var description: string = arguments[2]; + var failingUrl: string = arguments[3]; + + super.onReceivedError(view, errorCode, description, failingUrl); + + if (this._view) { + trace.write("WebViewClientClass.onReceivedError(" + errorCode + ", " + description + ", " + failingUrl + ")", trace.categories.Debug); + this._view._onLoadFinished(failingUrl, description + "(" + errorCode + ")"); + } + } else { + + var request: any = arguments[1]; + var error: any = arguments[2]; + + super.onReceivedError(view, request, error); + + if (this._view) { + trace.write("WebViewClientClass.onReceivedError(" + error.getErrorCode() + ", " + error.getDescription() + ", " + (error.getUrl && error.getUrl()) + ")", trace.categories.Debug); + this._view._onLoadFinished(error.getUrl && error.getUrl(), error.getDescription() + "(" + error.getErrorCode() + ")"); + } + } + } + }; + + WebViewClientClass = WebViewClientClassInner; +} export class WebView extends common.WebView { private _android: android.webkit.WebView; @@ -74,6 +83,7 @@ export class WebView extends common.WebView { constructor() { super(); + ensureWebViewClientClass(); this._webViewClient = new WebViewClientClass(this); } diff --git a/utils/debug.ts b/utils/debug.ts index c44882290..e1ffb4027 100644 --- a/utils/debug.ts +++ b/utils/debug.ts @@ -3,8 +3,13 @@ import { knownFolders } from "file-system" export var debug = true; // TODO: Get this from the runtimes... -var applicationRootPath = knownFolders.currentApp().path; -applicationRootPath = applicationRootPath.substr(0, applicationRootPath.length - "app/".length); +var applicationRootPath; +function ensureAppRootPath() { + if (!applicationRootPath) { + applicationRootPath = knownFolders.currentApp().path; + applicationRootPath = applicationRootPath.substr(0, applicationRootPath.length - "app/".length); + } +} export class Source { private _uri: string; @@ -14,7 +19,9 @@ export class Source { private static _source: symbol = Symbol("source"); private static _appRoot: string; - constructor(uri: string, line: number, column: number) { + constructor(uri: string, line: number, column: number) { + ensureAppRootPath(); + if (uri.length > applicationRootPath.length && uri.substr(0, applicationRootPath.length) === applicationRootPath) { this._uri = "file://" + uri.substr(applicationRootPath.length); } else {