// index.ts // Copyright (C) 2020 Dwayne Harris // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . export interface Attachment { url: string text?: string cover?: string } export interface PostData { [key: string]: any } export interface Post { text?: string cover?: string attachments?: Attachment[] data?: PostData visible: boolean } export interface Theme { primary: string primaryAlternate: string secondary: string backgroundPrimary: string backgroundSecondary: string text: string red: string green: string blue: string } export interface MessageContent { [key: string]: any settings?: InstallationSettings height?: number theme?: Theme colorScheme?: string parent?: Post } export interface IncomingMessageData { name: string content: MessageContent publicKey: string } export interface OutgoingMessageData { name: string content?: MessageContent error?: string settings?: object } export interface InstallationSettings { [key: string]: any } interface Listener { resolve: (value?: MessageContent | PromiseLike) => void reject: (reason: any) => void once: boolean } interface ListenerCollection { [name: string]: Listener } type PostOptions = Post export class Communicator { private origin = 'http://localhost:8080' private publicKey: string private listeners: ListenerCollection constructor(publicKey: string) { this.publicKey = publicKey this.listeners = {} window.addEventListener('message', (event: MessageEvent) => { if (event.origin !== this.origin) return try { const data = JSON.parse(event.data) as OutgoingMessageData this.emit(data) } catch (err) { console.error(err) return } }, false) } private emit(data: OutgoingMessageData) { const listener = this.listeners[data.name] if (listener) { if (data.content) listener.resolve(data.content) if (data.error) listener.reject(data.error) if (listener.once) delete this.listeners[data.name] } } private async postAndReceive(name: string, content?: MessageContent) { if (window.parent) { window.parent.postMessage(JSON.stringify({ name, content, publicKey: this.publicKey, }), this.origin) return new Promise((resolve, reject) => { this.listeners[name] = { resolve, reject, once: true, } }) } } async init() { return this.postAndReceive('init') } async setHeight(height: number) { return this.postAndReceive('setHeight', { height }) } async saveSettings(settings: InstallationSettings) { return this.postAndReceive('saveSettings', { settings }) } async post(options: PostOptions) { return this.postAndReceive('post', options) } }