UNPKG

nwa-client

Version:

Native WebApp client library

219 lines (206 loc) 9.63 kB
import { AppRequest } from './models'; import { IApp } from './interfaces'; declare global { interface Window { App: IApp; Sentry: any; select: any; } } function getMeta(name) { const meta = document.querySelector('meta[name="' + name + '"]'); if (meta) { return meta.getAttribute('content'); } else { return '#FFFFFFFF'; } } const isAndroid = /android/i.test(navigator.userAgent); if (typeof window.App !== 'undefined') { if (!window.App.on) { const appDebug = localStorage && localStorage.getItem('appDebug') === 'true'; let requestId = 0; const handlers: ((...args) => boolean | void)[][] = []; const requests: AppRequest[] = []; window.App = new Proxy(window.App, { // eslint-disable-next-line @typescript-eslint/no-explicit-any get(target: any, propKey: string) { if (propKey === 'isWeb') { return false; } return (...args) => { if (window.Sentry && appDebug) { window.Sentry.captureMessage(propKey, { extra: args, level: 'info', }); } if (propKey === 'emit') { const channel = args.shift(); if (channel in handlers) { try { let success = true; for (const handler of handlers[channel]) { success = success && handler(...args) !== false; } return success; } catch (e) { return false; } } else { return false; } } else if (propKey === 'onSuccess' || propKey === 'onError' || propKey === 'resolve' || propKey === 'reject') { const request = requests[args[0]]; if (request) { if (args.length > 1) { return request[propKey](args[1]); } else { return request[propKey](); } } else { // eslint-disable-next-line max-len, no-console console.error('Unable to resolve request. (id=' + args[0] + ', now=' + Date.now() + ', data=' + JSON.stringify(args[1]) + ')'); } } else if (target[propKey] === undefined) { if (propKey === 'on') { if (!handlers[args[0]]) { handlers[args[0]] = []; } handlers[args[0]].push(args[1]); } const id = 'req-' + (requestId++) + '-' + Date.now(); if (isAndroid) { if (target.request) { return new Promise((resolve, reject) => { requests[id] = { resolve, reject }; target.request(propKey, id, JSON.stringify(args)); }); } else { return new Promise((resolve, reject) => { requests[id] = { resolve, reject }; target.postMessage(propKey, id, JSON.stringify(args)); }); } } else { return target.postMessage(JSON.stringify({ method: propKey, params: args })).then((result) => { if (result && result.compatError) { throw result.compatError; } else { return result; } }); } } }; }, }); // Bypass native browser functionalities if (isAndroid) { window.print = () => window.App.print(); navigator.share = (data) => window.App.share(data); navigator.clipboard.writeText = (data) => window.App.copy(data); navigator.clipboard.readText = () => window.App.paste(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore navigator.setAppBadge = (data) => window.App.setAppBadge(data); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore navigator.clearAppBadge = () => window.App.clearAppBadge(); navigator.vibrate = (data) => window.App.vibrate(data); window.open = (url, name) => window.App.openUrl(url, name); if (!('permissions' in navigator)) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore navigator.permissions = {}; } navigator.permissions.query = window.App.hasPermission; } else { const positionCallbacks: any[] = []; window.print = () => window.App.print(); window.open = (url, name) => window.App.openUrl(url, name); navigator.share = (data) => window.App.share(data); navigator.clipboard.writeText = (data) => window.App.copy(data); navigator.clipboard.readText = () => window.App.paste(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore navigator.setAppBadge = (data) => window.App.setAppBadge(data); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore navigator.clearAppBadge = () => window.App.clearAppBadge(); navigator.vibrate = (data) => window.App.vibrate(data); window.App.on('position', location => { if (positionCallbacks.length) { positionCallbacks.forEach(obj => obj.callback(location)); } else { window.App.watchPosition(false); } }) navigator.geolocation.watchPosition = (callback, errorCallback, options) => { const watchId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); if (!positionCallbacks.length) { window.App.watchPosition(true, options).then(callback).catch(errorCallback); } positionCallbacks.push({ id: watchId, callback, }); return watchId } navigator.geolocation.clearWatch = (watchId) => { positionCallbacks.filter((cb, i, arr) => { if (cb.id == watchId) { arr.splice(i, 1); return true; } else { return false; } }) if (!positionCallbacks.length) { window.App.watchPosition(false); } } navigator.geolocation.getCurrentPosition = (callback, errorCallback, settings) => window.App.getCurrentPosition(settings).then(callback).catch(errorCallback) } window.select = function (params: any) { return App.select(params).then((files: any) => { const dataTransfer = new DataTransfer(); for (const file of files) { const bytes = atob(file.data); let length = bytes.length; const out = new Uint8Array(length); // Loop and convert. while (length--) { out[length] = bytes.charCodeAt(length); } dataTransfer.items.add(new File([out], file.name, { type: file.type })); } return dataTransfer; }); }; } document.addEventListener('DOMContentLoaded', () => { try { const viewport = getMeta('viewport'); const keyboardResize = !!viewport && viewport.includes('interactive-widget=resizes-content'); const appBarOffset = !!viewport && !viewport.includes('viewport-fit=cover'); const navBarOffset = !!viewport && !viewport.includes('viewport-fit=cover'); const backgroundColor = parseInt(getMeta('theme-color')!.substring(1), 16); const appBarColor = parseInt(getMeta('app-bar-color')!.substring(1), 16); const navBarColor = parseInt(getMeta('nav-bar-color')!.substring(1), 16); window.App.updateAppStyle({ backgroundColor, appBarColor, navBarColor, appBarOffset, navBarOffset, keyboardResize, }); } catch (e) { // eslint-disable-next-line no-console console.error('Unable to update app style', e); } }, false); } const App: IApp = window.App; export default App;