mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-20 07:26:11 +08:00
Merge branch 'master' of github.com:NativeScript/NativeScript
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json",
|
||||
"rules": {},
|
||||
"ignorePatterns": ["!**/*", "**/node_modules/**/*", "**/__tests__/**/*"],
|
||||
"ignorePatterns": ["!**/*", "**/global-types.d.ts", "**/node_modules/**/*", "**/__tests__/**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
|
||||
11
packages/core/README.md
Normal file
11
packages/core/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
<p align="center">
|
||||
<a href="http://www.nativescript.org">
|
||||
<img alt="NativeScript" src="https://d1lfyz5kwt8vu9.cloudfront.net/nativescript-logo-2021.png" width="100"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## @nativescript/core
|
||||
|
||||
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
|
||||
|
||||
[Learn more at docs.nativescript.org](https://docs.nativescript.org/)
|
||||
@ -92,7 +92,7 @@ function updateCurrentHelperClasses(): void {
|
||||
const oldActiveFontScaleCategory = currentFontScaleCategory;
|
||||
switch (fontScaleCategory) {
|
||||
case FontScaleCategory.ExtraSmall: {
|
||||
currentFontScaleCategory = fontScaleMediumCategoryClass;
|
||||
currentFontScaleCategory = fontScaleExtraSmallCategoryClass;
|
||||
break;
|
||||
}
|
||||
case FontScaleCategory.Medium: {
|
||||
|
||||
@ -5,7 +5,7 @@ export const VALID_FONT_SCALES = global.isIOS // iOS supports a wider number of
|
||||
export function getClosestValidFontScale(fontScale: number): number {
|
||||
fontScale = Number(fontScale) || 1;
|
||||
|
||||
return VALID_FONT_SCALES.sort((a, b) => Math.abs(fontScale - a) - Math.abs(fontScale - b)).shift();
|
||||
return VALID_FONT_SCALES.sort((a, b) => Math.abs(fontScale - a) - Math.abs(fontScale - b))[0];
|
||||
}
|
||||
|
||||
export enum FontScaleCategory {
|
||||
|
||||
@ -11,6 +11,7 @@ function fontScaleChanged(origFontScale: number) {
|
||||
Application.notify({
|
||||
eventName: Application.fontScaleChangedEvent,
|
||||
object: Application,
|
||||
newValue: currentFontScale,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ function fontScaleChanged(origFontScale: number) {
|
||||
Application.notify({
|
||||
eventName: Application.fontScaleChangedEvent,
|
||||
object: Application,
|
||||
newValue: currentFontScale,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/core/application/index.d.ts
vendored
12
packages/core/application/index.d.ts
vendored
@ -135,6 +135,16 @@ export interface SystemAppearanceChangedEventData extends ApplicationEventData {
|
||||
newValue: 'light' | 'dark';
|
||||
}
|
||||
|
||||
/**
|
||||
* Event data containing information for font scale changed event.
|
||||
*/
|
||||
export interface FontScaleChangedEventData extends ApplicationEventData {
|
||||
/**
|
||||
* New font scale value.
|
||||
*/
|
||||
newValue: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event data containing information about unhandled application errors.
|
||||
*/
|
||||
@ -328,6 +338,8 @@ export function on(event: 'orientationChanged', callback: (args: OrientationChan
|
||||
*/
|
||||
export function on(event: 'systemAppearanceChanged', callback: (args: SystemAppearanceChangedEventData) => void, thisArg?: any);
|
||||
|
||||
export function on(event: 'fontScaleChanged', callback: (args: FontScaleChangedEventData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Gets the orientation of the application.
|
||||
* Available values: "portrait", "landscape", "unknown".
|
||||
|
||||
12
packages/core/data/observable/index.d.ts
vendored
12
packages/core/data/observable/index.d.ts
vendored
@ -78,7 +78,7 @@ export class Observable {
|
||||
/**
|
||||
* String value used when hooking to propertyChange event.
|
||||
*/
|
||||
public static propertyChangeEvent: string;
|
||||
static propertyChangeEvent: string;
|
||||
|
||||
/**
|
||||
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
|
||||
@ -88,6 +88,8 @@ export class Observable {
|
||||
*/
|
||||
on(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
|
||||
|
||||
static on(eventName: string, callback: any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Raised when a propertyChange occurs.
|
||||
*/
|
||||
@ -101,11 +103,15 @@ export class Observable {
|
||||
*/
|
||||
once(event: string, callback: (data: EventData) => void, thisArg?: any);
|
||||
|
||||
static once(eventName: string, callback: any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Shortcut alias to the removeEventListener method.
|
||||
*/
|
||||
off(eventNames: string, callback?: any, thisArg?: any);
|
||||
|
||||
static off(eventName: string, callback?: any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Adds a listener for the specified event name.
|
||||
* @param eventNames Comma delimited names of the events to attach the listener to.
|
||||
@ -114,6 +120,8 @@ export class Observable {
|
||||
*/
|
||||
addEventListener(eventNames: string, callback: (data: EventData) => void, thisArg?: any);
|
||||
|
||||
static addEventListener(eventName: string, callback: any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Removes listener(s) for the specified event name.
|
||||
* @param eventNames Comma delimited names of the events the specified listener is associated with.
|
||||
@ -122,6 +130,8 @@ export class Observable {
|
||||
*/
|
||||
removeEventListener(eventNames: string, callback?: any, thisArg?: any);
|
||||
|
||||
static removeEventListener(eventName: string, callback?: any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Updates the specified property with the provided value.
|
||||
*/
|
||||
|
||||
24
packages/core/global-types.d.ts
vendored
24
packages/core/global-types.d.ts
vendored
@ -350,31 +350,31 @@ declare class WeakRef<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Java long from a number
|
||||
*/
|
||||
* Create a Java long from a number
|
||||
*/
|
||||
declare function long(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java byte from a number
|
||||
*/
|
||||
* Create a Java byte from a number
|
||||
*/
|
||||
declare function byte(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java short from a number
|
||||
*/
|
||||
* Create a Java short from a number
|
||||
*/
|
||||
declare function short(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java double from a number
|
||||
*/
|
||||
* Create a Java double from a number
|
||||
*/
|
||||
declare function double(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java float from a number
|
||||
*/
|
||||
* Create a Java float from a number
|
||||
*/
|
||||
declare function float(value: number): any;
|
||||
|
||||
/**
|
||||
* Create a Java char from a string
|
||||
*/
|
||||
* Create a Java char from a string
|
||||
*/
|
||||
declare function char(value: string): any;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { ImageAssetBase, getRequestedImageSize } from './image-asset-common';
|
||||
import { path as fsPath, knownFolders } from '../file-system';
|
||||
|
||||
import { ad } from '../utils';
|
||||
import { Screen } from '../platform';
|
||||
export * from './image-asset-common';
|
||||
|
||||
export class ImageAsset extends ImageAssetBase {
|
||||
@ -25,66 +26,20 @@ export class ImageAsset extends ImageAssetBase {
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
const bitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
// read only the file size
|
||||
let bitmap = android.graphics.BitmapFactory.decodeFile(this.android, bitmapOptions);
|
||||
const sourceSize = {
|
||||
width: bitmapOptions.outWidth,
|
||||
height: bitmapOptions.outHeight,
|
||||
};
|
||||
const requestedSize = getRequestedImageSize(sourceSize, this.options);
|
||||
|
||||
const sampleSize = org.nativescript.widgets.image.Fetcher.calculateInSampleSize(bitmapOptions.outWidth, bitmapOptions.outHeight, requestedSize.width, requestedSize.height);
|
||||
|
||||
const finalBitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
finalBitmapOptions.inSampleSize = sampleSize;
|
||||
try {
|
||||
let error = null;
|
||||
// read as minimum bitmap as possible (slightly bigger than the requested size)
|
||||
bitmap = android.graphics.BitmapFactory.decodeFile(this.android, finalBitmapOptions);
|
||||
|
||||
if (bitmap) {
|
||||
if (requestedSize.width !== bitmap.getWidth() || requestedSize.height !== bitmap.getHeight()) {
|
||||
// scale to exact size
|
||||
bitmap = android.graphics.Bitmap.createScaledBitmap(bitmap, requestedSize.width, requestedSize.height, true);
|
||||
}
|
||||
|
||||
const rotationAngle = calculateAngleFromFile(this.android);
|
||||
if (rotationAngle !== 0) {
|
||||
const matrix = new android.graphics.Matrix();
|
||||
matrix.postRotate(rotationAngle);
|
||||
bitmap = android.graphics.Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitmap) {
|
||||
error = "Asset '" + this.android + "' cannot be found.";
|
||||
}
|
||||
|
||||
callback(bitmap, error);
|
||||
} catch (ex) {
|
||||
callback(null, ex);
|
||||
}
|
||||
org.nativescript.widgets.Utils.loadImageAsync(
|
||||
ad.getApplicationContext(),
|
||||
this.android,
|
||||
JSON.stringify(this.options || {}),
|
||||
Screen.mainScreen.widthPixels,
|
||||
Screen.mainScreen.heightPixels,
|
||||
new org.nativescript.widgets.Utils.AsyncImageCallback({
|
||||
onSuccess(bitmap) {
|
||||
callback(bitmap, null);
|
||||
},
|
||||
onError(ex) {
|
||||
callback(null, ex);
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateAngleFromFile(filename: string) {
|
||||
let rotationAngle = 0;
|
||||
const ei = new android.media.ExifInterface(filename);
|
||||
const orientation = ei.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_90:
|
||||
rotationAngle = 90;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_180:
|
||||
rotationAngle = 180;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_270:
|
||||
rotationAngle = 270;
|
||||
break;
|
||||
}
|
||||
|
||||
return rotationAngle;
|
||||
}
|
||||
|
||||
@ -340,7 +340,8 @@ export class ImageSource implements ImageSourceDefinition {
|
||||
const dim = getScaledDimensions(size.width, size.height, maxSize);
|
||||
|
||||
const newSize: CGSize = CGSizeMake(dim.width, dim.height);
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, true, this.ios.scale);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(newSize, options?.opaque ?? false, this.ios.scale);
|
||||
this.ios.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height));
|
||||
|
||||
const resizedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
5
packages/core/index.d.ts
vendored
5
packages/core/index.d.ts
vendored
@ -20,6 +20,7 @@ export declare const Application: {
|
||||
lowMemoryEvent: string;
|
||||
orientationChangedEvent: string;
|
||||
systemAppearanceChangedEvent: string;
|
||||
fontScaleChangedEvent: string;
|
||||
systemAppearanceChanged: typeof systemAppearanceChanged;
|
||||
getMainEntry: typeof getMainEntry;
|
||||
getRootView: typeof getRootView;
|
||||
@ -100,12 +101,13 @@ export type { InstrumentationMode, TimerInfo } from './profiling';
|
||||
export { encoding } from './text';
|
||||
export * from './trace';
|
||||
export * from './ui';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString } from './utils';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, escapeRegexSymbols, convertString, dismissSoftInput, queueMacrotask } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback } from './utils/types';
|
||||
export declare const Utils: {
|
||||
GC: typeof GC;
|
||||
RESOURCE_PREFIX: string;
|
||||
FILE_PREFIX: string;
|
||||
queueMacrotask: typeof queueMacrotask;
|
||||
isFontIconURI: typeof isFontIconURI;
|
||||
isDataURI: typeof isDataURI;
|
||||
isFileOrResourcePath: typeof isFileOrResourcePath;
|
||||
@ -143,5 +145,6 @@ export declare const Utils: {
|
||||
isUndefined: typeof isUndefined;
|
||||
toUIString: typeof toUIString;
|
||||
verifyCallback: typeof verifyCallback;
|
||||
dismissSoftInput: typeof dismissSoftInput;
|
||||
};
|
||||
export { XmlParser, ParserEventType, ParserEvent } from './xml';
|
||||
|
||||
@ -5,7 +5,7 @@ import './globals';
|
||||
export { iOSApplication, AndroidApplication } from './application';
|
||||
export type { ApplicationEventData, LaunchEventData, OrientationChangedEventData, UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData, AndroidActivityEventData, AndroidActivityBundleEventData, AndroidActivityRequestPermissionsEventData, AndroidActivityResultEventData, AndroidActivityNewIntentEventData, AndroidActivityBackPressedEventData, SystemAppearanceChangedEventData } from './application';
|
||||
|
||||
import { launchEvent, displayedEvent, uncaughtErrorEvent, discardedErrorEvent, suspendEvent, resumeEvent, exitEvent, lowMemoryEvent, orientationChangedEvent, systemAppearanceChanged, systemAppearanceChangedEvent, getMainEntry, getRootView, _resetRootView, getResources, setResources, setCssFileName, getCssFileName, loadAppCss, addCss, on, off, notify, hasListeners, run, orientation, getNativeApplication, hasLaunched, android as appAndroid, ios as iosApp, systemAppearance } from './application';
|
||||
import { fontScaleChangedEvent, launchEvent, displayedEvent, uncaughtErrorEvent, discardedErrorEvent, suspendEvent, resumeEvent, exitEvent, lowMemoryEvent, orientationChangedEvent, systemAppearanceChanged, systemAppearanceChangedEvent, getMainEntry, getRootView, _resetRootView, getResources, setResources, setCssFileName, getCssFileName, loadAppCss, addCss, on, off, notify, hasListeners, run, orientation, getNativeApplication, hasLaunched, android as appAndroid, ios as iosApp, systemAppearance } from './application';
|
||||
export const Application = {
|
||||
launchEvent,
|
||||
displayedEvent,
|
||||
@ -18,6 +18,7 @@ export const Application = {
|
||||
orientationChangedEvent,
|
||||
systemAppearanceChangedEvent,
|
||||
systemAppearanceChanged,
|
||||
fontScaleChangedEvent,
|
||||
|
||||
getMainEntry,
|
||||
getRootView,
|
||||
@ -121,7 +122,7 @@ export * from './trace';
|
||||
|
||||
export * from './ui';
|
||||
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, queueMacrotask, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString } from './utils';
|
||||
import { GC, isFontIconURI, isDataURI, isFileOrResourcePath, executeOnMainThread, mainThreadify, isMainThread, dispatchToMainThread, queueMacrotask, releaseNativeObject, getModuleName, openFile, openUrl, isRealDevice, layout, ad as androidUtils, iOSNativeHelper as iosUtils, Source, RESOURCE_PREFIX, FILE_PREFIX, escapeRegexSymbols, convertString, dismissSoftInput } from './utils';
|
||||
import { ClassInfo, getClass, getBaseClasses, getClassInfo, isBoolean, isDefined, isFunction, isNullOrUndefined, isNumber, isObject, isString, isUndefined, toUIString, verifyCallback } from './utils/types';
|
||||
|
||||
export const Utils = {
|
||||
@ -169,6 +170,7 @@ export const Utils = {
|
||||
isUndefined,
|
||||
toUIString,
|
||||
verifyCallback,
|
||||
dismissSoftInput,
|
||||
};
|
||||
|
||||
export { XmlParser, ParserEventType, ParserEvent } from './xml';
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
"name": "@akylas/nativescript",
|
||||
"main": "index",
|
||||
"types": "index.d.ts",
|
||||
"description": "NativeScript Core Modules",
|
||||
"version": "8.0.3",
|
||||
"description": "A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.",
|
||||
"version": "8.0.7",
|
||||
"homepage": "https://nativescript.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@ -67,8 +67,6 @@ class DeviceRef {
|
||||
private _sdkVersion: string;
|
||||
private _deviceType: 'Phone' | 'Tablet';
|
||||
private _uuid: string;
|
||||
private _language: string;
|
||||
private _region: string;
|
||||
|
||||
get manufacturer(): string {
|
||||
if (!this._manufacturer) {
|
||||
@ -130,19 +128,11 @@ class DeviceRef {
|
||||
}
|
||||
|
||||
get language(): string {
|
||||
if (!this._language) {
|
||||
this._language = java.util.Locale.getDefault().getLanguage().replace('_', '-');
|
||||
}
|
||||
|
||||
return this._language;
|
||||
return java.util.Locale.getDefault().getLanguage().replace('_', '-');
|
||||
}
|
||||
|
||||
get region(): string {
|
||||
if (!this._region) {
|
||||
this._region = java.util.Locale.getDefault().getCountry();
|
||||
}
|
||||
|
||||
return this._region;
|
||||
return java.util.Locale.getDefault().getCountry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,6 @@ class DeviceRef {
|
||||
private _osVersion: string;
|
||||
private _sdkVersion: string;
|
||||
private _deviceType: 'Phone' | 'Tablet';
|
||||
private _language: string;
|
||||
private _region: string;
|
||||
|
||||
get manufacturer(): string {
|
||||
return 'Apple';
|
||||
@ -72,20 +70,11 @@ class DeviceRef {
|
||||
}
|
||||
|
||||
get language(): string {
|
||||
if (!this._language) {
|
||||
const languages = NSLocale.preferredLanguages;
|
||||
this._language = languages[0];
|
||||
}
|
||||
|
||||
return this._language;
|
||||
return NSLocale.preferredLanguages[0];
|
||||
}
|
||||
|
||||
get region(): string {
|
||||
if (!this._region) {
|
||||
this._region = NSLocale.currentLocale.objectForKey(NSLocaleCountryCode);
|
||||
}
|
||||
|
||||
return this._region;
|
||||
return NSLocale.currentLocale.objectForKey(NSLocaleCountryCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@ -353,6 +353,9 @@ export class ActionBar extends ActionBarBase {
|
||||
}
|
||||
|
||||
private setColor(navBar: UINavigationBar, color?: Color) {
|
||||
if (!navBar) {
|
||||
return;
|
||||
}
|
||||
if (color) {
|
||||
navBar.titleTextAttributes = <any>{
|
||||
[NSForegroundColorAttributeName]: color.ios,
|
||||
@ -443,13 +446,12 @@ export class ActionBar extends ActionBarBase {
|
||||
}
|
||||
|
||||
private get navBar(): UINavigationBar {
|
||||
const page = this.page;
|
||||
// Page should be attached to frame to update the action bar.
|
||||
if (!page || !page.frame) {
|
||||
if (this.page?.frame?.ios?.controller) {
|
||||
return (<UINavigationController>this.page.frame.ios.controller).navigationBar;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (<UINavigationController>page.frame.ios.controller).navigationBar;
|
||||
}
|
||||
|
||||
[colorProperty.getDefault](): UIColor {
|
||||
|
||||
@ -224,7 +224,7 @@ export class Frame extends FrameBase {
|
||||
this._ios._disableNavBarAnimation = disableNavBarAnimationCache;
|
||||
}
|
||||
|
||||
if (this._ios.controller.navigationBar) {
|
||||
if (this._ios.controller?.navigationBar) {
|
||||
this._ios.controller.navigationBar.userInteractionEnabled = this.navigationQueueIsEmpty();
|
||||
}
|
||||
|
||||
@ -666,7 +666,9 @@ class iOSFrame implements iOSFrameDefinition {
|
||||
}
|
||||
public set showNavigationBar(value: boolean) {
|
||||
this._showNavigationBar = value;
|
||||
this._controller.setNavigationBarHiddenAnimated(!value, !this._disableNavBarAnimation);
|
||||
if (this._controller) {
|
||||
this._controller.setNavigationBarHiddenAnimated(!value, !this._disableNavBarAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
public get navBarVisibility(): 'auto' | 'never' | 'always' {
|
||||
|
||||
@ -10,6 +10,26 @@ export class RootLayout extends RootLayoutBase {
|
||||
super();
|
||||
}
|
||||
|
||||
insertChild(view: View, atIndex: number): void {
|
||||
super.insertChild(view, atIndex);
|
||||
if (!view.hasGestureObservers()) {
|
||||
// block tap events from going through to layers behind the view
|
||||
view.nativeViewProtected.setOnTouchListener(
|
||||
new android.view.View.OnTouchListener({
|
||||
onTouch: function (view, event) {
|
||||
return true;
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
removeChild(view: View): void {
|
||||
if (view.hasGestureObservers()) {
|
||||
view.nativeViewProtected.setOnTouchListener(null);
|
||||
}
|
||||
super.removeChild(view);
|
||||
}
|
||||
|
||||
protected _bringToFront(view: View) {
|
||||
(<android.view.View>view.nativeViewProtected).bringToFront();
|
||||
}
|
||||
|
||||
@ -177,7 +177,9 @@ class UIViewControllerImpl extends UIViewController {
|
||||
}
|
||||
|
||||
// If page was shown with custom animation - we need to set the navigationController.delegate to the animatedDelegate.
|
||||
frame.ios.controller.delegate = this[DELEGATE];
|
||||
if (frame.ios?.controller) {
|
||||
frame.ios.controller.delegate = this[DELEGATE];
|
||||
}
|
||||
|
||||
frame._processNavigationQueue(owner);
|
||||
|
||||
|
||||
@ -40,6 +40,10 @@ export function parseCSSShadow(value: string): CSSShadow {
|
||||
const first = parts[0];
|
||||
const last = parts[parts.length - 1];
|
||||
|
||||
if (first === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
let colorRaw = 'black';
|
||||
if (!isLength(first) && first !== 'inset') {
|
||||
colorRaw = first;
|
||||
|
||||
@ -452,6 +452,7 @@ export class CssState {
|
||||
|
||||
public onUnloaded(): void {
|
||||
this.unsubscribeFromDynamicUpdates();
|
||||
this.stopKeyframeAnimations();
|
||||
}
|
||||
|
||||
@profile
|
||||
|
||||
@ -446,6 +446,16 @@ export class TextBase extends TextBaseCommon {
|
||||
[paddingLeftProperty.setNative](value: CoreTypes.LengthType) {
|
||||
org.nativescript.widgets.ViewHelper.setPaddingLeft(this.nativeTextViewProtected, Length.toDevicePixels(value, 0) + Length.toDevicePixels(this.style.borderLeftWidth, 0));
|
||||
}
|
||||
|
||||
[accessibilityIdentifierProperty.setNative](value: string): void {
|
||||
// we override the default setter to apply it on nativeTextViewProtected
|
||||
const id = Utils.ad.resources.getId(':id/nativescript_accessibility_id');
|
||||
|
||||
if (id) {
|
||||
this.nativeTextViewProtected.setTag(id, value);
|
||||
this.nativeTextViewProtected.setTag(value);
|
||||
}
|
||||
}
|
||||
|
||||
_setNativeText(reset = false): void {
|
||||
if (reset) {
|
||||
|
||||
@ -28,6 +28,10 @@ export class TextView extends TextViewBaseCommon {
|
||||
|
||||
this.nativeTextViewProtected.setMaxLines(value);
|
||||
}
|
||||
|
||||
public _onReturnPress() {
|
||||
this.notify({ eventName: TextView.returnPressEvent, object: this });
|
||||
}
|
||||
}
|
||||
|
||||
TextView.prototype.recycleNativeView = 'auto';
|
||||
|
||||
@ -167,6 +167,10 @@ export class TextView extends TextViewBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
if (replacementString === '\n') {
|
||||
this.notify({ eventName: TextView.returnPressEvent, object: this });
|
||||
}
|
||||
|
||||
if (this.formattedText) {
|
||||
_updateCharactersInRangeReplacementString(this.formattedText, range.location, range.length, replacementString);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { EditableTextBase } from '../editable-text-base';
|
||||
import { Property } from '../core/properties';
|
||||
|
||||
export class TextViewBase extends EditableTextBase implements TextViewDefinition {
|
||||
public static returnPressEvent = 'returnPress';
|
||||
public maxLines: number;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { WebViewBase, WebViewClient } from './web-view-common';
|
||||
import { disableZoomProperty, WebViewBase, WebViewClient } from './web-view-common';
|
||||
import { Trace } from '../../trace';
|
||||
import { knownFolders } from '../../file-system';
|
||||
|
||||
@ -107,6 +107,7 @@ export class WebView extends WebViewBase {
|
||||
const client = new WebViewClient(<any>this);
|
||||
nativeView.setWebViewClient(client);
|
||||
(<any>nativeView).client = client;
|
||||
this._disableZoom(this.disableZoom);
|
||||
}
|
||||
|
||||
public disposeNativeView() {
|
||||
@ -119,6 +120,19 @@ export class WebView extends WebViewBase {
|
||||
super.disposeNativeView();
|
||||
}
|
||||
|
||||
private _disableZoom(value: boolean) {
|
||||
if (this.nativeView && value) {
|
||||
const settings = this.nativeView.getSettings();
|
||||
settings.setBuiltInZoomControls(false);
|
||||
settings.setSupportZoom(false);
|
||||
settings.setDisplayZoomControls(false);
|
||||
}
|
||||
}
|
||||
|
||||
[disableZoomProperty.setNative](value: boolean) {
|
||||
this._disableZoom(value);
|
||||
}
|
||||
|
||||
public _loadUrl(src: string) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (!nativeView) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { WebViewNavigationType } from '.';
|
||||
import { WebViewBase } from './web-view-common';
|
||||
import { disableZoomProperty, WebViewBase } from './web-view-common';
|
||||
import { profile } from '../../profiling';
|
||||
import { Trace } from '../../trace';
|
||||
export * from './web-view-common';
|
||||
@ -96,9 +96,73 @@ class WKNavigationDelegateImpl extends NSObject implements WKNavigationDelegate
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
class WKUIDelegateImpl extends NSObject implements WKUIDelegate {
|
||||
public static ObjCProtocols = [WKUIDelegate];
|
||||
public static initWithOwner(owner: WeakRef<WebView>): WKUIDelegateImpl {
|
||||
const handler = <WKUIDelegateImpl>WKUIDelegateImpl.new();
|
||||
handler._owner = owner;
|
||||
return handler;
|
||||
}
|
||||
private _owner: WeakRef<WebView>;
|
||||
|
||||
webViewCreateWebViewWithConfigurationForNavigationActionWindowFeatures(webView: WKWebView, configuration: WKWebViewConfiguration, navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures): WKWebView {
|
||||
if (navigationAction && (!navigationAction.targetFrame || (navigationAction.targetFrame && !navigationAction.targetFrame.mainFrame))) {
|
||||
webView.loadRequest(navigationAction.request);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
@ObjCClass(UIScrollViewDelegate)
|
||||
class UIScrollViewDelegateImpl extends NSObject implements UIScrollViewDelegate {
|
||||
public static initWithOwner(owner: WeakRef<WebView>): UIScrollViewDelegateImpl {
|
||||
const handler = <UIScrollViewDelegateImpl>UIScrollViewDelegateImpl.new();
|
||||
handler._owner = owner;
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
private _owner: WeakRef<WebView>;
|
||||
|
||||
private _initCurrentValues(scrollView: UIScrollView) {
|
||||
const owner = this._owner.get();
|
||||
if (owner && (owner._minimumZoomScale === undefined || owner._maximumZoomScale === undefined || owner._zoomScale === undefined)) {
|
||||
owner._minimumZoomScale = scrollView.minimumZoomScale;
|
||||
owner._maximumZoomScale = scrollView.maximumZoomScale;
|
||||
owner._zoomScale = scrollView.zoomScale;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleDisableZoom(scrollView: UIScrollView) {
|
||||
const owner = this._owner.get();
|
||||
if (owner.disableZoom) {
|
||||
this._initCurrentValues(scrollView);
|
||||
scrollView.maximumZoomScale = 1.0;
|
||||
scrollView.minimumZoomScale = 1.0;
|
||||
scrollView.zoomScale = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
scrollViewWillBeginZoomingWithView(scrollView: UIScrollView, view: UIView) {
|
||||
this._handleDisableZoom(scrollView);
|
||||
}
|
||||
|
||||
scrollViewDidZoom(scrollView) {
|
||||
this._handleDisableZoom(scrollView);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebView extends WebViewBase {
|
||||
nativeViewProtected: WKWebView;
|
||||
private _delegate: any;
|
||||
private _delegate: WKNavigationDelegateImpl;
|
||||
private _scrollDelegate: UIScrollViewDelegateImpl;
|
||||
private _uiDelegate: WKUIDelegateImpl;
|
||||
|
||||
_maximumZoomScale;
|
||||
_minimumZoomScale;
|
||||
_zoomScale;
|
||||
|
||||
createNativeView() {
|
||||
const jScript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'initial-scale=1.0'); document.getElementsByTagName('head')[0].appendChild(meta);";
|
||||
@ -118,7 +182,11 @@ export class WebView extends WebViewBase {
|
||||
initNativeView() {
|
||||
super.initNativeView();
|
||||
this._delegate = WKNavigationDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
this._scrollDelegate = UIScrollViewDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
this._uiDelegate = WKUIDelegateImpl.initWithOwner(new WeakRef(this));
|
||||
this.ios.navigationDelegate = this._delegate;
|
||||
this.ios.scrollView.delegate = this._scrollDelegate;
|
||||
this.ios.UIDelegate = this._uiDelegate;
|
||||
}
|
||||
|
||||
@profile
|
||||
@ -171,4 +239,17 @@ export class WebView extends WebViewBase {
|
||||
public reload() {
|
||||
this.ios.reload();
|
||||
}
|
||||
|
||||
[disableZoomProperty.setNative](value: boolean) {
|
||||
if (!value && typeof this._minimumZoomScale === 'number' && typeof this._maximumZoomScale === 'number' && typeof this._zoomScale === 'number') {
|
||||
if (this.ios.scrollView) {
|
||||
this.ios.scrollView.minimumZoomScale = this._minimumZoomScale;
|
||||
this.ios.scrollView.maximumZoomScale = this._maximumZoomScale;
|
||||
this.ios.scrollView.zoomScale = this._zoomScale;
|
||||
this._minimumZoomScale = undefined;
|
||||
this._maximumZoomScale = undefined;
|
||||
this._zoomScale = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,11 +3,14 @@ import { ContainerView, CSSType } from '../core/view';
|
||||
import { Property } from '../core/properties';
|
||||
import { EventData } from '../../data/observable';
|
||||
import { knownFolders } from '../../file-system';
|
||||
import { booleanConverter } from '../core/view-base';
|
||||
|
||||
export * from './web-view-interfaces';
|
||||
|
||||
export const srcProperty = new Property<WebViewBase, string>({ name: 'src' });
|
||||
|
||||
export const disableZoomProperty = new Property<WebViewBase, boolean>({ name: 'disableZoom', defaultValue: false, valueConverter: booleanConverter });
|
||||
|
||||
@CSSType('WebView')
|
||||
export abstract class WebViewBase extends ContainerView {
|
||||
public static loadStartedEvent = 'loadStarted';
|
||||
@ -15,6 +18,8 @@ export abstract class WebViewBase extends ContainerView {
|
||||
|
||||
public src: string;
|
||||
|
||||
public disableZoom: boolean;
|
||||
|
||||
public _onLoadFinished(url: string, error?: string) {
|
||||
const args = <LoadEventData>{
|
||||
eventName: WebViewBase.loadFinishedEvent,
|
||||
@ -102,3 +107,4 @@ export interface WebViewBase {
|
||||
}
|
||||
|
||||
srcProperty.register(WebViewBase);
|
||||
disableZoomProperty.register(WebViewBase);
|
||||
|
||||
@ -167,3 +167,7 @@ Please ensure you have your manifest correctly configured with the FileProvider.
|
||||
export function isRealDevice(): boolean {
|
||||
return ad.isRealDevice();
|
||||
}
|
||||
|
||||
export function dismissSoftInput(nativeView?: any): void {
|
||||
ad.dismissSoftInput(nativeView);
|
||||
}
|
||||
|
||||
5
packages/core/utils/index.d.ts
vendored
5
packages/core/utils/index.d.ts
vendored
@ -286,3 +286,8 @@ export function eliminateDuplicates(arr: Array<any>): Array<any>;
|
||||
* Checks whether the application is running on real device and not on simulator/emulator.
|
||||
*/
|
||||
export function isRealDevice(): boolean;
|
||||
|
||||
/**
|
||||
* Hides the soft input method, usually a soft keyboard.
|
||||
*/
|
||||
export function dismissSoftInput(nativeView?: any): void;
|
||||
|
||||
@ -48,3 +48,10 @@ export function isRealDevice(): boolean {
|
||||
}
|
||||
|
||||
export const ad = 0;
|
||||
|
||||
export function dismissSoftInput(nativeView?: UIView): void {
|
||||
if (nativeView instanceof UIView && !nativeView.isFirstResponder) {
|
||||
return;
|
||||
}
|
||||
UIApplication.sharedApplication.sendActionToFromForEvent('resignFirstResponder', null, null, null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user