Skip to content

Commit

Permalink
postMessage without serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Elephmoon committed May 16, 2021
1 parent d1ef3ff commit 54679a2
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 49 deletions.
11 changes: 3 additions & 8 deletions frontend/app/common/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface User {
export type User = {
name: string;
id: string;
picture: string;
Expand All @@ -7,15 +7,10 @@ export interface User {
block: boolean;
verified: boolean;
email_subscription?: boolean;
}
};

/** data which is used on user-info page */
export interface UserInfo {
id: User['id'];
name: string | '';
isDefaultPicture: boolean;
picture: string;
}
export type UserInfo = Pick<User, 'id' | 'name' | 'picture'>;

export interface BlockedUser {
id: string;
Expand Down
2 changes: 0 additions & 2 deletions frontend/app/common/user-info-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import type { UserInfo } from './types';

export const userInfo: UserInfo = parseQuery();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const isDefaultPicture = ((userInfo.isDefaultPicture as any) as string) !== '1';
export const id = userInfo.id;
export const name = userInfo.name;
export const picture = userInfo.picture;
6 changes: 4 additions & 2 deletions frontend/app/components/auth-panel/auth-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ class AuthPanelComponent extends Component<Props, State> {
toggleUserInfoVisibility = () => {
const { user } = this.props;

if (window.parent && user) {
postMessage({ isUserInfoShown: true, user });
if (user === null) {
return;
}

postMessage({ isUserInfoShown: true, user });
};

renderAuthorized = (user: User) => {
Expand Down
11 changes: 7 additions & 4 deletions frontend/app/components/dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import b from 'bem-react-helper';
import { Theme } from 'common/types';
import { sleep } from 'utils/sleep';
import { Button } from 'components/button';
import { parseMessage } from 'utils/postMessage';

type Props = RenderableProps<{
title: string;
Expand Down Expand Up @@ -133,12 +134,14 @@ export class Dropdown extends Component<Props, State> {
});
}

receiveMessage(e: { data: string | object }) {
receiveMessage(event: MessageEvent<{ clickOutside?: boolean }>) {
try {
const data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
const data = parseMessage(event);

if (!data || !data.clickOutside || !this.state.isActive) {
return;
}

if (!data.clickOutside) return;
if (!this.state.isActive) return;
this.setState(
{
contentTranslateX: 0,
Expand Down
13 changes: 5 additions & 8 deletions frontend/app/components/root/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import b from 'bem-react-helper';
import { IntlShape, useIntl, FormattedMessage, defineMessages } from 'react-intl';
import clsx from 'clsx';

import type { Sorting } from 'common/types';
import type { Sorting, Theme } from 'common/types';
import type { StoreState } from 'store';
import {
COMMENT_NODE_CLASSNAME_PREFIX,
Expand Down Expand Up @@ -39,7 +39,7 @@ import { ConnectedComment as Comment } from 'components/comment/connected-commen
import { uploadImage, getPreview } from 'common/api';
import { isUserAnonymous } from 'utils/isUserAnonymous';
import { bindActions } from 'utils/actionBinder';
import { postMessage } from 'utils/postMessage';
import { postMessage, parseMessage } from 'utils/postMessage';
import { useActions } from 'hooks/useAction';
import { setCollapse } from 'store/thread/actions';
import { logout } from 'components/auth/auth.api';
Expand Down Expand Up @@ -177,13 +177,10 @@ export class Root extends Component<Props, State> {
}
};

onMessage(event: { data: string | object }) {
if (!event.data) {
return;
}

onMessage(event: MessageEvent<{ theme?: Theme }>) {
try {
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
const data = parseMessage(event);

if (data.theme && THEMES.includes(data.theme)) {
this.props.setTheme(data.theme);
}
Expand Down
20 changes: 10 additions & 10 deletions frontend/app/embed.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { UserInfo, Theme } from 'common/types';
import { BASE_URL, NODE_ID, COMMENT_NODE_CLASSNAME_PREFIX } from 'common/constants.config';
import { parseMessage, ParentMessage } from 'utils/postMessage';

if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
Expand Down Expand Up @@ -199,9 +200,7 @@ function createInstance(config: typeof window.remark_config) {
this.closeEl.innerHTML = '&#10006;';
this.closeEl.onclick = () => this.close();
}
const queryUserInfo = `${query}&page=user-info&&id=${user.id}&name=${user.name}&picture=${
user.picture || ''
}&isDefaultPicture=${user.isDefaultPicture || 0}`;
const queryUserInfo = `${query}&page=user-info&&id=${user.id}&name=${user.name}&picture=${user.picture || ''}`;
const iframe = createFrame({ host: BASE_URL, query: queryUserInfo, height: '100%', margin: '0' });
this.node.appendChild(iframe);
this.iframe = iframe;
Expand Down Expand Up @@ -265,9 +264,10 @@ function createInstance(config: typeof window.remark_config) {
},
};

function receiveMessages(event: { data?: string }): void {
function receiveMessages(event: MessageEvent<ParentMessage>): void {
try {
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
const data = parseMessage(event);

if (data.remarkIframeHeight) {
iframe.style.height = `${data.remarkIframeHeight}px`;
}
Expand All @@ -278,7 +278,7 @@ function createInstance(config: typeof window.remark_config) {

if (Object.prototype.hasOwnProperty.call(data, 'isUserInfoShown')) {
if (data.isUserInfoShown) {
userInfo.init(data.user || {});
userInfo.init(data.user);
} else {
userInfo.close();
}
Expand All @@ -297,25 +297,25 @@ function createInstance(config: typeof window.remark_config) {
if (hash.indexOf(`#${COMMENT_NODE_CLASSNAME_PREFIX}`) === 0) {
if (e) e.preventDefault();

iframe.contentWindow!.postMessage(JSON.stringify({ hash }), '*');
iframe.contentWindow!.postMessage({ hash }, '*');
}
}

function postTitleToIframe(title: string) {
if (iframe.contentWindow) {
iframe.contentWindow.postMessage(JSON.stringify({ title }), '*');
iframe.contentWindow.postMessage({ title }, '*');
}
}

function postClickOutsideToIframe(e: MouseEvent) {
if (iframe.contentWindow && !iframe.contains(e.target as Node)) {
iframe.contentWindow.postMessage(JSON.stringify({ clickOutside: true }), '*');
iframe.contentWindow.postMessage({ clickOutside: true }, '*');
}
}

function changeTheme(theme: Theme) {
if (iframe.contentWindow) {
iframe.contentWindow.postMessage(JSON.stringify({ theme }), '*');
iframe.contentWindow.postMessage({ theme }, '*');
}
}

Expand Down
44 changes: 32 additions & 12 deletions frontend/app/utils/postMessage.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
import { User } from 'common/types';
import type { Theme, UserInfo } from 'common/types';

export type Message =
| { inited: true }
| {
isUserInfoShown: true;
user: User;
}
| { isUserInfoShown: false }
| { scrollTo: number }
| { remarkIframeHeight: number };
export type ParentMessage = {
inited?: true;
scrollTo?: number;
remarkIframeHeight?: number;
} & (
| { isUserInfoShown: true; user: UserInfo }
| { isUserInfoShown: false; user?: never }
| { isUserInfoShown?: never; user?: never }
);

export type ChildMessage = {
theme?: Theme;
};

type AllMessages = ParentMessage & ChildMessage;

/**
* Sends message to parent window
*
* @returns request success of fail
*/
export function postMessage(data: Message): boolean {
export function postMessage(data: AllMessages): boolean {
if (!window.parent || window.parent === window) return false;
window.parent.postMessage(JSON.stringify(data), '*');
window.parent.postMessage(data, '*');
return true;
}

/**
* Parses data from post message that was received in iframe
*
* @param evt post message event
* @returns
*/
export function parseMessage<T>({ data }: MessageEvent<T>): T {
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
return {} as T;
}

return data as T;
}
8 changes: 5 additions & 3 deletions frontend/templates/iframe.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,17 @@
setInterval(function () {
if (document.body.offsetHeight !== lastHeight && document.body.offsetHeight > 22) {
lastHeight = document.body.offsetHeight;
window.parent.postMessage(JSON.stringify({ remarkIframeHeight: lastHeight }), '*');
window.parent.postMessage({ remarkIframeHeight: lastHeight }, '*');
}
}, 200);
window.addEventListener('message', receiveMessages);
function receiveMessages(event) {
try {
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
const data = event.data;
const isObj = typeof data === 'object' && data !== null && !Array.isArray(data);
if (!isObj) return;
const isItHash = data.hash && data.hash.indexOf('#') === 0;
if (isItHash) {
Expand Down Expand Up @@ -170,7 +172,7 @@
return c;
}, {});
window.parent.postMessage(JSON.stringify({ inited: true }), '*');
window.parent.postMessage({ inited: true }, '*');
</script>
<script>
(function (d) {
Expand Down

0 comments on commit 54679a2

Please sign in to comment.