import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; 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 { 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"; import { LinkManager } from "../../util/LinkManager"; import { SearchUtil } from "../../util/SearchUtil"; import { Transform } from "../../util/Transform"; import { SEARCH_THUMBNAIL_SIZE } from "../../views/globalCssVariables.scss"; import { CollectionViewType } from "../collections/CollectionBaseView"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { ContextMenu } from "../ContextMenu"; import { DocumentView } from "../nodes/DocumentView"; import { SearchBox } from "./SearchBox"; import "./SearchItem.scss"; import "./SelectorContextMenu.scss"; export interface SearchItemProps { doc: Doc; query?: string; highlighting: string[]; } library.add(faCaretUp); library.add(faObjectGroup); library.add(faStickyNote); library.add(faFile); library.add(faFilePdf); library.add(faFilm); library.add(faMusic); library.add(faLink); library.add(faChartBar); library.add(faGlobeAsia, faFingerprint); @observer export class SelectorContextMenu extends React.Component { @observable private _docs: { col: Doc, target: Doc }[] = []; @observable private _otherDocs: { col: Doc, target: Doc }[] = []; constructor(props: SearchItemProps) { super(props); this.fetchDocuments(); } async fetchDocuments() { let aliases = (await SearchUtil.GetViewsOfDocument(this.props.doc)).filter(doc => doc !== this.props.doc); const { docs } = await SearchUtil.Search("", true, { fq: `data_l:"${this.props.doc[Id]}"` }); const map: Map = new Map; const allDocs = await Promise.all(aliases.map(doc => SearchUtil.Search("", true, { fq: `data_l:"${doc[Id]}"` }).then(result => result.docs))); allDocs.forEach((docs, index) => docs.forEach(doc => map.set(doc, aliases[index]))); docs.forEach(doc => map.delete(doc)); runInAction(() => { this._docs = docs.filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance.props.Document)).map(doc => ({ col: doc, target: this.props.doc })); this._otherDocs = Array.from(map.entries()).filter(entry => !Doc.AreProtosEqual(entry[0], CollectionDockingView.Instance.props.Document)).map(([col, target]) => ({ col, target })); }); } getOnClick({ col, target }: { col: Doc, target: Doc }) { return () => { col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col; if (NumCast(col.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { const newPanX = NumCast(target.x) + NumCast(target.width) / NumCast(target.zoomBasis, 1) / 2; const newPanY = NumCast(target.y) + NumCast(target.height) / NumCast(target.zoomBasis, 1) / 2; col.panX = newPanX; col.panY = newPanY; } CollectionDockingView.Instance.AddRightSplit(col, undefined); }; } render() { return (

Contexts:

{[...this._docs, ...this._otherDocs].map(doc => { let item = React.createRef(); return
doc.col, undefined, undefined, undefined, undefined, () => SearchBox.Instance.closeSearch())}>
{doc.col.title}
; })}
); } } export interface LinkMenuProps { doc1: Doc; doc2: Doc; } @observer export class LinkContextMenu extends React.Component { highlightDoc = (doc: Doc) => () => Doc.BrushDoc(doc); unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc); getOnClick = (col: Doc) => () => CollectionDockingView.Instance.AddRightSplit(col, undefined); render() { return (

Anchors:

Doc 1: {this.props.doc2.title}
Doc 2: {this.props.doc1.title}
); } } @observer export class SearchItem extends React.Component { @observable _selected: boolean = false; private _previewDoc?: Doc; onClick = () => { // I dont think this is the best functionality because clicking the name of the collection does that. Change it back if you'd like DocumentManager.Instance.jumpToDocument(this.props.doc, false); if (this.props.doc.data instanceof RichTextField) { this.highlightTextBox(this.props.doc); } // CollectionDockingView.Instance.AddRightSplit(this.props.doc, undefined); } @observable _useIcons = true; @observable _displayDim = 50; highlightTextBox = (doc: Doc) => { if (this.props.query) { const fieldkey = 'search_string'; if (Object.keys(doc).indexOf(fieldkey) === -1) { doc.search_string = this.props.query; } else { doc.search_string = undefined; } } } fitToBox = () => { let bounds = Doc.ComputeContentBounds([this.props.doc]); return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / Math.max((bounds.b - bounds.y), (bounds.r - bounds.x)), this._displayDim]; } componentWillUnmount() { if (this._previewDoc) { DocServer.DeleteDocument(this._previewDoc[Id]); } } //@computed @action public DocumentIcon() { let layoutresult = StrCast(this.props.doc.type); if (!this._useIcons) { let renderDoc = this.props.doc; //let box: number[] = []; if (layoutresult.indexOf(DocumentType.COL) !== -1) { renderDoc = Doc.MakeDelegate(renderDoc); let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => { var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; return { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) }; }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); let box = () => [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / (bounds.r - bounds.x), this._displayDim]; } let returnXDimension = () => this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); let returnYDimension = () => this._displayDim; let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension()); let newRenderDoc = Doc.MakeDelegate(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt this._previewDoc = newRenderDoc; const docview =
{ this._useIcons = !this._useIcons; this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); })} onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))} onPointerLeave={action(() => this._displayDim = 50)} >
; const data = renderDoc.data; if (data instanceof ObjectField) newRenderDoc.data = ObjectField.MakeCopy(data); newRenderDoc.preview = true; newRenderDoc.search_string = this.props.query; return docview; } if (this._previewDoc) { DocServer.DeleteDocument(this._previewDoc[Id]); } let button = layoutresult.indexOf(DocumentType.PDF) !== -1 ? faFilePdf : layoutresult.indexOf(DocumentType.IMG) !== -1 ? faImage : layoutresult.indexOf(DocumentType.TEXT) !== -1 ? faStickyNote : layoutresult.indexOf(DocumentType.VID) !== -1 ? faFilm : layoutresult.indexOf(DocumentType.COL) !== -1 ? faObjectGroup : layoutresult.indexOf(DocumentType.AUDIO) !== -1 ? faMusic : layoutresult.indexOf(DocumentType.LINK) !== -1 ? faLink : layoutresult.indexOf(DocumentType.HIST) !== -1 ? faChartBar : layoutresult.indexOf(DocumentType.WEB) !== -1 ? faGlobeAsia : faCaretUp; return
{ this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
; } collectionRef = React.createRef(); startDocDrag = () => { let doc = this.props.doc; const isProto = Doc.GetT(doc, "isPrototype", "boolean", true); if (isProto) { return Doc.MakeDelegate(doc); } else { return Doc.MakeAlias(doc); } } @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); } highlightDoc = (e: React.PointerEvent) => { if (this.props.doc.type === DocumentType.LINK) { if (this.props.doc.anchor1 && this.props.doc.anchor2) { let doc1 = Cast(this.props.doc.anchor1, Doc, null); let doc2 = Cast(this.props.doc.anchor2, Doc, null); Doc.BrushDoc(doc1); Doc.BrushDoc(doc2); } } else { DocumentManager.Instance.getAllDocumentViews(this.props.doc).forEach(element => Doc.BrushDoc(element.props.Document)); } } unHighlightDoc = (e: React.PointerEvent) => { if (this.props.doc.type === DocumentType.LINK) { if (this.props.doc.anchor1 && this.props.doc.anchor2) { let doc1 = Cast(this.props.doc.anchor1, Doc, null); let doc2 = Cast(this.props.doc.anchor2, Doc, null); Doc.UnBrushDoc(doc1); Doc.UnBrushDoc(doc2); } } else { DocumentManager.Instance.getAllDocumentViews(this.props.doc). forEach(element => Doc.UnBrushDoc(element.props.Document)); } } onContextMenu = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); ContextMenu.Instance.clearItems(); ContextMenu.Instance.addItem({ description: "Copy ID", event: () => { Utils.CopyText(this.props.doc[Id]); }, icon: "fingerprint" }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } onPointerDown = (e: React.PointerEvent) => { e.stopPropagation(); const doc = Doc.IsPrototype(this.props.doc) ? Doc.MakeDelegate(this.props.doc) : this.props.doc; DragManager.StartDocumentDrag([e.currentTarget], new DragManager.DocumentDragData([doc], []), e.clientX, e.clientY, { handlers: { dragComplete: emptyFunction }, hideSource: false, }); } render() { const doc1 = Cast(this.props.doc.anchor1, Doc); const doc2 = Cast(this.props.doc.anchor2, Doc); return (
{StrCast(this.props.doc.title)}
Matched fields: {this.props.highlighting.join(", ")}
{this.DocumentIcon()}
{this.props.doc.type ? this.props.doc.type : "Other"}
{this.linkCount}
{this.linkString}
{(doc1 instanceof Doc && doc2 instanceof Doc) && this.props.doc.type === DocumentType.LINK ? : }
); } }