From 694cbd8c810068ea27b94cce8d74d6e645939e39 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 20 Aug 2020 11:32:17 -0400 Subject: starting overhaul of SearchBox code. --- src/client/views/MainView.tsx | 21 +- .../views/collections/CollectionSchemaView.tsx | 2 +- src/client/views/search/SearchBox.tsx | 731 ++++++--------------- src/fields/Doc.ts | 4 +- 4 files changed, 200 insertions(+), 558 deletions(-) (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f3d8fc181..fbc843d53 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,12 +1,14 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons'; +import { faBuffer, faHireAHelper } from '@fortawesome/free-brands-svg-icons'; import * as fa from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; +import * as ReactDOM from 'react-dom'; import Measure from 'react-measure'; +import * as rp from 'request-promise'; import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; @@ -14,16 +16,20 @@ import { listSpec } from '../../fields/Schema'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils, simulateMouseClick } from '../../Utils'; +import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; +import { Networking } from '../Network'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DocumentManager } from '../util/DocumentManager'; import GroupManager from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; +import { Hypothesis } from '../util/HypothesisUtils'; +import { LinkManager } from '../util/LinkManager'; import { Scripting } from '../util/Scripting'; +import { SearchUtil } from '../util/SearchUtil'; import { SelectionManager } from '../util/SelectionManager'; import SettingsManager from '../util/SettingsManager'; import SharingManager from '../util/SharingManager'; @@ -53,18 +59,11 @@ import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; +import { WebBox } from './nodes/WebBox'; import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; -import { Hypothesis } from '../util/HypothesisUtils'; -import { WebBox } from './nodes/WebBox'; -import * as ReactDOM from 'react-dom'; import { SearchBox } from './search/SearchBox'; -import { SearchUtil } from '../util/SearchUtil'; -import { Networking } from '../Network'; -import * as rp from 'request-promise'; -import { LinkManager } from '../util/LinkManager'; -import RichTextMenu from './nodes/formattedText/RichTextMenu'; @observer export class MainView extends React.Component { @@ -544,7 +543,7 @@ export class MainView extends React.Component { switch (this.panelContent = title) { case "Tools": panelDoc = Doc.UserDoc()["sidebar-tools"] as Doc ?? undefined; break; case "Workspace": panelDoc = Doc.UserDoc()["sidebar-workspaces"] as Doc ?? undefined; break; - case "Catalog": SearchBox.Instance.searchFullDB = "My Stuff"; + case "Catalog": SearchBox.Instance._searchFullDB = "My Stuff"; SearchBox.Instance.newsearchstring = ""; SearchBox.Instance.enter(undefined); break; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index ed8496544..257099783 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -313,7 +313,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { else { this.props.Document._docFilters = undefined; if (this.props.Document.selectedDoc !== undefined) { - const doc = Cast(this.props.Document.selectedDoc, Doc) as Doc; + const doc = Cast(this.props.Document.selectedDoc, Doc, null); doc._docFilters = undefined; } } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 7b3086848..687dcaa93 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -1,30 +1,28 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from '@material-ui/core'; -import { action, computed, observable, runInAction, reaction, IReactionDisposer } from 'mobx'; +import { action, computed, IReactionDisposer, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import * as rp from 'request-promise'; -import { Doc, DocListCast, Opt, Field } from '../../../fields/Doc'; +import { Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; import { documentSchema } from "../../../fields/documentSchemas"; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { returnFalse, Utils, returnZero } from '../../../Utils'; +import { returnFalse, returnZero } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { SetupDrag } from '../../util/DragManager'; import { SearchUtil } from '../../util/SearchUtil'; import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; +import { ColumnType } from "../collections/CollectionSchemaView"; import { CollectionView, CollectionViewType } from '../collections/CollectionView'; import { ViewBoxBaseComponent } from "../DocComponent"; import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./SearchBox.scss"; -import { ColumnType } from "../collections/CollectionSchemaView"; export const searchSchema = createSchema({ id: "string", @@ -42,126 +40,70 @@ export enum Keys { type SearchBoxDocument = makeInterface<[typeof documentSchema, typeof searchSchema]>; const SearchBoxDocument = makeInterface(documentSchema, searchSchema); -//React.Component @observer export class SearchBox extends ViewBoxBaseComponent(SearchBoxDocument) { + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } + public static Instance: SearchBox; - get _searchString() { return this.layoutDoc.searchQuery; } - @computed set _searchString(value) { this.layoutDoc.searchQuery = (value); } - @observable private _resultsOpen: boolean = false; - @observable _searchbarOpen: boolean = false; - @observable private _results: [Doc, string[], string[]][] = []; - @observable private _openNoResults: boolean = false; - @observable private _visibleElements: JSX.Element[] = []; - @observable private _visibleDocuments: Doc[] = []; - - static NUM_SEARCH_RESULTS_PER_PAGE = 25; - - private _resultsSet = new Map(); - private _resultsRef = React.createRef(); - public inputRef = React.createRef(); - - private _isSearch: ("search" | "placeholder" | undefined)[] = []; - private _isSorted: ("sorted" | "placeholder" | undefined)[] = []; - + private _allIcons: string[] = [DocumentType.INK, DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.RTF, DocumentType.VID, DocumentType.WEB]; + private _numResultsPerPage = 4; private _numTotalResults = -1; private _endIndex = -1; - - static Instance: SearchBox; - + private _lockPromise?: Promise; + private _resultsSet = new Map(); + private _inputRef = React.createRef(); private _maxSearchIndex: number = 0; private _curRequest?: Promise = undefined; - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(SearchBox, fieldKey); } + private _disposers: { [name: string]: IReactionDisposer } = {}; - private new_buckets: { [characterName: string]: number } = {}; - //if true, any keywords can be used. if false, all keywords are required. - //this also serves as an indicator if the word status filter is applied - @observable private _basicWordStatus: boolean = false; - @observable private _nodeStatus: boolean = false; - @observable private _keyStatus: boolean = false; + private currentSelectedCollection: DocumentView | undefined = undefined; + private docsforfilter: Doc[] = []; + private realTotalResults: number = 0; + private collectionRef = React.createRef(); - @observable private newAssign: boolean = true; + @observable _icons: string[] = this._allIcons; + @observable _results: [Doc, string[], string[]][] = []; + @observable _visibleElements: JSX.Element[] = []; + @observable _visibleDocuments: Doc[] = []; + @observable _deletedDocsStatus: boolean = false; + @observable _onlyAliases: boolean = true; + @observable _searchbarOpen = false; + @observable _searchFullDB = "DB"; + @observable _noResults = ""; + @observable _pageStart = 0; + @observable open = false; + @observable children = 0; + @observable newsearchstring = ""; + @observable headercount: number = 0; + @observable headerscale: number = 0; + @observable filter = false; constructor(props: any) { super(props); SearchBox.Instance = this; - this.resultsScrolled = this.resultsScrolled.bind(this); - } - @observable setupButtons = false; - private _disposers: { [name: string]: IReactionDisposer } = {}; - - componentDidMount = () => { - this._disposers.filters = reaction(() => Cast(this.props.Document._docFilters, listSpec("string")), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks - newFilters => { - if (this.searchFullDB) { - runInAction(() => this._pageStart = 0); - this.submitSearch(); - // newFilters?.forEach(f => { - // console.log(f); - // }) - } - }); - if (this.setupButtons === false) { - runInAction(() => this.setupButtons = true); - } - if (this.inputRef.current) { - this.inputRef.current.focus(); - runInAction(() => { this._searchbarOpen = true; }); + componentDidMount = action(() => { + if (this._inputRef.current) { + this._inputRef.current.focus(); + this._searchbarOpen = true; } - if (this.rootDoc.searchQuery && this.newAssign) { - const sq = this.rootDoc.searchQuery; - runInAction(() => { - - // this._deletedDocsStatus=this.props.filterQuery!.deletedDocsStatus; - // this._authorFieldStatus=this.props.filterQuery!.authorFieldStatus - // this._titleFieldStatus=this.props.filterQuery!.titleFieldStatus; - // this._basicWordStatus=this.props.filterQuery!.basicWordStatus; - // this._icons=this.props.filterQuery!.icons; - this.newAssign = false; - }); - runInAction(() => { - this.layoutDoc._searchString = StrCast(sq); - this.submitSearch(); - }); - } - } + }) componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); } - @action getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc) - - @observable newsearchstring: string = ""; @action.bound onChange(e: React.ChangeEvent) { this.layoutDoc._searchString = e.target.value; this.newsearchstring = e.target.value; if (e.target.value === "") { - if (this.currentSelectedCollection !== undefined) { - let newarray: Doc[] = []; - let docs: Doc[] = []; - docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach((d) => { - if (d.data !== undefined) { - d._searchDocs = new List(); - d._docFilters = new List(); - DocListCast(d.data).forEach((newdoc) => newarray.push(newdoc)); - } - }); - docs = newarray; - } - - this.currentSelectedCollection.props.Document._searchDocs = new List([]); - this.currentSelectedCollection.props.Document._docFilters = new List(); - this.props.Document.selectedDoc = undefined; + if (this.currentSelectedCollection) { + this.doLoop(this.currentSelectedCollection, undefined); } this._results.forEach(result => { Doc.UnBrushDoc(result[0]); @@ -172,10 +114,8 @@ export class SearchBox extends ViewBoxBaseComponent([]); this.currentSelectedCollection = undefined; this.props.Document.selectedDoc = undefined; - } - runInAction(() => { this.open = false; }); - this._openNoResults = false; + this.open = false; this._results = []; this._resultsSet.clear(); this._visibleElements = []; @@ -190,58 +130,17 @@ export class SearchBox extends ViewBoxBaseComponent { - // if (i === 0) { - // if (i + 1 === limit) { - // query = query + " && " + filters[i] + "_t:" + filters; - // } - // else if (filters[i] === filters[i + 3]) { - // query = query + " && (" + filters[i] + "_t:" + filters; - // } - // else { - // query = query + " && " + filters[i] + "_t:" + filters; - // } - - // } - // else if (i + 3 > filters.length) { - - // } - // else { - - // } - - // }); - - // query = this.applyBasicFieldFilters(query); - - - - query = query.replace(/-\s+/g, ''); - // query = query.replace(/-/g, ""); - return query; + return query.replace(/-\s+/g, ''); } - basicRequireWords(query: string): string { - return query.split(" ").join(" + ").replace(/ + /, ""); - } @action filterDocsByType(docs: Doc[]) { @@ -352,27 +218,6 @@ export class SearchBox extends ViewBoxBaseComponent { - const proto = doc.proto; - const protoId = (proto || doc)[Id]; - const colString: string = "{!join from=data_l to=id}id:" + protoId + " "; - collectionString.push(colString); - }); - - let finalColString = collectionString.join(" "); - finalColString = finalColString.trim(); - return "+(" + finalColString + ")" + query; - } - - get filterTypes() { - return this._icons.length === this._allIcons.length ? undefined : this._icons; - } - //TODO: basically all of this //gets all of the collections of all the docviews that are selected //if a collection is the only thing selected, search only in that collection (not its container) @@ -398,9 +243,6 @@ export class SearchBox extends ViewBoxBaseComponent(docsforFilter); - docs = DocListCast(selectedCollection.dataDoc[Doc.LayoutFieldKey(selectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach(d => { - const docs = DocListCast(d.data); - if (docs.length) { - d._searchDocs = new List(docsforFilter); - docs.forEach((newdoc) => newarray.push(newdoc)); - } - }); - docs = newarray; - } + this.doLoop(selectedCollection, docsforFilter); } this._numTotalResults = found.length; this.realTotalResults = found.length; } else { - this.noresults = "No collection selected :("; + this._noResults = "No collection selected :("; } } - documentKeys(doc: Doc) { const keys: { [key: string]: boolean } = {}; // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. @@ -471,17 +301,6 @@ export class SearchBox extends ViewBoxBaseComponent newWords.push(mod + word)); - - query = newWords.join(" "); - - return query; + query.split(" ").forEach(word => newWords.push(mod + word)); + return newWords.join(" "); } - get fieldFiltersApplied() { return !(this._authorFieldStatus && this._titleFieldStatus); } - @action submitSearch = async (reset?: boolean) => { if (this.currentSelectedCollection !== undefined) { - let newarray: Doc[] = []; - let docs: Doc[] = []; - docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach((d) => { - if (d.data !== undefined) { - d._searchDocs = new List(); - //d._docFilters = new List(); - const newdocs = DocListCast(d.data); - newdocs.forEach((newdoc) => { - newarray.push(newdoc); - }); - } - }); - docs = newarray; - } - - this.currentSelectedCollection.props.Document._searchDocs = new List([]); - this.currentSelectedCollection.props.Document._docFilters = new List(); - this.props.Document.selectedDoc = undefined; + this.doLoop(this.currentSelectedCollection, undefined); } if (reset) { this.layoutDoc._searchString = ""; } //this.props.Document._docFilters = new List(); - this.noresults = ""; + this._noResults = ""; this.dataDoc[this.fieldKey] = new List([]); this.headercount = 0; this.children = 0; - this.buckets = []; - this.new_buckets = {}; let query = StrCast(this.layoutDoc._searchString); Doc.SetSearchQuery(query); - this.searchFullDB ? query = this.getFinalQuery(query) : console.log("local"); + this._searchFullDB ? query = this.getFinalQuery(query) : console.log("local"); this._results.forEach(result => { Doc.UnBrushDoc(result[0]); result[0].searchMatch = undefined; }); this._results = []; this._resultsSet.clear(); - this._isSearch = []; - this._isSorted = []; this._visibleElements = []; this._visibleDocuments = []; - if (StrCast(this.props.Document.searchQuery)) { - if (this._timeout) { clearTimeout(this._timeout); this._timeout = undefined; } - this._timeout = setTimeout(() => { - console.log("Resubmitting search"); - }, 60000); - } - if (query !== "" || this.searchFullDB === "My Stuff") { + if (query !== "" || this._searchFullDB === "My Stuff") { this._endIndex = 12; this._maxSearchIndex = 0; this._numTotalResults = -1; - this.searchFullDB ? await this.getResults(query) : this.searchCollection(query); + this._searchFullDB ? await this.getResults(query) : this.searchCollection(query); runInAction(() => { - this._resultsOpen = true; this._searchbarOpen = true; - this._openNoResults = true; this.resultsScrolled(); - }); } } - @observable searchFullDB = "DB"; - - @observable _timeout: any = undefined; - - @observable firststring: string = ""; - @observable secondstring: string = ""; - - @observable bucketcount: number[] = []; - @observable buckets: Doc[] | undefined; - getAllResults = async (query: string) => { return SearchUtil.Search(query, true, { fq: this.filterQuery, start: 0, rows: 10000000 }); } @@ -590,16 +360,14 @@ export class SearchBox extends ViewBoxBaseComponent `NOT ({!join from=id to=proto_i}type_t:${type}) AND NOT type_t:${type}`).join(" AND ")}`; // fq: type_t:collection OR {!join from=id to=proto_i}type_t:collection q:text_t:hello const query = [baseExpr, authorExpr, includeDeleted, typeExpr].filter(q => q).join(" AND ").replace(/AND $/, ""); return query; } - getDataStatus() { return this._deletedDocsStatus; } - @computed get primarySort() { const suffixMap = (type: ColumnType) => { switch (type) { @@ -612,15 +380,11 @@ export class SearchBox extends ViewBoxBaseComponent, header: SchemaHeaderField) => p || (header.desc !== undefined && suffixMap(header.type) ? (header.heading + suffixMap(header.type) + (header.desc ? " desc" : " asc")) : undefined), undefined); } - private NumResults = 500; - private lockPromise?: Promise; getResults = async (query: string) => { - if (this.lockPromise) { - await this.lockPromise; - } - this.lockPromise = new Promise(async res => { + this._lockPromise && (await this._lockPromise); + this._lockPromise = new Promise(async res => { while (this._results.length <= this._endIndex && (this._numTotalResults === -1 || this._maxSearchIndex < this._numTotalResults)) { - this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, /*sort: this.primarySort,*/ fq: this.filterQuery, start: 0, rows: this.NumResults, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { + this._curRequest = SearchUtil.Search(query, true, { onlyAliases: true, allowAliases: true, /*sort: this.primarySort,*/ fq: this.filterQuery, start: 0, rows: this._numResultsPerPage, hl: true, "hl.fl": "*", }).then(action(async (res: SearchUtil.DocSearchResult) => { // happens at the beginning this.realTotalResults = res.numFound <= 0 ? 0 : res.numFound; if (res.numFound !== this._numTotalResults && this._numTotalResults === -1) { @@ -635,28 +399,26 @@ export class SearchBox extends ViewBoxBaseComponent highlights[doc[Id]] = highlightList[index]); const filteredDocs = this.filterDocsByType(docs); - runInAction(() => { - filteredDocs.forEach((doc, i) => { - const index = this._resultsSet.get(doc); - const highlight = highlights[doc[Id]]; - const line = lines.get(doc[Id]) || []; - const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)).filter(k => k) : []; - // if (this.findCommonElements(hlights)) { - // } - if (index === undefined) { - this._resultsSet.set(doc, this._results.length); - this._results.push([doc, hlights, line]); - } else { - this._results[index][1].push(...hlights); - this._results[index][2].push(...line); - } + runInAction(() => filteredDocs.forEach((doc, i) => { + const index = this._resultsSet.get(doc); + const highlight = highlights[doc[Id]]; + const line = lines.get(doc[Id]) || []; + const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)).filter(k => k) : []; + // if (this.findCommonElements(hlights)) { + // } + if (index === undefined) { + this._resultsSet.set(doc, this._results.length); + this._results.push([doc, hlights, line]); + } else { + this._results[index][1].push(...hlights); + this._results[index][2].push(...line); + } - }); - }); + })); this._curRequest = undefined; })); - this._maxSearchIndex += this.NumResults; + this._maxSearchIndex += this._numResultsPerPage; await this._curRequest; } @@ -664,21 +426,13 @@ export class SearchBox extends ViewBoxBaseComponent(); + startDragCollection = async () => { const res = await this.getAllResults(this.getFinalQuery(StrCast(this.layoutDoc._searchString))); const filtered = this.filterDocsByType(res.docs); - const docs = filtered.map(doc => { - const isProto = Doc.GetT(doc, "isPrototype", "boolean", true); - if (isProto) { - return Doc.MakeDelegate(doc); - } else { - return Doc.MakeAlias(doc); - } - }); + const docs = filtered.map(doc => Doc.GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeDelegate(doc) : Doc.MakeAlias(doc)); let x = 0; let y = 0; for (const doc of docs.map(d => Doc.Layout(d))) { @@ -707,30 +461,22 @@ export class SearchBox extends ViewBoxBaseComponent { - Doc.BrushDoc(result[0]); - }); e.stopPropagation(); - this._openNoResults = false; - this._resultsOpen = true; + this._results.forEach(result => Doc.BrushDoc(result[0])); this._searchbarOpen = true; } - realTotalResults: number = 0; - @action.bound closeSearch = () => { this._results.forEach(result => { Doc.UnBrushDoc(result[0]); result[0].searchMatch = undefined; }); - //this.closeResults(); this._searchbarOpen = false; } @action.bound closeResults() { - this._resultsOpen = false; this._results = []; this._resultsSet.clear(); this._visibleElements = []; @@ -740,21 +486,10 @@ export class SearchBox extends ViewBoxBaseComponent) => { - if (!this._resultsRef.current) return; this._endIndex = 30; const headers = new Set(["title", "author", "text", "type", "data", "*lastModified", "context"]); - // if ((this._numTotalResults === 0 || this._results.length === 0) && this._openNoResults) { - // if (this.noresults === "") { - // this.noresults = "No search results :("; - // } - // return; - // } if (this._numTotalResults <= this._maxSearchIndex) { this._numTotalResults = this._results.length; @@ -766,139 +501,125 @@ export class SearchBox extends ViewBoxBaseComponent(this._numTotalResults === -1 ? 0 : this._numTotalResults); this._visibleDocuments = Array(this._numTotalResults === -1 ? 0 : this._numTotalResults); - // indicates if things are placeholders - this._isSearch = Array(this._numTotalResults === -1 ? 0 : this._numTotalResults); - this._isSorted = Array(this._numTotalResults === -1 ? 0 : this._numTotalResults); - } - let max = this.NumResults; + let max = this._numResultsPerPage; max > this._results.length ? max = this._results.length : console.log(""); for (let i = this._pageStart; i < max; i++) { //if the index is out of the window then put a placeholder in //should ones that have already been found get set to placeholders? - if (this._isSearch[i] !== "search") { - let result: [Doc, string[], string[]] | undefined = undefined; - - result = this._results[i]; - if (result) { - const highlights = Array.from([...Array.from(new Set(result[1]).values())]); - const lines = new List(result[2]); - highlights.forEach((item) => headers.add(item)); - result[0].lines = lines; - result[0].highlighting = highlights.join(", "); - result[0].searchMatch = true; - if (i < this._visibleDocuments.length) { - this._visibleDocuments[i] = result[0]; - this._isSearch[i] = "search"; - Doc.BrushDoc(result[0]); - Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]); - this.children++; - } - + let result: [Doc, string[], string[]] | undefined = undefined; + + result = this._results[i]; + if (result) { + const highlights = Array.from([...Array.from(new Set(result[1]).values())]); + const lines = new List(result[2]); + highlights.forEach((item) => headers.add(item)); + result[0].lines = lines; + result[0].highlighting = highlights.join(", "); + result[0].searchMatch = true; + if (i < this._visibleDocuments.length) { + this._visibleDocuments[i] = result[0]; + Doc.BrushDoc(result[0]); + Doc.AddDocToList(this.dataDoc, this.props.fieldKey, result[0]); + this.children++; } - } } this.headerscale = headers.size; - if (Cast(this.props.Document._docFilters, listSpec("string"), []).length === 0) { - const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []); - if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") { - const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i); - headers.forEach(header => { - if (oldSchemaHeaders.includes(header) === false) { - newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb")); - } - }); - this.headercount = newSchemaHeaders.length; - this.props.Document._schemaHeaders = new List(newSchemaHeaders); - } else if (this.props.Document._schemaHeaders === undefined) { - this.props.Document._schemaHeaders = new List([new SchemaHeaderField("title", "#f1efeb")]); - } + const oldSchemaHeaders = Cast(this.props.Document._schemaHeaders, listSpec("string"), []); + if (oldSchemaHeaders?.length && typeof oldSchemaHeaders[0] !== "object") { + const newSchemaHeaders = oldSchemaHeaders.map(i => typeof i === "string" ? new SchemaHeaderField(i, "#f1efeb") : i); + headers.forEach(header => { + if (oldSchemaHeaders.includes(header) === false) { + newSchemaHeaders.push(new SchemaHeaderField(header, "#f1efeb")); + } + }); + this.headercount = newSchemaHeaders.length; + this.props.Document._schemaHeaders = new List(newSchemaHeaders); + } else if (this.props.Document._schemaHeaders === undefined) { + this.props.Document._schemaHeaders = new List([new SchemaHeaderField("title", "#f1efeb")]); } if (this._maxSearchIndex >= this._numTotalResults) { this._visibleElements.length = this._results.length; this._visibleDocuments.length = this._results.length; - this._isSearch.length = this._results.length; } } - @observable headercount: number = 0; - @observable headerscale: number = 0; findCommonElements(arr2: string[]) { const arr1 = ["layout", "data"]; return arr1.some(item => arr2.includes(item)); } - @computed - get resFull() { return this._numTotalResults <= 8; } - - @computed - get resultHeight() { return this._numTotalResults * 70; } - - addButtonDoc = (doc: Doc) => Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc); - remButtonDoc = (doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc); - moveButtonDoc = (doc: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => this.remButtonDoc(doc) && addDocument(doc); + getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight + panelHeight = () => this.props.PanelHeight(); - @computed get searchItemTemplate() { return Cast(Doc.UserDoc().searchItemTemplate, Doc, null); } - - @computed get viewspec() { return Cast(this.props.Document._docFilters, listSpec("string"), []); } - - getTransform = () => { - return this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight - } - panelHeight = () => { - return this.props.PanelHeight(); - } selectElement = (doc: Doc) => { //this.gotoDocument(this.childDocs.indexOf(doc), NumCasst(this.layoutDoc._itemIndex)); } - - addDocument = (doc: Doc) => { - return null; - } - - @observable filter = false; - - @action newpage() { - this._pageStart += SearchBox.NUM_SEARCH_RESULTS_PER_PAGE; - this.dataDoc[this.fieldKey] = new List([]); - this.resultsScrolled(); - } returnHeight = () => 31 + 31 * 6; - returnLength = () => { - const cols = Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length; - return cols * 205 + 51; - } + returnLength = () => 51 + 205 * Cast(this.props.Document._schemaHeaders, listSpec(SchemaHeaderField), []).length; + @action changeSearchScope = (scope: string) => { scope && (this.filter = false); - this.searchFullDB = scope; + this._searchFullDB = scope; this.dataDoc[this.fieldKey] = new List([]); if (this.currentSelectedCollection !== undefined) { - let newarray: Doc[] = []; - let docs: Doc[] = []; - docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach((d) => { - if (d.data !== undefined) { - d._searchDocs = new List(); - d._docFilters = new List(); - const newdocs = DocListCast(d.data); - newdocs.forEach((newdoc) => { - newarray.push(newdoc); - }); - } - }); - docs = newarray; - } - this.currentSelectedCollection.props.Document._docFilters = new List(); - this.currentSelectedCollection.props.Document._searchDocs = undefined; - this.currentSelectedCollection = undefined; + this.doLoop(this.currentSelectedCollection, undefined); } this.submitSearch(); } + + @computed get scopeButtons() { + return
+
+
+
+ +
+
+ +
+
+
+
; + } + + doLoop = (collectionView: DocumentView, filter: Doc[] | undefined) => { + let docs = DocListCast(collectionView.dataDoc[Doc.LayoutFieldKey(collectionView.dataDoc)]); + let newarray: Doc[] = []; + while (docs.length > 0) { + newarray = []; + docs.forEach(d => { + const subDocs = DocListCast(d.data); + if (subDocs.length) { + d._searchDocs = filter ? new List(filter) : undefined; + DocListCast(d.data).forEach(newdoc => newarray.push(newdoc)); + } + }); + docs = newarray; + } + collectionView.props.Document._searchDocs = filter ? new List(filter) : undefined; + this.props.Document.selectedDoc = filter ? collectionView.props.Document : undefined; + } + render() { this.props.Document._chromeStatus === "disabled"; this.props.Document._searchDoc = true; @@ -908,7 +629,7 @@ export class SearchBox extends ViewBoxBaseComponent{Doc.CurrentUserEmail}
-
@@ -923,116 +644,38 @@ export class SearchBox extends ViewBoxBaseComponent
only display documents matching search
} > -
{ e.stopPropagation(); SetupDrag(this.collectionRef, () => StrCast(this.layoutDoc._searchString) ? this.startDragCollection() : undefined); }} - onClick={action(() => { - ///DONT Change without emailing andy r first. - this.filter = !this.filter && !this.searchFullDB; - if (this.filter === true && this.currentSelectedCollection !== undefined) { - this.currentSelectedCollection.props.Document._searchDocs = new List(this.docsforfilter); - let newarray: Doc[] = []; - let docs: Doc[] = []; - docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach((d) => { - if (d.data !== undefined) { - d._searchDocs = new List(this.docsforfilter); - const newdocs = DocListCast(d.data); - newdocs.forEach(newdoc => newarray.push(newdoc)); - } - }); - docs = newarray; - } - - this.currentSelectedCollection.props.Document._docFilters = new List(this.viewspec); - this.props.Document.selectedDoc = this.currentSelectedCollection.props.Document; - } - else if (this.filter === false && this.currentSelectedCollection !== undefined) { - let newarray: Doc[] = []; - let docs: Doc[] = []; - docs = DocListCast(this.currentSelectedCollection.dataDoc[Doc.LayoutFieldKey(this.currentSelectedCollection.dataDoc)]); - while (docs.length > 0) { - newarray = []; - docs.forEach((d) => { - if (d.data !== undefined) { - d._searchDocs = new List(); - d._docFilters = new List(); - const newdocs = DocListCast(d.data); - newdocs.forEach(newdoc => newarray.push(newdoc)); - } - }); - docs = newarray; - } - - this.currentSelectedCollection.props.Document._searchDocs = new List([]); - this.currentSelectedCollection.props.Document._docFilters = new List(); - this.props.Document.selectedDoc = undefined; - } - } - )} />
- -
-
-
-
-
- -
-
- -
+
+ { e.stopPropagation(); SetupDrag(this.collectionRef, () => this.layoutDoc._searchString ? this.startDragCollection() : undefined); }} + onClick={action(() => { + this.filter = !this.filter && !this._searchFullDB; + this.currentSelectedCollection && this.doLoop(this.currentSelectedCollection, this.filter ? this.docsforfilter : undefined); + })} />
- +
+ {this.scopeButtons}
-
- {this._searchbarOpen === true ? -
- {this.noresults === "" ?
- window.innerWidth || rows > 6 ? true : false} - focus={this.selectElement} - ScreenToLocalTransform={Transform.Identity} - /> -
: -
-
{this.noresults}
-
} -
: undefined} -
- -
-
+ {!this._searchbarOpen ? (null) :
+
+
+ window.innerWidth || rows > 6 ? true : false} + focus={this.selectElement} + ScreenToLocalTransform={Transform.Identity} + /> +
+
+
} ); } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 3fdeb8e71..c4a49962b 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -206,11 +206,11 @@ export class Doc extends RefField { private [Self] = this; private [SelfProxy]: any; - public [FieldsSym] = (clear?: boolean) => clear ? this.___fields = this.___fieldKeys = {} : this.___fields; + public [FieldsSym](clear?: boolean) { return clear ? this.___fields = this.___fieldKeys = {} : this.___fields; } public [WidthSym] = () => NumCast(this[SelfProxy]._width); public [HeightSym] = () => NumCast(this[SelfProxy]._height); public [ToScriptString] = () => `DOC-"${this[Self][Id]}"-`; - public [ToString] = () => `Doc(${GetEffectiveAcl(this) === AclPrivate ? "-inaccessible-" : this.title})`; + public [ToString] = () => `Doc(${GetEffectiveAcl(this[SelfProxy]) === AclPrivate ? "-inaccessible-" : this[SelfProxy].title})`; public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } public get [DataSym]() { const self = this[SelfProxy]; -- cgit v1.2.3-70-g09d2