diff --git a/angular/src/index.ts b/angular/src/index.ts index 51b6264f0c4..ea02877f802 100644 --- a/angular/src/index.ts +++ b/angular/src/index.ts @@ -45,7 +45,7 @@ export * from './types/ionic-lifecycle-hooks'; export { IonicModule } from './ionic-module'; // UTILS -export { IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core'; +export { PlatformConfig, IonicSafeString, getPlatforms, isPlatform, createAnimation, IonicSwiper } from '@ionic/core'; // CORE TYPES export { diff --git a/core/src/global/ionic-global.ts b/core/src/global/ionic-global.ts index f9b27de523f..ac3ac4fd4b4 100644 --- a/core/src/global/ionic-global.ts +++ b/core/src/global/ionic-global.ts @@ -21,9 +21,6 @@ export const initialize = (userConfig: IonicConfig = {}) => { Context.config = config; const Ionic = (win as any).Ionic = (win as any).Ionic || {}; - // Setup platforms - setupPlatforms(win); - const platformHelpers: any = {}; if (userConfig._ael) { platformHelpers.ael = userConfig._ael; @@ -51,6 +48,9 @@ export const initialize = (userConfig: IonicConfig = {}) => { saveConfig(win, configObj); } + // Setup platforms + setupPlatforms(win); + // first see if the mode was set as an attribute on // which could have been set by the user, or by pre-rendering // otherwise get the mode via config settings, and fallback to md diff --git a/core/src/index.ts b/core/src/index.ts index f493a61802b..d6940bd4e90 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -7,7 +7,7 @@ export { getTimeGivenProgression } from './utils/animation/cubic-bezier'; export { createGesture } from './utils/gesture'; export { initialize } from './global/ionic-global'; export { componentOnReady } from './utils/helpers'; -export { isPlatform, Platforms, getPlatforms } from './utils/platform'; +export { isPlatform, Platforms, PlatformConfig, getPlatforms } from './utils/platform'; export { IonicSafeString } from './utils/sanitization'; export { IonicConfig, getMode, setupConfig } from './utils/config'; export { LIFECYCLE_WILL_ENTER, LIFECYCLE_DID_ENTER, LIFECYCLE_WILL_LEAVE, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_UNLOAD } from './components/nav/constants'; diff --git a/core/src/utils/config.ts b/core/src/utils/config.ts index 97ddab103a5..944bc7cfdae 100644 --- a/core/src/utils/config.ts +++ b/core/src/utils/config.ts @@ -1,5 +1,7 @@ import { AnimationBuilder, Mode, SpinnerTypes, TabButtonLayout } from '../interface'; +import { PlatformConfig } from './platform'; + export interface IonicConfig { /** * When it's set to `false`, disables all animation and transition across the app. @@ -175,6 +177,11 @@ export interface IonicConfig { */ sanitizerEnabled?: boolean; + /** + * Overrides the default platform detection methods. + */ + platform?: PlatformConfig; + // PRIVATE configs keyboardHeight?: number; inputShims?: boolean; diff --git a/core/src/utils/platform.ts b/core/src/utils/platform.ts index f292f3eab09..4950e3c29d5 100644 --- a/core/src/utils/platform.ts +++ b/core/src/utils/platform.ts @@ -1,3 +1,4 @@ +import { config } from '../global/config'; export type Platforms = keyof typeof PLATFORMS_MAP; @@ -29,8 +30,13 @@ export const setupPlatforms = (win: any = window) => { return platforms; }; -const detectPlatforms = (win: Window) => - (Object.keys(PLATFORMS_MAP) as Platforms[]).filter(p => PLATFORMS_MAP[p](win)); +const detectPlatforms = (win: Window) => { + const customPlatformMethods = config.get('platform'); + return (Object.keys(PLATFORMS_MAP) as Platforms[]).filter(p => { + const customMethod = customPlatformMethods && customPlatformMethods[p]; + return typeof customMethod === 'function' ? customMethod(win) : PLATFORMS_MAP[p](win); + }); +} const isMobileWeb = (win: Window): boolean => isMobile(win) && !isHybrid(win); @@ -117,6 +123,8 @@ export const testUserAgent = (win: Window, expr: RegExp) => const matchMedia = (win: Window, query: string): boolean => win.matchMedia && win.matchMedia(query).matches; +export type PlatformConfig = Partial; + const PLATFORMS_MAP = { 'ipad': isIpad, 'iphone': isIphone, diff --git a/core/src/utils/test/platform.spec.ts b/core/src/utils/test/platform.spec.ts index 478961c2705..31e606ef40c 100644 --- a/core/src/utils/test/platform.spec.ts +++ b/core/src/utils/test/platform.spec.ts @@ -1,3 +1,5 @@ +import initialize from '../../global/ionic-global'; + import { testUserAgent, getPlatforms, isPlatform } from '../platform'; import { PlatformConfiguration, configureBrowser } from './platform.utils'; @@ -122,7 +124,7 @@ describe('Platform Tests', () => { expect(isPlatform(win, 'pwa')).toEqual(true); expect(isPlatform(win, 'cordova')).toEqual(false); }); - + it('should return true for "ios", "ipad", and "tablet" and false for "iphone" and "android"', () => { const win = configureBrowser(PlatformConfiguration.iPadOS); expect(isPlatform(win, 'ios')).toEqual(true); @@ -132,4 +134,21 @@ describe('Platform Tests', () => { expect(isPlatform(win, 'android')).toEqual(false); }); }) -}); \ No newline at end of file + + describe('Custom Platform Config', () => { + it('should use custom platform detection methods', () => { + const win = configureBrowser(PlatformConfiguration.DesktopSafari); + + initialize({ + 'platform': { + 'desktop': (win) => false, + 'cordova': (win) => true + } + }); + + expect(isPlatform(win, 'desktop')).toEqual(false); + expect(isPlatform(win, 'cordova')).toEqual(true); + expect(getPlatforms(win).includes('cordova')).toEqual(true); + }); + }) +}); diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts index 6ab65c6985b..70f375c0cbe 100644 --- a/packages/react/src/components/index.ts +++ b/packages/react/src/components/index.ts @@ -35,6 +35,7 @@ export { NavComponentWithProps, setupConfig, IonicSwiper, + PlatformConfig, SpinnerTypes, diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 9e37d05ac1d..8b7010b7d3b 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -41,7 +41,7 @@ export { IonicSafeString, // Platform - isPlatform, Platforms, getPlatforms, + isPlatform, Platforms, PlatformConfig, getPlatforms, // Gesture Gesture,