315 lines
9.2 KiB
TypeScript
315 lines
9.2 KiB
TypeScript
/* eslint-disable no-console, @typescript-eslint/no-explicit-any */
|
|
declare let remark_config: CommentsConfig;
|
|
|
|
import { BASE_URL, NODE_ID, COMMENT_NODE_CLASSNAME_PREFIX } from '@app/common/constants.config';
|
|
import { UserInfo, Theme } from '@app/common/types';
|
|
import { CommentsConfig } from '@app/common/config-types';
|
|
|
|
const HOST = remark_config.host || BASE_URL;
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
|
|
function removeDomNode(node: HTMLElement | null) {
|
|
if (node && node.parentNode) {
|
|
node.parentNode.removeChild(node);
|
|
}
|
|
}
|
|
|
|
function createFrame({
|
|
host,
|
|
query,
|
|
height,
|
|
__colors__ = {},
|
|
}: {
|
|
host: string;
|
|
query: string;
|
|
height?: string;
|
|
__colors__?: any;
|
|
}) {
|
|
const iframe = document.createElement('iframe');
|
|
iframe.src = `${host}/web/iframe.html?${query}`;
|
|
iframe.name = JSON.stringify({ __colors__ });
|
|
iframe.setAttribute('width', '100%');
|
|
if (height) {
|
|
iframe.setAttribute('height', height);
|
|
}
|
|
iframe.setAttribute('frameborder', '0');
|
|
iframe.setAttribute('allowtransparency', 'true');
|
|
iframe.setAttribute('scrolling', 'no');
|
|
iframe.setAttribute('tabindex', '0');
|
|
iframe.setAttribute('title', 'Remark42');
|
|
iframe.setAttribute('horizontalscrolling', 'no');
|
|
iframe.setAttribute('verticalscrolling', 'no');
|
|
iframe.setAttribute(
|
|
'style',
|
|
'width: 1px !important; min-width: 100% !important; border: none !important; overflow: hidden !important;'
|
|
);
|
|
return iframe;
|
|
}
|
|
|
|
function init(): void {
|
|
const node = document.getElementById(remark_config.node || NODE_ID);
|
|
|
|
if (!node) {
|
|
console.error("Remark42: Can't find root node.");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
remark_config = remark_config || {};
|
|
} catch (e) {
|
|
console.error('Remark42: Config object is undefined.');
|
|
return;
|
|
}
|
|
|
|
if (!remark_config.site_id) {
|
|
console.error('Remark42: Site ID is undefined.');
|
|
return;
|
|
}
|
|
|
|
remark_config.url = (remark_config.url || window.location.origin + window.location.pathname).split('#')[0];
|
|
|
|
(window as any).REMARK42 = (window as any).REMARK42 || {};
|
|
(window as any).REMARK42.changeTheme = changeTheme;
|
|
|
|
const query = Object.keys(remark_config)
|
|
.filter((key: any) => key !== `__colors__`)
|
|
.map((key: any) => {
|
|
return `${encodeURIComponent(key)}=${encodeURIComponent((remark_config as any)[key])}`;
|
|
})
|
|
.join('&');
|
|
const iframe = createFrame({ host: HOST, query, __colors__: remark_config.__colors__ });
|
|
|
|
node.appendChild(iframe);
|
|
|
|
window.addEventListener('message', receiveMessages);
|
|
window.addEventListener('hashchange', postHashToIframe);
|
|
document.addEventListener('click', postClickOutsideToIframe);
|
|
|
|
const titleElement = document.querySelector('title');
|
|
if (titleElement) {
|
|
new MutationObserver(mutations => postTitleToIframe(mutations[0].target.textContent!)).observe(titleElement, {
|
|
subtree: true,
|
|
characterData: true,
|
|
childList: true,
|
|
});
|
|
}
|
|
|
|
const remarkRootId = 'remark-km423lmfdslkm34';
|
|
const userInfo: {
|
|
node: HTMLElement | null;
|
|
back: HTMLElement | null;
|
|
closeEl: HTMLElement | null;
|
|
iframe: HTMLIFrameElement | null;
|
|
style: HTMLStyleElement | null;
|
|
init: (user: UserInfo) => void;
|
|
close: () => void;
|
|
delay: number | null;
|
|
events: string[];
|
|
onAnimationClose: () => void;
|
|
onKeyDown: (e: KeyboardEvent) => void;
|
|
animationStop: () => void;
|
|
remove: () => void;
|
|
} = {
|
|
node: null,
|
|
back: null,
|
|
closeEl: null,
|
|
iframe: null,
|
|
style: null,
|
|
init(user) {
|
|
this.animationStop();
|
|
if (!this.style) {
|
|
this.style = document.createElement('style');
|
|
this.style.setAttribute('rel', 'stylesheet');
|
|
this.style.setAttribute('type', 'text/css');
|
|
this.style.innerHTML = `
|
|
#${remarkRootId}-node {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 400px;
|
|
transition: transform 0.4s ease-out;
|
|
max-width: 100%;
|
|
transform: translate(400px, 0);
|
|
}
|
|
#${remarkRootId}-node[data-animation] {
|
|
transform: translate(0, 0);
|
|
}
|
|
#${remarkRootId}-back {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0,0,0,0.7);
|
|
opacity: 0;
|
|
transition: opacity 0.4s ease-out;
|
|
}
|
|
#${remarkRootId}-back[data-animation] {
|
|
opacity: 1;
|
|
}
|
|
#${remarkRootId}-close {
|
|
top: 0px;
|
|
right: 400px;
|
|
position: absolute;
|
|
text-align: center;
|
|
font-size: 25px;
|
|
cursor: pointer;
|
|
color: white;
|
|
border-color: transparent;
|
|
border-width: 0;
|
|
padding: 0;
|
|
margin-right: 4px;
|
|
background-color: transparent;
|
|
}
|
|
@media all and (max-width: 430px) {
|
|
#${remarkRootId}-close {
|
|
right: 0px;
|
|
font-size: 20px;
|
|
color: black;
|
|
}
|
|
}
|
|
`;
|
|
}
|
|
if (!this.node) {
|
|
this.node = document.createElement('div');
|
|
this.node.id = remarkRootId + '-node';
|
|
}
|
|
if (!this.back) {
|
|
this.back = document.createElement('div');
|
|
this.back.id = remarkRootId + '-back';
|
|
this.back.onclick = () => this.close();
|
|
}
|
|
if (!this.closeEl) {
|
|
this.closeEl = document.createElement('button');
|
|
this.closeEl.id = remarkRootId + '-close';
|
|
this.closeEl.innerHTML = '✖';
|
|
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 iframe = createFrame({ host: HOST, query: queryUserInfo, height: '100%' });
|
|
this.node.appendChild(iframe);
|
|
this.iframe = iframe;
|
|
this.node.appendChild(this.closeEl);
|
|
document.body.appendChild(this.style);
|
|
document.body.appendChild(this.back);
|
|
document.body.appendChild(this.node);
|
|
document.addEventListener('keydown', this.onKeyDown);
|
|
setTimeout(() => {
|
|
this.back!.setAttribute('data-animation', '');
|
|
this.node!.setAttribute('data-animation', '');
|
|
this.iframe!.focus();
|
|
}, 400);
|
|
},
|
|
close() {
|
|
if (this.node) {
|
|
if (this.iframe) {
|
|
this.node.removeChild(this.iframe);
|
|
}
|
|
this.onAnimationClose();
|
|
this.node.removeAttribute('data-animation');
|
|
}
|
|
if (this.back) {
|
|
this.back.removeAttribute('data-animation');
|
|
}
|
|
document.removeEventListener('keydown', this.onKeyDown);
|
|
},
|
|
delay: null,
|
|
events: ['', 'webkit', 'moz', 'MS', 'o'].map(prefix => (prefix ? `${prefix}TransitionEnd` : 'transitionend')),
|
|
onAnimationClose() {
|
|
const el = this.node!;
|
|
if (!this.node) {
|
|
return;
|
|
}
|
|
this.delay = window.setTimeout(this.animationStop, 1000);
|
|
this.events.forEach(event => el.addEventListener(event, this.animationStop, false));
|
|
},
|
|
onKeyDown(e) {
|
|
// ESCAPE key pressed
|
|
if (e.keyCode === 27) {
|
|
userInfo.close();
|
|
}
|
|
},
|
|
animationStop() {
|
|
const t = userInfo;
|
|
if (!t.node) {
|
|
return;
|
|
}
|
|
if (t.delay) {
|
|
clearTimeout(t.delay);
|
|
t.delay = null;
|
|
}
|
|
t.events.forEach(event => t.node!.removeEventListener(event, t.animationStop, false));
|
|
return t.remove();
|
|
},
|
|
remove() {
|
|
const t = userInfo;
|
|
removeDomNode(t.node);
|
|
removeDomNode(t.back);
|
|
removeDomNode(t.style);
|
|
},
|
|
};
|
|
|
|
function receiveMessages(event: { data?: string }): void {
|
|
try {
|
|
const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;
|
|
if (data.remarkIframeHeight) {
|
|
iframe.style.height = `${data.remarkIframeHeight}px`;
|
|
}
|
|
|
|
if (data.scrollTo) {
|
|
window.scrollTo(window.pageXOffset, data.scrollTo + iframe.getBoundingClientRect().top + window.pageYOffset);
|
|
}
|
|
|
|
if (Object.prototype.hasOwnProperty.call(data, 'isUserInfoShown')) {
|
|
if (data.isUserInfoShown) {
|
|
userInfo.init(data.user || {});
|
|
} else {
|
|
userInfo.close();
|
|
}
|
|
}
|
|
|
|
if (data.inited) {
|
|
postHashToIframe();
|
|
postTitleToIframe(document.title);
|
|
}
|
|
} catch (e) {}
|
|
}
|
|
|
|
function postHashToIframe(
|
|
e?: Event & {
|
|
newURL: string;
|
|
}
|
|
): void {
|
|
const hash = e ? `#${e.newURL.split('#')[1]}` : window.location.hash;
|
|
|
|
if (hash.indexOf(`#${COMMENT_NODE_CLASSNAME_PREFIX}`) === 0) {
|
|
if (e) e.preventDefault();
|
|
|
|
iframe.contentWindow!.postMessage(JSON.stringify({ hash }), '*');
|
|
}
|
|
}
|
|
|
|
function postTitleToIframe(title: string): void {
|
|
iframe.contentWindow!.postMessage(JSON.stringify({ title }), '*');
|
|
}
|
|
|
|
function postClickOutsideToIframe(e: MouseEvent): void {
|
|
if (!iframe.contains(e.target as Node)) {
|
|
iframe.contentWindow!.postMessage(JSON.stringify({ clickOutside: true }), '*');
|
|
}
|
|
}
|
|
|
|
function changeTheme(theme: Theme): void {
|
|
iframe.contentWindow!.postMessage(JSON.stringify({ theme }), '*');
|
|
}
|
|
}
|