feature(events): add ion-events pub/sub component

This commit is contained in:
Dan Bucholtz
2017-12-22 14:50:37 -06:00
parent 467304df13
commit b2d60f3b7f
6 changed files with 226 additions and 0 deletions

View File

@ -766,6 +766,36 @@ declare global {
} }
import {
Events as IonEvents
} from './components/events/events';
declare global {
interface HTMLIonEventsElement extends IonEvents, HTMLElement {
}
var HTMLIonEventsElement: {
prototype: HTMLIonEventsElement;
new (): HTMLIonEventsElement;
};
interface HTMLElementTagNameMap {
"ion-events": HTMLIonEventsElement;
}
interface ElementTagNameMap {
"ion-events": HTMLIonEventsElement;
}
namespace JSX {
interface IntrinsicElements {
"ion-events": JSXElements.IonEventsAttributes;
}
}
namespace JSXElements {
export interface IonEventsAttributes extends HTMLAttributes {
}
}
}
import { import {
FabButton as IonFabButton FabButton as IonFabButton
} from './components/fab-button/fab-button'; } from './components/fab-button/fab-button';

View File

@ -0,0 +1,52 @@
import { Component, Listen, Method } from '@stencil/core';
const subscriptions = new Map<string, ((event?: any) => void)[]>();
@Component({
tag: 'ion-events'
})
export class Events {
@Method()
subscribe(topic: string, handler: (event?: any) => void) {
const handlers = subscriptions.get(topic) || [];
handlers.push(handler);
subscriptions.set(topic, handlers);
}
@Method()
unsubscribe(topic: string, handler: (event?: any) => void) {
const handlers = subscriptions.get(topic) || [];
const newHandlers = handlers.filter(fun => fun !== handler);
subscriptions.set(topic, newHandlers);
}
@Method()
publish(topic: string, event?: any) {
return publishImpl(topic, event);
}
@Listen('window:online')
@Listen('window:offline')
@Listen('window:orientationchange')
online(event: Event) {
return publishImpl(`app:${event.type}`, event);
}
@Listen('window:statusTap')
statusTap(event: Event) {
console.log('TODO: Finish the status tap: ', event);
return Promise.resolve();
}
}
// make this method async just to give the browser a chance to chill and do what it needs to do before firing this off
function publishImpl(topic: string, event: any): Promise<any> {
return Promise.resolve().then(() => {
const handlers = subscriptions.get(topic) || [];
for (const handler of handlers) {
handler(event);
}
});
}

View File

@ -0,0 +1,22 @@
# ion-events
<!-- Auto Generated Below -->
## Methods
#### publish()
#### subscribe()
#### unsubscribe()
----------------------------------------------
*Built by [StencilJS](https://stenciljs.com/)*

View File

@ -0,0 +1,55 @@
'use strict';
const { By, until } = require('selenium-webdriver');
const { register, Page, platforms } = require('../../../../../scripts/e2e');
const expect = require('chai').expect;
class E2ETestPage extends Page {
constructor(driver, platform) {
super(driver, `http://localhost:3333/src/components/events/test/basic?ionicplatform=${platform}`);
}
}
platforms.forEach(platform => {
describe('events/basic', () => {
register('should init', driver => {
const page = new E2ETestPage(driver, platform);
return page.navigate();
});
register('subscribers should receive event on or shortly after button click', async (driver, testContext) => {
testContext.timeout(1000);
const page = new E2ETestPage(driver, platform);
// go to page two
const publishButtonSelector = 'ion-button.publish.hydrated';
const publishButton = await getElement(driver, publishButtonSelector);
publishButton.click();
await wait(300);
const secretOneElement = await getElement(driver, '.secret-one');
const secretOneText = await secretOneElement.getText();
expect(secretOneText).to.equal('Taco');
const secretTwoElement = await getElement(driver, '.secret-two');
const secretTwoText = await secretTwoElement.getText();
expect(secretTwoText).to.equal('Burrito');
});
});
});
async function getElement(driver, selector) {
driver.wait(until.elementLocated(By.css(selector)));
const element = driver.findElement(By.css(selector));
await driver.wait(until.elementIsVisible(driver.findElement(By.css(selector))));
return element;
}
function wait(duration) {
return new Promise(resolve => {
setTimeout(resolve, duration);
})
}

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Events</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="init()">
<ion-events></ion-events>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Events</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<div class="container">
<div>
The first secret is: <span class="secret-one">TBD</span>
</div>
<div>
The second secret is: <span class="secret-two">TBD</span>
</div>
</div>
<ion-button class="publish">Publish the data</ion-button>
</ion-content>
</ion-page>
</ion-app>
<script>
async function runTest() {
const ionEvents = document.querySelector('ion-events');
await ionEvents.componentOnReady();
ionEvents.subscribe('secretOne', (secretOne) => {
const span = document.querySelector('.secret-one');
span.textContent = secretOne;
});
ionEvents.subscribe('secretTwo', (secretTwo) => {
const span = document.querySelector('.secret-two');
span.textContent = secretTwo;
});
const publishButton = document.querySelector('ion-button .publish');
publishButton.addEventListener('click', async () => {
await ionEvents.publish('secretOne', 'Taco');
await ionEvents.publish('secretTwo', 'Burrito');
});
}
function init() {
setTimeout(runTest(), 100);
}
</script>
</body>
</html>

View File

@ -14,6 +14,7 @@ exports.config = {
{ components: ['ion-checkbox'] }, { components: ['ion-checkbox'] },
{ components: ['ion-chip', 'ion-chip-button'] }, { components: ['ion-chip', 'ion-chip-button'] },
{ components: ['ion-datetime', 'ion-picker', 'ion-picker-column', 'ion-picker-controller'] }, { components: ['ion-datetime', 'ion-picker', 'ion-picker-column', 'ion-picker-controller'] },
{ components: ['ion-events'] },
{ components: ['ion-fab', 'ion-fab-list'] }, { components: ['ion-fab', 'ion-fab-list'] },
{ components: ['ion-fab-button'] }, { components: ['ion-fab-button'] },
{ components: ['ion-gesture'], priority: 'low' }, { components: ['ion-gesture'], priority: 'low' },