diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index 8ce9194f20..4ba1ed559d 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -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 { FabButton as IonFabButton } from './components/fab-button/fab-button'; diff --git a/packages/core/src/components/events/events.tsx b/packages/core/src/components/events/events.tsx new file mode 100644 index 0000000000..bc8aac8403 --- /dev/null +++ b/packages/core/src/components/events/events.tsx @@ -0,0 +1,52 @@ +import { Component, Listen, Method } from '@stencil/core'; + +const subscriptions = new Map 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 { + return Promise.resolve().then(() => { + const handlers = subscriptions.get(topic) || []; + for (const handler of handlers) { + handler(event); + } + }); +} diff --git a/packages/core/src/components/events/readme.md b/packages/core/src/components/events/readme.md new file mode 100644 index 0000000000..1265e44cdb --- /dev/null +++ b/packages/core/src/components/events/readme.md @@ -0,0 +1,22 @@ +# ion-events + + + + + + +## Methods + +#### publish() + + +#### subscribe() + + +#### unsubscribe() + + + +---------------------------------------------- + +*Built by [StencilJS](https://stenciljs.com/)* diff --git a/packages/core/src/components/events/test/basic/e2e.js b/packages/core/src/components/events/test/basic/e2e.js new file mode 100644 index 0000000000..68911239a5 --- /dev/null +++ b/packages/core/src/components/events/test/basic/e2e.js @@ -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); + }) +} diff --git a/packages/core/src/components/events/test/basic/index.html b/packages/core/src/components/events/test/basic/index.html new file mode 100644 index 0000000000..c7832eb3c8 --- /dev/null +++ b/packages/core/src/components/events/test/basic/index.html @@ -0,0 +1,66 @@ + + + + + + Events + + + + + + + + + + + Events + + + + + +
+
+ The first secret is: TBD +
+
+ The second secret is: TBD +
+
+ Publish the data +
+ +
+
+ + + + + diff --git a/packages/core/stencil.config.js b/packages/core/stencil.config.js index c6e93dc8ea..0009c34041 100644 --- a/packages/core/stencil.config.js +++ b/packages/core/stencil.config.js @@ -14,6 +14,7 @@ exports.config = { { components: ['ion-checkbox'] }, { components: ['ion-chip', 'ion-chip-button'] }, { components: ['ion-datetime', 'ion-picker', 'ion-picker-column', 'ion-picker-controller'] }, + { components: ['ion-events'] }, { components: ['ion-fab', 'ion-fab-list'] }, { components: ['ion-fab-button'] }, { components: ['ion-gesture'], priority: 'low' },