diff options
| author | bobzel <zzzman@gmail.com> | 2024-04-24 14:56:48 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2024-04-24 14:56:48 -0400 |
| commit | aa4f7b37483c516b92181d3374d3151972b98383 (patch) | |
| tree | 042520fc1fad30c00e27c532a872b4129f29264d /src/client/views/search | |
| parent | 9d69ab27de83ead3e499edc9028ba85749407a1e (diff) | |
fixed search on pdfs to display results when pDF is not selected. fixed presentation transitions to animate. changed so that annotaitons on pdfs would highlight when following a pres slide. fixed scrolling to annotations (and other viewSpecs) from presentations by using the slide target, not the slide as the focus document. cleaned up search and fixed to unhighlight searches on close. fixe pdf search unhighligting to work.
Diffstat (limited to 'src/client/views/search')
| -rw-r--r-- | src/client/views/search/SearchBox.tsx | 189 |
1 files changed, 116 insertions, 73 deletions
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 0c1a419aa..384e6d654 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -6,7 +6,6 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCastAsync, Field, FieldType } from '../../../fields/Doc'; import { DirectLinks, DocData } from '../../../fields/DocSymbols'; -import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocUtils } from '../../documents/Documents'; @@ -16,16 +15,111 @@ import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxBaseComponent } from '../DocComponent'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { IRecommendation, Recommendation } from '../newlightbox/components'; import { fetchRecommendations } from '../newlightbox/utils'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './SearchBox.scss'; +import { Id } from '../../../fields/FieldSymbols'; +import { ClientUtils } from '../../../ClientUtils'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; const ERROR = 0.03; +export interface SearchBoxItemProps { + Document: Doc; + searchString: string; + isLinkSearch: boolean; + matchedKeys: string[]; + className: string; + linkFrom: Doc | undefined; + selectItem: (doc: Doc) => void; + linkCreateAnchor?: () => Doc | undefined; + linkCreated?: (link: Doc) => void; +} +@observer +export class SearchBoxItem extends ObservableReactComponent<SearchBoxItemProps> { + constructor(props: SearchBoxItemProps) { + super(props); + makeObservable(this); + } + + /** + * @param {Doc} doc - doc to be selected + * + * This method selects a doc by either jumping to it (centering/zooming in on it) + * or opening it in a new tab. + */ + selectElement = async (doc: Doc, finishFunc: () => void) => { + await DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, finishFunc); + }; + + /** + * @param {Doc} doc - doc of the search result that has been clicked on + * + * This method is called when the user clicks on a search result. The _selectedResult is + * updated accordingly and the doc is highlighted with the selectElement method. + */ + onResultClick = action(async (doc: Doc) => { + this._props.selectItem(doc); + this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._props.searchString, undefined, false)); + }); + + componentWillUnmount(): void { + const doc = this._props.Document; + DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.('', undefined, true); + } + + @undoBatch + makeLink = action((linkTo: Doc) => { + const linkFrom = this._props.linkCreateAnchor?.(); + if (linkFrom) { + const link = DocUtils.MakeLink(linkFrom, linkTo, {}); + link && this._props.linkCreated?.(link); + } + }); + + render() { + // eslint-disable-next-line no-use-before-define + const formattedType = SearchBox.formatType(StrCast(this._props.Document.type), StrCast(this._props.Document.type_collection)); + const { title } = this._props.Document; + + return ( + <Tooltip placement="right" title={<div className="dash-tooltip">{title as string}</div>}> + <div + onClick={ + this._props.isLinkSearch + ? () => this.makeLink(this._props.Document) + : e => { + this.onResultClick(this._props.Document); + e.stopPropagation(); + } + } + style={{ + fontWeight: LinkManager.Links(this._props.linkFrom).find( + link => + Doc.AreProtosEqual(LinkManager.getOppositeAnchor(link, this._props.linkFrom!), this._props.Document) || + Doc.AreProtosEqual(DocCast(LinkManager.getOppositeAnchor(link, this._props.linkFrom!)?.annotationOn), this._props.Document) + ) + ? 'bold' + : '', + }} + className={this._props.className}> + <div className="searchBox-result-title">{title as string}</div> + <div className="searchBox-result-type" style={{ color: SettingsManager.userVariantColor }}> + {formattedType} + </div> + <div className="searchBox-result-keys" style={{ color: SettingsManager.userVariantColor }}> + {this._props.matchedKeys.join(', ')} + </div> + </div> + </Tooltip> + ); + } +} + export interface SearchBoxProps extends FieldViewProps { linkSearch: boolean; linkFrom?: (() => Doc | undefined) | undefined; @@ -112,26 +206,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { }); /** - * @param {Doc} doc - doc of the search result that has been clicked on - * - * This method is called when the user clicks on a search result. The _selectedResult is - * updated accordingly and the doc is highlighted with the selectElement method. - */ - onResultClick = action(async (doc: Doc) => { - this._selectedResult = doc; - this.selectElement(doc, () => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, false)); - }); - - @undoBatch - makeLink = action((linkTo: Doc) => { - const linkFrom = this._props.linkCreateAnchor?.(); - if (linkFrom) { - const link = DocUtils.MakeLink(linkFrom, linkTo, {}); - link && this._props.linkCreated?.(link); - } - }); - - /** * @param {Doc[]} docs - docs to be searched through recursively * @param {number, Doc => void} func - function to be called on each doc * @@ -217,7 +291,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { if (doc[DocData][DirectLinks].size === 0) { this._linkedDocsOut.set(doc, new Set(this._results.keys())); - this._results.forEach((_, linkedDoc) => { + this._results.forEach((__, linkedDoc) => { this._linkedDocsIn.get(linkedDoc)?.add(doc); }); } else { @@ -251,7 +325,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { pageRankIteration(): boolean { let converged = true; const pageRankFromAll = (1 - DAMPENING_FACTOR) / this._results.size; - const nextPageRanks = new Map<Doc, number>(); this._results.forEach((_, doc) => { @@ -346,16 +419,6 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { }); /** - * @param {Doc} doc - doc to be selected - * - * This method selects a doc by either jumping to it (centering/zooming in on it) - * or opening it in a new tab. - */ - selectElement = async (doc: Doc, finishFunc: () => void) => { - await DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, finishFunc); - }; - - /** * This method returns a JSX list of the options in the select drop-down menu, which * is used to filter the types of documents that appear in the search results. */ @@ -365,7 +428,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { return selectValues.map(value => ( <option key={value} value={value}> - {SearchBox.formatType(value, '')} + {ClientUtils.cleanDocumentTypeExt(value as DocumentType)} </option> )); } @@ -374,56 +437,36 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { * This method renders the search input box, select drop-down menu, and search results. */ render() { - let validResults = 0; - const isLinkSearch: boolean = this._props.linkSearch; - const sortedResults = Array.from(this._results.entries()).sort((a, b) => (this._pageRanks.get(b[0]) ?? 0) - (this._pageRanks.get(a[0]) ?? 0)); // sorted by page rank - const resultsJSX = [] as any[]; + const linkFrom = this._props.linkFrom?.(); - const fromDoc = this._props.linkFrom?.(); - - sortedResults.forEach(result => { + let validResults = 0; + sortedResults.forEach(([Document, matchedKeys]) => { let className = 'searchBox-results-scroll-view-result'; - if (this._selectedResult === result[0]) { + if (this._selectedResult === Document) { className += ' searchBox-results-scroll-view-result-selected'; } - const formattedType = SearchBox.formatType(StrCast(result[0].type), StrCast(result[0].type_collection)); - const { title } = result[0]; - - if (this._docTypeString === 'keys' || this._docTypeString === 'all' || this._docTypeString === result[0].type) { + if (this._docTypeString === 'keys' || this._docTypeString === 'all' || this._docTypeString === Document.type) { validResults++; resultsJSX.push( - <Tooltip key={result[0][Id]} placement="right" title={<div className="dash-tooltip">{title as string}</div>}> - <div - onClick={ - isLinkSearch - ? () => this.makeLink(result[0]) - : e => { - this.onResultClick(result[0]); - e.stopPropagation(); - } - } - style={{ - fontWeight: LinkManager.Links(fromDoc).find( - link => Doc.AreProtosEqual(LinkManager.getOppositeAnchor(link, fromDoc!), result[0] as Doc) || Doc.AreProtosEqual(DocCast(LinkManager.getOppositeAnchor(link, fromDoc!)?.annotationOn), result[0] as Doc) - ) - ? 'bold' - : '', - }} - className={className}> - <div className="searchBox-result-title">{title as string}</div> - <div className="searchBox-result-type" style={{ color: SettingsManager.userVariantColor }}> - {formattedType} - </div> - <div className="searchBox-result-keys" style={{ color: SettingsManager.userVariantColor }}> - {result[1].join(', ')} - </div> - </div> - </Tooltip> + <SearchBoxItem + key={Document[Id]} + Document={Document} + selectItem={action((doc: Doc) => { + this._selectedResult = doc; + })} + isLinkSearch={isLinkSearch} + searchString={this._searchString} + matchedKeys={matchedKeys} + linkFrom={linkFrom} + className={className} + linkCreateAnchor={this._props.linkCreateAnchor} + linkCreated={this._props.linkCreated} + /> ); } }); |
