aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-07-10 11:58:14 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-07-10 11:58:14 -0400
commitbb55fa2d6e4f9bec26b2eea3c2df50b7bc584c46 (patch)
tree9138414f1880675084e852ce50ae4f42622e96d1 /src/client/views
parentdfd3427bf23c3c8df5c78fd3e993588800771269 (diff)
parent2cd8ac79b4731ca98aafe8a92fa6fb132fe9e86f (diff)
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/EditableView.tsx9
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/collections/CollectionSubView.tsx60
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx111
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx26
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx5
-rw-r--r--src/client/views/nodes/DocumentView.tsx36
-rw-r--r--src/client/views/nodes/ImageBox.tsx4
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx79
10 files changed, 161 insertions, 175 deletions
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index f7aa6cc94..989fb1be9 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -14,7 +14,7 @@ export interface EditableProps {
* @param value - The string entered by the user to set the value to
* @returns `true` if setting the value was successful, `false` otherwise
* */
- SetValue(value: string): boolean;
+ SetValue(value: string, shiftDown?: boolean): boolean;
OnFillDown?(value: string): void;
@@ -53,7 +53,7 @@ export class EditableView extends React.Component<EditableProps> {
this.props.OnTab && this.props.OnTab();
} else if (e.key === "Enter") {
if (!e.ctrlKey) {
- if (this.props.SetValue(e.currentTarget.value)) {
+ if (this.props.SetValue(e.currentTarget.value, e.shiftKey)) {
this._editing = false;
}
} else if (this.props.OnFillDown) {
@@ -77,6 +77,11 @@ export class EditableView extends React.Component<EditableProps> {
e.stopPropagation();
}
+ @action
+ setIsFocused = (value: boolean) => {
+ this._editing = value;
+ }
+
render() {
if (this._editing) {
return <input className="editableView-input" defaultValue={this.props.GetValue()} onKeyDown={this.onKeyDown} autoFocus
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 3d9750a85..281d9159b 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -8,4 +8,4 @@ import * as React from 'react';
await Docs.initProtos();
await CurrentUserUtils.loadCurrentUser();
ReactDOM.render(<MainView />, document.getElementById('root'));
-})();
+})(); \ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 204503d7f..dd07fdc3a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -363,11 +363,13 @@ export class MainView extends React.Component {
let addColNode = action(() => Docs.FreeformDocument([], { width: this.pwidth * .7, height: this.pheight, title: "a freeform collection" }));
let addTreeNode = action(() => CurrentUserUtils.UserDocument);
let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" }));
+ let addImportCollectionNode = action(() => Docs.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 }));
let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [
[React.createRef<HTMLDivElement>(), "image", "Add Image", addImageNode],
[React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode],
[React.createRef<HTMLDivElement>(), "tree", "Add Tree", addTreeNode],
+ [React.createRef<HTMLDivElement>(), "arrow-up", "Import Directory", addImportCollectionNode],
];
return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} >
@@ -416,7 +418,7 @@ export class MainView extends React.Component {
return [
this.isSearchVisible ? <div className="main-searchDiv" key="search" style={{ top: '34px', right: '1px', position: 'absolute' }} > <FilterBox /> </div> : null,
<div className="main-buttonDiv" key="logout" style={{ bottom: '0px', right: '1px', position: 'absolute' }} ref={logoutRef}>
- <button onClick={() => request.get(DocServer.prepend(RouteStore.logout), emptyFunction)}>Log Out</button></div>
+ <button onClick={() => window.location.assign(DocServer.prepend(RouteStore.logout))}>Log Out</button></div>
];
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5287d3c13..873fb518c 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -19,6 +19,7 @@ import { CollectionPDFView } from "./CollectionPDFView";
import { CollectionVideoView } from "./CollectionVideoView";
import { CollectionView } from "./CollectionView";
import React = require("react");
+import { MainView } from "../MainView";
export interface CollectionViewProps extends FieldViewProps {
addDocument: (document: Doc, allowDuplicates?: boolean) => boolean;
@@ -67,10 +68,17 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
let email = CurrentUserUtils.email;
let pos = { x: position[0], y: position[1] };
if (id && email) {
- const proto = await doc.proto;
+ const proto = Doc.GetProto(doc);
if (!proto) {
return;
}
+ // The following conditional detects a recurring bug we've seen on the server
+ if (proto[Id] === "collectionProto") {
+ alert("COLLECTION PROTO CURSOR ISSUE DETECTED! Check console for more info...");
+ console.log(doc);
+ console.log(proto);
+ throw new Error(`AHA! You were trying to set a cursor on a collection's proto, which is the original collection proto! Look at the two previously printed lines for document values!`);
+ }
let cursors = Cast(proto.cursors, listSpec(CursorField));
if (!cursors) {
proto.cursors = cursors = new List<CursorField>();
@@ -108,47 +116,6 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
return false;
}
- protected async getDocumentFromType(type: string, path: string, options: DocumentOptions): Promise<Opt<Doc>> {
- let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise<Doc | undefined>)) | undefined = undefined;
- if (type.indexOf("image") !== -1) {
- ctor = Docs.ImageDocument;
- }
- if (type.indexOf("video") !== -1) {
- ctor = Docs.VideoDocument;
- }
- if (type.indexOf("audio") !== -1) {
- ctor = Docs.AudioDocument;
- }
- if (type.indexOf("pdf") !== -1) {
- ctor = Docs.PdfDocument;
- options.nativeWidth = 1200;
- }
- if (type.indexOf("excel") !== -1) {
- ctor = Docs.DBDocument;
- options.dropAction = "copy";
- }
- if (type.indexOf("html") !== -1) {
- if (path.includes(window.location.hostname)) {
- let s = path.split('/');
- let id = s[s.length - 1];
- DocServer.GetRefField(id).then(field => {
- if (field instanceof Doc) {
- let alias = Doc.MakeAlias(field);
- alias.x = options.x || 0;
- alias.y = options.y || 0;
- alias.width = options.width || 300;
- alias.height = options.height || options.width || 300;
- this.props.addDocument(alias, false);
- }
- });
- return undefined;
- }
- ctor = Docs.WebDocument;
- options = { height: options.width, ...options, title: path, nativeWidth: undefined };
- }
- return ctor ? ctor(path, options) : undefined;
- }
-
@undoBatch
@action
protected onDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
@@ -229,7 +196,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
.then(result => {
let type = result["content-type"];
if (type) {
- this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 })
+ Docs.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 })
.then(doc => doc && this.props.addDocument(doc, false));
}
});
@@ -250,10 +217,9 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
body: formData
}).then(async (res: Response) => {
(await res.json()).map(action((file: any) => {
- let path = window.location.origin + file;
- let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName });
-
- docPromise.then(doc => doc && this.props.addDocument(doc));
+ let full = { ...options, nativeWidth: 300, width: 300, title: dropFileName };
+ let path = DocServer.prepend(file);
+ Docs.getDocumentFromType(type, path, full).then(doc => doc && this.props.addDocument(doc));
}));
});
promises.push(prom);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index ebeb1fcee..2d94f1b8e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -17,58 +17,56 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
_brushReactionDisposer?: IReactionDisposer;
componentDidMount() {
- this._brushReactionDisposer = reaction(
- () => {
- let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
- return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
- },
- () => {
- let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
- let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
- views.forEach((dstDoc, i) => {
- views.forEach((srcDoc, j) => {
- let dstTarg = dstDoc;
- let srcTarg = srcDoc;
- let x1 = NumCast(srcDoc.x);
- let x2 = NumCast(dstDoc.x);
- let x1w = NumCast(srcDoc.width, -1) / NumCast(srcDoc.zoomBasis, 1);
- let x2w = NumCast(dstDoc.width, -1) / NumCast(srcDoc.zoomBasis, 1);
- if (x1w < 0 || x2w < 0 || i === j) { }
- else {
- let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
- let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
- return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
- });
- let brushAction = (field: (Doc | Promise<Doc>)[]) => {
- let found = findBrush(field);
- if (found !== -1) {
- console.log("REMOVE BRUSH " + srcTarg.title + " " + dstTarg.title);
- field.splice(found, 1);
- }
- };
- if (Math.abs(x1 + x1w - x2) < 20) {
- let linkDoc: Doc = new Doc();
- linkDoc.title = "Histogram Brush";
- linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
- linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
+ // this._brushReactionDisposer = reaction(
+ // () => {
+ // let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+ // return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
+ // },
+ // () => {
+ // let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+ // let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
+ // views.forEach((dstDoc, i) => {
+ // views.forEach((srcDoc, j) => {
+ // let dstTarg = dstDoc;
+ // let srcTarg = srcDoc;
+ // let x1 = NumCast(srcDoc.x);
+ // let x2 = NumCast(dstDoc.x);
+ // let x1w = NumCast(srcDoc.width, -1) / NumCast(srcDoc.zoomBasis, 1);
+ // let x2w = NumCast(dstDoc.width, -1) / NumCast(srcDoc.zoomBasis, 1);
+ // if (x1w < 0 || x2w < 0 || i === j) { }
+ // else {
+ // let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
+ // let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
+ // return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
+ // });
+ // let brushAction = (field: (Doc | Promise<Doc>)[]) => {
+ // let found = findBrush(field);
+ // if (found !== -1) {
+ // field.splice(found, 1);
+ // }
+ // };
+ // if (Math.abs(x1 + x1w - x2) < 20) {
+ // let linkDoc: Doc = new Doc();
+ // linkDoc.title = "Histogram Brush";
+ // linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
+ // linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
- brushAction = (field: (Doc | Promise<Doc>)[]) => {
- if (findBrush(field) === -1) {
- console.log("ADD BRUSH " + srcTarg.title + " " + dstTarg.title);
- field.push(linkDoc);
- }
- };
- }
- if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
- if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
- let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
- let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
- brushAction(dstBrushDocs);
- brushAction(srcBrushDocs);
- }
- });
- });
- });
+ // brushAction = (field: (Doc | Promise<Doc>)[]) => {
+ // if (findBrush(field) === -1) {
+ // field.push(linkDoc);
+ // }
+ // };
+ // }
+ // if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
+ // if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
+ // let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
+ // let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
+ // brushAction(dstBrushDocs);
+ // brushAction(srcBrushDocs);
+ // }
+ // });
+ // });
+ // });
}
componentWillUnmount() {
if (this._brushReactionDisposer) {
@@ -115,19 +113,16 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
});
return drawnPairs;
}, [] as { a: Doc, b: Doc, l: Doc[] }[]);
- return connections.map(c => {
- let x = c.l.reduce((p, l) => p + l[Id], "");
- return <CollectionFreeFormLinkView key={x} A={c.a} B={c.b} LinkDocs={c.l}
- removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />;
- });
+ return connections.map(c => <CollectionFreeFormLinkView key={c.l.reduce((p, l) => p + l[Id], "")} A={c.a} B={c.b} LinkDocs={c.l}
+ removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />);
}
render() {
return (
<div className="collectionfreeformlinksview-container">
- <svg className="collectionfreeformlinksview-svgCanvas">
+ {/* <svg className="collectionfreeformlinksview-svgCanvas">
{this.uniqueConnections}
- </svg>
+ </svg> */}
{this.props.children}
</div>
);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c83e1e3f5..8a619bfae 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,7 +1,7 @@
import * as htmlToImage from "html-to-image";
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc } from "../../../../new_fields/Doc";
+import { Doc, FieldResult } from "../../../../new_fields/Doc";
import { Id } from "../../../../new_fields/FieldSymbols";
import { InkField, StrokeData } from "../../../../new_fields/InkField";
import { List } from "../../../../new_fields/List";
@@ -224,6 +224,18 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
}
+ get ink() {
+ let container = this.props.container.Document;
+ let containerKey = this.props.container.props.fieldKey;
+ return Cast(container[containerKey + "_ink"], InkField);
+ }
+
+ set ink(value: InkField | undefined) {
+ let container = Doc.GetProto(this.props.container.Document);
+ let containerKey = this.props.container.props.fieldKey;
+ container[containerKey + "_ink"] = value;
+ }
+
@undoBatch
@action
marqueeCommand = async (e: KeyboardEvent) => {
@@ -235,9 +247,8 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
e.stopPropagation();
(e as any).propagationIsStopped = true;
this.marqueeSelect().map(d => this.props.removeDocument(d));
- let ink = Cast(this.props.container.props.Document.ink, InkField);
- if (ink) {
- this.marqueeInkDelete(ink.inkData);
+ if (this.ink) {
+ this.marqueeInkDelete(this.ink.inkData);
}
SelectionManager.DeselectAll();
this.cleanupInteractions(false);
@@ -259,8 +270,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
return d;
});
}
- let ink = Cast(this.props.container.props.Document.ink, InkField);
- let inkData = ink ? ink.inkData : undefined;
+ let inkData = this.ink ? this.ink.inkData : undefined;
let newCollection = Docs.FreeformDocument(selected, {
x: bounds.left,
y: bounds.top,
@@ -269,9 +279,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white",
width: bounds.width,
height: bounds.height,
- ink: inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined,
title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection",
});
+ newCollection.data_ink = inkData ? new InkField(this.marqueeInkSelect(inkData)) : undefined;
this.marqueeInkDelete(inkData);
if (e.key === "s") {
@@ -348,7 +358,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let idata = new Map();
ink.forEach((value: StrokeData, key: string, map: any) =>
!InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
- Doc.SetOnPrototype(this.props.container.props.Document, "ink", new InkField(idata));
+ this.ink = new InkField(idata);
}
}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 745520bc4..eb786d537 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -24,6 +24,7 @@ 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 { CollectionViewType } from "../collections/CollectionBaseView";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -68,7 +69,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
// this document as the data document for the layout.
return this.props.Document;
}
- return this.props.DataDoc
+ return this.props.DataDoc;
}
get layoutDoc() {
// if this document's layout field contains a document (ie, a rendering template), then we will use that
@@ -123,7 +124,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
if (this.props.renderDepth > 7) return (null);
if (!this.layout && (this.props.layoutKey !== "overlayLayout" || !this.templates.length)) return (null);
return <ObserverJsxParser
- components={{ FormattedTextBox, ImageBox, IconBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
+ components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }}
bindings={this.CreateBindings()}
jsx={this.finalLayout}
showWarnings={true}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 47ec3b5a1..430409ee3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -339,30 +339,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
else if (linkedDocs.length) {
- let linkedDoc = linkedDocs.length ? linkedDocs[0] : expandedDocs[0];
- let linkedPages = [linkedDocs.length ? NumCast(linkedDocs[0].anchor1Page, undefined) : NumCast(linkedDocs[0].anchor2Page, undefined),
- linkedDocs.length ? NumCast(linkedDocs[0].anchor2Page, undefined) : NumCast(linkedDocs[0].anchor1Page, undefined)];
- let maxLocation = StrCast(linkedDoc.maximizeLocation, "inTab");
- DocumentManager.Instance.jumpToDocument(linkedDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, maxLocation), linkedPages[altKey ? 1 : 0]);
-
- // else if (linkedToDocs.length || linkedFromDocs.length) {
- // let linkedFwdDocs = [
- // linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : expandedDocs[0],
- // linkedFromDocs.length ? linkedFromDocs[0].linkedFrom as Doc : linkedToDocs.length ? linkedToDocs[0].linkedTo as Doc : expandedDocs[0]];
-
- // let linkedFwdContextDocs = [
- // linkedToDocs.length ? await (linkedToDocs[0].linkedToContext) as Doc : linkedFromDocs.length ? await PromiseValue(linkedFromDocs[0].linkedFromContext) as Doc : undefined,
- // linkedFromDocs.length ? await (linkedFromDocs[0].linkedFromContext) as Doc : linkedToDocs.length ? await PromiseValue(linkedToDocs[0].linkedToContext) as Doc : undefined];
-
- // let linkedFwdPage = [
- // linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : undefined,
- // linkedFromDocs.length ? NumCast(linkedFromDocs[0].linkedFromPage, undefined) : linkedToDocs.length ? NumCast(linkedToDocs[0].linkedToPage, undefined) : undefined];
-
- // if (!linkedFwdDocs.some(l => l instanceof Promise)) {
- // let maxLocation = StrCast(linkedFwdDocs[altKey ? 1 : 0].maximizeLocation, "inTab");
- // let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined;
- // DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, document => this.props.addDocTab(document, undefined, maxLocation), linkedFwdPage[altKey ? 1 : 0], targetContext);
- // }
+ let first = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor1 as Doc, this.props.Document));
+ let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : [expandedDocs[0], expandedDocs[0]];
+
+ let linkedFwdContextDocs = [first.length ? await (first[0].context) as Doc : undefined, undefined];
+
+ let linkedFwdPage = [first.length ? NumCast(first[0].linkedToPage, undefined) : undefined, undefined];
+
+ if (!linkedFwdDocs.some(l => l instanceof Promise)) {
+ let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab");
+ let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined;
+ DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, document => this.props.addDocTab(document, undefined, maxLocation), linkedFwdPage[altKey ? 1 : 0], targetContext);
+ }
}
}
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b9cecdd24..f0363d0b8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -216,7 +216,9 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
}), 0);
}
})
- .catch((err: any) => console.log(err));
+ .catch((err: any) => {
+ console.log(err);
+ });
}
render() {
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 9407d742c..2f5a0f963 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -8,7 +8,7 @@ import "./KeyValueBox.scss";
import { KeyValuePair } from "./KeyValuePair";
import React = require("react");
import { NumCast, Cast, FieldValue, StrCast } from "../../../new_fields/Types";
-import { Doc, Field, FieldResult } from "../../../new_fields/Doc";
+import { Doc, Field, FieldResult, DocListCastAsync } from "../../../new_fields/Doc";
import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
import { SetupDrag } from "../../util/DragManager";
import { Docs } from "../../documents/Documents";
@@ -18,6 +18,8 @@ import { List } from "../../../new_fields/List";
import { TextField } from "../../util/ProsemirrorCopy/prompt";
import { RichTextField } from "../../../new_fields/RichTextField";
import { ImageField } from "../../../new_fields/URLField";
+import { SelectionManager } from "../../util/SelectionManager";
+import { listSpec } from "../../../new_fields/Schema";
@observer
export class KeyValueBox extends React.Component<FieldViewProps> {
@@ -159,7 +161,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
getTemplate = async () => {
let parent = Docs.StackingDocument([], { width: 800, height: 800, title: "Template" });
parent.singleColumn = false;
- parent.columnWidth = 50;
+ parent.columnWidth = 100;
for (let row of this.rows.filter(row => row.isChecked)) {
await this.createTemplateField(parent, row);
row.uncheck();
@@ -167,45 +169,60 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
return parent;
}
- createTemplateField = async (parent: Doc, row: KeyValuePair) => {
- let collectionKeyProp = `fieldKey={"data"}`;
+ createTemplateField = async (parentStackingDoc: Doc, row: KeyValuePair) => {
let metaKey = row.props.keyName;
- let metaKeyProp = `fieldKey={"${metaKey}"}`;
-
let sourceDoc = await Cast(this.props.Document.data, Doc);
if (!sourceDoc) {
return;
}
- let target = this.inferType(sourceDoc[metaKey], metaKey);
-
- let template = Doc.MakeAlias(target);
- template.proto = parent;
- template.title = metaKey;
- template.nativeWidth = 0;
- template.nativeHeight = 0;
- template.embed = true;
- template.isTemplate = true;
- template.templates = new List<string>([Templates.TitleBar(metaKey)]);
- if (target.backgroundLayout) {
- let metaAnoKeyProp = `fieldKey={"${metaKey}"} fieldExt={"annotations"}`;
- let collectionAnoKeyProp = `fieldKey={"annotations"}`;
- template.layout = StrCast(target.layout).replace(collectionAnoKeyProp, metaAnoKeyProp);
- template.backgroundLayout = StrCast(target.backgroundLayout).replace(collectionKeyProp, metaKeyProp);
- } else {
- template.layout = StrCast(target.layout).replace(collectionKeyProp, metaKeyProp);
+
+ let fieldTemplate = await this.inferType(sourceDoc[metaKey], metaKey);
+ let previousViewType = fieldTemplate.viewType;
+
+ // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
+ let backgroundLayout = StrCast(fieldTemplate.backgroundLayout);
+ let layout = StrCast(fieldTemplate.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
+ if (backgroundLayout) {
+ layout = StrCast(fieldTemplate.layout).replace(/fieldKey={"annotations"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`);
+ backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
}
- Doc.AddDocToList(parent, "data", template);
- row.uncheck();
+ let nw = NumCast(fieldTemplate.nativeWidth);
+ let nh = NumCast(fieldTemplate.nativeHeight);
+
+ fieldTemplate.title = metaKey;
+ fieldTemplate.layout = layout;
+ fieldTemplate.backgroundLayout = backgroundLayout;
+ fieldTemplate.nativeWidth = nw;
+ fieldTemplate.nativeHeight = nh;
+ fieldTemplate.embed = true;
+ fieldTemplate.isTemplate = true;
+ fieldTemplate.templates = new List<string>([Templates.TitleBar(metaKey)]);
+ fieldTemplate.proto = Doc.GetProto(parentStackingDoc);
+ previousViewType && (fieldTemplate.viewType = previousViewType);
+
+ Cast(parentStackingDoc.data, listSpec(Doc))!.push(fieldTemplate);
}
- inferType = (field: FieldResult, metaKey: string) => {
+ inferType = async (data: FieldResult, metaKey: string) => {
let options = { width: 300, height: 300, title: metaKey };
- if (field instanceof RichTextField || typeof field === "string" || typeof field === "number") {
+ if (data instanceof RichTextField || typeof data === "string" || typeof data === "number") {
return Docs.TextDocument(options);
- } else if (field instanceof List) {
- return Docs.StackingDocument([], options);
- } else if (field instanceof ImageField) {
- return Docs.ImageDocument("https://www.freepik.com/free-icon/picture-frame-with-mountain-image_748687.htm", options);
+ } else if (data instanceof List) {
+ if (data.length === 0) {
+ return Docs.StackingDocument([], options);
+ }
+ let first = await Cast(data[0], Doc);
+ if (!first) {
+ return Docs.StackingDocument([], options);
+ }
+ switch (first.type) {
+ case "image":
+ return Docs.StackingDocument([], options);
+ case "text":
+ return Docs.TreeDocument([], options);
+ }
+ } else if (data instanceof ImageField) {
+ return Docs.ImageDocument("https://image.flaticon.com/icons/png/512/23/23765.png", options);
}
return new Doc;
}