@nativescript-community/ui-webview
Version:
Advanced WebView plugin for NativeScript
942 lines • 33.8 kB
JavaScript
var WebViewExtBase_1;
/* eslint-disable @typescript-eslint/unified-signatures */
/* eslint-disable @typescript-eslint/adjacent-overload-signatures */
import { CSSType, ContainerView, File, Property, Trace, booleanConverter, knownFolders, path } from '@nativescript/core';
import { isEnabledProperty } from '@nativescript/core/ui/core/view';
import { metadataViewPort, webViewBridge } from './nativescript-webview-bridge-loader';
export const WebViewTraceCategory = 'AWebView';
export const autoInjectJSBridgeProperty = new Property({
name: 'autoInjectJSBridge',
defaultValue: true,
valueConverter: booleanConverter
});
export const builtInZoomControlsProperty = new Property({
name: 'builtInZoomControls',
defaultValue: true,
valueConverter: booleanConverter
});
export const cacheModeProperty = new Property({
name: 'cacheMode',
defaultValue: 'default'
});
export const databaseStorageProperty = new Property({
name: 'databaseStorage',
defaultValue: false,
valueConverter: booleanConverter
});
export const domStorageProperty = new Property({
name: 'domStorage',
defaultValue: false,
valueConverter: booleanConverter
});
export const debugModeProperty = new Property({
name: 'debugMode',
defaultValue: false,
valueConverter: booleanConverter
});
export const webConsoleProperty = new Property({
name: 'webConsoleEnabled',
defaultValue: true,
valueConverter: booleanConverter
});
export const displayZoomControlsProperty = new Property({
name: 'displayZoomControls',
defaultValue: true,
valueConverter: booleanConverter
});
export const supportZoomProperty = new Property({
name: 'supportZoom',
defaultValue: false,
valueConverter: booleanConverter
});
export const mediaPlaybackRequiresUserActionProperty = new Property({
name: 'mediaPlaybackRequiresUserAction',
defaultValue: true,
valueConverter: booleanConverter
});
export const allowsInlineMediaPlaybackProperty = new Property({
name: 'allowsInlineMediaPlayback',
valueConverter: booleanConverter
});
export const supportPopupsProperty = new Property({
name: 'supportPopups',
defaultValue: true,
valueConverter: booleanConverter
});
export const srcProperty = new Property({
name: 'src'
});
export const scrollBounceProperty = new Property({
name: 'scrollBounce',
valueConverter: booleanConverter
});
export const scalesPageToFitProperty = new Property({
name: 'scalesPageToFit',
defaultValue: false,
valueConverter: booleanConverter
});
export const isScrollEnabledProperty = new Property({
name: 'isScrollEnabled',
defaultValue: true,
valueConverter: booleanConverter
});
export const limitsNavigationsToAppBoundDomainsProperty = new Property({
name: 'limitsNavigationsToAppBoundDomains',
valueConverter: booleanConverter
});
export const scrollBarIndicatorVisibleProperty = new Property({
name: 'scrollBarIndicatorVisible',
defaultValue: true,
valueConverter: booleanConverter
});
export const useWideViewPortProperty = new Property({
name: 'useWideViewPort',
defaultValue: true,
valueConverter: booleanConverter
});
export const customUserAgentProperty = new Property({
name: 'userAgent'
});
export const viewPortProperty = new Property({
name: 'viewPortSize',
defaultValue: false,
valueConverter(value) {
const defaultViewPort = {
initialScale: 1.0
};
const valueLowerCaseStr = `${value || ''}`.toLowerCase();
if (valueLowerCaseStr === 'false') {
return false;
}
else if (valueLowerCaseStr === 'true' || valueLowerCaseStr === '') {
return defaultViewPort;
}
let viewPortInputValues = { ...defaultViewPort };
if (typeof value === 'object') {
viewPortInputValues = { ...value };
}
else if (typeof value === 'string') {
try {
viewPortInputValues = JSON.parse(value);
}
catch (err) {
for (const part of value.split(',').map((v) => v.trim())) {
if (!part) {
continue;
}
const [key, v] = part.split('=').map((v) => v.trim());
if (!key || !v) {
continue;
}
const lcValue = `${v}`.toLowerCase();
switch (key) {
case 'user-scalable':
case 'userScalable': {
switch (lcValue) {
case 'yes':
case 'true': {
viewPortInputValues.userScalable = true;
break;
}
case 'no':
case 'false': {
viewPortInputValues.userScalable = false;
break;
}
}
break;
}
case 'width': {
if (lcValue === 'device-width') {
viewPortInputValues.width = 'device-width';
}
else {
viewPortInputValues.width = Number(v);
}
break;
}
case 'height': {
if (lcValue === 'device-height') {
viewPortInputValues.height = 'device-height';
}
else {
viewPortInputValues.height = Number(v);
}
break;
}
case 'minimumScale':
case 'minimum-scale': {
viewPortInputValues.minimumScale = Number(v);
break;
}
case 'maximumScale':
case 'maximum-scale': {
viewPortInputValues.maximumScale = Number(v);
break;
}
case 'initialScale':
case 'initial-scale': {
viewPortInputValues.initialScale = Number(v);
break;
}
}
}
}
}
const { initialScale = defaultViewPort.initialScale, width, height, userScalable, minimumScale, maximumScale } = viewPortInputValues;
return {
initialScale,
width,
height,
userScalable,
minimumScale,
maximumScale
};
}
});
export var EventNames;
(function (EventNames) {
EventNames["LoadFinished"] = "loadFinished";
EventNames["LoadProgress"] = "loadProgress";
EventNames["LoadStarted"] = "loadStarted";
EventNames["ShouldOverrideUrlLoading"] = "shouldOverrideUrlLoading";
EventNames["TitleChanged"] = "titleChanged";
EventNames["WebAlert"] = "webAlert";
EventNames["WebConfirm"] = "webConfirm";
EventNames["WebConsole"] = "webConsole";
EventNames["EnterFullscreen"] = "enterFullscreen";
EventNames["ExitFullscreen"] = "exitFullscreen";
EventNames["WebPrompt"] = "webPrompt";
EventNames["RequestPermissions"] = "requestPermissions";
})(EventNames || (EventNames = {}));
export class UnsupportedSDKError extends Error {
constructor(minSdk) {
super(`Android API < ${minSdk} not supported`);
Object.setPrototypeOf(this, UnsupportedSDKError.prototype);
}
}
let WebViewExtBase = WebViewExtBase_1 = class WebViewExtBase extends ContainerView {
constructor() {
super(...arguments);
/**
* Auto Inject WebView JavaScript Bridge on load finished? Defaults to true.
*/
this.autoInjectJSBridge = true;
/**
* List of js-files to be auto injected on load finished
*/
this.autoInjectScriptFiles = [];
/**
* List of css-files to be auto injected on load finished
*/
this.autoInjectStyleSheetFiles = [];
/**
* List of code blocks to be executed after JS-files and CSS-files have been loaded.
*/
this.autoInjectJavaScriptBlocks = [];
/**
* Prevent this.src loading changes from the webview's onLoadFinished-event
*/
this.tempSuspendSrcLoading = false;
/**
* Whether to install promise polyfill
*/
this.injectPolyfills = true;
/**
* Whether to install event bridge
*/
this.injectBridge = true;
}
get interceptScheme() {
return 'x-local';
}
/**
* String value used when hooking to loadStarted event.
*/
static get loadStartedEvent() {
return EventNames.LoadStarted;
}
/**
* String value used when hooking to loadFinished event.
*/
static get loadFinishedEvent() {
return EventNames.LoadFinished;
}
/** String value used when hooking to shouldOverrideUrlLoading event */
static get shouldOverrideUrlLoadingEvent() {
return EventNames.ShouldOverrideUrlLoading;
}
static get loadProgressEvent() {
return EventNames.LoadProgress;
}
static get titleChangedEvent() {
return EventNames.TitleChanged;
}
static get webAlertEvent() {
return EventNames.WebAlert;
}
static get webConfirmEvent() {
return EventNames.WebConfirm;
}
static get webPromptEvent() {
return EventNames.WebPrompt;
}
static get webConsoleEvent() {
return EventNames.WebConsole;
}
static get enterFullscreenEvent() {
return EventNames.EnterFullscreen;
}
static get exitFullscreenEvent() {
return EventNames.ExitFullscreen;
}
static get requestPermissionsEvent() {
return EventNames.RequestPermissions;
}
/**
* Callback for the loadFinished-event. Called from the native-webview
*/
async _onLoadFinished(url, error) {
if (!error) {
// When this is called without an error, update with this.src value without loading the url.
// This is needed to keep src up-to-date when linked are clicked inside the webview.
try {
this.tempSuspendSrcLoading = true;
this.src = url;
this.tempSuspendSrcLoading = false;
}
finally {
this.tempSuspendSrcLoading = false;
}
}
const args = {
error,
eventName: WebViewExtBase_1.loadFinishedEvent,
url
};
if (error) {
this.notify(args);
throw args;
}
if (Trace.isEnabled()) {
Trace.write(`WebViewExt._onLoadFinished("${url}", ${error || void 0}) - > Injecting webview-bridge JS code`, WebViewTraceCategory, Trace.messageType.info);
}
if (!this.autoInjectJSBridge) {
return args;
}
try {
await this.injectWebViewBridge();
await this.loadJavaScriptFiles(this.autoInjectScriptFiles);
await this.loadStyleSheetFiles(this.autoInjectStyleSheetFiles);
await this.executePromises(this.autoInjectJavaScriptBlocks.map((data) => data.scriptCode), -1);
}
catch (error) {
console.error(error);
args.error = error;
}
this.notify(args);
if (this.hasListeners(WebViewExtBase_1.titleChangedEvent)) {
this.getTitle().then((title) => title && this._titleChanged(title));
}
return args;
}
/**
* Callback for onLoadStarted-event from the native webview
*
* @param url URL being loaded
* @param navigationType Type of navigation (iOS-only)
*/
_onLoadStarted(url, navigationType) {
const args = {
eventName: WebViewExtBase_1.loadStartedEvent,
navigationType,
url
};
this.notify(args);
}
/**
* Callback for should override url loading.
* Called from the native-webview
*
* @param url
* @param httpMethod GET, POST etc
* @param navigationType Type of navigation (iOS-only)
*/
_onShouldOverrideUrlLoading(url, httpMethod, navigationType) {
const args = {
eventName: WebViewExtBase_1.shouldOverrideUrlLoadingEvent,
httpMethod,
navigationType,
url
};
this.notify(args);
return args.cancel;
}
_loadProgress(progress) {
const args = {
eventName: WebViewExtBase_1.loadProgressEvent,
progress,
url: this.src
};
this.notify(args);
}
_titleChanged(title) {
this.notify({
eventName: WebViewExtBase_1.titleChangedEvent,
title,
url: this.src
});
}
_webAlert(message, callback) {
if (!this.hasListeners(WebViewExtBase_1.webAlertEvent)) {
return false;
}
const args = {
eventName: WebViewExtBase_1.webAlertEvent,
message,
url: this.src,
callback
};
this.notify(args);
return true;
}
_webConfirm(message, callback) {
if (!this.hasListeners(WebViewExtBase_1.webConfirmEvent)) {
return false;
}
const args = {
eventName: WebViewExtBase_1.webConfirmEvent,
message,
url: this.src,
callback
};
this.notify(args);
return true;
}
_webPrompt(message, defaultText, callback) {
if (!this.hasListeners(WebViewExtBase_1.webPromptEvent)) {
return false;
}
const args = {
eventName: WebViewExtBase_1.webPromptEvent,
message,
defaultText,
url: this.src,
callback
};
this.notify(args);
return true;
}
_webConsole(message, lineNo, level) {
if (!this.hasListeners(WebViewExtBase_1.webConsoleEvent)) {
return false;
}
const args = {
eventName: WebViewExtBase_1.webConsoleEvent,
data: {
message,
lineNo,
level
},
url: this.src
};
this.notify(args);
return true;
}
_onEnterFullscreen(exitFullscreen) {
if (!this.hasListeners(WebViewExtBase_1.enterFullscreenEvent)) {
return false;
}
const args = {
eventName: WebViewExtBase_1.enterFullscreenEvent,
exitFullscreen,
url: this.src
};
this.notify(args);
return true;
}
_onExitFullscreen() {
const args = {
eventName: WebViewExtBase_1.exitFullscreenEvent,
url: this.src
};
this.notify(args);
return true;
}
[srcProperty.getDefault]() {
return '';
}
[srcProperty.setNative](src) {
if (!src || this.tempSuspendSrcLoading) {
return;
}
const originSrc = src;
this.stopLoading();
// Add file:/// prefix for local files.
// They should be loaded with _loadUrl() method as it handles query params.
if (src.startsWith('~/')) {
src = `file://${knownFolders.currentApp().path}/${src.substring(2)}`;
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.src = "${originSrc}" startsWith ~/ resolved to "${src}"`, WebViewTraceCategory, Trace.messageType.info);
}
}
else if (src.startsWith('/')) {
src = `file://${src}`;
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.src = "${originSrc}" startsWith "/" resolved to ${src}`, WebViewTraceCategory, Trace.messageType.info);
}
}
const lcSrc = src.toLowerCase();
// loading local files from paths with spaces may fail
if (lcSrc.startsWith('file:///')) {
src = encodeURI(src);
if (lcSrc !== src) {
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.src = "${originSrc}" escaped to "${src}"`, WebViewTraceCategory, Trace.messageType.info);
}
}
}
if (lcSrc.startsWith(this.interceptScheme) || lcSrc.startsWith('http://') || lcSrc.startsWith('https://') || lcSrc.startsWith('file:///')) {
if (originSrc !== src) {
// Make sure the src-property reflects the actual value.
try {
this.tempSuspendSrcLoading = true;
this.src = src;
}
catch {
// ignore
}
finally {
this.tempSuspendSrcLoading = false;
}
}
this._loadUrl(src);
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.src = "${originSrc}" - LoadUrl("${src}")`, WebViewTraceCategory, Trace.messageType.info);
}
}
else {
this._loadData(src);
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.src = "${originSrc}" - LoadData("${src}")`, WebViewTraceCategory, Trace.messageType.info);
}
}
}
[viewPortProperty.setNative](value) {
if (this.src) {
this.injectViewPortMeta();
}
}
resolveLocalResourceFilePath(filepath) {
if (!filepath) {
if (Trace.isEnabled()) {
Trace.write('WebViewExt.resolveLocalResourceFilePath() no filepath', WebViewTraceCategory, Trace.messageType.error);
}
return;
}
if (filepath.startsWith('~')) {
filepath = path.normalize(knownFolders.currentApp().path + filepath.substring(1));
}
if (filepath.startsWith('file://')) {
filepath = filepath.replace(/^file:\/\//, '');
}
if (!File.exists(filepath)) {
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.resolveLocalResourceFilePath("${filepath}") - no such file`, WebViewTraceCategory, Trace.messageType.error);
}
return;
}
return filepath;
}
/**
* Load URL - Wait for promise
*
* @param {string} src
* @returns {Promise<LoadFinishedEventData>}
*/
loadUrl(src) {
if (!src) {
return this._onLoadFinished(src, 'empty src');
}
return new Promise((resolve, reject) => {
const loadFinishedEvent = (args) => {
this.off(WebViewExtBase_1.loadFinishedEvent, loadFinishedEvent);
if (args.error) {
reject(args);
}
else {
resolve(args);
}
};
this.on(WebViewExtBase_1.loadFinishedEvent, loadFinishedEvent);
this.src = src;
});
}
/**
* Load a JavaScript file on the current page in the webview.
*/
loadJavaScriptFile(scriptName, filepath) {
return this.loadJavaScriptFiles([
{
resourceName: scriptName,
filepath
}
]);
}
/**
* Load multiple JavaScript-files on the current page in the webview.
*/
async loadJavaScriptFiles(files) {
if (!files || !files.length) {
return;
}
const promiseScriptCodes = [];
for (const { resourceName, filepath } of files) {
const scriptCode = this.generateLoadJavaScriptFileScriptCode(resourceName, filepath);
promiseScriptCodes.push(scriptCode);
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.loadJavaScriptFiles() - > Loading javascript file: "${filepath}" "${scriptCode}"`, WebViewTraceCategory, Trace.messageType.info);
}
}
if (promiseScriptCodes.length !== files.length) {
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.loadJavaScriptFiles() - > Num of generated scriptCodes ${promiseScriptCodes.length} differ from num files ${files.length}`, WebViewTraceCategory, Trace.messageType.error);
}
}
if (!promiseScriptCodes.length) {
if (Trace.isEnabled()) {
Trace.write('WebViewExt.loadJavaScriptFiles() - > No files', WebViewTraceCategory, Trace.messageType.info);
}
return;
}
if (!promiseScriptCodes.length) {
return;
}
await this.executePromises(await Promise.all(promiseScriptCodes));
}
/**
* Load a stylesheet file on the current page in the webview.
*/
loadStyleSheetFile(stylesheetName, filepath, insertBefore = true) {
return this.loadStyleSheetFiles([
{
resourceName: stylesheetName,
filepath,
insertBefore
}
]);
}
/**
* Load multiple stylesheet-files on the current page in the webview
*/
async loadStyleSheetFiles(files) {
if (!files || !files.length) {
return;
}
const promiseScriptCodes = [];
for (const { resourceName, filepath, insertBefore } of files) {
const scriptCode = this.generateLoadCSSFileScriptCode(resourceName, filepath, insertBefore);
promiseScriptCodes.push(scriptCode);
}
if (promiseScriptCodes.length !== files.length) {
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.loadStyleSheetFiles() - > Num of generated scriptCodes ${promiseScriptCodes.length} differ from num files ${files.length}`, WebViewTraceCategory, Trace.messageType.error);
}
}
if (!promiseScriptCodes.length) {
if (Trace.isEnabled()) {
Trace.write('WebViewExt.loadStyleSheetFiles() - > No files', WebViewTraceCategory, Trace.messageType.info);
}
return;
}
await this.executePromises(await Promise.all(promiseScriptCodes));
}
/**
* Auto-load a JavaScript-file after the page have been loaded.
*/
autoLoadJavaScriptFile(resourceName, filepath) {
if (this.src) {
this.loadJavaScriptFile(resourceName, filepath);
}
this.autoInjectScriptFiles.push({ resourceName, filepath });
}
removeAutoLoadJavaScriptFile(resourceName) {
this.autoInjectScriptFiles = this.autoInjectScriptFiles.filter((data) => data.resourceName !== resourceName);
}
/**
* Auto-load a stylesheet-file after the page have been loaded.
*/
autoLoadStyleSheetFile(resourceName, filepath, insertBefore) {
if (this.src) {
this.loadStyleSheetFile(resourceName, filepath, insertBefore);
}
this.autoInjectStyleSheetFiles.push({
resourceName,
filepath,
insertBefore
});
}
removeAutoLoadStyleSheetFile(resourceName) {
this.autoInjectStyleSheetFiles = this.autoInjectStyleSheetFiles.filter((data) => data.resourceName !== resourceName);
}
autoExecuteJavaScript(scriptCode, name) {
if (this.src) {
this.executePromise(scriptCode);
}
this.removeAutoExecuteJavaScript(name);
const fixedCodeBlock = scriptCode.trim();
this.autoInjectJavaScriptBlocks.push({
scriptCode: fixedCodeBlock,
name
});
}
removeAutoExecuteJavaScript(name) {
this.autoInjectJavaScriptBlocks = this.autoInjectJavaScriptBlocks.filter((data) => data.name !== name);
}
/**
* Execute a promise inside the webview and wait for it to resolve.
* Note: The scriptCode must return a promise.
*/
async executePromise(scriptCode, timeout = 2000) {
const results = await this.executePromises([scriptCode], timeout);
return results && results[0];
}
async executePromises(scriptCodes, timeout = 2000) {
if (scriptCodes.length === 0) {
return;
}
if (Trace.isEnabled()) {
Trace.write(`WebViewExt.executePromises: ${scriptCodes}`, WebViewTraceCategory, Trace.messageType.info);
}
const scriptBody = [];
for (const scriptCode of scriptCodes) {
if (typeof scriptCode !== 'string') {
if (Trace.isEnabled()) {
Trace.write('WebViewExt.executePromises() - scriptCode is not a string', WebViewTraceCategory, Trace.messageType.info);
}
continue;
}
// Wrapped in a Promise.then to delay executing scriptCode till the previous promise have finished
scriptBody.push(`p = p.then(() => {${scriptCode.trim()}});promises.push(p);`);
}
const scriptCode = `(() => {
var promises = [];
var p = Promise.resolve();
${scriptBody.join(';')}
return Promise.all(promises);
})()`.trim();
const reqId = `${Math.round(Math.random() * 1000)}`;
const eventName = `tmp-promise-event-${reqId}`;
const promiseScriptCode = `
(() => {
var n = ${JSON.stringify(eventName)};
try {
window.nsWebViewBridge.executePromise(${scriptCode}, n);
} catch (err) {
console.error(err, err.stack);
window.nsWebViewBridge.emitError(err, n);
}
})();
`.trim();
return new Promise((resolve, reject) => {
let timer;
const tmpPromiseEvent = (args) => {
clearTimeout(timer);
const { data, err } = args.data || {};
// Was it a success? No 'err' received.
if (!err) {
resolve(data);
return;
}
// Rejected promise.
if (typeof err === 'object') {
// err is an object. Might be a serialized Error-object.
const error = new Error(err.message || err.name || err);
if (err.stack) {
// Add the web stack to the Error object.
error.webStack = err.stack;
}
for (const [key, value] of Object.entries(err)) {
if (key in error) {
continue;
}
error[key] = value;
}
reject(error);
}
else {
reject(new Error(err));
}
};
this.once(eventName, tmpPromiseEvent);
this.executeJavaScript(promiseScriptCode, false);
if (timeout > 0) {
timer = setTimeout(() => {
reject(new Error(`Timed out after: ${timeout}`));
this.off(eventName);
}, timeout);
}
});
}
/**
* Generate script code for loading javascript-file.
*/
async generateLoadJavaScriptFileScriptCode(resourceName, path) {
if (this.supportXLocalScheme) {
const fixedResourceName = this.fixLocalResourceName(resourceName);
if (path) {
this.registerLocalResource(fixedResourceName, path);
}
const scriptHref = `${this.interceptScheme}://${fixedResourceName}`;
return `window.nsWebViewBridge.injectJavaScriptFile(${JSON.stringify(scriptHref)});`;
}
else {
const elId = resourceName.replace(/^[:]*:\/\//, '').replace(/[^a-z0-9]/g, '');
const scriptCode = await File.fromPath(this.resolveLocalResourceFilePath(path)).readText();
return `window.nsWebViewBridge.injectJavaScript(${JSON.stringify(elId)}, ${scriptCode});`;
}
}
/**
* Generate script code for loading CSS-file.generateLoadCSSFileScriptCode
*/
async generateLoadCSSFileScriptCode(resourceName, path, insertBefore = false) {
if (this.supportXLocalScheme) {
resourceName = this.fixLocalResourceName(resourceName);
if (path) {
this.registerLocalResource(resourceName, path);
}
const stylesheetHref = `${this.interceptScheme}://${resourceName}`;
return `window.nsWebViewBridge.injectStyleSheetFile(${JSON.stringify(stylesheetHref)}, ${!!insertBefore});`;
}
else {
const elId = resourceName.replace(/^[:]*:\/\//, '').replace(/[^a-z0-9]/g, '');
const stylesheetCode = await File.fromPath(this.resolveLocalResourceFilePath(path)).readText();
return `window.nsWebViewBridge.injectStyleSheet(${JSON.stringify(elId)}, ${JSON.stringify(stylesheetCode)}, ${!!insertBefore})`;
}
}
/**
* Inject WebView JavaScript Bridge.
*/
async injectWebViewBridge() {
if (this.injectBridge) {
await this.executeJavaScript(webViewBridge, false);
}
// if (this.injectPolyfills) {
// await this.ensurePolyfills();
// }
await this.injectViewPortMeta();
}
async injectViewPortMeta() {
const scriptCode = await this.generateViewPortCode();
if (!scriptCode) {
return;
}
await this.executeJavaScript(scriptCode, false);
}
async generateViewPortCode() {
if (this.viewPortSize === false) {
return null;
}
const scriptCodeTmpl = metadataViewPort;
const viewPortCode = JSON.stringify(this.viewPortSize || {});
return scriptCodeTmpl.replace('"<%= VIEW_PORT %>"', viewPortCode);
}
/**
* Convert response from WebView into usable JS-type.
*/
parseWebViewJavascriptResult(result) {
if (result === undefined) {
return;
}
if (typeof result !== 'string') {
return result;
}
try {
return JSON.parse(result);
}
catch (err) {
return result;
}
}
writeTrace(message, type = Trace.messageType.info) {
if (Trace.isEnabled()) {
Trace.write(message, WebViewTraceCategory, type);
}
}
/**
* Emit event into the webview.
*/
emitToWebView(eventName, data) {
const scriptCode = `
window.nsWebViewBridge && nsWebViewBridge.onNativeEvent(${JSON.stringify(eventName)}, ${JSON.stringify(data)});
`;
this.executeJavaScript(scriptCode, false);
}
/**
* Called from delegate on webview event.
* Triggered by: window.nsWebViewBridge.emit(eventName: string, data: any); inside the webview
*/
onWebViewEvent(eventName, data) {
this.notify({
eventName,
data
});
}
/**
* Helper function, strips 'x-local://' from a resource name
*/
fixLocalResourceName(resourceName) {
if (resourceName.startsWith(this.interceptScheme)) {
return resourceName.substring(this.interceptScheme.length + 3);
}
return resourceName;
}
[isEnabledProperty.getDefault]() {
return true;
}
async _onRequestPermissions(permissions) {
if (!this.hasListeners(EventNames.RequestPermissions)) {
return false;
}
return new Promise((resolve, reject) => {
const args = {
eventName: EventNames.RequestPermissions,
url: this.src,
permissions,
callback(allow) {
if (allow) {
resolve();
}
else {
reject();
}
}
};
this.notify(args);
});
}
};
WebViewExtBase = WebViewExtBase_1 = __decorate([
CSSType('WebView')
], WebViewExtBase);
export { WebViewExtBase };
customUserAgentProperty.register(WebViewExtBase);
autoInjectJSBridgeProperty.register(WebViewExtBase);
builtInZoomControlsProperty.register(WebViewExtBase);
cacheModeProperty.register(WebViewExtBase);
databaseStorageProperty.register(WebViewExtBase);
debugModeProperty.register(WebViewExtBase);
webConsoleProperty.register(WebViewExtBase);
displayZoomControlsProperty.register(WebViewExtBase);
domStorageProperty.register(WebViewExtBase);
srcProperty.register(WebViewExtBase);
supportZoomProperty.register(WebViewExtBase);
scrollBounceProperty.register(WebViewExtBase);
viewPortProperty.register(WebViewExtBase);
isScrollEnabledProperty.register(WebViewExtBase);
scalesPageToFitProperty.register(WebViewExtBase);
mediaPlaybackRequiresUserActionProperty.register(WebViewExtBase);
supportPopupsProperty.register(WebViewExtBase);
limitsNavigationsToAppBoundDomainsProperty.register(WebViewExtBase);
scrollBarIndicatorVisibleProperty.register(WebViewExtBase);
//# sourceMappingURL=index.common.js.map