mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
perf(platform): remove from critical path
This commit is contained in:
@ -1,115 +1,121 @@
|
||||
|
||||
import { PlatformConfig } from '@ionic/core';
|
||||
|
||||
export type DocumentDirection = 'ltr' | 'rtl';
|
||||
|
||||
let dir: DocumentDirection = 'ltr';
|
||||
let isRtl = false;
|
||||
let lang = '';
|
||||
|
||||
export class Platform {
|
||||
|
||||
_element: HTMLIonPlatformElement;
|
||||
private _platforms: PlatformConfig[];
|
||||
private _readyPromise: Promise<any>;
|
||||
private _readyResolve: any;
|
||||
|
||||
constructor() {
|
||||
initialize(this);
|
||||
this._readyPromise = new Promise(res => { this._readyResolve = res; } );
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean} returns true/false based on platform.
|
||||
* @description
|
||||
* Depending on the platform the user is on, `is(platformName)` will
|
||||
* return `true` or `false`. Note that the same app can return `true`
|
||||
* for more than one platform name. For example, an app running from
|
||||
* an iPad would return `true` for the platform names: `mobile`,
|
||||
* `ios`, `ipad`, and `tablet`. Additionally, if the app was running
|
||||
* from Cordova then `cordova` would be true, and if it was running
|
||||
* from a web browser on the iPad then `mobileweb` would be `true`.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* if (this.platform.is('ios')) {
|
||||
* // This will only print when on iOS
|
||||
* console.log('I am an iOS device!');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* | Platform Name | Description |
|
||||
* |-----------------|------------------------------------|
|
||||
* | android | on a device running Android. |
|
||||
* | cordova | on a device running Cordova. |
|
||||
* | core | on a desktop device. |
|
||||
* | ios | on a device running iOS. |
|
||||
* | ipad | on an iPad device. |
|
||||
* | iphone | on an iPhone device. |
|
||||
* | mobile | on a mobile device. |
|
||||
* | mobileweb | in a browser on a mobile device. |
|
||||
* | phablet | on a phablet device. |
|
||||
* | tablet | on a tablet device. |
|
||||
* | windows | on a device running Windows. |
|
||||
* | electron | in Electron on a desktop device. |
|
||||
*
|
||||
* @param {string} platformName
|
||||
*/
|
||||
is(platformName: string): boolean {
|
||||
return isImpl(this, platformName);
|
||||
}
|
||||
|
||||
isAsync(platformName: string): Promise<boolean> {
|
||||
return isAsyncImpl(this, platformName);
|
||||
return this._platforms.some(p => p.name === platformName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {array} the array of platforms
|
||||
* @description
|
||||
* Depending on what device you are on, `platforms` can return multiple values.
|
||||
* Each possible value is a hierarchy of platforms. For example, on an iPhone,
|
||||
* it would return `mobile`, `ios`, and `iphone`.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* // This will print an array of the current platforms
|
||||
* console.log(this.platform.platforms());
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
platforms(): string[] {
|
||||
return platformsImpl(this);
|
||||
}
|
||||
|
||||
platformsAsync(): Promise<string[]> {
|
||||
return platformsAsyncImpl(this);
|
||||
return this._platforms.map(platform => platform.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing version information about all of the platforms.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* // This will print an object containing
|
||||
* // all of the platforms and their versions
|
||||
* console.log(platform.versions());
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @returns {object} An object containing all of the platforms and their versions.
|
||||
*/
|
||||
versions(): PlatformConfig[] {
|
||||
return versionsImpl(this);
|
||||
return this._platforms.slice();
|
||||
}
|
||||
|
||||
versionsAsync(): Promise<PlatformConfig[]> {
|
||||
return versionsAsyncImpl(this);
|
||||
}
|
||||
|
||||
ready(): Promise<any> {
|
||||
return readyImpl(this);
|
||||
ready(): Promise<string> {
|
||||
return this._readyPromise;
|
||||
}
|
||||
|
||||
get isRTL(): boolean {
|
||||
return isRtl;
|
||||
return document.dir === 'rtl';
|
||||
}
|
||||
|
||||
setDir(_dir: DocumentDirection, updateDocument: boolean) {
|
||||
dir = _dir;
|
||||
isRtl = dir === 'rtl';
|
||||
|
||||
if (updateDocument !== false) {
|
||||
document.documentElement.setAttribute('dir', dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns app's language direction.
|
||||
* We recommend the app's `index.html` file already has the correct `dir`
|
||||
* attribute value set, such as `<html dir="ltr">` or `<html dir="rtl">`.
|
||||
* [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir)
|
||||
* @returns {DocumentDirection}
|
||||
*/
|
||||
dir(): DocumentDirection {
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the app's language and optionally the country code, which will update
|
||||
* the `lang` attribute on the app's root `<html>` element.
|
||||
* We recommend the app's `index.html` file already has the correct `lang`
|
||||
* attribute value set, such as `<html lang="en">`. This method is useful if
|
||||
* the language needs to be dynamically changed per user/session.
|
||||
* [W3C: Declaring language in HTML](http://www.w3.org/International/questions/qa-html-language-declarations)
|
||||
* @param {string} language Examples: `en-US`, `en-GB`, `ar`, `de`, `zh`, `es-MX`
|
||||
* @param {boolean} updateDocument Specifies whether the `lang` attribute of `<html>` should be updated
|
||||
*/
|
||||
setLang(language: string, updateDocument: boolean) {
|
||||
lang = language;
|
||||
if (updateDocument !== false) {
|
||||
document.documentElement.setAttribute('lang', language);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns app's language and optional country code.
|
||||
* We recommend the app's `index.html` file already has the correct `lang`
|
||||
* attribute value set, such as `<html lang="en">`.
|
||||
* [W3C: Declaring language in HTML](http://www.w3.org/International/questions/qa-html-language-declarations)
|
||||
* @returns {string}
|
||||
*/
|
||||
lang(): string {
|
||||
return lang;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query string parameter
|
||||
*/
|
||||
getQueryParam(key: string): string {
|
||||
return getQueryParamImpl(this, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query string parameter
|
||||
*/
|
||||
getQueryParamAsync(key: string): Promise<string> {
|
||||
return getQueryParamAsyncImpl(this, key);
|
||||
}
|
||||
|
||||
height(): number {
|
||||
return window.innerHeight;
|
||||
return readQueryParam(window.location.href, key);
|
||||
}
|
||||
|
||||
isLandscape(): boolean {
|
||||
@ -131,98 +137,15 @@ export class Platform {
|
||||
width() {
|
||||
return window.innerWidth;
|
||||
}
|
||||
}
|
||||
|
||||
export function isImpl(platform: Platform, platformName: string) {
|
||||
if (platform._element && platform._element.is) {
|
||||
return platform._element.is(platformName);
|
||||
height(): number {
|
||||
return window.innerHeight;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isAsyncImpl(platform: Platform, platformName: string) {
|
||||
return getHydratedPlatform(platform).then(() => {
|
||||
return platform._element.is(platformName);
|
||||
});
|
||||
}
|
||||
|
||||
export function platformsImpl(platform: Platform): string[] {
|
||||
if (platform._element && platform._element.platforms) {
|
||||
return platform._element.platforms();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function platformsAsyncImpl(platform: Platform): Promise<string[]> {
|
||||
return getHydratedPlatform(platform).then(() => {
|
||||
return platform._element.platforms();
|
||||
});
|
||||
}
|
||||
|
||||
export function versionsImpl(platform: Platform): PlatformConfig[] {
|
||||
if (platform._element && platform._element.versions) {
|
||||
return platform._element.versions();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function versionsAsyncImpl(platform: Platform): Promise<PlatformConfig[]> {
|
||||
return getHydratedPlatform(platform).then(() => {
|
||||
return platform._element.versions();
|
||||
});
|
||||
}
|
||||
|
||||
export function readyImpl(platform: Platform) {
|
||||
return getHydratedPlatform(platform).then(() => {
|
||||
return platform._element.ready();
|
||||
});
|
||||
}
|
||||
|
||||
export function getQueryParamImpl(platform: Platform, key: string): string {
|
||||
if (platform._element && platform._element.getQueryParam) {
|
||||
return platform._element.getQueryParam(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getQueryParamAsyncImpl(platform: Platform, key: string) {
|
||||
return getHydratedPlatform(platform).then(() => {
|
||||
return platform._element.getQueryParam(key);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export function initialize(platform: Platform) {
|
||||
// first see if there is an ion-app, if there is, platform will eventually show up
|
||||
// if not, add platform to the document.body
|
||||
const ionApp = document.querySelector('ion-app');
|
||||
if (ionApp) {
|
||||
return ionApp.componentOnReady(() => {
|
||||
platform._element = ionApp.querySelector('ion-platform');
|
||||
});
|
||||
}
|
||||
|
||||
// okay, there isn't an ion-app, so add <ion-platform> to the document.body
|
||||
let platformElement = document.querySelector('ion-platform');
|
||||
if (!platformElement) {
|
||||
platformElement = document.createElement('ion-platform');
|
||||
document.body.appendChild(platformElement);
|
||||
}
|
||||
platform._element = platformElement;
|
||||
}
|
||||
|
||||
export function getHydratedPlatform(platform: Platform): Promise<HTMLIonPlatformElement> {
|
||||
if (!platform._element) {
|
||||
const ionApp = document.querySelector('ion-app');
|
||||
return (ionApp as any).componentOnReady(() => {
|
||||
const platformEl = ionApp.querySelector('ion-platform');
|
||||
return platformEl.componentOnReady().then(() => {
|
||||
platform._element = platformEl;
|
||||
return platformEl;
|
||||
});
|
||||
});
|
||||
}
|
||||
return platform._element.componentOnReady();
|
||||
function readQueryParam(url: string, key: string) {
|
||||
key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
|
||||
const results = regex.exec(url);
|
||||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
|
||||
}
|
||||
|
103
core/src/components.d.ts
vendored
103
core/src/components.d.ts
vendored
@ -38,7 +38,6 @@ import {
|
||||
ModalOptions,
|
||||
PickerColumn,
|
||||
PickerOptions,
|
||||
PlatformConfig,
|
||||
PopoverOptions,
|
||||
ToastOptions,
|
||||
} from './index';
|
||||
@ -1555,40 +1554,6 @@ declare global {
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
|
||||
namespace StencilComponents {
|
||||
interface IonCordovaPlatform {
|
||||
'exitCordovaApp': () => void;
|
||||
'ready': () => Promise<void>;
|
||||
}
|
||||
}
|
||||
|
||||
interface HTMLIonCordovaPlatformElement extends StencilComponents.IonCordovaPlatform, HTMLStencilElement {}
|
||||
|
||||
var HTMLIonCordovaPlatformElement: {
|
||||
prototype: HTMLIonCordovaPlatformElement;
|
||||
new (): HTMLIonCordovaPlatformElement;
|
||||
};
|
||||
interface HTMLElementTagNameMap {
|
||||
'ion-cordova-platform': HTMLIonCordovaPlatformElement;
|
||||
}
|
||||
interface ElementTagNameMap {
|
||||
'ion-cordova-platform': HTMLIonCordovaPlatformElement;
|
||||
}
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
'ion-cordova-platform': JSXElements.IonCordovaPlatformAttributes;
|
||||
}
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonCordovaPlatformAttributes extends HTMLAttributes {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
|
||||
namespace StencilComponents {
|
||||
@ -2205,12 +2170,12 @@ declare global {
|
||||
|
||||
namespace StencilComponents {
|
||||
interface IonHideWhen {
|
||||
'mediaQuery': string|undefined;
|
||||
'mode': string|undefined;
|
||||
'mediaQuery': string;
|
||||
'mode': string;
|
||||
'or': boolean;
|
||||
'orientation': string|undefined;
|
||||
'platform': string|undefined;
|
||||
'size': string|undefined;
|
||||
'orientation': string;
|
||||
'platform': string;
|
||||
'size': string;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2233,12 +2198,12 @@ declare global {
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonHideWhenAttributes extends HTMLAttributes {
|
||||
'mediaQuery'?: string|undefined;
|
||||
'mode'?: string|undefined;
|
||||
'mediaQuery'?: string;
|
||||
'mode'?: string;
|
||||
'or'?: boolean;
|
||||
'orientation'?: string|undefined;
|
||||
'platform'?: string|undefined;
|
||||
'size'?: string|undefined;
|
||||
'orientation'?: string;
|
||||
'platform'?: string;
|
||||
'size'?: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4235,54 +4200,6 @@ declare global {
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
|
||||
namespace StencilComponents {
|
||||
interface IonPlatform {
|
||||
'getQueryParam': (param: string) => string;
|
||||
/**
|
||||
* Depending on the platform the user is on, `is(platformName)` will return `true` or `false`. Note that the same app can return `true` for more than one platform name. For example, an app running from an iPad would return `true` for the platform names: `mobile`, `ios`, `ipad`, and `tablet`. Additionally, if the app was running from Cordova then `cordova` would be true, and if it was running from a web browser on the iPad then `mobileweb` would be `true`. * ``` import { Platform } from 'ionic-angular';
|
||||
*/
|
||||
'is': (platformName: string) => boolean;
|
||||
/**
|
||||
* Returns whether the device is in landscape orientation
|
||||
*/
|
||||
'isLandscape': () => boolean;
|
||||
/**
|
||||
* Returns whether the device is in portration orientation
|
||||
*/
|
||||
'isPortrait': () => boolean;
|
||||
'platforms': () => string[];
|
||||
'ready': () => any;
|
||||
'versions': () => PlatformConfig[];
|
||||
}
|
||||
}
|
||||
|
||||
interface HTMLIonPlatformElement extends StencilComponents.IonPlatform, HTMLStencilElement {}
|
||||
|
||||
var HTMLIonPlatformElement: {
|
||||
prototype: HTMLIonPlatformElement;
|
||||
new (): HTMLIonPlatformElement;
|
||||
};
|
||||
interface HTMLElementTagNameMap {
|
||||
'ion-platform': HTMLIonPlatformElement;
|
||||
}
|
||||
interface ElementTagNameMap {
|
||||
'ion-platform': HTMLIonPlatformElement;
|
||||
}
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
'ion-platform': JSXElements.IonPlatformAttributes;
|
||||
}
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonPlatformAttributes extends HTMLAttributes {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
|
||||
namespace StencilComponents {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Component, Element, Prop } from '@stencil/core';
|
||||
import { Config } from '../../index';
|
||||
import { isDevice, isHybrid, needInputShims } from '../../utils/platform';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-app',
|
||||
@ -12,36 +13,36 @@ import { Config } from '../../index';
|
||||
}
|
||||
})
|
||||
export class App {
|
||||
mode: string;
|
||||
|
||||
private isDevice = false;
|
||||
private deviceHacks = false;
|
||||
mode: string;
|
||||
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
@Prop({ context: 'window' }) win: Window;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
|
||||
componentWillLoad() {
|
||||
this.isDevice = this.config.getBoolean('isDevice', false);
|
||||
this.deviceHacks = this.config.getBoolean('deviceHacks', false);
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const hoverCSS = this.config.getBoolean('hoverCSS', false);
|
||||
const hybrid = isHybrid(this.win);
|
||||
const hoverCSS = this.config.getBoolean('hoverCSS', !hybrid);
|
||||
const statusBar = this.config.getBoolean('statusbarPadding', hybrid);
|
||||
|
||||
return {
|
||||
class: {
|
||||
[this.mode]: true,
|
||||
'statusbar-padding': statusBar,
|
||||
'enable-hover': hoverCSS
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const device = this.config.getBoolean('isDevice', isDevice(this.win));
|
||||
const inputShims = this.config.getBoolean('inputShims', needInputShims(this.win));
|
||||
|
||||
return [
|
||||
this.deviceHacks && <ion-input-shims></ion-input-shims>,
|
||||
inputShims && <ion-input-shims></ion-input-shims>,
|
||||
<ion-tap-click></ion-tap-click>,
|
||||
this.isDevice && <ion-status-tap></ion-status-tap>,
|
||||
device && <ion-status-tap></ion-status-tap>,
|
||||
<slot></slot>
|
||||
];
|
||||
}
|
||||
|
@ -130,14 +130,6 @@ export class Content {
|
||||
}
|
||||
}
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: {
|
||||
'statusbar-padding': this.config.getBoolean('statusbarPadding')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
this.resize();
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
import { Component, Listen, Method} from '@stencil/core';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-cordova-platform',
|
||||
})
|
||||
export class CordovaPlatform {
|
||||
|
||||
private readyPromise: Promise<void>;
|
||||
private readyResolve: Function;
|
||||
|
||||
constructor() {
|
||||
this.readyPromise = new Promise(resolve => this.readyResolve = resolve);
|
||||
}
|
||||
|
||||
@Method()
|
||||
ready(): Promise<void> {
|
||||
return this.readyPromise;
|
||||
}
|
||||
|
||||
@Listen('document:deviceready')
|
||||
deviceReadyHandler() {
|
||||
this.readyResolve();
|
||||
}
|
||||
|
||||
@Method()
|
||||
@Listen('body:exitApp')
|
||||
exitCordovaApp() {
|
||||
// this is lifted directly from Ionic 3
|
||||
const app = (window.navigator as any).app;
|
||||
if (app && app.exitApp) {
|
||||
app.exitApp();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
# ion-cordova-platform
|
||||
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### exitCordovaApp()
|
||||
|
||||
|
||||
#### ready()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
@ -1,9 +1,8 @@
|
||||
import { Component, Element, Listen, Prop, State } from '@stencil/core';
|
||||
import { Config, PlatformConfig } from '../../index';
|
||||
import { Config } from '../../index';
|
||||
|
||||
import {
|
||||
DisplayWhen,
|
||||
updateTestResults,
|
||||
DisplayWhen, PLATFORM_CONFIGS, PlatformConfig, detectPlatforms, updateTestResults,
|
||||
} from '../../utils/show-hide-when-utils';
|
||||
|
||||
@Component({
|
||||
@ -12,22 +11,29 @@ import {
|
||||
})
|
||||
export class HideWhen implements DisplayWhen {
|
||||
|
||||
calculatedPlatforms: PlatformConfig[];
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
@Prop({ context: 'platforms' }) calculatedPlatforms: PlatformConfig[];
|
||||
@Prop({ context: 'window'}) win: Window;
|
||||
|
||||
@Prop() orientation: string|undefined;
|
||||
@Prop() mediaQuery: string|undefined;
|
||||
@Prop() size: string|undefined;
|
||||
@Prop() mode: string|undefined;
|
||||
@Prop() platform: string|undefined;
|
||||
@Prop() orientation: string;
|
||||
@Prop() mediaQuery: string;
|
||||
@Prop() size: string;
|
||||
@Prop() mode: string;
|
||||
@Prop() platform: string;
|
||||
@Prop() or = false;
|
||||
|
||||
@State() passesTest = false;
|
||||
|
||||
@Listen('window:resize')
|
||||
componentWillLoad() {
|
||||
return updateTestResults(this);
|
||||
this.calculatedPlatforms = detectPlatforms(this.win, PLATFORM_CONFIGS);
|
||||
this.onResize();
|
||||
}
|
||||
|
||||
@Listen('window:resize')
|
||||
onResize() {
|
||||
updateTestResults(this);
|
||||
}
|
||||
|
||||
hostData() {
|
||||
|
@ -1,133 +0,0 @@
|
||||
import { Component, Element, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { PlatformConfig } from '../../index';
|
||||
import { isCordova } from '../../global/platform-utils';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-platform',
|
||||
})
|
||||
export class Platform {
|
||||
|
||||
@Prop({ context: 'platforms' }) _platforms: PlatformConfig[];
|
||||
@Prop({ context: 'readQueryParam'}) readQueryParam: (url: string, key: string) => string;
|
||||
@Element() el: HTMLElement;
|
||||
|
||||
/**
|
||||
* Depending on the platform the user is on, `is(platformName)` will
|
||||
* return `true` or `false`. Note that the same app can return `true`
|
||||
* for more than one platform name. For example, an app running from
|
||||
* an iPad would return `true` for the platform names: `mobile`,
|
||||
* `ios`, `ipad`, and `tablet`. Additionally, if the app was running
|
||||
* from Cordova then `cordova` would be true, and if it was running
|
||||
* from a web browser on the iPad then `mobileweb` would be `true`.
|
||||
*
|
||||
* *
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* if (this.platform.is('ios')) {
|
||||
* // This will only print when on iOS
|
||||
* console.log('I am an iOS device!');
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* | Platform Name | Description |
|
||||
* |-----------------|------------------------------------|
|
||||
* | android | on a device running Android. |
|
||||
* | cordova | on a device running Cordova. |
|
||||
* | core | on a desktop device. |
|
||||
* | ios | on a device running iOS. |
|
||||
* | ipad | on an iPad device. |
|
||||
* | iphone | on an iPhone device. |
|
||||
* | mobile | on a mobile device. |
|
||||
* | mobileweb | in a browser on a mobile device. |
|
||||
* | phablet | on a phablet device. |
|
||||
* | tablet | on a tablet device. |
|
||||
* | windows | on a device running Windows. |
|
||||
*
|
||||
* @param {string} platformName
|
||||
*/
|
||||
@Method()
|
||||
is(platformName: string): boolean {
|
||||
for (const platform of this._platforms) {
|
||||
if (platform.name === platformName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {array} the array of platforms
|
||||
* @description
|
||||
* Depending on what device you are on, `platforms` can return multiple values.
|
||||
* Each possible value is a hierarchy of platforms. For example, on an iPhone,
|
||||
* it would return `mobile`, `ios`, and `iphone`.
|
||||
*
|
||||
* ```
|
||||
* import { Platform } from 'ionic-angular';
|
||||
*
|
||||
* @Component({...})
|
||||
* export MyPage {
|
||||
* constructor(public platform: Platform) {
|
||||
* // This will print an array of the current platforms
|
||||
* console.log(this.platform.platforms());
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@Method()
|
||||
platforms() {
|
||||
return this._platforms.map(platform => platform.name);
|
||||
}
|
||||
|
||||
@Method()
|
||||
versions() {
|
||||
return this._platforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the device is in landscape orientation
|
||||
*/
|
||||
@Method()
|
||||
isLandscape(): boolean {
|
||||
return !this.isPortrait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the device is in portration orientation
|
||||
*/
|
||||
@Method()
|
||||
isPortrait(): boolean {
|
||||
return window.matchMedia('(orientation: portrait)').matches;
|
||||
}
|
||||
|
||||
@Method()
|
||||
ready() {
|
||||
// revisit this later on
|
||||
if (isCordova()) {
|
||||
const cordovaPlatform = this.el.querySelector('ion-cordova-plaform') as any;
|
||||
return cordovaPlatform.componentOnReady().then(() => {
|
||||
return cordovaPlatform.ready();
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@Method()
|
||||
getQueryParam(param: string): string {
|
||||
return this.readQueryParam(window.location.href, param);
|
||||
}
|
||||
|
||||
render() {
|
||||
return [
|
||||
isCordova() && <ion-cordova-platform/>
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
# ion-platform
|
||||
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### getQueryParam()
|
||||
|
||||
|
||||
#### is()
|
||||
|
||||
Depending on the platform the user is on, `is(platformName)` will
|
||||
return `true` or `false`. Note that the same app can return `true`
|
||||
for more than one platform name. For example, an app running from
|
||||
an iPad would return `true` for the platform names: `mobile`,
|
||||
`ios`, `ipad`, and `tablet`. Additionally, if the app was running
|
||||
from Cordova then `cordova` would be true, and if it was running
|
||||
from a web browser on the iPad then `mobileweb` would be `true`.
|
||||
|
||||
*
|
||||
```
|
||||
import { Platform } from 'ionic-angular';
|
||||
|
||||
|
||||
#### isLandscape()
|
||||
|
||||
Returns whether the device is in landscape orientation
|
||||
|
||||
|
||||
#### isPortrait()
|
||||
|
||||
Returns whether the device is in portration orientation
|
||||
|
||||
|
||||
#### platforms()
|
||||
|
||||
|
||||
#### ready()
|
||||
|
||||
|
||||
#### versions()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
@ -1,72 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Platform Basic</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<script src="/dist/ionic.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize()">
|
||||
<ion-platform></ion-platform>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Platform - basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<h2>The Platforms are:</h2>
|
||||
<ul class="platform-name-list"></ul>
|
||||
|
||||
<h2>The Platforms versions are:</h2>
|
||||
<ul class="platform-version-list"></ul>
|
||||
|
||||
<h2>The orientation is <span class="orientation"></span></h2>
|
||||
|
||||
<h2>The ready event has fired: <span class="ready"></span></h2>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
async function initialize() {
|
||||
const platform = document.querySelector('ion-platform');
|
||||
await platform.componentOnReady();
|
||||
|
||||
const platforms = platform.platforms();
|
||||
const platformListElement = document.querySelector('.platform-name-list');
|
||||
platforms.forEach(platform => {
|
||||
const element = document.createElement('li');
|
||||
element.textContent = platform;
|
||||
platformListElement.appendChild(element);
|
||||
});
|
||||
|
||||
const platformVersionList = document.querySelector('.platform-version-list');
|
||||
const versions = platform.versions();
|
||||
versions.forEach(version => {
|
||||
const element = document.createElement('li');
|
||||
element.textContent = JSON.stringify(version);
|
||||
platformVersionList.appendChild(element);
|
||||
});
|
||||
|
||||
const orientationText = platform.isPortrait() ? 'portrait' : 'landscape';
|
||||
document.querySelector('.orientation').textContent = orientationText;
|
||||
|
||||
|
||||
const readyElement = document.querySelector('.ready');
|
||||
readyElement.textContent = 'No';
|
||||
|
||||
// use artificial timeout to see the visual
|
||||
setTimeout(() => {
|
||||
platform.ready().then(() => {
|
||||
readyElement.textContent = 'Yes';
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,76 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Platform Basic</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||
<script src="/dist/ionic.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="initialize()">
|
||||
<ion-app>
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Platform</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<h2>The Platforms are:</h2>
|
||||
<ul class="platform-name-list"></ul>
|
||||
|
||||
<h2>The Platforms versions are:</h2>
|
||||
<ul class="platform-version-list"></ul>
|
||||
|
||||
<h2>The orientation is <span class="orientation"></span></h2>
|
||||
|
||||
<h2>The ready event has fired: <span class="ready"></span></h2>
|
||||
</ion-content>
|
||||
|
||||
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
async function initialize() {
|
||||
const app = document.querySelector('ion-app');
|
||||
await app.componentOnReady();
|
||||
const platform = document.querySelector('ion-platform');
|
||||
await platform.componentOnReady();
|
||||
|
||||
const platforms = platform.platforms();
|
||||
const platformListElement = document.querySelector('.platform-name-list');
|
||||
platforms.forEach(platform => {
|
||||
const element = document.createElement('li');
|
||||
element.textContent = platform;
|
||||
platformListElement.appendChild(element);
|
||||
});
|
||||
|
||||
const platformVersionList = document.querySelector('.platform-version-list');
|
||||
const versions = platform.versions();
|
||||
versions.forEach(version => {
|
||||
const element = document.createElement('li');
|
||||
element.textContent = JSON.stringify(version);
|
||||
platformVersionList.appendChild(element);
|
||||
});
|
||||
|
||||
const orientationText = platform.isPortrait() ? 'portrait' : 'landscape';
|
||||
document.querySelector('.orientation').textContent = orientationText;
|
||||
|
||||
|
||||
const readyElement = document.querySelector('.ready');
|
||||
readyElement.textContent = 'No';
|
||||
|
||||
// use artificial timeout to see the visual
|
||||
setTimeout(() => {
|
||||
platform.ready().then(() => {
|
||||
readyElement.textContent = 'Yes';
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,9 +1,8 @@
|
||||
import { Component, Element, Listen, Prop, State } from '@stencil/core';
|
||||
import { Config, PlatformConfig } from '../../index';
|
||||
import { Config } from '../../index';
|
||||
|
||||
import {
|
||||
DisplayWhen,
|
||||
updateTestResults,
|
||||
DisplayWhen, PLATFORM_CONFIGS, PlatformConfig, detectPlatforms, updateTestResults,
|
||||
} from '../../utils/show-hide-when-utils';
|
||||
|
||||
@Component({
|
||||
@ -12,9 +11,11 @@ import {
|
||||
})
|
||||
export class ShowWhen implements DisplayWhen {
|
||||
|
||||
calculatedPlatforms: PlatformConfig[];
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
@Prop({ context: 'platforms' }) calculatedPlatforms: PlatformConfig[];
|
||||
@Prop({ context: 'window'}) win: Window;
|
||||
|
||||
@Prop() orientation: string;
|
||||
@Prop() mediaQuery: string;
|
||||
@ -25,9 +26,14 @@ export class ShowWhen implements DisplayWhen {
|
||||
|
||||
@State() passesTest = false;
|
||||
|
||||
@Listen('window:resize')
|
||||
componentWillLoad() {
|
||||
return updateTestResults(this);
|
||||
this.calculatedPlatforms = detectPlatforms(this.win, PLATFORM_CONFIGS);
|
||||
this.onResize();
|
||||
}
|
||||
|
||||
@Listen('window:resize')
|
||||
onResize() {
|
||||
updateTestResults(this);
|
||||
}
|
||||
|
||||
hostData() {
|
||||
|
@ -42,13 +42,8 @@ export class Toolbar {
|
||||
hostData() {
|
||||
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'toolbar-translucent') : {};
|
||||
|
||||
const hostClasses = {
|
||||
...themedClasses,
|
||||
'statusbar-padding': this.config.getBoolean('statusbarPadding')
|
||||
};
|
||||
|
||||
return {
|
||||
class: hostClasses
|
||||
class: themedClasses
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,57 +0,0 @@
|
||||
import { Config } from '../index';
|
||||
import { PlatformConfig, readQueryParam } from './platform-configs';
|
||||
import { isDef } from '../utils/helpers';
|
||||
|
||||
export function createConfigController(configObj: any, platforms: PlatformConfig[]): Config {
|
||||
configObj = configObj || {};
|
||||
|
||||
function get(key: string, fallback?: any): any {
|
||||
|
||||
const queryValue = readQueryParam(window.location.href, `ionic${key}`);
|
||||
if (isDef(queryValue)) {
|
||||
return configObj[key] = (queryValue === 'true' ? true : queryValue === 'false' ? false : queryValue);
|
||||
}
|
||||
|
||||
if (isDef(configObj[key])) {
|
||||
return configObj[key];
|
||||
}
|
||||
|
||||
let settings: any = null;
|
||||
|
||||
for (let i = 0; i < platforms.length; i++) {
|
||||
settings = platforms[i]['settings'];
|
||||
if (settings && isDef(settings[key])) {
|
||||
return settings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return fallback !== undefined ? fallback : null;
|
||||
}
|
||||
|
||||
function getBoolean(key: string, fallback?: boolean): boolean {
|
||||
const val = get(key);
|
||||
if (val === null) {
|
||||
return fallback !== undefined ? fallback : false;
|
||||
}
|
||||
if (typeof val === 'string') {
|
||||
return val === 'true';
|
||||
}
|
||||
return !!val;
|
||||
}
|
||||
|
||||
function getNumber(key: string, fallback?: number): number {
|
||||
const val = parseFloat(get(key));
|
||||
return isNaN(val) ? (fallback !== undefined ? fallback : NaN) : val;
|
||||
}
|
||||
|
||||
function set(key: string, value: string) {
|
||||
configObj[key] = value;
|
||||
}
|
||||
|
||||
return {
|
||||
get,
|
||||
getBoolean,
|
||||
getNumber,
|
||||
set
|
||||
};
|
||||
}
|
34
core/src/global/config.ts
Normal file
34
core/src/global/config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
export class Config {
|
||||
|
||||
private m: Map<string, any>;
|
||||
|
||||
constructor(configObj: {[key: string]: any}|undefined) {
|
||||
this.m = new Map<string, any>(configObj ? Object.entries(configObj) : undefined);
|
||||
}
|
||||
|
||||
get(key: string, fallback?: any): any {
|
||||
const value = this.m.get(key);
|
||||
return (value !== undefined) ? value : fallback;
|
||||
}
|
||||
|
||||
getBoolean(key: string, fallback = false): boolean {
|
||||
const val = this.m.get(key);
|
||||
if (val === undefined) {
|
||||
return fallback;
|
||||
}
|
||||
if (typeof val === 'string') {
|
||||
return val === 'true';
|
||||
}
|
||||
return !!val;
|
||||
}
|
||||
|
||||
getNumber(key: string, fallback?: number): number {
|
||||
const val = parseFloat(this.m.get(key));
|
||||
return isNaN(val) ? (fallback !== undefined ? fallback : NaN) : val;
|
||||
}
|
||||
|
||||
set(key: string, value: any) {
|
||||
this.m.set(key, value);
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
import 'ionicons';
|
||||
import { createConfigController } from './config-controller';
|
||||
import { PLATFORM_CONFIGS, detectPlatforms, readQueryParam } from './platform-configs';
|
||||
|
||||
import { Config } from './config';
|
||||
import { configFromURL, isIOS } from '../utils/platform';
|
||||
|
||||
const Ionic = (window as any).Ionic = (window as any).Ionic || {};
|
||||
|
||||
declare const Context: any;
|
||||
|
||||
// queue used to coordinate DOM reads and
|
||||
@ -13,25 +11,18 @@ Object.defineProperty(Ionic, 'queue', {
|
||||
get: () => Context.queue
|
||||
});
|
||||
|
||||
if (!Context.platforms) {
|
||||
Context.platforms = detectPlatforms(window.location.href, window.navigator.userAgent, PLATFORM_CONFIGS, 'core');
|
||||
}
|
||||
|
||||
if (!Context.readQueryParam) {
|
||||
Context.readQueryParam = readQueryParam;
|
||||
}
|
||||
|
||||
// create the Ionic.config from raw config object (if it exists)
|
||||
// and convert Ionic.config into a ConfigApi that has a get() fn
|
||||
Ionic.config = Context.config = createConfigController(
|
||||
Ionic.config,
|
||||
Context.platforms
|
||||
);
|
||||
const config = Ionic.config = Context.config = new Config({
|
||||
...configFromURL(window),
|
||||
...Ionic.config,
|
||||
});
|
||||
|
||||
// first see if the mode was set as an attribute on <html>
|
||||
// which could have been set by the user, or by prerendering
|
||||
// otherwise get the mode via config settings, and fallback to md
|
||||
Ionic.mode = Context.mode = document.documentElement.getAttribute('mode') || Context.config.get('mode', 'md');
|
||||
|
||||
// ensure we've got the mode attribute set on <html>
|
||||
document.documentElement.setAttribute('mode', Ionic.mode);
|
||||
const documentElement = document.documentElement;
|
||||
const mode = config.get('mode', documentElement.getAttribute('mode') || (isIOS(window) ? 'ios' : 'md'));
|
||||
Ionic.mode = Context.mode = mode;
|
||||
config.set('mode', mode);
|
||||
documentElement.setAttribute('mode', Ionic.mode);
|
||||
|
@ -1,153 +0,0 @@
|
||||
import { isCordova, isElectron, } from './platform-utils';
|
||||
|
||||
import {
|
||||
ANDROID,
|
||||
CORDOVA,
|
||||
CORE,
|
||||
ELECTRON,
|
||||
IOS,
|
||||
IPAD,
|
||||
IPHONE,
|
||||
MOBILE,
|
||||
PHABLET,
|
||||
TABLET,
|
||||
WINDOWS_PHONE,
|
||||
} from './platform-utils';
|
||||
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
|
||||
// order from most specifc to least specific
|
||||
export const PLATFORM_CONFIGS: PlatformConfig[] = [
|
||||
|
||||
{
|
||||
name: IPAD,
|
||||
settings: {
|
||||
keyboardHeight: 500,
|
||||
},
|
||||
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, IPAD, [IPAD], WINDOWS_PHONE)
|
||||
},
|
||||
|
||||
{
|
||||
name: IPHONE,
|
||||
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, IPHONE, [IPHONE], WINDOWS_PHONE)
|
||||
},
|
||||
|
||||
{
|
||||
name: IOS,
|
||||
settings: {
|
||||
mode: 'ios',
|
||||
tabsHighlight: false,
|
||||
statusbarPadding: isCordova(),
|
||||
keyboardHeight: 250,
|
||||
isDevice: true,
|
||||
deviceHacks: true,
|
||||
},
|
||||
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, IOS, [IPHONE, IPAD, 'ipod'], WINDOWS_PHONE)
|
||||
},
|
||||
|
||||
{
|
||||
name: ANDROID,
|
||||
settings: {
|
||||
mode: 'md',
|
||||
isDevice: true,
|
||||
keyboardHeight: 300,
|
||||
},
|
||||
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, ANDROID, [ANDROID, 'silk'], WINDOWS_PHONE)
|
||||
},
|
||||
|
||||
{
|
||||
name: CORE,
|
||||
settings: {
|
||||
mode: 'md'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: PHABLET,
|
||||
isMatch: () => {
|
||||
const smallest = Math.min(width, height);
|
||||
const largest = Math.max(width, height);
|
||||
return (smallest > 390 && smallest < 520) &&
|
||||
(largest > 620 && largest < 800);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: MOBILE
|
||||
},
|
||||
|
||||
{
|
||||
name: TABLET,
|
||||
isMatch: () => {
|
||||
const smallest = Math.min(width, height);
|
||||
const largest = Math.max(width, height);
|
||||
return (smallest > 460 && smallest < 820) &&
|
||||
(largest > 780 && largest < 1400);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: CORDOVA,
|
||||
isMatch: () => {
|
||||
return isCordova();
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: ELECTRON,
|
||||
isMatch: () => {
|
||||
return isElectron();
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
export function detectPlatforms(url: string, userAgent: string, platforms: PlatformConfig[], defaultPlatform: string) {
|
||||
// bracket notation to ensure they're not property renamed
|
||||
let validPlatforms = platforms.filter(p => p.isMatch && p.isMatch(url, userAgent));
|
||||
|
||||
if (!validPlatforms.length) {
|
||||
validPlatforms = platforms.filter(p => p.name === defaultPlatform);
|
||||
}
|
||||
|
||||
return validPlatforms;
|
||||
}
|
||||
|
||||
export function isPlatformMatch(url: string, userAgent: string, platformName: string, userAgentAtLeastHas: string[], userAgentMustNotHave: string[]) {
|
||||
const queryValue = readQueryParam(url, 'ionicplatform');
|
||||
if (queryValue) {
|
||||
return queryValue === platformName;
|
||||
}
|
||||
|
||||
if (userAgent) {
|
||||
userAgent = userAgent.toLowerCase();
|
||||
|
||||
for (let i = 0; i < userAgentAtLeastHas.length; i++) {
|
||||
if (userAgent.indexOf(userAgentAtLeastHas[i]) > -1) {
|
||||
for (let j = 0; j < userAgentMustNotHave.length; j++) {
|
||||
if (userAgent.indexOf(userAgentMustNotHave[j]) > -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
export function readQueryParam(url: string, key: string) {
|
||||
key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
const regex = new RegExp('[\\?&]' + key + '=([^&#]*)');
|
||||
const results = regex.exec(url);
|
||||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null;
|
||||
}
|
||||
|
||||
export interface PlatformConfig {
|
||||
name: string;
|
||||
isMatch?: {(url: string, userAgent: string): boolean};
|
||||
settings?: any;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
|
||||
export function isCordova(): boolean {
|
||||
const win = window as any;
|
||||
return !!(win[CORDOVA] || win[PHONEGAP_CAMELCASE] || win[PHONEGAP] || win[CAPACITOR]);
|
||||
}
|
||||
|
||||
export function isElectron(): boolean {
|
||||
return testUserAgent(getUserAgent(), ELECTRON);
|
||||
}
|
||||
|
||||
export function getUserAgent(): string {
|
||||
return window.navigator.userAgent;
|
||||
}
|
||||
|
||||
export function testUserAgent(userAgent: string, expression: string): boolean {
|
||||
return userAgent ? userAgent.indexOf(expression) >= 0 : false;
|
||||
}
|
||||
|
||||
export const ANDROID = 'android';
|
||||
export const CORDOVA = 'cordova';
|
||||
export const CORE = 'core';
|
||||
export const ELECTRON = 'electron';
|
||||
export const IOS = 'ios';
|
||||
export const IPAD = 'ipad';
|
||||
export const IPHONE = 'iphone';
|
||||
export const MOBILE = 'mobile';
|
||||
export const MOBILE_WEB = 'mobileweb';
|
||||
export const PHABLET = 'phablet';
|
||||
export const TABLET = 'tablet';
|
||||
export const WINDOWS_PHONE = ['windows phone'];
|
||||
|
||||
export const PHONEGAP = 'phonegap';
|
||||
export const PHONEGAP_CAMELCASE = 'PhoneGap';
|
||||
export const CAPACITOR = 'Capacitor';
|
||||
|
12
core/src/index.d.ts
vendored
12
core/src/index.d.ts
vendored
@ -101,26 +101,18 @@ export { ToastController } from './components/toast-controller/toast-controller'
|
||||
export { Toggle } from './components/toggle/toggle';
|
||||
export { Toolbar } from './components/toolbar/toolbar';
|
||||
|
||||
export { PlatformConfig } from './global/platform-configs';
|
||||
|
||||
// export all of the component declarations that are dynamically created
|
||||
export * from './components';
|
||||
|
||||
export { Config } from './global/config';
|
||||
export { QueueController, RafCallback } from './global/queue-controller';
|
||||
export { FrameworkDelegate } from './utils/framework-delegate';
|
||||
export { OverlayEventDetail } from './utils/overlays';
|
||||
export * from './utils/platform';
|
||||
export * from './utils/transition';
|
||||
|
||||
export type ComponentRef = Function | HTMLElement | string;
|
||||
export type ComponentProps = {[key: string]: any};
|
||||
|
||||
export interface Config {
|
||||
get: (key: string, fallback?: any) => any;
|
||||
getBoolean: (key: string, fallback?: boolean) => boolean;
|
||||
getNumber: (key: string, fallback?: number) => number;
|
||||
set: (key: string, value: any) => void;
|
||||
}
|
||||
|
||||
export type CssClassMap = { [className: string]: boolean };
|
||||
|
||||
export interface BaseInputComponent {
|
||||
|
@ -706,23 +706,14 @@
|
||||
// --------------------------------------------------------------------------------
|
||||
@mixin toolbar-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $statusbar-padding) {
|
||||
|
||||
> .toolbar.statusbar-padding:first-child {
|
||||
.statusbar-padding {
|
||||
> .toolbar:first-child {
|
||||
@include padding(calc(#{$statusbar-padding} + #{$toolbar-padding}), null, null, null);
|
||||
@include safe-area-padding($toolbar-padding, null, null, null);
|
||||
|
||||
min-height: calc(#{$toolbar-height} + #{$statusbar-padding});
|
||||
@include safe-area-sizing(min-height, safe-area-inset-top, $toolbar-height);
|
||||
}
|
||||
|
||||
> ion-content.statusbar-padding:first-child .scroll-content {
|
||||
@include padding($statusbar-padding, null, null, null);
|
||||
@include safe-area-padding(0px, null, null, null);
|
||||
}
|
||||
|
||||
> ion-content.statusbar-padding:first-child[padding] .scroll-content,
|
||||
> ion-content.statusbar-padding:first-child[padding-top] .scroll-content {
|
||||
@include padding(calc(#{$content-padding} + #{$statusbar-padding}), null, null, null);
|
||||
@include safe-area-padding(0px, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -738,8 +729,9 @@
|
||||
// --------------------------------------------------------------------------------
|
||||
@mixin toolbar-title-statusbar-padding($toolbar-height, $toolbar-padding, $content-padding, $statusbar-padding) {
|
||||
|
||||
> .toolbar.statusbar-padding:first-child ion-segment,
|
||||
> .toolbar.statusbar-padding:first-child ion-title {
|
||||
.statusbar-padding {
|
||||
> .toolbar:first-child ion-segment,
|
||||
> .toolbar:first-child ion-title {
|
||||
@include padding($statusbar-padding, null, null, null);
|
||||
@include safe-area-padding(0px, null, null, null);
|
||||
|
||||
@ -750,9 +742,10 @@
|
||||
@include safe-area-sizing(min-height, safe-area-inset-top, $toolbar-height)
|
||||
}
|
||||
|
||||
> ion-content.statusbar-padding:first-child ion-scroll {
|
||||
> ion-content:first-child ion-scroll {
|
||||
@include padding($statusbar-padding, null, null, null);
|
||||
@include safe-area-padding(0px, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
78
core/src/utils/platform.ts
Normal file
78
core/src/utils/platform.ts
Normal file
@ -0,0 +1,78 @@
|
||||
|
||||
export function isIpad(win: Window) {
|
||||
return testUserAgent(win, /iPad/i);
|
||||
}
|
||||
|
||||
export function isIphone(win: Window) {
|
||||
return testUserAgent(win, /iPhone/i);
|
||||
}
|
||||
|
||||
export function isIOS(win: Window) {
|
||||
return testUserAgent(win, /iPad|iPhone|iPod/i);
|
||||
}
|
||||
|
||||
export function isAndroid(win: Window) {
|
||||
return !isIOS(win);
|
||||
}
|
||||
|
||||
export function isPhablet(win: Window) {
|
||||
const width = win.innerWidth;
|
||||
const height = win.innerHeight;
|
||||
const smallest = Math.min(width, height);
|
||||
const largest = Math.max(width, height);
|
||||
|
||||
return (smallest > 390 && smallest < 520) &&
|
||||
(largest > 620 && largest < 800);
|
||||
}
|
||||
|
||||
export function isTablet(win: Window) {
|
||||
const width = win.innerWidth;
|
||||
const height = win.innerHeight;
|
||||
const smallest = Math.min(width, height);
|
||||
const largest = Math.max(width, height);
|
||||
return (smallest > 460 && smallest < 820) &&
|
||||
(largest > 780 && largest < 1400);
|
||||
}
|
||||
|
||||
export function isDevice(win: Window) {
|
||||
return win.matchMedia('(any-pointer:coarse)').matches;
|
||||
}
|
||||
|
||||
export function isHybrid(win: Window) {
|
||||
return isCordova(win) || isCapacitor(win);
|
||||
}
|
||||
|
||||
export function isCordova(window: Window): boolean {
|
||||
const win = window as any;
|
||||
return !!(win['cordova'] || win['phonegap'] || win['PhoneGap']);
|
||||
}
|
||||
|
||||
export function isCapacitor(window: Window): boolean {
|
||||
const win = window as any;
|
||||
return !!(win['Capacitor']);
|
||||
}
|
||||
|
||||
export function isElectron(win: Window): boolean {
|
||||
return testUserAgent(win, /electron/);
|
||||
}
|
||||
|
||||
export function needInputShims(win: Window) {
|
||||
return isIOS(win) && isDevice(win);
|
||||
}
|
||||
|
||||
export function testUserAgent(win: Window, expr: RegExp) {
|
||||
return expr.test(win.navigator.userAgent);
|
||||
}
|
||||
|
||||
export function configFromURL(win: Window) {
|
||||
const config: any = {};
|
||||
win.location.search.slice(1)
|
||||
.split('&')
|
||||
.filter(entryText => entryText.startsWith('ionic:'))
|
||||
.map(entryText => entryText.split('='))
|
||||
.forEach(entry => {
|
||||
config[entry[0].slice(6)] = decodeURIComponent(entry[1]);
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { Config, PlatformConfig } from '../index';
|
||||
import { isAndroid, isCordova, isElectron, isIOS, isIpad, isIphone, isPhablet, isTablet } from './platform';
|
||||
import { Config } from '..';
|
||||
|
||||
export function updateTestResults(displayWhen: DisplayWhen) {
|
||||
displayWhen.passesTest = getTestResult(displayWhen);
|
||||
@ -23,7 +24,6 @@ export function isModeMatch(config: Config, multiModeString: string) {
|
||||
return modes.indexOf(currentMode) >= 0;
|
||||
}
|
||||
|
||||
|
||||
export function isMediaQueryMatch(mediaQuery: string) {
|
||||
return window.matchMedia(mediaQuery).matches;
|
||||
}
|
||||
@ -94,6 +94,54 @@ const SIZE_TO_MEDIA: any = {
|
||||
'xl': '(min-width: 1200px)',
|
||||
};
|
||||
|
||||
// order from most specifc to least specific
|
||||
export const PLATFORM_CONFIGS: PlatformConfig[] = [
|
||||
|
||||
{
|
||||
name: 'ipad',
|
||||
isMatch: isIpad
|
||||
},
|
||||
{
|
||||
name: 'iphone',
|
||||
isMatch: isIphone
|
||||
},
|
||||
{
|
||||
name: 'ios',
|
||||
isMatch: isIOS
|
||||
},
|
||||
{
|
||||
name: 'android',
|
||||
isMatch: isAndroid
|
||||
},
|
||||
{
|
||||
name: 'phablet',
|
||||
isMatch: isPhablet
|
||||
},
|
||||
{
|
||||
name: 'tablet',
|
||||
isMatch: isTablet
|
||||
},
|
||||
{
|
||||
name: 'cordova',
|
||||
isMatch: isCordova
|
||||
},
|
||||
{
|
||||
name: 'electron',
|
||||
isMatch: isElectron
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
export interface PlatformConfig {
|
||||
name: string;
|
||||
isMatch: (win: Window) => boolean;
|
||||
}
|
||||
|
||||
export function detectPlatforms(win: Window, platforms: PlatformConfig[]) {
|
||||
// bracket notation to ensure they're not property renamed
|
||||
return platforms.filter(p => p.isMatch(win));
|
||||
}
|
||||
|
||||
export interface DisplayWhen {
|
||||
calculatedPlatforms: PlatformConfig[];
|
||||
config: Config;
|
||||
@ -105,3 +153,4 @@ export interface DisplayWhen {
|
||||
platform: string|undefined;
|
||||
size: string|undefined;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@ exports.config = {
|
||||
{ components: ['ion-tabs', 'ion-tab', 'ion-tabbar', 'ion-tab-button'] },
|
||||
{ components: ['ion-toast', 'ion-toast-controller'] },
|
||||
{ components: ['ion-status-tap'] },
|
||||
{ components: ['ion-platform', 'ion-cordova-platform'] },
|
||||
{ components: ['ion-hide-when', 'ion-show-when'] },
|
||||
],
|
||||
plugins: [
|
||||
|
Reference in New Issue
Block a user