Files
talk/src/core/client/embed/StreamEmbed.ts
T
Kiwi 097294909b [next] Embed: Defer login/logout until ready (#2123)
* feat: Embed defer login/-out until ready

* fix: make remove work with lazy render

* fix: typo

* fix: another typo

* fix: test

* chore: replace query-string for querystringify

* fix: types

* chore: small refactor

* feat: added webpack analzyer

* chore: rename compile -> generate

* fix: fix scripts and improve bundle size

* fix: lodash webpack plugin
2018-12-15 00:07:09 +00:00

161 lines
4.1 KiB
TypeScript

import { EventEmitter2 } from "eventemitter2";
import { stringifyQuery } from "talk-common/utils";
import ensureNoEndSlash from "talk-common/utils/ensureNoEndSlash";
import urls from "talk-framework/helpers/urls";
import { ExternalConfig } from "talk-framework/lib/externalConfig";
import {
Decorator,
withAutoHeight,
withClickEvent,
withConfig,
withEventEmitter,
withIOSSafariWidthWorkaround,
withPymStorage,
withSetCommentID,
} from "./decorators";
import onIntersect, { OnIntersectCancellation } from "./onIntersect";
import PymControl, {
defaultPymControlFactory,
PymControlFactory,
} from "./PymControl";
export interface StreamEmbedConfig {
storyID?: string;
storyURL?: string;
commentID?: string;
autoRender?: boolean;
title: string;
eventEmitter: EventEmitter2;
id: string;
rootURL: string;
authToken?: string;
}
export class StreamEmbed {
private config: StreamEmbedConfig;
private pymControl?: PymControl;
private pymControlFactory: PymControlFactory;
private ready = false;
private cancelAutoRender: OnIntersectCancellation | null = null;
constructor(
config: StreamEmbedConfig,
pymControlFactory = defaultPymControlFactory
) {
this.config = config;
this.pymControlFactory = pymControlFactory;
if (config.commentID) {
// Delay emit of `showPermalink` event to allow
// user enough time to setup event listeners.
setTimeout(() => config.eventEmitter.emit("showPermalink"), 0);
}
if (config.autoRender) {
if (config.commentID) {
this.render();
} else {
this.cancelAutoRender = onIntersect(
document.getElementById(config.id)!,
() => {
this.cancelAutoRender = null;
if (!this.rendered) {
this.render();
}
}
);
}
}
config.eventEmitter.once("ready", () => {
this.ready = true;
});
}
private assertRendered() {
if (!this.pymControl) {
throw new Error("Stream Embed must be rendered first");
}
}
public on(eventName: string, callback: (data: any) => void) {
return this.config.eventEmitter.on(eventName, callback);
}
public off(eventName: string, callback: (data: any) => void) {
return this.config.eventEmitter.off(eventName, callback);
}
public login(token: string) {
if (!this.ready) {
this.config.eventEmitter.once("ready", () => this.login(token));
return;
}
this.pymControl!.sendMessage("login", token);
}
public logout() {
if (!this.ready) {
this.config.eventEmitter.once("ready", () => this.logout());
return;
}
this.pymControl!.sendMessage("logout");
}
public remove() {
// If lazy render was enabled, just cancel it.
if (this.cancelAutoRender) {
this.cancelAutoRender();
this.cancelAutoRender = null;
return;
}
this.assertRendered();
this.pymControl!.remove();
this.pymControl = undefined;
}
get rendered() {
return !!this.pymControl;
}
public render() {
if (this.pymControl) {
throw new Error("Stream Embed already rendered");
}
const externalConfig: ExternalConfig = {
authToken: this.config.authToken,
};
const streamDecorators: ReadonlyArray<Decorator> = [
withIOSSafariWidthWorkaround,
withAutoHeight,
withClickEvent,
withSetCommentID,
withEventEmitter(this.config.eventEmitter),
withPymStorage(localStorage, "localStorage"),
withPymStorage(sessionStorage, "sessionStorage"),
withConfig(externalConfig),
];
const query = stringifyQuery({
storyID: this.config.storyID,
storyURL: this.config.storyURL,
commentID: this.config.commentID,
});
const url = `${ensureNoEndSlash(this.config.rootURL)}${urls.embed.stream}${
query ? `?${query}` : ""
}`;
this.pymControl = this.pymControlFactory({
id: this.config.id,
title: this.config.title,
decorators: streamDecorators,
url,
});
}
}
export default function createStreamEmbed(config: StreamEmbedConfig) {
return new StreamEmbed(config);
}