From 2d3deb7291b7d98acf71566a67c4d648a90ef5af Mon Sep 17 00:00:00 2001 From: yipstanley Date: Sat, 28 Sep 2019 16:00:44 -0400 Subject: search bar filtering updatesA --- src/client/views/search/SearchBox.scss | 9 +++++++++ src/client/views/search/SearchBox.tsx | 11 ++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/client/views/search') diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 5ed33a596..0dd4d3dc5 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -34,6 +34,9 @@ &.searchBox-filter { align-self: stretch; + } + + &.searchBox-submit { margin-left: 2px; margin-right: 2px } @@ -45,6 +48,12 @@ } } +.searchBox-quickFilter { + width: 500px; + margin-left: 25px; + margin-top: 10px; +} + .searchBox-results { margin-right: 136px; top: 300px; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 0d50124dd..1b8177842 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -18,6 +18,7 @@ import { FilterBox } from './FilterBox'; import "./FilterBox.scss"; import "./SearchBox.scss"; import { SearchItem } from './SearchItem'; +import { IconBar } from './IconBar'; library.add(faTimes); @@ -231,7 +232,7 @@ export class SearchBox extends React.Component { } @action.bound - openSearch(e: React.PointerEvent) { + openSearch(e: React.SyntheticEvent) { e.stopPropagation(); this._openNoResults = false; FilterBox.Instance.closeFilter(); @@ -337,12 +338,16 @@ export class SearchBox extends React.Component { + - + {(this._numTotalResults > 0 || !this._searchbarOpen) ? (null) : + (
+
+
)}
Date: Sun, 29 Sep 2019 22:27:03 -0400 Subject: added pdf text searching --- package.json | 2 + src/client/util/SearchUtil.ts | 27 +++++++++++-- src/client/views/collections/CollectionSubView.tsx | 8 +++- src/client/views/search/SearchBox.tsx | 15 ++++--- src/client/views/search/SearchItem.tsx | 3 +- src/server/index.ts | 47 ++++++++++++++++++++-- 6 files changed, 86 insertions(+), 16 deletions(-) (limited to 'src/client/views/search') diff --git a/package.json b/package.json index b373ee4a5..307283214 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "express-session": "^1.15.6", "express-validator": "^5.3.1", "expressjs": "^1.0.1", + "find-in-files": "^0.5.0", "flexlayout-react": "^0.3.3", "font-awesome": "^4.7.0", "formidable": "^1.2.1", @@ -165,6 +166,7 @@ "p-limit": "^2.2.0", "passport": "^0.4.0", "passport-local": "^1.0.0", + "pdf-parse": "^1.1.1", "pdfjs-dist": "^2.0.943", "probe-image-size": "^4.0.0", "prosemirror-commands": "^1.0.8", diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index ee5a83710..d8b9dbec6 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -3,18 +3,22 @@ import { DocServer } from '../DocServer'; import { Doc } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; import { Utils } from '../../Utils'; +import { ResultParameters } from '../northstar/model/idea/idea'; +import { DocumentType } from '../documents/DocumentTypes'; export namespace SearchUtil { export type HighlightingResult = { [id: string]: { [key: string]: string[] } }; export interface IdSearchResult { ids: string[]; + lines: string[][]; numFound: number; highlighting: HighlightingResult | undefined; } export interface DocSearchResult { docs: Doc[]; + lines: string[][]; numFound: number; highlighting: HighlightingResult | undefined; } @@ -30,16 +34,31 @@ export namespace SearchUtil { export function Search(query: string, returnDocs: false, options?: SearchParams): Promise; export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) { query = query || "*"; //If we just have a filter query, search for * as the query - const result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), { + let result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), { qs: { ...options, q: query }, })); if (!returnDocs) { return result; } - const { ids, numFound, highlighting } = result; + + let { ids, numFound, highlighting } = result; + let lines: string[][] = ids.map(i => []); + + let txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), { + qs: { ...options, q: query }, + })); + let fileids = txtresult ? txtresult.ids : []; + await Promise.all(fileids.map(async (tr: string, i: number) => { + let docQuery = "fileUpload_t:" + tr.substr(0, 7); //If we just have a filter query, search for * as the query + let docResult = JSON.parse(await rp.get(Utils.prepend("/search"), { qs: { ...options, q: docQuery } })); + ids.push(...docResult.ids); + lines.push(...docResult.ids.map((dr: any) => txtresult.lines[i])); + numFound += docResult.numFound; + })); + const docMap = await DocServer.GetRefFields(ids); - const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc); - return { docs, numFound, highlighting }; + const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc && doc.type !== DocumentType.KVP); + return { docs, numFound, highlighting, lines }; } export async function GetAliasesOfDocument(doc: Doc): Promise; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 954a27cbd..cdeba6e16 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -22,6 +22,7 @@ import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; import { CollectionView } from "./CollectionView"; import React = require("react"); +var path = require('path'); export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; @@ -261,8 +262,11 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { }).then(async (res: Response) => { (await res.json()).map(action((file: any) => { let full = { ...options, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300, width: 300, title: dropFileName }; - let path = Utils.prepend(file); - Docs.Get.DocumentFromType(type, path, full).then(doc => doc && this.props.addDocument(doc)); + let pathname = Utils.prepend(file); + Docs.Get.DocumentFromType(type, pathname, full).then(doc => { + doc && (doc.fileUpload = path.basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "")); + doc && this.props.addDocument(doc); + }); })); }); promises.push(prom); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 0d50124dd..f53270c64 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -18,6 +18,7 @@ import { FilterBox } from './FilterBox'; import "./FilterBox.scss"; import "./SearchBox.scss"; import { SearchItem } from './SearchItem'; +import { string } from 'prop-types'; library.add(faTimes); @@ -27,7 +28,7 @@ export class SearchBox extends React.Component { @observable private _searchString: string = ""; @observable private _resultsOpen: boolean = false; @observable private _searchbarOpen: boolean = false; - @observable private _results: [Doc, string[]][] = []; + @observable private _results: [Doc, string[], string[]][] = []; private _resultsSet = new Map(); @observable private _openNoResults: boolean = false; @observable private _visibleElements: JSX.Element[] = []; @@ -159,6 +160,8 @@ export class SearchBox extends React.Component { const highlighting = res.highlighting || {}; const highlightList = res.docs.map(doc => highlighting[doc[Id]]); + const lines = new Map(); + res.docs.map((doc, i) => lines.set(doc[Id], res.lines[i])); const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc)); const highlights: typeof res.highlighting = {}; docs.forEach((doc, index) => highlights[doc[Id]] = highlightList[index]); @@ -168,12 +171,14 @@ export class SearchBox extends React.Component { filteredDocs.forEach(doc => { 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)) : []; if (index === undefined) { this._resultsSet.set(doc, this._results.length); - this._results.push([doc, hlights]); + this._results.push([doc, hlights, line]); } else { this._results[index][1].push(...hlights); + this._results[index][2].push(...line); } }); }); @@ -296,13 +301,13 @@ export class SearchBox extends React.Component { } else { if (this._isSearch[i] !== "search") { - let result: [Doc, string[]] | undefined = undefined; + let result: [Doc, string[], string[]] | undefined = undefined; if (i >= this._results.length) { this.getResults(this._searchString); if (i < this._results.length) result = this._results[i]; if (result) { let highlights = Array.from([...Array.from(new Set(result[1]).values())]).filter(v => v !== "search_string"); - this._visibleElements[i] = ; + this._visibleElements[i] = ; this._isSearch[i] = "search"; } } @@ -310,7 +315,7 @@ export class SearchBox extends React.Component { result = this._results[i]; if (result) { let highlights = Array.from([...Array.from(new Set(result[1]).values())]).filter(v => v !== "search_string"); - this._visibleElements[i] = ; + this._visibleElements[i] = ; this._isSearch[i] = "search"; } } diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 96eefacc2..4d021216d 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -30,6 +30,7 @@ export interface SearchItemProps { doc: Doc; query: string; highlighting: string[]; + lines: string[]; } library.add(faCaretUp); @@ -288,7 +289,7 @@ export class SearchItem extends React.Component {
{StrCast(this.props.doc.title)}
-
Matched fields: {this.props.highlighting.join(", ")}
+
{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? "Text:" + this.props.lines[0] : ""}
diff --git a/src/server/index.ts b/src/server/index.ts index 50ce2b14e..524407a83 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -42,13 +42,11 @@ var AdmZip = require('adm-zip'); import * as YoutubeApi from "./apis/youtube/youtubeApiSample"; import { Response } from 'express-serve-static-core'; import { GoogleApiServerUtils } from "./apis/google/GoogleApiServerUtils"; -import { GaxiosResponse } from 'gaxios'; -import { Opt } from '../new_fields/Doc'; -import { docs_v1 } from 'googleapis'; -import { Endpoint } from 'googleapis-common'; const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); const probe = require("probe-image-size"); +const pdf = require('pdf-parse'); +var findInFiles = require('find-in-files'); const download = (url: string, dest: fs.PathLike) => request.get(url).pipe(fs.createWriteStream(dest)); let youtubeApiKey: string; @@ -196,6 +194,23 @@ const solrURL = "http://localhost:8983/solr/#/dash"; // GETTERS +app.get("/textsearch", async (req, res) => { + let q = req.query.q; + console.log("TEXTSEARCH " + q); + if (q === undefined) { + res.send([]); + return; + } + let results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, uploadDir + "text", ".txt$"); + let resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] }; + for (var result in results) { + resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); + resObj.lines.push(results[result].line); + resObj.numFound++; + } + res.send(resObj); +}); + app.get("/search", async (req, res) => { const solrQuery: any = {}; ["q", "fq", "start", "rows", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]); @@ -597,6 +612,30 @@ app.post( fs.createReadStream(uploadDir + file).pipe(resizer.resizer).pipe(fs.createWriteStream(uploadDir + file.substring(0, file.length - ext.length) + resizer.suffix + ext)); }); } + if (ext.endsWith("pdf")) { + var filePath = uploadDir + file; + + let dataBuffer = fs.readFileSync(filePath); + + pdf(dataBuffer).then(async function (data: any) { + + // number of pages + // console.log(data.numpages); + // // number of rendered pages + // console.log(data.numrender); + // // PDF info + // console.log(data.info); + // // PDF metadata + // console.log(data.metadata); + // // PDF.js version + // // check https://mozilla.github.io/pdf.js/getting_started/ + // console.log(data.version); + // // PDF text + // console.log(data.text); + fs.createWriteStream(uploadDir + "text/" + file.substring(0, file.length - ext.length) + ".txt").write(data.text); + }); + + } names.push(`/files/` + file); } res.send(names); -- cgit v1.2.3-70-g09d2 From 2413d93a31ad4c97e09f79b97bc19346e72a1537 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 3 Oct 2019 16:31:31 -0400 Subject: improved search results to avoid showing aliases. improved Pdf results display. --- src/client/util/SearchUtil.ts | 34 ++++++++++++++++++++++++----- src/client/views/nodes/FormattedTextBox.tsx | 5 ----- src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFViewer.scss | 17 ++++++++++----- src/client/views/pdf/PDFViewer.tsx | 33 +++++++++++++++++++--------- src/client/views/search/SearchItem.scss | 13 +++++++++-- src/client/views/search/SearchItem.tsx | 19 ++++++++++------ 7 files changed, 87 insertions(+), 36 deletions(-) (limited to 'src/client/views/search') diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e37f1f90d..6706dcb89 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -41,23 +41,45 @@ export namespace SearchUtil { } let { ids, numFound, highlighting } = result; - let lines: string[][] = ids.map(i => []); let txtresult = query !== "*" && JSON.parse(await rp.get(Utils.prepend("/textsearch"), { qs: { ...options, q: query }, })); + let fileids = txtresult ? txtresult.ids : []; + let newIds: string[] = []; + let newLines: string[][] = []; await Promise.all(fileids.map(async (tr: string, i: number) => { let docQuery = "fileUpload_t:" + tr.substr(0, 7); //If we just have a filter query, search for * as the query let docResult = JSON.parse(await rp.get(Utils.prepend("/search"), { qs: { ...options, q: docQuery } })); - ids.push(...docResult.ids); - lines.push(...docResult.ids.map((dr: any) => txtresult.lines[i])); - numFound += docResult.numFound; + newIds.push(...docResult.ids); + newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i])); })); + + let theDocs: Doc[] = []; + let theLines: string[][] = []; + const textDocMap = await DocServer.GetRefFields(newIds); + const textDocs = newIds.map((id: string) => textDocMap[id]).map(doc => doc as Doc); + for (let i = 0; i < textDocs.length; i++) { + let testDoc = textDocs[i]; + if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { + theDocs.push(Doc.GetProto(testDoc)); + theLines.push(newLines[i].map(line => line.replace(query, query.toUpperCase()))); + } + } + const docMap = await DocServer.GetRefFields(ids); - const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc && doc.type !== DocumentType.KVP); - return { docs, numFound, highlighting, lines }; + const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc); + for (let i = 0; i < ids.length; i++) { + let testDoc = docs[i]; + if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { + theDocs.push(testDoc); + theLines.push([]); + } + } + + return { docs: theDocs, numFound: theDocs.length, highlighting, lines: theLines }; } export async function GetAliasesOfDocument(doc: Doc): Promise; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 9347868b3..c37258f50 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -474,11 +474,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._searchReactionDisposer = reaction(() => { return StrCast(this.props.Document.search_string); }, searchString => { - const fieldkey = 'preview'; - let preview = false; - // if (!this._editorView && Object.keys(this.props.Document).indexOf(fieldkey) !== -1) { - // preview = true; - // } if (searchString) { this.highlightSearchTerms([searchString]); } diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 26de12a0d..134e757d1 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -122,7 +122,7 @@ class RegionAnnotation extends React.Component { left: this.props.x, width: this.props.width, height: this.props.height, - transition: "background-color 0.5s, opacity 0.5s", + transition: "opacity 0.5s", opacity: this._brushed ? 0.5 : undefined, backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.color) }} />); diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 8027e93a3..a71e4f81e 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -11,10 +11,17 @@ // transform: scale(0.75); // transform-origin: top left; // } - // .textLayer { - // transform: scale(0.75); - // transform-origin: top left; - // } + .textLayer { + + mix-blend-mode: multiply; + opacity: 0.9; + } + .textLayer .highlight { + background-color: yellow; + } + .textLayer .highlight.selected { + background-color: orange; + } .page { position: relative; @@ -30,7 +37,6 @@ } .pdfViewer-overlay { - transform: scale(2.14359); transform-origin: left top; position: absolute; top: 0px; @@ -43,6 +49,7 @@ top: 0; width: 100%; pointer-events: none; + mix-blend-mode: multiply; .pdfPage-annotationBox { position: absolute; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 20dfc4d8c..9ff3e1bd1 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -9,7 +9,7 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import smoothScroll, { Utils, emptyFunction, returnOne } from "../../../Utils"; +import smoothScroll, { Utils, emptyFunction, returnOne, intersectRect } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { CompiledScript, CompileScript } from "../../util/Scripting"; @@ -85,6 +85,7 @@ export class PDFViewer extends React.Component { private _selectionReactionDisposer?: IReactionDisposer; private _annotationReactionDisposer?: IReactionDisposer; private _filterReactionDisposer?: IReactionDisposer; + private _searchReactionDisposer?: IReactionDisposer; private _viewer: React.RefObject = React.createRef(); private _mainCont: React.RefObject = React.createRef(); private _selectionText: string = ""; @@ -103,12 +104,24 @@ export class PDFViewer extends React.Component { return this._annotations.filter(anno => this._script.run({ this: anno }, console.log, true).result); } + _lastSearch: string = ""; componentDidMount = async () => { // change the address to be the file address of the PNG version of each page // file address of the pdf this._coverPath = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/".length, this.props.url.length - ".pdf".length)}-${NumCast(this.props.Document.curPage, 1)}.PNG`))); runInAction(() => this._showWaiting = this._showCover = true); this.props.startupLive && this.setupPdfJsViewer(); + this._searchReactionDisposer = reaction(() => StrCast(this.props.Document.search_string), searchString => { + if (searchString) { + this.search(searchString, true); + this._lastSearch = searchString; + } + else { + setTimeout(() => this._lastSearch === "mxytzlaf" && this.search("mxytzlaf", true), 200); // bcz: how do we clear search highlights? + this._lastSearch && (this._lastSearch = "mxytzlaf"); + } + }, { fireImmediately: true }); + this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => (this.props.isSelected() && SelectionManager.SelectedDocuments().length === 1) && this.setupPdfJsViewer(), { fireImmediately: true }); this._reactionDisposer = reaction( () => this.props.Document.scrollY, @@ -130,6 +143,7 @@ export class PDFViewer extends React.Component { this._annotationReactionDisposer && this._annotationReactionDisposer(); this._filterReactionDisposer && this._filterReactionDisposer(); this._selectionReactionDisposer && this._selectionReactionDisposer(); + this._searchReactionDisposer && this._searchReactionDisposer(); document.removeEventListener("copy", this.copy); } @@ -298,12 +312,9 @@ export class PDFViewer extends React.Component { @action scrollToAnnotation = (scrollToAnnotation: Doc) => { - this.allAnnotations.forEach(d => Doc.UnBrushDoc(d)); - let windowHgt = this.props.PanelHeight() / this.props.ContentScaling(); - let scrollRange = this._mainCont.current!.scrollHeight - windowHgt; - let pgScroll = scrollRange / this._pageSizes.length; - this._mainCont.current!.scrollTo(0, NumCast(scrollToAnnotation.y) - pgScroll / 2); - Doc.BrushDoc(scrollToAnnotation); + let offset = this.visibleHeight() / 2 * 96 / 72; + this._mainCont.current && smoothScroll(500, this._mainCont.current, NumCast(scrollToAnnotation.y) - offset); + Doc.linkFollowHighlight(scrollToAnnotation); } sendAnnotations = (page: number) => { @@ -454,7 +465,8 @@ export class PDFViewer extends React.Component { if (rect/* && rect.width !== this._mainCont.current.getBoundingClientRect().width && rect.height !== this._mainCont.current.getBoundingClientRect().height / this.props.pdf.numPages*/) { let scaleY = this._mainCont.current.offsetHeight / boundingRect.height; let scaleX = this._mainCont.current.offsetWidth / boundingRect.width; - if (rect.width !== this._mainCont.current.clientWidth) { + if (rect.width !== this._mainCont.current.clientWidth && + (i == 0 || !intersectRect(clientRects[i], clientRects[i - 1]))) { let annoBox = document.createElement("div"); annoBox.className = "pdfPage-annotationBox"; // transforms the positions from screen onto the pdf div @@ -659,17 +671,18 @@ export class PDFViewer extends React.Component { marqueeX = () => this._marqueeX; marqueeY = () => this._marqueeY; marqueeing = () => this._marqueeing; + visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96; render() { return (
{this.pdfViewerDiv} + {this.annotationLayer}
- {this.annotationLayer} NumCast(this.props.Document.scrollHeight, NumCast(this.props.Document.nativeHeight))} PanelWidth={() => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : NumCast(this.props.Document.nativeWidth)} - VisibleHeight={() => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96} + VisibleHeight={this.visibleHeight} focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss index 273d49349..62715c5eb 100644 --- a/src/client/views/search/SearchItem.scss +++ b/src/client/views/search/SearchItem.scss @@ -4,7 +4,6 @@ display: flex; flex-direction: row-reverse; justify-content: flex-end; - height: 70px; z-index: 0; } @@ -15,9 +14,12 @@ border-color: $intermediate-color; border-bottom-style: solid; padding: 10px; - height: 70px; + min-height: 70px; + max-height: 150px; + height: auto; z-index: 0; display: inline-block; + overflow: auto; .main-search-info { display: flex; @@ -26,6 +28,7 @@ .search-title-container { width: 100%; + overflow: hidden; .search-title { text-transform: uppercase; @@ -181,6 +184,12 @@ background: $lighter-alt-accent; } +.search-highlighting { + overflow: hidden; + text-overflow: ellipsis; + white-space: pre; +} + .searchBox-instances { float: left; opacity: 1; diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 4d021216d..a7822ed46 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -4,13 +4,10 @@ import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlob import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -import { ObjectField } from "../../../new_fields/ObjectField"; -import { RichTextField } from "../../../new_fields/RichTextField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../../Utils"; -import { DocServer } from "../../DocServer"; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager, SetupDrag } from "../../util/DragManager"; @@ -228,6 +225,12 @@ export class SearchItem extends React.Component { @action pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); } + nextHighlight = (e: React.PointerEvent) => { + e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); + let sstring = StrCast(this.props.doc.search_string); + this.props.doc.search_string = ""; + setTimeout(() => this.props.doc.search_string = sstring, 0); + } highlightDoc = (e: React.PointerEvent) => { if (this.props.doc.type === DocumentType.LINK) { if (this.props.doc.anchor1 && this.props.doc.anchor2) { @@ -240,6 +243,7 @@ export class SearchItem extends React.Component { } else { Doc.BrushDoc(this.props.doc); } + e.stopPropagation(); } unHighlightDoc = (e: React.PointerEvent) => { @@ -283,13 +287,14 @@ export class SearchItem extends React.Component { const doc2 = Cast(this.props.doc.anchor2, Doc); return (
-
+
{StrCast(this.props.doc.title)}
-
{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? "Text:" + this.props.lines[0] : ""}
+
{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? this.props.lines[0] : ""}
+ {this.props.lines.filter((m, i) => i).map((l, i) =>
`${l}`
)}
-- cgit v1.2.3-70-g09d2 From a73a72586c72cd620c16dd7bc0baad88c8e49a34 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 11 Oct 2019 01:38:48 -0400 Subject: switching search around to left-hand side. --- src/client/documents/DocumentTypes.ts | 3 +- src/client/documents/Documents.ts | 10 +++++ src/client/views/GlobalKeyHandler.ts | 4 ++ src/client/views/MainView.tsx | 10 +++-- .../views/collections/CollectionTreeView.tsx | 5 ++- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/QueryBox.scss | 0 src/client/views/nodes/QueryBox.tsx | 50 ++++++++++++++++++++++ src/client/views/search/FilterBox.tsx | 4 +- src/client/views/search/IconBar.tsx | 14 ------ src/client/views/search/SearchBox.scss | 17 ++++++-- src/client/views/search/SearchBox.tsx | 2 - src/client/views/search/SearchItem.scss | 39 +++++++---------- src/client/views/search/SearchItem.tsx | 19 +++----- .../authentication/models/current_user_utils.ts | 6 +++ 15 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 src/client/views/nodes/QueryBox.scss create mode 100644 src/client/views/nodes/QueryBox.tsx (limited to 'src/client/views/search') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index e5d5885cd..7abaa4043 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -20,5 +20,6 @@ export enum DocumentType { DRAGBOX = "dragbox", PRES = "presentation", LINKFOLLOW = "linkfollow", - PRESELEMENT = "preselement" + PRESELEMENT = "preselement", + QUERY = "search", } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0114f82d8..7f6ab50d8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -45,6 +45,7 @@ import { ProxyField } from "../../new_fields/Proxy"; import { DocumentType } from "./DocumentTypes"; import { LinkFollowBox } from "../views/linking/LinkFollowBox"; import { PresElementBox } from "../views/presentationview/PresElementBox"; +import { QueryBox } from "../views/nodes/QueryBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -62,6 +63,7 @@ export interface DocumentOptions { panY?: number; page?: number; scale?: number; + fitWidth?: boolean; layout?: string | Doc; isTemplate?: boolean; templates?: List; @@ -119,6 +121,10 @@ export namespace Docs { layout: { view: HistogramBox, collectionView: [CollectionView, data] as CollectionViewType }, options: { height: 300, backgroundColor: "black" } }], + [DocumentType.QUERY, { + layout: { view: QueryBox }, + options: { width: 400, fitWidth: true } + }], [DocumentType.IMG, { layout: { view: ImageBox, ext: anno }, options: {} @@ -374,6 +380,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.HIST), new HistogramField(histoOp), options); } + export function QueryDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.QUERY), "", options); + } + export function TextDocument(options: DocumentOptions = {}) { return InstanceFromProto(Prototypes.get(DocumentType.TEXT), "", options); } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c519991a5..6815ff926 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -7,6 +7,8 @@ import { action, runInAction } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { Cast, PromiseValue } from "../../new_fields/Types"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -162,6 +164,8 @@ export default class KeyManager { break; case "f": MainView.Instance.isSearchVisible = !MainView.Instance.isSearchVisible; + MainView.Instance.flyoutWidth = MainView.Instance.isSearchVisible ? 400 : 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.searchBox, Doc)).then(pv => pv && (pv.treeViewOpen = (MainView.Instance.flyoutWidth > 0))); break; case "o": let target = SelectionManager.SelectedDocuments()[0]; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ba4224875..1ec21f638 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -12,7 +12,7 @@ import { Id } from '../../new_fields/FieldSymbols'; import { InkTool } from '../../new_fields/InkField'; import { List } from '../../new_fields/List'; import { listSpec } from '../../new_fields/Schema'; -import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { BoolCast, Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; @@ -463,7 +463,7 @@ export class MainView extends React.Component { return (null); } return
: null, + //this.isSearchVisible ?
: null, ]; } @@ -648,7 +648,9 @@ export class MainView extends React.Component { @observable isSearchVisible = false; @action.bound toggleSearch = () => { - this.isSearchVisible = !this.isSearchVisible; + this.isSearchVisible = !MainView.Instance.isSearchVisible; + MainView.Instance.flyoutWidth = MainView.Instance.isSearchVisible ? 400 : 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.searchBox, Doc)).then(pv => pv && (pv.treeViewOpen = (MainView.Instance.flyoutWidth > 0))); } @computed private get dictationOverlay() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 37eb151b1..6f5587b5a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -260,7 +260,10 @@ class TreeView extends React.Component { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); if (aspect) return this.docWidth() * aspect; if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x); - return NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50; + return this.props.document.fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection.height) : + Math.min(this.docWidth() * NumCast(this.props.document.scrollHeight, NumCast(this.props.document.nativeHeight)) / NumCast(this.props.document.nativeWidth, + NumCast(this.props.containingCollection.height)))) : + NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50; })()); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e4b2ecffd..d4e7c6d4e 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,6 +24,7 @@ import { ImageBox } from "./ImageBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { PresBox } from "./PresBox"; +import { QueryBox } from "./QueryBox"; import { PresElementBox } from "../presentationview/PresElementBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; @@ -99,7 +100,7 @@ export class DocumentContentsView extends React.Component { + public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(QueryBox, fieldKey); } + _docListChangedReaction: IReactionDisposer | undefined; + componentDidMount() { + } + + componentWillUnmount() { + this._docListChangedReaction && this._docListChangedReaction(); + } + + render() { + return
+ +
+ } +} \ No newline at end of file diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index da733d64b..b841190d4 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -33,7 +33,7 @@ export enum Keys { export class FilterBox extends React.Component { static Instance: FilterBox; - public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.HIST, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB]; + public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB]; //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 @@ -393,7 +393,7 @@ export class FilterBox extends React.Component {
- {this.getActiveFilters()} + {/* {this.getActiveFilters()} */}
{this._filterOpen ? (
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx index c9924222f..bdeb57d5c 100644 --- a/src/client/views/search/IconBar.tsx +++ b/src/client/views/search/IconBar.tsx @@ -59,23 +59,9 @@ export class IconBar extends React.Component { render() { return (
-
-
- -
-
Select All
-
{FilterBox.Instance._allIcons.map((type: string) => )} -
-
- -
-
Clear
-
); } diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 0dd4d3dc5..bc11604a5 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -1,6 +1,15 @@ @import "../globalCssVariables"; @import "./NaviconButton.scss"; +.searchBox-container { + display: flex; + flex-direction: column; + width:100%; + height:100%; + position: absolute; + font-size: 10px; + line-height: 1; +} .searchBox-bar { height: 32px; display: flex; @@ -49,17 +58,17 @@ } .searchBox-quickFilter { - width: 500px; - margin-left: 25px; + width: 100%; + height: 40px; margin-top: 10px; } .searchBox-results { - margin-right: 136px; + display:flex; + flex-direction: column; top: 300px; display: flex; flex-direction: column; - margin-right: 72px; // height: 560px; height: 100%; // overflow: hidden; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index be75a29e0..62c8c255e 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -346,8 +346,6 @@ export class SearchBox extends React.Component { className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch} style={{ width: this._searchbarOpen ? "500px" : "100px" }} /> - -
{(this._numTotalResults > 0 || !this._searchbarOpen) ? (null) : (
diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss index 62715c5eb..9f12994c3 100644 --- a/src/client/views/search/SearchItem.scss +++ b/src/client/views/search/SearchItem.scss @@ -2,19 +2,27 @@ .search-overview { display: flex; - flex-direction: row-reverse; + flex-direction: reverse; justify-content: flex-end; z-index: 0; } +.link-count { + background: black; + border-radius: 20px; + color: white; + width: 15px; + text-align: center; + margin-top: 5px; +} .searchBox-placeholder, .search-overview .search-item { - width: 500px; + width: 100%; background: $light-color-secondary; border-color: $intermediate-color; border-bottom-style: solid; padding: 10px; - min-height: 70px; + min-height: 50px; max-height: 150px; height: auto; z-index: 0; @@ -61,16 +69,6 @@ overflow: hidden; position: relative; - .link-count { - opacity: 1; - position: absolute; - z-index: 1000; - text-align: center; - -webkit-transition: opacity 0.2s ease-in-out; - -moz-transition: opacity 0.2s ease-in-out; - -o-transition: opacity 0.2s ease-in-out; - transition: opacity 0.2s ease-in-out; - } .link-extended { // display: none; @@ -112,7 +110,7 @@ .icon-icons, .icon-live { - height: 50px; + height: auto; margin: auto; overflow: hidden; @@ -174,9 +172,7 @@ .searchBox-instances:active { opacity: 1; background: $lighter-alt-accent; - -webkit-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); + width:150px } .search-item:hover { @@ -193,13 +189,10 @@ .searchBox-instances { float: left; opacity: 1; - width: 150px; + width: 0px; transition: all 0.2s ease; color: black; - transform-origin: top right; - -webkit-transform: scale(0); - -ms-transform: scale(0); - transform: scale(0); + overflow: hidden; } @@ -208,7 +201,7 @@ } .searchBox-placeholder { - min-height: 70px; + min-height: 50px; margin-left: 150px; text-transform: uppercase; text-align: left; diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index a7822ed46..b8cff16f2 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -213,15 +213,6 @@ export class SearchItem extends React.Component { @computed get linkCount() { return LinkManager.Instance.getAllRelatedLinks(this.props.doc).length; } - @computed - get linkString(): string { - let num = this.linkCount; - if (num === 1) { - return num.toString() + " link"; - } - return num.toString() + " links"; - } - @action pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); } @@ -290,7 +281,11 @@ export class SearchItem extends React.Component {
-
+
+
+
{this.linkCount}
+
+
{StrCast(this.props.doc.title)}
{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? this.props.lines[0] : ""}
@@ -301,10 +296,6 @@ export class SearchItem extends React.Component {
{this.DocumentIcon()}
{this.props.doc.type ? this.props.doc.type : "Other"}
-
-
{this.linkCount}
-
{this.linkString}
-
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index f3d5555ed..32da29932 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -97,6 +97,12 @@ export class CurrentUserUtils { curPresentation.boxShadow = "0 0"; doc.curPresentation = curPresentation; } + if (doc.searchBox === undefined) { + const searchBox = Docs.Create.QueryDocument({ title: "Searching" }); + searchBox.boxShadow = "0 0"; + searchBox.ignoreClick = true; + doc.searchBox = searchBox; + } if (doc.sidebar === undefined) { const sidebar = Docs.Create.TreeDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" }); -- cgit v1.2.3-70-g09d2 From 4aa9759d8eb2c4db5f572d60d85460f6c9c9116f Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 11 Oct 2019 10:38:51 -0400 Subject: fixed search to look in extension docs. --- src/client/views/search/SearchBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/search') diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 62c8c255e..b728ffaa9 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -141,7 +141,7 @@ export class SearchBox extends React.Component { private get filterQuery() { const types = FilterBox.Instance.filterTypes; const includeDeleted = FilterBox.Instance.getDataStatus(); - return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted_b:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}"`).join(" ")})` : ""); + return "NOT baseProto_b:true" + (includeDeleted ? "" : " AND NOT deleted_b:true") + (types ? ` AND (${types.map(type => `({!join from=id to=proto_i}type_t:"${type}" AND NOT type_t:*) OR type_t:"${type}" OR type_t:"extension"`).join(" ")})` : ""); } -- cgit v1.2.3-70-g09d2 From 3afceef2f8c2be1bddf67cecd97086a41ec6dc48 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 11 Oct 2019 16:47:42 -0400 Subject: changes to menu layouts --- src/client/documents/Documents.ts | 2 + src/client/views/GlobalKeyHandler.ts | 30 +++++- src/client/views/Main.tsx | 5 - src/client/views/MainView.tsx | 108 +++++++++++++-------- .../collections/CollectionMasonryViewFieldRow.tsx | 2 +- .../CollectionStackingViewFieldColumn.tsx | 4 +- src/client/views/nodes/ButtonBox.scss | 2 + src/client/views/nodes/DragBox.tsx | 4 +- src/client/views/nodes/IconBox.tsx | 4 +- src/client/views/search/IconBar.tsx | 2 +- src/client/views/search/IconButton.scss | 2 +- .../authentication/models/current_user_utils.ts | 73 +++++++++++--- 12 files changed, 167 insertions(+), 71 deletions(-) (limited to 'src/client/views/search') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7f6ab50d8..6b56fb443 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -74,6 +74,7 @@ export interface DocumentOptions { dropAction?: dropActionType; backgroundLayout?: string; chromeStatus?: string; + columnWidth?: number; fontSize?: number; curPage?: number; currentTimecode?: number; @@ -83,6 +84,7 @@ export interface DocumentOptions { dockingConfig?: string; autoHeight?: boolean; dbDoc?: Doc; + icon?: string; // [key: string]: Opt; } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 557b3e366..9d239d0bf 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -9,6 +9,7 @@ import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import { Cast, PromiseValue } from "../../new_fields/Types"; +import { ScriptField } from "../../new_fields/ScriptField"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -162,12 +163,31 @@ export default class KeyManager { } } break; + case "c": + if (MainView.Instance.flyoutWidth > 0) { + MainView.Instance.flyoutWidth = 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + } else { + MainView.Instance.flyoutWidth = 400; + PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + } + break; + case "l": + if (MainView.Instance.flyoutWidth > 0) { + MainView.Instance.flyoutWidth = 0; + } else { + MainView.Instance.flyoutWidth = 400; + PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + } + break; case "f": - stopPropagation = false; - preventDefault = false; - MainView.Instance.isSearchVisible = !MainView.Instance.isSearchVisible; - MainView.Instance.flyoutWidth = MainView.Instance.isSearchVisible ? 400 : 0; - PromiseValue(Cast(CurrentUserUtils.UserDocument.searchBox, Doc)).then(pv => pv && (pv.treeViewOpen = (MainView.Instance.flyoutWidth > 0))); + if (MainView.Instance.flyoutWidth > 0) { + MainView.Instance.flyoutWidth = 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + } else { + MainView.Instance.flyoutWidth = 400; + PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + } break; case "o": let target = SelectionManager.SelectedDocuments()[0]; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 3bd898ac0..a91a2b69e 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -38,11 +38,6 @@ let swapDocs = async () => { if (info.id !== "__guest__") { // a guest will not have an id registered await CurrentUserUtils.loadUserDocument(info); - // updates old user documents to prevent chrome on tree view. - (await Cast(CurrentUserUtils.UserDocument.workspaces, Doc))!.chromeStatus = "disabled"; - (await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc))!.chromeStatus = "disabled"; - (await Cast(CurrentUserUtils.UserDocument.sidebar, Doc))!.chromeStatus = "disabled"; - CurrentUserUtils.UserDocument.chromeStatus = "disabled"; await swapDocs(); } document.getElementById('root')!.addEventListener('wheel', event => { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1ec21f638..6f60de1c4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -15,7 +15,7 @@ import { listSpec } from '../../new_fields/Schema'; import { BoolCast, Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; +import { emptyFunction, returnEmptyString, returnOne, returnTrue, returnFalse, Utils } from '../../Utils'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; import { ClientUtils } from '../util/ClientUtils'; @@ -40,6 +40,8 @@ import { PreviewCursor } from './PreviewCursor'; import { FilterBox } from './search/FilterBox'; import { OverlayView } from './OverlayView'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; +import { CollectionStackingView } from './collections/CollectionStackingView'; +import { ScriptField } from '../../new_fields/ScriptField'; @observer export class MainView extends React.Component { @@ -459,33 +461,63 @@ export class MainView extends React.Component { @computed get flyout() { let sidebar: FieldResult; - if (!this.userDoc || !((sidebar = this.userDoc.sidebar) instanceof Doc)) { + if (!this.userDoc || !((sidebar = this.userDoc.sidebarContainer) instanceof Doc)) { return (null); } - return - ; + (Cast(CurrentUserUtils.UserDocument.libraryButtons, Doc) as Doc).columnWidth = this.flyoutWidthFunc() / 3 - 30; + return
+
+ + +
+
+ + +
; } @computed @@ -493,7 +525,7 @@ export class MainView extends React.Component { if (!this.userDoc) { return (
{this.dockingContent}
); } - let sidebar = this.userDoc.sidebar; + let sidebar = this.userDoc.sidebarContainer; if (!(sidebar instanceof Doc)) { return (null); } @@ -585,16 +617,16 @@ export class MainView extends React.Component { // let googlePhotosSearch = () => GooglePhotosClientUtils.CollectionFromSearch(Docs.Create.MasonryDocument, { included: [GooglePhotosClientUtils.ContentCategories.LANDSCAPES] }); let btns: [React.RefObject, IconName, string, () => Doc | Promise][] = [ - [React.createRef(), "object-group", "Add Collection", addColNode], - [React.createRef(), "tv", "Add Presentation Trail", addPresNode], - [React.createRef(), "globe-asia", "Add Website", addWebNode], - [React.createRef(), "bolt", "Add Button", addButtonDocument], - [React.createRef(), "file", "Add Document Dragger", addDragboxNode], + //[React.createRef(), "object-group", "Add Collection", addColNode], + //[React.createRef(), "tv", "Add Presentation Trail", addPresNode], + //[React.createRef(), "globe-asia", "Add Website", addWebNode], + //[React.createRef(), "bolt", "Add Button", addButtonDocument], + //[React.createRef(), "file", "Add Document Dragger", addDragboxNode], // [React.createRef(), "object-group", "Test Google Photos Search", googlePhotosSearch], - [React.createRef(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], //remove at some point in favor of addImportCollectionNode + //[React.createRef(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], //remove at some point in favor of addImportCollectionNode //[React.createRef(), "play", "Add Youtube Searcher", addYoutubeSearcher], ]; - if (!ClientUtils.RELEASE) btns.unshift([React.createRef(), "cat", "Add Cat Image", addImageNode]); + //if (!ClientUtils.RELEASE) btns.unshift([React.createRef(), "cat", "Add Cat Image", addImageNode]); return < div id="add-nodes-menu" style={{ left: (this.flyoutTranslate ? this.flyoutWidth : 0) + 20, bottom: 20 }} > @@ -603,7 +635,7 @@ export class MainView extends React.Component {
    -
  • + {/*
  • */}
  • {btns.map(btn => @@ -612,7 +644,7 @@ export class MainView extends React.Component {
)} -
  • + {/*
  • */}