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

Merge pull request #4542 from weseek/feat/77515-79940-highlight-page-path

Feat/77515 79940 highlight page path
Yuki Takei 4 лет назад
Родитель
Сommit
71ed123f74

+ 1 - 1
packages/app/src/components/PageList/Page.jsx

@@ -11,7 +11,7 @@ export default class Page extends React.Component {
       page, noLink,
     } = this.props;
 
-    let pagePathElem = <PagePathLabel page={page} additionalClassNames={['mx-1']} />;
+    let pagePathElem = <PagePathLabel path={page.path} additionalClassNames={['mx-1']} />;
     if (!noLink) {
       pagePathElem = <a className="text-break" href={page.path}>{pagePathElem}</a>;
     }

+ 4 - 1
packages/app/src/components/SearchPage/SearchResultListItem.tsx

@@ -15,6 +15,7 @@ type Props ={
     lastUpdateUser: any
     elasticSearchResult: {
       snippet: string,
+      highlightedPath: string,
     }
   },
   onClickInvoked: (data: string) => void,
@@ -27,8 +28,10 @@ const SearchResultListItem: FC<Props> = (props:Props) => {
   // Add prefix 'id_' in pageId, because scrollspy of bootstrap doesn't work when the first letter of id attr of target component is numeral.
   const pageId = `#${page._id}`;
 
+  const isPathIncludedHtml = props.page.elasticSearchResult.highlightedPath != null;
+
   const dPagePath = new DevidedPagePath(page.path, false, true);
-  const pagePathElem = <PagePathLabel page={page} isFormerOnly />;
+  const pagePathElem = <PagePathLabel path={props.page.elasticSearchResult.highlightedPath} isFormerOnly isPathIncludedHtml={isPathIncludedHtml} />;
 
   // TODO : send cetain  length of body (revisionBody) from elastisearch by adding some settings to the query and
   //         when keyword is not in page content, display revisionBody.

+ 1 - 1
packages/app/src/components/SearchTypeahead.jsx

@@ -180,7 +180,7 @@ class SearchTypeahead extends React.Component {
     return (
       <span>
         <UserPicture user={page.lastUpdateUser} size="sm" noLink />
-        <span className="ml-1 text-break text-wrap"><PagePathLabel page={page} /></span>
+        <span className="ml-1 text-break text-wrap"><PagePathLabel path={page.path} /></span>
         <PageListMeta page={page} />
       </span>
     );

+ 1 - 2
packages/app/src/server/service/search.js

@@ -170,8 +170,7 @@ class SearchService {
 
       data.elasticSearchResult = {
         snippet: filterXss.process(snippet),
-        // todo: use filter xss.process() for matchedPath;
-        matchedPath: pathMatch,
+        highlightedPath: filterXss.process(pathMatch),
       };
     });
     return esResult;

+ 2 - 2
packages/core/src/models/devided-page-path.js

@@ -2,8 +2,8 @@ import * as pathUtils from '../utils/path-utils';
 
 // https://regex101.com/r/BahpKX/2
 const PATTERN_INCLUDE_DATE = /^(.+\/[^/]+)\/(\d{4}|\d{4}\/\d{2}|\d{4}\/\d{2}\/\d{2})$/;
-// https://regex101.com/r/WVpPpY/1
-const PATTERN_DEFAULT = /^((.*)\/)?([^/]+)$/;
+// https://regex101.com/r/HJNvMW/1
+const PATTERN_DEFAULT = /^((.*)(?<!<)\/)?(.+)$/;
 
 export class DevidedPagePath {
 

+ 1 - 1
packages/plugin-lsx/src/client/js/components/LsxPageList/PagePathWrapper.jsx

@@ -13,7 +13,7 @@ export class PagePathWrapper extends React.Component {
     }
 
     return (
-      <PagePathLabel page={{ path: this.props.pagePath }} isLatterOnly additionalClassNames={classNames} />
+      <PagePathLabel path={this.props.pagePath} isLatterOnly additionalClassNames={classNames} />
     );
   }
 

+ 0 - 40
packages/ui/src/components/PagePath/PagePathLabel.jsx

@@ -1,40 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-
-import { DevidedPagePath } from '@growi/core';
-
-export const PagePathLabel = (props) => {
-
-  const dPagePath = new DevidedPagePath(props.page.path, false, true);
-
-  let classNames = [''];
-  classNames = classNames.concat(props.additionalClassNames);
-
-  if (props.isLatterOnly) {
-    return <span className={classNames.join(' ')}>{dPagePath.latter}</span>;
-  }
-
-  if (props.isFormerOnly) {
-    const textElem = dPagePath.isFormerRoot
-      ? <>/</>
-      : <>{dPagePath.former}</>;
-    return <span className={classNames.join(' ')}>{textElem}</span>;
-  }
-
-  const textElem = dPagePath.isRoot
-    ? <><strong>/</strong></>
-    : <>{dPagePath.former}/<strong>{dPagePath.latter}</strong></>;
-
-  return <span className={classNames.join(' ')}>{textElem}</span>;
-};
-
-PagePathLabel.propTypes = {
-  page: PropTypes.object.isRequired,
-  isLatterOnly: PropTypes.bool,
-  isFormerOnly: PropTypes.bool,
-  additionalClassNames: PropTypes.arrayOf(PropTypes.string),
-};
-
-PagePathLabel.defaultProps = {
-  additionalClassNames: [],
-};

+ 56 - 0
packages/ui/src/components/PagePath/PagePathLabel.tsx

@@ -0,0 +1,56 @@
+import React, { FC } from 'react';
+
+import { DevidedPagePath } from '@growi/core';
+
+
+type TextElemProps = {
+  children?: React.ReactNode
+  isHTML?: boolean,
+}
+
+const TextElement: FC<TextElemProps> = (props: TextElemProps) => (
+  <>
+    { props.isHTML
+      // eslint-disable-next-line react/no-danger
+      ? <span dangerouslySetInnerHTML={{ __html: props.children?.toString() || '' }}></span>
+      : <>{props.children}</>
+    }
+  </>
+);
+
+
+type Props = {
+  path: string,
+  isLatterOnly?: boolean,
+  isFormerOnly?: boolean,
+  isPathIncludedHtml?: boolean,
+  additionalClassNames?: string[],
+}
+
+export const PagePathLabel: FC<Props> = (props:Props) => {
+  const {
+    isLatterOnly, isFormerOnly, isPathIncludedHtml, additionalClassNames, path,
+  } = props;
+
+  const dPagePath = new DevidedPagePath(path, false, true);
+
+  const classNames = additionalClassNames || [];
+
+  let textElem;
+
+  if (isLatterOnly) {
+    textElem = <TextElement isHTML={isPathIncludedHtml}>{dPagePath.latter}</TextElement>;
+  }
+  else if (isFormerOnly) {
+    textElem = dPagePath.isFormerRoot
+      ? <>/</>
+      : <TextElement isHTML={isPathIncludedHtml}>{dPagePath.former}</TextElement>;
+  }
+  else {
+    textElem = dPagePath.isRoot
+      ? <strong>/</strong>
+      : <TextElement isHTML={isPathIncludedHtml}>{dPagePath.former}/<strong>{dPagePath.latter}</strong></TextElement>;
+  }
+
+  return <span className={classNames.join(' ')}>{textElem}</span>;
+};