From af59d641022119e25402f1f13ae2c3f3eb4c20a2 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Mon, 16 Sep 2019 14:39:44 -0400
Subject: initial commit

---
 src/client/views/nodes/DocumentContentsView.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index d77662355..c8a636727 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -29,6 +29,7 @@ import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
 import { List } from "../../../new_fields/List";
 import { Doc } from "../../../new_fields/Doc";
 import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
+import { RecommendationsBox } from "../../views/Recommendations";
 import { ScriptField } from "../../../new_fields/ScriptField";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -108,7 +109,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         if (!this.layout && (this.props.layoutKey !== "overlayLayout" || !this.templates.length)) return (null);
         return <ObserverJsxParser
             blacklistedAttrs={[]}
-            components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox }}
+            components={{ FormattedTextBox, ImageBox, RecommendationsBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox }}
             bindings={this.CreateBindings()}
             jsx={this.finalLayout}
             showWarnings={true}
-- 
cgit v1.2.3-70-g09d2


From c6e2eee8e5b035ed4cab1e7bb1315a36d43255c5 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Tue, 8 Oct 2019 16:02:25 -0400
Subject: switching out

---
 src/client/views/MainView.tsx                           |  1 -
 src/client/views/Recommendations.tsx                    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx       |  3 ---
 src/client/views/nodes/DocumentContentsView.tsx         |  6 ------
 src/client/views/nodes/DocumentView.tsx                 |  4 ++--
 src/client/views/nodes/ImageBox.tsx                     |  1 -
 src/new_fields/RichTextField.ts                         | 17 ++++++++++++++++-
 7 files changed, 19 insertions(+), 15 deletions(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 17de708a2..e6f500e75 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -41,7 +41,6 @@ import { FilterBox } from './search/FilterBox';
 import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
 //import { DocumentManager } from '../util/DocumentManager';
 import { RecommendationsBox } from './Recommendations';
-import PresModeMenu from './presentationview/PresentationModeMenu';
 import { PresBox } from './nodes/PresBox';
 import { OverlayView } from './OverlayView';
 
diff --git a/src/client/views/Recommendations.tsx b/src/client/views/Recommendations.tsx
index b7b1d84d0..c44dfc032 100644
--- a/src/client/views/Recommendations.tsx
+++ b/src/client/views/Recommendations.tsx
@@ -174,7 +174,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                                 {this.DocumentIcon(doc)}
                             </span>
                             <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, true, undefined, undefined, undefined, this.props.Document.sourceDocContext as Doc)}>
+                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
                                 <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
                             </div>
                             <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink(this.props.Document.sourceDoc as Doc, doc, undefined, "User Selected Link", "Generated from Recommender", undefined)}>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3ee069e4c..d2b8afa02 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -12,7 +12,6 @@ import { BoolCast, Cast, DateCast, NumCast, StrCast } from "../../../../new_fiel
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { aggregateBounds, emptyFunction, intersectRect, returnEmptyString, returnOne, Utils } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
-import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { DocumentManager } from "../../../util/DocumentManager";
@@ -28,7 +27,6 @@ import { InkingCanvas } from "../../InkingCanvas";
 import { CollectionFreeFormDocumentView, positionSchema } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { documentSchema, DocumentViewProps } from "../../nodes/DocumentView";
-import { FormattedTextBox } from "../../nodes/FormattedTextBox";
 import { pageSchema } from "../../nodes/ImageBox";
 import PDFMenu from "../../pdf/PDFMenu";
 import { CollectionSubView } from "../CollectionSubView";
@@ -41,7 +39,6 @@ import React = require("react");
 import v5 = require("uuid/v5");
 import { ClientRecommender } from "../../../ClientRecommender";
 import { SearchUtil } from "../../../util/SearchUtil";
-import { SearchBox } from "../../SearchBox";
 import { RouteStore } from "../../../../server/RouteStore";
 import { string, number, elementType } from "prop-types";
 import { DocServer } from "../../../DocServer";
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index e5eb8dbce..919c13055 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -2,8 +2,6 @@ import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../new_fields/Doc";
 import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast } from "../../../new_fields/Types";
-import { OmitKeys, Without } from "../../../Utils";
 import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
 import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
@@ -30,14 +28,10 @@ import { PresElementBox } from "../presentationview/PresElementBox";
 import { VideoBox } from "./VideoBox";
 import { WebBox } from "./WebBox";
 import React = require("react");
-import { FieldViewProps } from "./FieldView";
 import { Without, OmitKeys } from "../../../Utils";
 import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
 import { List } from "../../../new_fields/List";
-import { Doc } from "../../../new_fields/Doc";
-import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
 import { RecommendationsBox } from "../../views/Recommendations";
-import { ScriptField } from "../../../new_fields/ScriptField";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 type BindingProps = Without<FieldViewProps, 'fieldKey'>;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0064b98c3..070b1f426 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -621,7 +621,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         recommendations.documentIconHeight = 150;
         recommendations.sourceDoc = this.props.Document;
         recommendations.sourceDocContext = this.props.ContainingCollectionView!.props.Document;
-        CollectionDockingView.Instance.AddRightSplit(recommendations, undefined);
+        CollectionDockingView.AddRightSplit(recommendations, undefined);
 
         // RecommendationsBox.Instance.displayRecommendations(e.pageX + 100, e.pageY);
     }
@@ -641,7 +641,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             body.href = urls[i];
             bodies.push(body);
         }
-        CollectionDockingView.Instance.AddRightSplit(Docs.Create.SchemaDocument(headers, bodies, { title: `Showing External Recommendations for "${StrCast(doc.title)}"` }), undefined);
+        CollectionDockingView.AddRightSplit(Docs.Create.SchemaDocument(headers, bodies, { title: `Showing External Recommendations for "${StrCast(doc.title)}"` }), undefined);
     }
 
     onPointerEnter = (e: React.PointerEvent): void => { Doc.BrushDoc(this.props.Document); };
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index f36b9895f..7ffe64b9b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -29,7 +29,6 @@ import "./ImageBox.scss";
 import React = require("react");
 import { SearchUtil } from '../../util/SearchUtil';
 import { ClientRecommender } from '../../ClientRecommender';
-import { DocumentType } from '../../documents/Documents';
 var requestImageSize = require('../../util/request-image-size');
 var path = require('path');
 const { Howl } = require('howler');
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index 390045ee1..f41ea0350 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,6 +4,9 @@ import { Deserializable } from "../client/util/SerializationHelper";
 import { Copy, ToScriptString, ToPlainText } from "./FieldSymbols";
 import { scriptingGlobal } from "../client/util/Scripting";
 
+const delimiter = "\n";
+const joiner = "";
+
 @scriptingGlobal
 @Deserializable("RichTextField")
 export class RichTextField extends ObjectField {
@@ -24,7 +27,19 @@ export class RichTextField extends ObjectField {
     }
 
     [ToPlainText]() {
-        return this.Data;
+        // Because we're working with plain text, just concatenate all paragraphs
+        let content = JSON.parse(this.Data).doc.content;
+        let paragraphs = content.filter((item: any) => item.type === "paragraph");
+
+        // Functions to flatten ProseMirror paragraph objects (and their components) to plain text
+        // While this function already exists in state.doc.textBeteen(), it doesn't account for newlines 
+        let blockText = (block: any) => block.text;
+        let concatenateParagraph = (p: any) => (p.content ? p.content.map(blockText).join(joiner) : "") + delimiter;
+
+        // Concatentate paragraphs and string the result together
+        let textParagraphs: string[] = paragraphs.map(concatenateParagraph);
+        let plainText = textParagraphs.join(joiner);
+        return plainText.substring(0, plainText.length - 1);
     }
 
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 3a2ade7686c587ce8666d5c8be7a0be432d025d3 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Wed, 9 Oct 2019 17:09:29 -0400
Subject: fixed JSX parser registration for recommendation box in document
 contents view

---
 src/client/views/nodes/DocumentContentsView.tsx | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 919c13055..43abc30a1 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -29,8 +29,7 @@ import { VideoBox } from "./VideoBox";
 import { WebBox } from "./WebBox";
 import React = require("react");
 import { Without, OmitKeys } from "../../../Utils";
-import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
-import { List } from "../../../new_fields/List";
+import { Cast } from "../../../new_fields/Types";
 import { RecommendationsBox } from "../../views/Recommendations";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
@@ -103,7 +102,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         if (!this.layout && this.props.layoutKey !== "overlayLayout") return (null);
         return <ObserverJsxParser
             blacklistedAttrs={[]}
-            components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox }}
+            components={{ FormattedTextBox, RecommendationsBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox }}
             bindings={this.CreateBindings()}
             jsx={this.finalLayout}
             showWarnings={true}
-- 
cgit v1.2.3-70-g09d2


From 301784883375860a7c693db97fe8f279e5380caf Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Sat, 19 Oct 2019 16:51:45 -0400
Subject: image stuff

---
 src/client/ClientRecommender.tsx                |   3 +-
 src/client/documents/Documents.ts               |   2 +-
 src/client/views/GlobalKeyHandler.ts            |   2 +-
 src/client/views/MainView.tsx                   |   2 +-
 src/client/views/Recommendations.scss           |  68 ---------
 src/client/views/Recommendations.tsx            | 185 ------------------------
 src/client/views/RecommendationsBox.scss        |  68 +++++++++
 src/client/views/RecommendationsBox.tsx         | 185 ++++++++++++++++++++++++
 src/client/views/nodes/DocumentContentsView.tsx |   4 +-
 src/client/views/nodes/DocumentView.tsx         |   2 +-
 10 files changed, 261 insertions(+), 260 deletions(-)
 delete mode 100644 src/client/views/Recommendations.scss
 delete mode 100644 src/client/views/Recommendations.tsx
 create mode 100644 src/client/views/RecommendationsBox.scss
 create mode 100644 src/client/views/RecommendationsBox.tsx

(limited to 'src/client/views/nodes/DocumentContentsView.tsx')

diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 73b05cf1a..97efedd89 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -12,6 +12,7 @@ import "./ClientRecommender.scss";
 import { JSXElement } from "babel-types";
 import { RichTextField } from "../new_fields/RichTextField";
 import { ToPlainText } from "../new_fields/FieldSymbols";
+import { listSpec } from "../new_fields/Schema";
 
 export interface RecommenderProps {
     title: string;
@@ -148,7 +149,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
     public async extractText(dataDoc: Doc, extDoc: Doc, internal: boolean = true, isMainDoc: boolean = false, image: boolean = false) {
         let fielddata = Cast(dataDoc.data, RichTextField);
         if (image && extDoc.generatedTags) {
-            console.log(StrCast(extDoc.generatedTags));
+            console.log(Cast(extDoc.generatedTags, listSpec("string")));
         }
         let data: string;
         fielddata ? data = fielddata[ToPlainText]() : data = "";
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1179f0238..36f20199c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -43,7 +43,7 @@ import { PresBox } from "../views/nodes/PresBox";
 import { ComputedField, ScriptField } from "../../new_fields/ScriptField";
 import { ProxyField } from "../../new_fields/Proxy";
 import { DocumentType } from "./DocumentTypes";
-import { RecommendationsBox } from "../views/Recommendations";
+import { RecommendationsBox } from "../views/RecommendationsBox";
 //import { PresBox } from "../views/nodes/PresBox";
 //import { PresField } from "../../new_fields/PresField";
 import { LinkFollowBox } from "../views/linking/LinkFollowBox";
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 189e2bbe0..b0d0a0d28 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -6,7 +6,7 @@ import { DragManager } from "../util/DragManager";
 import { action, runInAction } from "mobx";
 import { Doc } from "../../new_fields/Doc";
 import { DictationManager } from "../util/DictationManager";
-import { RecommendationsBox } from "./Recommendations";
+import { RecommendationsBox } from "./RecommendationsBox";
 import SharingManager from "../util/SharingManager";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 import { Cast, PromiseValue } from "../../new_fields/Types";
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bfd9c2163..2b47c2534 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -38,7 +38,7 @@ import { PreviewCursor } from './PreviewCursor';
 import { FilterBox } from './search/FilterBox';
 import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
 //import { DocumentManager } from '../util/DocumentManager';
-import { RecommendationsBox } from './Recommendations';
+import { RecommendationsBox } from './RecommendationsBox';
 import { PresBox } from './nodes/PresBox';
 import { OverlayView } from './OverlayView';
 
diff --git a/src/client/views/Recommendations.scss b/src/client/views/Recommendations.scss
deleted file mode 100644
index dd8a105f6..000000000
--- a/src/client/views/Recommendations.scss
+++ /dev/null
@@ -1,68 +0,0 @@
-@import "globalCssVariables";
-
-.rec-content *{
-    display: inline-block;
-    margin: auto;
-    width: 50;
-    height: 150px;
-    border: 1px dashed grey;
-    padding: 10px 10px;
-}
-
-.rec-content {
-    float: left;
-    width: inherit;
-    align-content: center;
-}
-
-.rec-scroll {
-    overflow-y: scroll;
-    overflow-x: hidden;
-    position: absolute;
-    pointer-events: all;
-    // display: flex;
-    z-index: 10000;
-    box-shadow: gray 0.2vw 0.2vw 0.4vw;
-    // flex-direction: column;
-    background: whitesmoke;
-    padding-bottom: 10px;
-    padding-top: 20px;
-    // border-radius: 15px;
-    border: solid #BBBBBBBB 1px;
-    width: 100%;
-    text-align: center;
-    // max-height: 250px;
-    height: 100%;
-    text-transform: uppercase;
-    color: grey;
-    letter-spacing: 2px;
-}
-
-.content {
-    padding: 10px;
-    display: flex;
-    flex-direction: row;
-    align-items: center;
-    justify-content: center;
-}
-
-.image-background {
-    pointer-events: none;
-    background-color: transparent;
-    width: 50%;
-    text-align: center;
-    margin-left: 5px;
-}
-
-img{
-    width: 100%;
-    height: 100%;
-}
-
-.score {
-    // margin-left: 15px;
-    width: 50%;
-    height: 100%;
-    text-align: center;
-    margin-left: 10px;
-}
diff --git a/src/client/views/Recommendations.tsx b/src/client/views/Recommendations.tsx
deleted file mode 100644
index f965d655b..000000000
--- a/src/client/views/Recommendations.tsx
+++ /dev/null
@@ -1,185 +0,0 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { observable, action } from "mobx";
-import Measure from "react-measure";
-import "./Recommendations.scss";
-import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
-import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast } from "../../new_fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { ObjectField } from "../../new_fields/ObjectField";
-import { DocumentView } from "./nodes/DocumentView";
-import { DocumentType } from '../documents/DocumentTypes';
-import { ClientRecommender } from "../ClientRecommender";
-import { DocServer } from "../DocServer";
-import { Id } from "../../new_fields/FieldSymbols";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { DocumentManager } from "../util/DocumentManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { DocUtils } from "../documents/Documents";
-
-export interface RecProps {
-    documents: { preview: Doc, similarity: number }[];
-    node: Doc;
-}
-
-library.add(faBullseye, faLink);
-
-@observer
-export class RecommendationsBox extends React.Component<FieldViewProps> {
-
-    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
-
-    static Instance: RecommendationsBox;
-    // @observable private _display: boolean = false;
-    @observable private _pageX: number = 0;
-    @observable private _pageY: number = 0;
-    @observable private _width: number = 0;
-    @observable private _height: number = 0;
-    // @observable private _documents: { preview: Doc, score: number }[] = [];
-    private previewDocs: Doc[] = [];
-
-    constructor(props: FieldViewProps) {
-        super(props);
-        RecommendationsBox.Instance = this;
-    }
-
-    private DocumentIcon(doc: Doc) {
-        let layoutresult = StrCast(doc.type);
-        let renderDoc = 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 returnXDimension = () => 150;
-        let returnYDimension = () => 150;
-        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
-        //let scale = () => 1;
-        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
-        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
-        newRenderDoc.autoHeight = false;
-        const docview = <div>
-            <DocumentView
-                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
-                Document={newRenderDoc}
-                addDocument={returnFalse}
-                removeDocument={returnFalse}
-                ruleProvider={undefined}
-                ScreenToLocalTransform={Transform.Identity}
-                addDocTab={returnFalse}
-                pinToPres={returnFalse}
-                renderDepth={1}
-                PanelWidth={returnXDimension}
-                PanelHeight={returnYDimension}
-                focus={emptyFunction}
-                backgroundColor={returnEmptyString}
-                parentActive={returnFalse}
-                whenActiveChanged={returnFalse}
-                bringToFront={emptyFunction}
-                zoomToScale={emptyFunction}
-                getScale={returnOne}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                ContentScaling={scale}
-            />
-        </div>;
-        return docview;
-
-    }
-
-    // @action
-    // closeMenu = () => {
-    //     this._display = false;
-    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
-    //     this.previewDocs = [];
-    // }
-
-    // @action
-    // resetDocuments = () => {
-    //     this._documents = [];
-    // }
-
-    // @action
-    // displayRecommendations(x: number, y: number) {
-    //     this._pageX = x;
-    //     this._pageY = y;
-    //     this._display = true;
-    // }
-
-    static readonly buffer = 20;
-
-    // get pageX() {
-    //     const x = this._pageX;
-    //     if (x < 0) {
-    //         return 0;
-    //     }
-    //     const width = this._width;
-    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
-    //         return window.innerWidth - RecommendationsBox.buffer - width;
-    //     }
-    //     return x;
-    // }
-
-    // get pageY() {
-    //     const y = this._pageY;
-    //     if (y < 0) {
-    //         return 0;
-    //     }
-    //     const height = this._height;
-    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
-    //         return window.innerHeight - RecommendationsBox.buffer - height;
-    //     }
-    //     return y;
-    // }
-
-    render() {
-        // if (!this._display) {
-        //     return null;
-        // }
-        // let style = { left: this.pageX, top: this.pageY };
-        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
-        let title = StrCast((this.props.Document.sourceDoc as Doc).title);
-        if (title.length > 15) {
-            title = title.substring(0, 15) + "...";
-        }
-        return (
-            // <Measure offset onResize={action((r: any) => { this._width = r.offset.width; this._height = r.offset.height; })}>
-            // {({ measureRef }) => (
-            <div className="rec-scroll">
-                <p>Recommendations for "{title}"</p>
-                {DocListCast(this.props.Document.data).map(doc => {
-                    return (
-                        <div className="content">
-                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
-                                {this.DocumentIcon(doc)}
-                            </span>
-                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
-                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
-                            </div>
-                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
-                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
-                            </div>
-                        </div>
-                    );
-                })}
-
-            </div>
-            // );
-            // }
-
-            // </Measure>
-        );
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/RecommendationsBox.scss b/src/client/views/RecommendationsBox.scss
new file mode 100644
index 000000000..dd8a105f6
--- /dev/null
+++ b/src/client/views/RecommendationsBox.scss
@@ -0,0 +1,68 @@
+@import "globalCssVariables";
+
+.rec-content *{
+    display: inline-block;
+    margin: auto;
+    width: 50;
+    height: 150px;
+    border: 1px dashed grey;
+    padding: 10px 10px;
+}
+
+.rec-content {
+    float: left;
+    width: inherit;
+    align-content: center;
+}
+
+.rec-scroll {
+    overflow-y: scroll;
+    overflow-x: hidden;
+    position: absolute;
+    pointer-events: all;
+    // display: flex;
+    z-index: 10000;
+    box-shadow: gray 0.2vw 0.2vw 0.4vw;
+    // flex-direction: column;
+    background: whitesmoke;
+    padding-bottom: 10px;
+    padding-top: 20px;
+    // border-radius: 15px;
+    border: solid #BBBBBBBB 1px;
+    width: 100%;
+    text-align: center;
+    // max-height: 250px;
+    height: 100%;
+    text-transform: uppercase;
+    color: grey;
+    letter-spacing: 2px;
+}
+
+.content {
+    padding: 10px;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: center;
+}
+
+.image-background {
+    pointer-events: none;
+    background-color: transparent;
+    width: 50%;
+    text-align: center;
+    margin-left: 5px;
+}
+
+img{
+    width: 100%;
+    height: 100%;
+}
+
+.score {
+    // margin-left: 15px;
+    width: 50%;
+    height: 100%;
+    text-align: center;
+    margin-left: 10px;
+}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
new file mode 100644
index 000000000..3938a8690
--- /dev/null
+++ b/src/client/views/RecommendationsBox.tsx
@@ -0,0 +1,185 @@
+import { observer } from "mobx-react";
+import React = require("react");
+import { observable, action } from "mobx";
+import Measure from "react-measure";
+import "./RecommendationsBox.scss";
+import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
+import { DocumentIcon } from "./nodes/DocumentIcon";
+import { StrCast, NumCast } from "../../new_fields/Types";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { ObjectField } from "../../new_fields/ObjectField";
+import { DocumentView } from "./nodes/DocumentView";
+import { DocumentType } from '../documents/DocumentTypes';
+import { ClientRecommender } from "../ClientRecommender";
+import { DocServer } from "../DocServer";
+import { Id } from "../../new_fields/FieldSymbols";
+import { FieldView, FieldViewProps } from "./nodes/FieldView";
+import { DocumentManager } from "../util/DocumentManager";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
+import { DocUtils } from "../documents/Documents";
+
+export interface RecProps {
+    documents: { preview: Doc, similarity: number }[];
+    node: Doc;
+}
+
+library.add(faBullseye, faLink);
+
+@observer
+export class RecommendationsBox extends React.Component<FieldViewProps> {
+
+    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
+
+    static Instance: RecommendationsBox;
+    // @observable private _display: boolean = false;
+    @observable private _pageX: number = 0;
+    @observable private _pageY: number = 0;
+    @observable private _width: number = 0;
+    @observable private _height: number = 0;
+    // @observable private _documents: { preview: Doc, score: number }[] = [];
+    private previewDocs: Doc[] = [];
+
+    constructor(props: FieldViewProps) {
+        super(props);
+        RecommendationsBox.Instance = this;
+    }
+
+    private DocumentIcon(doc: Doc) {
+        let layoutresult = StrCast(doc.type);
+        let renderDoc = 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 returnXDimension = () => 150;
+        let returnYDimension = () => 150;
+        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+        //let scale = () => 1;
+        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+        newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
+        newRenderDoc.autoHeight = false;
+        const docview = <div>
+            <DocumentView
+                fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
+                Document={newRenderDoc}
+                addDocument={returnFalse}
+                removeDocument={returnFalse}
+                ruleProvider={undefined}
+                ScreenToLocalTransform={Transform.Identity}
+                addDocTab={returnFalse}
+                pinToPres={returnFalse}
+                renderDepth={1}
+                PanelWidth={returnXDimension}
+                PanelHeight={returnYDimension}
+                focus={emptyFunction}
+                backgroundColor={returnEmptyString}
+                parentActive={returnFalse}
+                whenActiveChanged={returnFalse}
+                bringToFront={emptyFunction}
+                zoomToScale={emptyFunction}
+                getScale={returnOne}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                ContentScaling={scale}
+            />
+        </div>;
+        return docview;
+
+    }
+
+    // @action
+    // closeMenu = () => {
+    //     this._display = false;
+    //     this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
+    //     this.previewDocs = [];
+    // }
+
+    // @action
+    // resetDocuments = () => {
+    //     this._documents = [];
+    // }
+
+    // @action
+    // displayRecommendations(x: number, y: number) {
+    //     this._pageX = x;
+    //     this._pageY = y;
+    //     this._display = true;
+    // }
+
+    static readonly buffer = 20;
+
+    // get pageX() {
+    //     const x = this._pageX;
+    //     if (x < 0) {
+    //         return 0;
+    //     }
+    //     const width = this._width;
+    //     if (x + width > window.innerWidth - RecommendationsBox.buffer) {
+    //         return window.innerWidth - RecommendationsBox.buffer - width;
+    //     }
+    //     return x;
+    // }
+
+    // get pageY() {
+    //     const y = this._pageY;
+    //     if (y < 0) {
+    //         return 0;
+    //     }
+    //     const height = this._height;
+    //     if (y + height > window.innerHeight - RecommendationsBox.buffer) {
+    //         return window.innerHeight - RecommendationsBox.buffer - height;
+    //     }
+    //     return y;
+    // }
+
+    render() {
+        // if (!this._display) {
+        //     return null;
+        // }
+        // let style = { left: this.pageX, top: this.pageY };
+        //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
+        let title = StrCast((this.props.Document.sourceDoc as Doc).title);
+        if (title.length > 15) {
+            title = title.substring(0, 15) + "...";
+        }
+        return (
+            // <Measure offset onResize={action((r: any) => { this._width = r.offset.width; this._height = r.offset.height; })}>
+            // {({ measureRef }) => (
+            <div className="rec-scroll">
+                <p>Recommendations for "{title}"</p>
+                {DocListCast(this.props.Document.data).map(doc => {
+                    return (
+                        <div className="content">
+                            <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
+                                {this.DocumentIcon(doc)}
+                            </span>
+                            <span className="score">{NumCast(doc.score).toFixed(4)}</span>
+                            <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
+                            </div>
+                            <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
+                                <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
+                            </div>
+                        </div>
+                    );
+                })}
+
+            </div>
+            // );
+            // }
+
+            // </Measure>
+        );
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 32d74b193..01096e5e5 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -31,7 +31,7 @@ import { WebBox } from "./WebBox";
 import React = require("react");
 import { Without, OmitKeys } from "../../../Utils";
 import { Cast } from "../../../new_fields/Types";
-import { RecommendationsBox } from "../../views/Recommendations";
+import { RecommendationsBox } from "../RecommendationsBox";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -96,7 +96,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 components={{
                     FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, FontIconBox: FontIconBox, ButtonBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
-                    PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox, ColorBox, DocuLinkBox
+                    PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox, ColorBox, DocuLinkBox, RecommendationsBox
                 }}
                 bindings={this.CreateBindings()}
                 jsx={this.layout}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 56a399139..bc7cef650 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -34,7 +34,7 @@ import "./DocumentView.scss";
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require("react");
 import requestPromise = require('request-promise');
-import { RecommendationsBox } from '../Recommendations';
+import { RecommendationsBox } from '../RecommendationsBox';
 import { SearchUtil } from '../../util/SearchUtil';
 import { ClientRecommender } from '../../ClientRecommender';
 import { DocumentType } from '../../documents/DocumentTypes';
-- 
cgit v1.2.3-70-g09d2

