feature(platform): implement a web component that provides access to a small subset of platform information

This commit is contained in:
Dan Bucholtz
2018-02-19 14:19:42 -06:00
committed by GitHub
parent 8956708f06
commit 6c1056b9cb
18 changed files with 740 additions and 25 deletions

View File

@@ -2,10 +2,10 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State }
import { Config, NavEvent, OverlayController, PublicNav, PublicViewController } from '../../index';
import { getOrAppendElement } from '../../utils/helpers';
import { isCordova } from '../../global/platform-utils';
const rootNavs = new Map<number, HTMLIonNavElement>();
const ACTIVE_SCROLLING_TIME = 100;
let backButtonActions: BackButtonAction[] = [];
@Component({
tag: 'ion-app',
@@ -143,8 +143,51 @@ export class App {
return null;
}
/**
* The back button event is triggered when the user presses the native
* platform's back button, also referred to as the "hardware" back button.
* This event is only used within Cordova apps running on Android and
* Windows platforms. This event is not fired on iOS since iOS doesn't come
* with a hardware back button in the same sense an Android or Windows device
* does.
*
* Registering a hardware back button action and setting a priority allows
* apps to control which action should be called when the hardware back
* button is pressed. This method decides which of the registered back button
* actions has the highest priority and should be called.
*
* @param {Function} fn Called when the back button is pressed,
* if this registered action has the highest priority.
* @param {number} priority Set the priority for this action. Only the highest priority will execute. Defaults to `0`.
* @returns {Function} A function that, when called, will unregister
* the back button action.
*/
@Method()
registerBackButtonAction(fn: Function, priority = 0): () => void {
const newAction = {
fn,
priority
};
backButtonActions.push(newAction);
return () => {
backButtonActions = backButtonActions.filter(bbAction => bbAction !== newAction);
};
}
@Listen('document:backbutton')
hardwareBackButtonPressed() {
// okay cool, we need to execute the user's custom method if they have one
const actionToExecute = backButtonActions.reduce((previous, current) => {
if (current.priority >= previous.priority) {
return current;
}
return previous;
});
actionToExecute && actionToExecute.fn && actionToExecute.fn();
// okay great, we've done the user action, now do the default actions
// check if menu exists and is open
return checkIfMenuIsOpen().then((done: boolean) => {
if (!done) {
@@ -199,9 +242,9 @@ export class App {
render() {
const isDevice = true;
return [
isCordova() && <ion-cordova-platform/>,
isDevice && <ion-tap-click />,
isDevice && <ion-status-tap />,
<ion-platform />,
<slot></slot>
];
}
@@ -347,3 +390,8 @@ export interface ExitAppEvent extends CustomEvent {
export interface ExitAppEventDetail {
}
export interface BackButtonAction {
fn: Function;
priority: number;
}

View File

@@ -47,6 +47,21 @@ Returns whether the application is enabled or not
Boolean if the app is actively scrolling or not.
#### registerBackButtonAction()
The back button event is triggered when the user presses the native
platform's back button, also referred to as the "hardware" back button.
This event is only used within Cordova apps running on Android and
Windows platforms. This event is not fired on iOS since iOS doesn't come
with a hardware back button in the same sense an Android or Windows device
does.
Registering a hardware back button action and setting a priority allows
apps to control which action should be called when the hardware back
button is pressed. This method decides which of the registered back button
actions has the highest priority and should be called.
#### setExternalNavPromise()
Updates the Promise set by an external navigation system

View File

@@ -0,0 +1,133 @@
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 [
<ion-cordova-platform/>
];
}
}

View File

@@ -0,0 +1,50 @@
# 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/)*

View File

@@ -0,0 +1,76 @@
<!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-page>
<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-page>
</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>