Просмотр исходного кода

maintain global EventEmitter and InterceptorManager

Yuki Takei 3 лет назад
Родитель
Сommit
04a207e357

+ 12 - 10
packages/app/src/components/Page/RevisionRenderer.jsx

@@ -5,7 +5,9 @@ import PropTypes from 'prop-types';
 
 import { blinkElem } from '~/client/util/blink-section-header';
 import { addSmoothScrollEvent } from '~/client/util/smooth-scroll';
+import InterceptorManager from '~/services/interceptor-manager';
 import GrowiRenderer from '~/services/renderer/growi-renderer';
+import { useInterceptorManager } from '~/stores/context';
 import { useEditorSettings } from '~/stores/editor';
 
 import RevisionBody from './RevisionBody';
@@ -42,7 +44,7 @@ class LegacyRevisionRenderer extends React.PureComponent {
 
   componentDidUpdate(prevProps) {
     const { markdown: prevMarkdown, highlightKeywords: prevHighlightKeywords } = prevProps;
-    const { markdown, highlightKeywords } = this.props;
+    const { markdown, highlightKeywords, interceptorManager } = this.props;
 
     // render only when props.markdown is updated
     if (markdown !== prevMarkdown || highlightKeywords !== prevHighlightKeywords) {
@@ -55,8 +57,6 @@ class LegacyRevisionRenderer extends React.PureComponent {
     const HeaderLinkArray = Array.from(HeaderLink);
     addSmoothScrollEvent(HeaderLinkArray, blinkElem);
 
-    const { interceptorManager } = window;
-
     interceptorManager.process('postRenderHtml', this.currentRenderingContext);
   }
 
@@ -127,11 +127,15 @@ class LegacyRevisionRenderer extends React.PureComponent {
 
   async renderHtml() {
     const {
+      interceptorManager,
       growiRenderer,
       highlightKeywords,
     } = this.props;
 
-    const { interceptorManager } = window;
+    if (interceptorManager == null || growiRenderer == null) {
+      return;
+    }
+
     const context = this.currentRenderingContext;
 
     await interceptorManager.process('preRender', context);
@@ -153,13 +157,9 @@ class LegacyRevisionRenderer extends React.PureComponent {
   }
 
   render() {
-    const config = this.props.appContainer.getConfig();
-    const isMathJaxEnabled = !!config.env.MATHJAX;
-
     return (
       <RevisionBody
         html={this.state.html}
-        isMathJaxEnabled={isMathJaxEnabled}
         additionalClassName={this.props.additionalClassName}
         renderMathJaxOnInit
       />
@@ -169,6 +169,7 @@ class LegacyRevisionRenderer extends React.PureComponent {
 }
 
 LegacyRevisionRenderer.propTypes = {
+  interceptorManager: PropTypes.instanceOf(InterceptorManager).isRequired,
   growiRenderer: PropTypes.instanceOf(GrowiRenderer).isRequired,
   markdown: PropTypes.string.isRequired,
   pagePath: PropTypes.string.isRequired,
@@ -178,10 +179,11 @@ LegacyRevisionRenderer.propTypes = {
 };
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-const RevisionRenderer = () => {
+const RevisionRenderer = (props) => {
+  const { data: interceptorManager } = useInterceptorManager();
   const { data: editorSettings } = useEditorSettings();
 
-  return <LegacyRevisionRenderer editorSettings={editorSettings} />;
+  return <LegacyRevisionRenderer {...props} interceptorManager={interceptorManager} editorSettings={editorSettings} />;
 };
 
 RevisionRenderer.propTypes = {

+ 6 - 3
packages/app/src/components/TableOfContents.jsx

@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
 import PageContainer from '~/client/services/PageContainer';
 import { blinkElem } from '~/client/util/blink-section-header';
 import { addSmoothScrollEvent } from '~/client/util/smooth-scroll';
+import { useGlobalEventEmitter } from '~/stores/context';
 import loggerFactory from '~/utils/logger';
 
 
@@ -25,6 +26,8 @@ const TableOfContents = (props) => {
   const { pageUser } = pageContainer.state;
   const isUserPage = pageUser != null;
 
+  const { data: globalEmitter } = useGlobalEventEmitter();
+
   const [tocHtml, setTocHtml] = useState('');
 
   const calcViewHeight = useCallback(() => {
@@ -56,12 +59,12 @@ const TableOfContents = (props) => {
   // set handler to render ToC
   useEffect(() => {
     const handler = html => setTocHtml(html);
-    window.globalEmitter.on('renderTocHtml', handler);
+    globalEmitter.on('renderTocHtml', handler);
 
     return function cleanup() {
-      window.globalEmitter.removeListener('renderTocHtml', handler);
+      globalEmitter.removeListener('renderTocHtml', handler);
     };
-  }, []);
+  }, [globalEmitter]);
 
   return (
     <StickyStretchableScroller

+ 0 - 2
packages/app/src/interfaces/global.ts

@@ -4,11 +4,9 @@ import GrowiRenderer from '~/services/renderer/growi-renderer';
 import Xss from '~/services/xss';
 
 import { IGraphViewer } from './graph-viewer';
-import { IInterceptorManager } from './interceptor-manager';
 
 export type CustomWindow = Window
                          & typeof globalThis
-                         & { interceptorManager: IInterceptorManager }
                          & { globalEmitter: EventEmitter }
                          & { GraphViewer: IGraphViewer }
                          & { growiRenderer: GrowiRenderer }

+ 8 - 0
packages/app/src/pages/[[...path]].page.tsx

@@ -1,5 +1,7 @@
 import React, { useEffect } from 'react';
 
+import EventEmitter from 'events';
+
 import { isClient, pagePathUtils, pathUtils } from '@growi/core';
 import ExtensibleCustomError from 'extensible-custom-error';
 import {
@@ -18,6 +20,7 @@ import { CrowiRequest } from '~/interfaces/crowi-request';
 // import { useIndentSize } from '~/stores/editor';
 // import { useRendererSettings } from '~/stores/renderer';
 // import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
+import { CustomWindow } from '~/interfaces/global';
 import { IPageWithMeta } from '~/interfaces/page';
 import { GrowiRendererConfig, RendererSettings } from '~/interfaces/services/renderer';
 import { ISidebarConfig } from '~/interfaces/sidebar-config';
@@ -125,6 +128,11 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
 
   const { data: currentUser } = useCurrentUser(props.currentUser != null ? JSON.parse(props.currentUser) : null);
 
+  // register global EventEmitter
+  if (isClient()) {
+    (window as CustomWindow).globalEmitter = new EventEmitter();
+  }
+
   // commons
   useAppTitle(props.appTitle);
   useSiteUrl(props.siteUrl);

+ 12 - 1
packages/app/src/stores/context.tsx

@@ -1,10 +1,13 @@
-import { pagePathUtils } from '@growi/core';
+import EventEmitter from 'events';
+
 import { Key, SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
 
 import { SupportedActionType } from '~/interfaces/activity';
+import { CustomWindow } from '~/interfaces/global';
 import { GrowiRendererConfig } from '~/interfaces/services/renderer';
+import InterceptorManager from '~/services/interceptor-manager';
 
 import { TargetAndAncestors } from '../interfaces/page-listing-results';
 import { IUser } from '../interfaces/user';
@@ -15,6 +18,14 @@ import { useStaticSWR } from './use-static-swr';
 type Nullable<T> = T | null;
 
 
+export const useGlobalEventEmitter = (): SWRResponse<EventEmitter, Error> => {
+  return useStaticSWR<EventEmitter, Error>('globalEventEmitter', undefined, { fallbackData: (window as CustomWindow).globalEmitter });
+};
+
+export const useInterceptorManager = (): SWRResponse<InterceptorManager, Error> => {
+  return useStaticSWR<InterceptorManager, Error>('interceptorManager', undefined, { fallbackData: new InterceptorManager() });
+};
+
 export const useCsrfToken = (initialData?: string): SWRResponse<string, Error> => {
   return useStaticSWR<string, Error>('csrfToken', initialData);
 };