diff options
| author | Tyler Schicke <tyler_schicke@brown.edu> | 2019-07-10 11:58:14 -0400 |
|---|---|---|
| committer | Tyler Schicke <tyler_schicke@brown.edu> | 2019-07-10 11:58:14 -0400 |
| commit | bb55fa2d6e4f9bec26b2eea3c2df50b7bc584c46 (patch) | |
| tree | 9138414f1880675084e852ce50ae4f42622e96d1 /src/client/views | |
| parent | dfd3427bf23c3c8df5c78fd3e993588800771269 (diff) | |
| parent | 2cd8ac79b4731ca98aafe8a92fa6fb132fe9e86f (diff) | |
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web
Diffstat (limited to 'src/client/views')
| -rw-r--r-- | src/client/views/EditableView.tsx | 9 | ||||
| -rw-r--r-- | src/client/views/Main.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/MainView.tsx | 4 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 60 | ||||
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx | 111 | ||||
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 26 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 5 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 36 | ||||
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 4 | ||||
| -rw-r--r-- | src/client/views/nodes/KeyValueBox.tsx | 79 |
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; } |
