postMessage without serialization

This commit is contained in:
Elephmoon
2021-05-16 13:41:50 -05:00
committed by Umputun
parent d1ef3ff247
commit 992b843cf5
8 changed files with 66 additions and 49 deletions
+3 -8
View File
@@ -1,4 +1,4 @@
export interface User {
export type User = {
name: string;
id: string;
picture: string;
@@ -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;
@@ -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;
@@ -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) => {
@@ -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;
@@ -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,
+5 -8
View File
@@ -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,
@@ -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';
@@ -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);
}
+10 -10
View File
@@ -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);
@@ -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;
@@ -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`;
}
@@ -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();
}
@@ -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 }, '*');
}
}
+32 -12
View File
@@ -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;
}
+5 -3
View File
@@ -134,7 +134,7 @@
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);
@@ -142,7 +142,9 @@
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) {
@@ -170,7 +172,7 @@
return c;
}, {});
window.parent.postMessage(JSON.stringify({ inited: true }), '*');
window.parent.postMessage({ inited: true }, '*');
</script>
<script>
(function (d) {