fix: on mobile open links from editor in external browser (#1860)
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { SNLog } from './../Log'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { AlertService, DeviceInterface, namespacedKey, RawStorageKey } from '@standardnotes/services'
|
||||
|
||||
@@ -940,7 +940,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
}
|
||||
|
||||
isNativeMobileWeb() {
|
||||
return this.environment === Environment.NativeMobileWeb
|
||||
return this.environment === Environment.Mobile
|
||||
}
|
||||
|
||||
getDeinitMode(): DeinitMode {
|
||||
@@ -1353,10 +1353,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
}
|
||||
|
||||
private createComponentManager() {
|
||||
const MaybeSwappedComponentManager = this.getClass<typeof InternalServices.SNComponentManager>(
|
||||
InternalServices.SNComponentManager,
|
||||
)
|
||||
this.componentManagerService = new MaybeSwappedComponentManager(
|
||||
this.componentManagerService = new InternalServices.SNComponentManager(
|
||||
this.itemManager,
|
||||
this.syncService,
|
||||
this.featuresService,
|
||||
@@ -1365,6 +1362,7 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
this.environment,
|
||||
this.platform,
|
||||
this.internalEventBus,
|
||||
this.deviceInterface,
|
||||
)
|
||||
this.services.push(this.componentManagerService)
|
||||
}
|
||||
@@ -1647,13 +1645,4 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli
|
||||
this.statusService = new ExternalServices.StatusService(this.internalEventBus)
|
||||
this.services.push(this.statusService)
|
||||
}
|
||||
|
||||
private getClass<T>(base: T) {
|
||||
const swapClass = this.options.swapClasses?.find((candidate) => candidate.swap === base)
|
||||
if (swapClass) {
|
||||
return swapClass.with as T
|
||||
} else {
|
||||
return base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,6 @@ export interface ApplicationDisplayOptions {
|
||||
}
|
||||
|
||||
export interface ApplicationOptionalConfiguratioOptions {
|
||||
/**
|
||||
* Gives consumers the ability to provide their own custom
|
||||
* subclass for a service. swapClasses should be an array of key/value pairs
|
||||
* consisting of keys 'swap' and 'with'. 'swap' is the base class you wish to replace,
|
||||
* and 'with' is the custom subclass to use.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
swapClasses?: { swap: any; with: any }[]
|
||||
/**
|
||||
* URL for WebSocket providing permissions and roles information.
|
||||
*/
|
||||
|
||||
@@ -28,22 +28,11 @@ export function platformToString(platform: Platform) {
|
||||
return map[platform]
|
||||
}
|
||||
|
||||
export function environmentFromString(string: string) {
|
||||
const map: Record<string, Environment> = {
|
||||
web: Environment.Web,
|
||||
desktop: Environment.Desktop,
|
||||
mobile: Environment.Mobile,
|
||||
nativeMobileWeb: Environment.NativeMobileWeb,
|
||||
}
|
||||
return map[string]
|
||||
}
|
||||
|
||||
export function environmentToString(environment: Environment) {
|
||||
const map = {
|
||||
[Environment.Web]: 'web',
|
||||
[Environment.Desktop]: 'desktop',
|
||||
[Environment.Mobile]: 'mobile',
|
||||
[Environment.NativeMobileWeb]: 'native-mobile-web',
|
||||
[Environment.Mobile]: 'native-mobile-web',
|
||||
}
|
||||
return map[environment]
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@ import {
|
||||
} from '@standardnotes/features'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { GenericItem, SNComponent, Environment, Platform } from '@standardnotes/models'
|
||||
import { DesktopManagerInterface, InternalEventBusInterface, AlertService } from '@standardnotes/services'
|
||||
import {
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
AlertService,
|
||||
DeviceInterface,
|
||||
} from '@standardnotes/services'
|
||||
import { ItemManager } from '@Lib/Services/Items/ItemManager'
|
||||
import { SNFeaturesService } from '@Lib/Services/Features/FeaturesService'
|
||||
import { SNComponentManager } from './ComponentManager'
|
||||
@@ -27,6 +32,7 @@ describe('featuresService', () => {
|
||||
let syncService: SNSyncService
|
||||
let prefsService: SNPreferencesService
|
||||
let internalEventBus: InternalEventBusInterface
|
||||
let device: DeviceInterface
|
||||
|
||||
const desktopExtHost = 'http://localhost:123'
|
||||
|
||||
@@ -53,6 +59,7 @@ describe('featuresService', () => {
|
||||
environment,
|
||||
platform,
|
||||
internalEventBus,
|
||||
device,
|
||||
)
|
||||
manager.setDesktopManager(desktopManager)
|
||||
return manager
|
||||
@@ -81,6 +88,8 @@ describe('featuresService', () => {
|
||||
|
||||
internalEventBus = {} as jest.Mocked<InternalEventBusInterface>
|
||||
internalEventBus.publish = jest.fn()
|
||||
|
||||
device = {} as jest.Mocked<DeviceInterface>
|
||||
})
|
||||
|
||||
const nativeComponent = (identifier?: FeatureIdentifier, file_type?: FeatureDescription['file_type']) => {
|
||||
|
||||
@@ -36,6 +36,8 @@ import {
|
||||
DesktopManagerInterface,
|
||||
InternalEventBusInterface,
|
||||
AlertService,
|
||||
DeviceInterface,
|
||||
isMobileDevice,
|
||||
} from '@standardnotes/services'
|
||||
|
||||
const DESKTOP_URL_PREFIX = 'sn://'
|
||||
@@ -82,23 +84,21 @@ export class SNComponentManager
|
||||
private environment: Environment,
|
||||
private platform: Platform,
|
||||
protected override internalEventBus: InternalEventBusInterface,
|
||||
private device: DeviceInterface,
|
||||
) {
|
||||
super(internalEventBus)
|
||||
this.loggingEnabled = false
|
||||
|
||||
this.addItemObserver()
|
||||
|
||||
/* On mobile, events listeners are handled by a respective component */
|
||||
if (environment !== Environment.Mobile) {
|
||||
window.addEventListener
|
||||
? window.addEventListener('focus', this.detectFocusChange, true)
|
||||
: window.attachEvent('onfocusout', this.detectFocusChange)
|
||||
window.addEventListener
|
||||
? window.addEventListener('blur', this.detectFocusChange, true)
|
||||
: window.attachEvent('onblur', this.detectFocusChange)
|
||||
window.addEventListener
|
||||
? window.addEventListener('focus', this.detectFocusChange, true)
|
||||
: window.attachEvent('onfocusout', this.detectFocusChange)
|
||||
window.addEventListener
|
||||
? window.addEventListener('blur', this.detectFocusChange, true)
|
||||
: window.attachEvent('onblur', this.detectFocusChange)
|
||||
|
||||
window.addEventListener('message', this.onWindowMessage, true)
|
||||
}
|
||||
window.addEventListener('message', this.onWindowMessage, true)
|
||||
}
|
||||
|
||||
get isDesktop(): boolean {
|
||||
@@ -143,7 +143,7 @@ export class SNComponentManager
|
||||
this.removeItemObserver?.()
|
||||
;(this.removeItemObserver as unknown) = undefined
|
||||
|
||||
if (window && !this.isMobile) {
|
||||
if (window) {
|
||||
window.removeEventListener('focus', this.detectFocusChange, true)
|
||||
window.removeEventListener('blur', this.detectFocusChange, true)
|
||||
window.removeEventListener('message', this.onWindowMessage, true)
|
||||
@@ -221,9 +221,23 @@ export class SNComponentManager
|
||||
addItemObserver(): void {
|
||||
this.removeItemObserver = this.itemManager.addObserver<SNComponent>(
|
||||
[ContentType.Component, ContentType.Theme],
|
||||
({ changed, inserted, source }) => {
|
||||
({ changed, inserted, removed, source }) => {
|
||||
const items = [...changed, ...inserted]
|
||||
this.handleChangedComponents(items, source)
|
||||
|
||||
const device = this.device
|
||||
if (isMobileDevice(device) && 'addComponentUrl' in device) {
|
||||
inserted.forEach((component) => {
|
||||
const url = this.urlForComponent(component)
|
||||
if (url) {
|
||||
device.addComponentUrl(component.uuid, url)
|
||||
}
|
||||
})
|
||||
|
||||
removed.forEach((component) => {
|
||||
device.removeComponentUrl(component.uuid)
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -271,9 +285,6 @@ export class SNComponentManager
|
||||
}
|
||||
|
||||
getActiveThemes(): SNTheme[] {
|
||||
if (this.environment === Environment.Mobile) {
|
||||
throw Error('getActiveThemes must be handled separately by mobile')
|
||||
}
|
||||
return this.componentsForArea(ComponentArea.Themes).filter((theme) => {
|
||||
return theme.active
|
||||
}) as SNTheme[]
|
||||
@@ -301,14 +312,10 @@ export class SNComponentManager
|
||||
}
|
||||
}
|
||||
|
||||
const isWeb = this.environment === Environment.Web
|
||||
const isMobileWebView = this.environment === Environment.NativeMobileWeb
|
||||
const isMobile = this.environment === Environment.Mobile
|
||||
if (nativeFeature) {
|
||||
if (!isWeb && !isMobileWebView) {
|
||||
throw Error('Mobile must override urlForComponent to handle native paths')
|
||||
}
|
||||
let baseUrlRequiredForThemesInsideEditors = window.location.origin
|
||||
if (isMobileWebView) {
|
||||
if (isMobile) {
|
||||
baseUrlRequiredForThemesInsideEditors = window.location.href.split('/index.html')[0]
|
||||
}
|
||||
return `${baseUrlRequiredForThemesInsideEditors}/components/assets/${component.identifier}/${nativeFeature.index_path}`
|
||||
|
||||
@@ -92,7 +92,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
|
||||
public setEncryptionPolicy(encryptionPolicy: Services.StorageEncryptionPolicy, persist = true): void {
|
||||
if (
|
||||
encryptionPolicy === Services.StorageEncryptionPolicy.Disabled &&
|
||||
![Environment.Mobile, Environment.NativeMobileWeb].includes(this.environment)
|
||||
![Environment.Mobile].includes(this.environment)
|
||||
) {
|
||||
throw Error('Disabling storage encryption is only available on mobile.')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user