aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/search/SearchItem.tsx
diff options
context:
space:
mode:
authorab <abdullah_ahmed@brown.edu>2019-07-01 15:40:55 -0400
committerab <abdullah_ahmed@brown.edu>2019-07-01 15:40:55 -0400
commit0fc7edd5f9bd1234f8de6e5b1c7b8f23668d784c (patch)
tree2ddff97c032657fb86de37c3be2cf2d201980088 /src/client/views/search/SearchItem.tsx
parent4f8b7cecea3ceed6861c38bde9ce03c9c46e2d09 (diff)
parent6bd79baf2d9301304194d87667bb5c66c17e5298 (diff)
Merge branch 'monikasearch2' of https://github.com/browngraphicslab/Dash-Web into text_box_ab
Diffstat (limited to 'src/client/views/search/SearchItem.tsx')
-rw-r--r--src/client/views/search/SearchItem.tsx191
1 files changed, 153 insertions, 38 deletions
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 5160d9469..f4ea3ee09 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -1,24 +1,26 @@
import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faMusic, faLink, faChartBar, faGlobeAsia } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Cast, NumCast } from "../../../new_fields/Types";
-import { observable, runInAction, computed, action } from "mobx";
-import { listSpec } from "../../../new_fields/Schema";
-import { Doc } from "../../../new_fields/Doc";
+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 { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { emptyFunction, returnFalse, returnOne } from "../../../Utils";
+import { DocTypes } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { SetupDrag } from "../../util/DragManager";
+import { LinkManager } from "../../util/LinkManager";
import { SearchUtil } from "../../util/SearchUtil";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { observer } from "mobx-react";
-import "./SearchItem.scss";
+import { Transform } from "../../util/Transform";
+import { SEARCH_THUMBNAIL_SIZE } from "../../views/globalCssVariables.scss";
import { CollectionViewType } from "../collections/CollectionBaseView";
-import { DocTypes } from "../../documents/Documents";
-import { FilterBox } from "./FilterBox";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
import { DocumentView } from "../nodes/DocumentView";
-import "./SelectorContextMenu.scss";
import { SearchBox } from "./SearchBox";
+import "./SearchItem.scss";
+import "./SelectorContextMenu.scss";
export interface SearchItemProps {
doc: Doc;
@@ -69,18 +71,63 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
CollectionDockingView.Instance.AddRightSplit(col, undefined);
};
}
-
render() {
return (
- < div className="parents">
+ <div className="parents">
<p className="contexts">Contexts:</p>
- {this._docs.map(doc => <div className="collection"><a className="title" onClick={this.getOnClick(doc)}>{doc.col.title}</a></div>)}
- {this._otherDocs.map(doc => <div className="collection"><a className="title" onClick={this.getOnClick(doc)}>{doc.col.title}</a></div>)}
+ {[...this._docs, ...this._otherDocs].map(doc => {
+ let item = React.createRef<HTMLDivElement>();
+ return <div className="collection" key={doc.col[Id] + doc.target[Id]} ref={item}>
+ <div className="collection-item" onPointerDown={
+ SetupDrag(item, () => doc.col, undefined, undefined, undefined, undefined, () => SearchBox.Instance.closeSearch())}>
+ <FontAwesomeIcon icon={faStickyNote} />
+ </div>
+ <a onClick={this.getOnClick(doc)}>{doc.col.title}</a>
+ </div>;
+ })}
</div>
);
}
}
+export interface LinkMenuProps {
+ doc1: Doc;
+ doc2: Doc;
+}
+
+@observer
+export class LinkContextMenu extends React.Component<LinkMenuProps> {
+
+ highlightDoc = (doc: Doc) => {
+ return () => {
+ doc.libraryBrush = true;
+ };
+ }
+
+ unHighlightDoc = (doc: Doc) => {
+ return () => {
+ doc.libraryBrush = false;
+ };
+ }
+
+ getOnClick(col: Doc) {
+ return () => {
+ CollectionDockingView.Instance.AddRightSplit(col, undefined);
+ };
+ }
+
+ render() {
+ return (
+ <div className="parents">
+ <p className="contexts">Anchors:</p>
+ <div className = "collection"><a onMouseEnter = {this.highlightDoc(this.props.doc1)} onMouseLeave = {this.unHighlightDoc(this.props.doc1)} onClick = {this.getOnClick(this.props.doc1)}>Doc 1: {this.props.doc2.title}</a></div>
+ <div><a onMouseEnter = {this.highlightDoc(this.props.doc2)} onMouseLeave = {this.unHighlightDoc(this.props.doc2)} onClick = {this.getOnClick(this.props.doc2)}>Doc 2: {this.props.doc1.title}</a></div>
+ </div>
+ )
+ }
+
+}
+
@observer
export class SearchItem extends React.Component<SearchItemProps> {
@@ -89,10 +136,56 @@ export class SearchItem extends React.Component<SearchItemProps> {
onClick = () => {
DocumentManager.Instance.jumpToDocument(this.props.doc, false);
}
+ @observable _useIcons = true;
+ @observable _displayDim = 50;
@computed
public get DocumentIcon() {
- let layoutresult = Cast(this.props.doc.type, "string", "");
+ let layoutresult = StrCast(this.props.doc.type);
+ if (!this._useIcons) {
+ let renderDoc = this.props.doc;
+ let box: number[] = [];
+ if (layoutresult.indexOf(DocTypes.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 });
+ 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());
+ return <div
+ onPointerDown={action(() => { 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)} >
+ <DocumentView
+ fitToBox={box}
+ Document={renderDoc}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ addDocTab={returnFalse}
+ renderDepth={1}
+ PanelWidth={returnXDimension}
+ PanelHeight={returnYDimension}
+ focus={emptyFunction}
+ selectOnLoad={false}
+ parentActive={returnFalse}
+ whenActiveChanged={returnFalse}
+ bringToFront={emptyFunction}
+ zoomToScale={emptyFunction}
+ getScale={returnOne}
+ ContainingCollectionView={undefined}
+ ContentScaling={scale}
+ />
+ </div>;
+ }
let button = layoutresult.indexOf(DocTypes.PDF) !== -1 ? faFilePdf :
layoutresult.indexOf(DocTypes.IMG) !== -1 ? faImage :
@@ -104,7 +197,9 @@ export class SearchItem extends React.Component<SearchItemProps> {
layoutresult.indexOf(DocTypes.HIST) !== -1 ? faChartBar :
layoutresult.indexOf(DocTypes.WEB) !== -1 ? faGlobeAsia :
faCaretUp;
- return <FontAwesomeIcon icon={button} size="2x" />;
+ return <div onPointerDown={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
+ <FontAwesomeIcon icon={button} size="2x" />
+ </div>;
}
collectionRef = React.createRef<HTMLDivElement>();
@@ -119,7 +214,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
}
@computed
- get linkCount() { return Cast(this.props.doc.linkedToDocs, listSpec(Doc), []).length + Cast(this.props.doc.linkedFromDocs, listSpec(Doc), []).length; }
+ get linkCount() { return LinkManager.Instance.getAllRelatedLinks(this.props.doc).length; }
@computed
get linkString(): string {
@@ -130,45 +225,65 @@ export class SearchItem extends React.Component<SearchItemProps> {
return num.toString() + " links";
}
- pointerDown = (e: React.PointerEvent) => { SearchBox.Instance.openSearch(e); };
+ @action
+ pointerDown = (e: React.PointerEvent) => SearchBox.Instance.openSearch(e)
highlightDoc = (e: React.PointerEvent) => {
- let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
- docViews.forEach(element => {
- element.props.Document.libraryBrush = true;
- });
+ if (this.props.doc.type === DocTypes.LINK) {
+ if (this.props.doc.anchor1 && this.props.doc.anchor2) {
+
+ let doc1 = Cast(this.props.doc.anchor1, Doc, new Doc());
+ let doc2 = Cast(this.props.doc.anchor2, Doc, new Doc());
+ doc1.libraryBrush = true;
+ doc2.libraryBrush = true;
+ }
+ } else {
+ let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
+ docViews.forEach(element => {
+ element.props.Document.libraryBrush = true;
+ });
+ }
}
unHighlightDoc = (e: React.PointerEvent) => {
- let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
- docViews.forEach(element => {
- element.props.Document.libraryBrush = false;
- });
+ if (this.props.doc.type === DocTypes.LINK) {
+ if (this.props.doc.anchor1 && this.props.doc.anchor2) {
+
+ let doc1 = Cast(this.props.doc.anchor1, Doc, new Doc());
+ let doc2 = Cast(this.props.doc.anchor2, Doc, new Doc());
+ doc1.libraryBrush = false;
+ doc2.libraryBrush = false;
+ }
+ } else {
+ let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
+ docViews.forEach(element => {
+ element.props.Document.libraryBrush = false;
+ });
+ }
}
render() {
return (
<div className="search-overview" onPointerDown={this.pointerDown}>
- <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} ref={this.collectionRef} id="result" onClick={this.onClick} onPointerDown={() => {
- this.pointerDown;
- SetupDrag(this.collectionRef, this.startDocDrag);
- }} >
+ <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} ref={this.collectionRef} id="result"
+ onClick={this.onClick} onPointerDown={this.pointerDown} >
<div className="main-search-info">
<div className="search-title" id="result" >{this.props.doc.title}</div>
- <div className="search-info">
+ <div className="search-info" style={{ width: this._useIcons ? "15%" : "400px" }}>
+ <div className={`icon-${this._useIcons ? "icons" : "live"}`}>
+ <div className="search-type" >{this.DocumentIcon}</div>
+ <div className="search-label">{this.props.doc.type}</div>
+ </div>
<div className="link-container item">
<div className="link-count">{this.linkCount}</div>
<div className="link-extended">{this.linkString}</div>
</div>
- <div className="icon">
- <div className="search-type" >{this.DocumentIcon}</div>
- <div className="search-label">{this.props.doc.type}</div>
- </div>
</div>
</div>
</div>
<div className="searchBox-instances">
- <SelectorContextMenu {...this.props} />
+ {this.props.doc.type === DocTypes.LINK ? <LinkContextMenu doc1 = {Cast(this.props.doc.anchor1, Doc, new Doc())} doc2 = {Cast(this.props.doc.anchor2, Doc, new Doc())}/> :
+ <SelectorContextMenu {...this.props} /> }
</div>
</div>
);