aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2019-05-10 23:01:08 -0400
committerBob Zeleznik <zzzman@gmail.com>2019-05-10 23:01:08 -0400
commit7da76d2538ebde21d7a878b5096d5a673e5d6375 (patch)
tree0ec7a4599fdbebb19de9d25ca8fbe30136bffd19 /src
parent464843e773022edc9a6ce6228b88ffb72021fa85 (diff)
added summary screen grab icon as a template view of a text document. converted Cast(...ListSpec(Doc)) pattern to DocListCast
Diffstat (limited to 'src')
-rw-r--r--src/client/northstar/dash-nodes/HistogramBox.tsx10
-rw-r--r--src/client/util/DocumentManager.ts6
-rw-r--r--src/client/util/DragManager.ts6
-rw-r--r--src/client/views/PresentationView.tsx11
-rw-r--r--src/client/views/Templates.tsx35
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx8
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx6
-rw-r--r--src/client/views/collections/CollectionSubView.tsx4
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx22
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx12
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx24
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx28
-rw-r--r--src/client/views/nodes/DocumentView.tsx23
-rw-r--r--src/client/views/nodes/IconBox.tsx4
-rw-r--r--src/client/views/nodes/ImageBox.tsx14
-rw-r--r--src/client/views/nodes/LinkMenu.tsx6
-rw-r--r--src/new_fields/Doc.ts10
17 files changed, 137 insertions, 92 deletions
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 5e7b867b3..ed556cf45 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -19,7 +19,7 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
import { StyleConstants } from "../utils/StyleContants";
import { NumCast, Cast } from "../../../new_fields/Types";
import { listSpec } from "../../../new_fields/Schema";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/RefField";
@@ -117,15 +117,15 @@ export class HistogramBox extends React.Component<FieldViewProps> {
runInAction(() => {
this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty;
if (this.HistoOp !== HistogramOperation.Empty) {
- reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
- reaction(() => Cast(this.props.Document.brushingDocs, listSpec(Doc), []).length,
+ reaction(() => DocListCast(this.props.Document.linkedFromDocs), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
+ reaction(() => DocListCast(this.props.Document.brushingDocs).length,
() => {
- let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ let brushingDocs = DocListCast(this.props.Document.brushingDocs);
const proto = this.props.Document.proto;
if (proto) {
this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => {
brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length];
- let brushed = Cast(brush.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ let brushed = DocListCast(brush.brushingDocs);
return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] };
}));
}
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index a8b643d4d..9a7a94228 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,6 +1,6 @@
import { computed, observable } from 'mobx';
import { DocumentView } from '../views/nodes/DocumentView';
-import { Doc } from '../../new_fields/Doc';
+import { Doc, DocListCast } from '../../new_fields/Doc';
import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types';
import { listSpec } from '../../new_fields/Schema';
import { undoBatch } from './UndoManager';
@@ -73,7 +73,7 @@ export class DocumentManager {
@computed
public get LinkedDocumentViews() {
return DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => {
- let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ let linksList = DocListCast(dv.props.Document.linkedToDocs);
if (linksList && linksList.length) {
pairs.push(...linksList.reduce((pairs, link) => {
if (link) {
@@ -86,7 +86,7 @@ export class DocumentManager {
return pairs;
}, [] as { a: DocumentView, b: DocumentView, l: Doc }[]));
}
- linksList = Cast(dv.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ linksList = DocListCast(dv.props.Document.linkedFromDocs);
if (linksList && linksList.length) {
pairs.push(...linksList.reduce((pairs, link) => {
if (link) {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index c0402f0c9..2da0d5b51 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,5 +1,5 @@
import { action, runInAction } from "mobx";
-import { Doc, DocListCast } from "../../new_fields/Doc";
+import { Doc, DocListCastAsync } from "../../new_fields/Doc";
import { Cast } from "../../new_fields/Types";
import { emptyFunction } from "../../Utils";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
@@ -43,8 +43,8 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n
let draggedDocs: Doc[] = [];
let draggedFromDocs: Doc[] = []
if (srcTarg) {
- let linkToDocs = await DocListCast(srcTarg.linkedToDocs);
- let linkFromDocs = await DocListCast(srcTarg.linkedFromDocs);
+ let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs);
+ let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs);
if (linkToDocs) draggedDocs = linkToDocs.map(linkDoc => Cast(linkDoc.linkedTo, Doc) as Doc);
if (linkFromDocs) draggedFromDocs = linkFromDocs.map(linkDoc => Cast(linkDoc.linkedFrom, Doc) as Doc);
}
diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx
index 4853eb151..3fb24a339 100644
--- a/src/client/views/PresentationView.tsx
+++ b/src/client/views/PresentationView.tsx
@@ -141,8 +141,15 @@ export class PresentationView extends React.Component<PresViewProps> {
(activeW) => {
if (activeW && activeW instanceof Doc) {
PromiseValue(Cast(activeW.presentationView, Doc)).
- then(pv => runInAction(() =>
- self.Document = pv ? pv : (activeW.presentationView = new Doc())))
+ then(pv => runInAction(() => {
+ if (pv) self.Document = pv;
+ else {
+ pv = new Doc();
+ pv.title = "Presentation Doc";
+ activeW.presentationView = pv;
+ self.Document = pv;
+ }
+ }))
}
},
{ fireImmediately: true });
diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx
index bbedc95f1..a98870b04 100644
--- a/src/client/views/Templates.tsx
+++ b/src/client/views/Templates.tsx
@@ -5,6 +5,7 @@ export enum TemplatePosition {
InnerBottom,
InnerRight,
InnerLeft,
+ TopRight,
OutterTop,
OutterBottom,
OutterRight,
@@ -39,30 +40,42 @@ export namespace Templates {
// export const BasicLayout = new Template("Basic layout", "{layout}");
export const Caption = new Template("Caption", TemplatePosition.OutterBottom,
- `<div id="screenSpace" style="top: 100%; font-size:14px; background:yellow; width:100%; position:absolute"><FormattedTextBox {...props} fieldKey={"caption"} /></div>`
- );
+ `<div id="screenSpace" style="top: 100%; font-size:14px; background:yellow; width:100%; position:absolute">
+ <FormattedTextBox {...props} fieldKey={"caption"} />
+ </div>` );
+
export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop,
- `<div><div style="height:100%; width:100%;position:absolute;">{layout}</div>
- <div style="height:25px; width:100%; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white; ">
- <span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
- </div></div>`
- );
+ `<div>
+ <div style="height:100%; width:100%;position:absolute;">{layout}</div>
+ <div style="height:25px; width:100%; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white; ">
+ <span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
+ </div>
+ </div>` );
+
export const Title = new Template("Title", TemplatePosition.InnerTop,
`<div><div style="height:calc(100% - 25px); margin-top: 25px; width:100%;position:absolute;">{layout}</div>
<div style="height:25px; width:100%; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white; ">
<span style="text-align:center;width:100%;font-size:20px;position:absolute;overflow:hidden;white-space:nowrap;text-overflow:ellipsis">{props.Document.title}</span>
- </div></div>`
- );
+ </div></div>` );
export const Bullet = new Template("Bullet", TemplatePosition.InnerTop,
`<div><div style="height:100%; width:100%;position:absolute;">{layout}</div>
- <div id="isBullet" style="height:15px; width:15px; margin-left:-16px; pointer-events:all; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white;">
- <img id="isBullet" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAZlBMVEX///8AAABmZmb7+/tYWFhgYGBFRUVSUlL4+Pg/Pz9jY2N5eXmcnJyioqKBgYFzc3NtbW1LS0s3NzfW1taWlpaOjo6IiIgvLy9WVlampqZcXFw5OTlvb28mJiYxMTHe3t7l5eUjIyMY8kIZAAAD2UlEQVR4nO2d61biMBRGW1FBEVHxfp15/5ecOVa5lHxtArmck/Xtn1BotjtNoXQtm4YQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEFIrX6UHEA1gsmrneceRjHm7cj28attKFOf/TRyKIliH4vzbZE+xE2zbZYkxRWX5Y9JT/BW0X3G+NtlR3Ahar7jcMtlS3Ba0XXG+Y7JW3BW0XHHZM/lR7AvaVewL/ijuC1pV3Bf8VnQJ2lR0CYriq/Nxg4puwfa1aZ7dz9yUHnEgN26NZ3luWkPFd7fEtHsWVDwpO+YgTgYKCuYn6tAU7TBecaygcGpZEQie7m5luKJPQQFUvCwx5iAuvQoK4KShvSIoOHVtCz7dnOUecxBn7kG/urc2eCz6T9EOcxXDCgpAUetyAwoOCBqrGF5QMKR4mCA8L+pTBIJwkRl95eifJjPHTDYTFQ8vePyrs3BsBfXLzfFHkvKKMY4j1ctNnCmmuGKslfCQT0RZiPdFVmnFmOcy36sDWYn7DU9hxdifRkKuEGQh/pWW0K/QiUlxtUxVxTTXyhQtN6kuI6mpmO5qpxJFIBjl1yMVimmvV4PfrnIq3iYsKICTRj7F9L84gIq38fYwCCj4HnMfRY/FPL8ZFayYo6BQbLlJeZrYpVDFXAUFcMtKWkUgmOhmnwKKOQsK4NaxdIp5CwqZj8X8gv27jNecJ9nZuXtnie/SzjhRQcHkt6Fnq1imoAAUY1csVVDIUrFcQSGDIhC8jriLQZIrli0oXKdVLF1QSFqxfEEBVLyI8NYXCgoKySaqhinakajimxrBRBX1FBQSVNRyDP4SXVGbYHRFfYJN8xhTESwyj5HHHEjEihoLCqDiXfAb3aksKESqCAoqEIxUUW9BAS03E+93mOhcZDYcXVF3QeHBPcI3v4qo4EPiUQcBKr75vHaiv6AAKt6NV0SCqgoKqOKYovpFZgOo+DmsOHkyUlA4ZKKamaIdQPEJK5oqKKCKM7D9zFZBIayiuYICWm5cFWef7o3vs486CP8VdQIEVRcU7sFE7VecgSmqvKDgVxEJqi8ogIof2xVnH2YLCuMT1fAU7RirOPtrXHCsovmCwlDFCgoKWNH4IrMBTdQ/NUzRjiu3CeCq9HAPAVSspaDgX9FkQcG3ollB34qGBf0UTQv6KBoXHFc0LzimWIFg0ywGBBelBxcHXLGKggKqWElBwV2xIkF3xaoEXYqVCe4rVifYV3wpPZwULOouKLzUXVBY1F1QeKm7oLCoXVAqVi7YNM7/F0YIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCG+/ANh4i1CHdc63QAAAABJRU5ErkJggg=="
+ <div id="isExpander" style="height:15px; width:15px; margin-left:-16px; pointer-events:all; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white;">
+ <img id="isExpander" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAZlBMVEX///8AAABmZmb7+/tYWFhgYGBFRUVSUlL4+Pg/Pz9jY2N5eXmcnJyioqKBgYFzc3NtbW1LS0s3NzfW1taWlpaOjo6IiIgvLy9WVlampqZcXFw5OTlvb28mJiYxMTHe3t7l5eUjIyMY8kIZAAAD2UlEQVR4nO2d61biMBRGW1FBEVHxfp15/5ecOVa5lHxtArmck/Xtn1BotjtNoXQtm4YQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEFIrX6UHEA1gsmrneceRjHm7cj28attKFOf/TRyKIliH4vzbZE+xE2zbZYkxRWX5Y9JT/BW0X3G+NtlR3Ahar7jcMtlS3Ba0XXG+Y7JW3BW0XHHZM/lR7AvaVewL/ijuC1pV3Bf8VnQJ2lR0CYriq/Nxg4puwfa1aZ7dz9yUHnEgN26NZ3luWkPFd7fEtHsWVDwpO+YgTgYKCuYn6tAU7TBecaygcGpZEQie7m5luKJPQQFUvCwx5iAuvQoK4KShvSIoOHVtCz7dnOUecxBn7kG/urc2eCz6T9EOcxXDCgpAUetyAwoOCBqrGF5QMKR4mCA8L+pTBIJwkRl95eifJjPHTDYTFQ8vePyrs3BsBfXLzfFHkvKKMY4j1ctNnCmmuGKslfCQT0RZiPdFVmnFmOcy36sDWYn7DU9hxdifRkKuEGQh/pWW0K/QiUlxtUxVxTTXyhQtN6kuI6mpmO5qpxJFIBjl1yMVimmvV4PfrnIq3iYsKICTRj7F9L84gIq38fYwCCj4HnMfRY/FPL8ZFayYo6BQbLlJeZrYpVDFXAUFcMtKWkUgmOhmnwKKOQsK4NaxdIp5CwqZj8X8gv27jNecJ9nZuXtnie/SzjhRQcHkt6Fnq1imoAAUY1csVVDIUrFcQSGDIhC8jriLQZIrli0oXKdVLF1QSFqxfEEBVLyI8NYXCgoKySaqhinakajimxrBRBX1FBQSVNRyDP4SXVGbYHRFfYJN8xhTESwyj5HHHEjEihoLCqDiXfAb3aksKESqCAoqEIxUUW9BAS03E+93mOhcZDYcXVF3QeHBPcI3v4qo4EPiUQcBKr75vHaiv6AAKt6NV0SCqgoKqOKYovpFZgOo+DmsOHkyUlA4ZKKamaIdQPEJK5oqKKCKM7D9zFZBIayiuYICWm5cFWef7o3vs486CP8VdQIEVRcU7sFE7VecgSmqvKDgVxEJqi8ogIof2xVnH2YLCuMT1fAU7RirOPtrXHCsovmCwlDFCgoKWNH4IrMBTdQ/NUzRjiu3CeCq9HAPAVSspaDgX9FkQcG3ollB34qGBf0UTQv6KBoXHFc0LzimWIFg0ywGBBelBxcHXLGKggKqWElBwV2xIkF3xaoEXYqVCe4rVifYV3wpPZwULOouKLzUXVBY1F1QeKm7oLCoXVAqVi7YNM7/F0YIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCG+/ANh4i1CHdc63QAAAABJRU5ErkJggg=="
width="15px" height="15px"/>
</div>
</div>`
);
+ export function ImageOverlay(width: number, height: number, field: string = "thumbnail") {
+ return (`<div>
+ <div style="height:100%; width:100%;position:absolute;">{layout}</div>
+ <div style="width:${width}px; height:${height}px; top:0; right:0; background:rgba(0,0,0,0.25); position:absolute;overflow:hidden;">
+ <ImageBox id="isExpander" {...props} PanelWidth={${width}} fieldKey={"${field}"} />
+ </div>
+ </div>`);
+ }
+
export const TemplateList: Template[] = [Title, TitleOverlay, Caption, Bullet];
export function sortTemplates(a: Template, b: Template) {
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 2b1f7bb37..645296d27 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
import { ContextMenu } from '../ContextMenu';
import { FieldViewProps } from '../nodes/FieldView';
import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types';
-import { Doc, FieldResult, Opt } from '../../../new_fields/Doc';
+import { Doc, FieldResult, Opt, DocListCast } from '../../../new_fields/Doc';
import { listSpec } from '../../../new_fields/Schema';
import { List } from '../../../new_fields/List';
import { Id } from '../../../new_fields/RefField';
@@ -63,13 +63,13 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
if (!(documentToAdd instanceof Doc)) {
return false;
}
- let data = Cast(documentToAdd.data, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
- for (const doc of data.filter(d => d instanceof Document)) {
+ let data = DocListCast(documentToAdd.data);
+ for (const doc of data) {
if (this.createsCycle(doc, containerDocument)) {
return true;
}
}
- let annots = Cast(documentToAdd.annotations, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ let annots = DocListCast(documentToAdd.annotations);
for (const annot of annots) {
if (this.createsCycle(annot, containerDocument)) {
return true;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index ae949b2ed..506e60a65 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -19,7 +19,7 @@ import { DocumentView } from "../nodes/DocumentView";
import { FieldView, FieldViewProps } from "../nodes/FieldView";
import "./CollectionSchemaView.scss";
import { CollectionSubView } from "./CollectionSubView";
-import { Opt, Field, Doc, DocListCast } from "../../../new_fields/Doc";
+import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc";
import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
import { listSpec } from "../../../new_fields/Schema";
import { List } from "../../../new_fields/List";
@@ -118,7 +118,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
}
const run = script.run;
//TODO This should be able to be refactored to compile the script once
- const val = await DocListCast(this.props.Document[this.props.fieldKey])
+ const val = await DocListCastAsync(this.props.Document[this.props.fieldKey])
val && val.forEach(doc => applyToDoc(doc, run));
}}>
</EditableView>
@@ -276,7 +276,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
}
get documentKeysCheckList() {
- const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ const docs = DocListCast(this.props.Document[this.props.fieldKey]);
let keys: { [key: string]: boolean } = {};
// bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields.
// then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 0b08e150a..a86d250bd 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -10,7 +10,7 @@ import * as rp from 'request-promise';
import { CollectionView } from "./CollectionView";
import { CollectionPDFView } from "./CollectionPDFView";
import { CollectionVideoView } from "./CollectionVideoView";
-import { Doc, Opt, FieldResult } from "../../../new_fields/Doc";
+import { Doc, Opt, FieldResult, DocListCast } from "../../../new_fields/Doc";
import { DocComponent } from "../DocComponent";
import { listSpec } from "../../../new_fields/Schema";
import { Cast, PromiseValue, FieldValue, ListSpec } from "../../../new_fields/Types";
@@ -49,7 +49,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
get children() {
//TODO tfs: This might not be what we want?
//This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue)
- return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)).map(doc => doc as Doc);
+ return DocListCast(this.props.Document[this.props.fieldKey]);
}
@action
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 33787f06b..78c84cc89 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -18,9 +18,7 @@ import { Main } from '../Main';
import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
import { CollectionDockingView } from './CollectionDockingView';
import { DocumentManager } from '../../util/DocumentManager';
-import { Utils } from '../../../Utils';
import { List } from '../../../new_fields/List';
-import { indexOf } from 'typescript-collections/dist/lib/arrays';
export interface TreeViewProps {
@@ -155,16 +153,21 @@ class TreeView extends React.Component<TreeViewProps> {
let keys = Array.from(Object.keys(this.props.document));
if (this.props.document.proto instanceof Doc) {
keys.push(...Array.from(Object.keys(this.props.document.proto)));
+ while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
}
keys.map(key => {
- let docList = Cast(this.props.document[key], listSpec(Doc));
- if (docList instanceof List && docList.length && docList[0] instanceof Doc) {
+ let docList = DocListCast(this.props.document[key]);
+ let doc = Cast(this.props.document[key], Doc);
+ if (doc instanceof Doc || docList.length) {
if (!this._collapsed) {
bulletType = BulletType.Collapsible;
+ let spacing = (key === "data") ? 0 : -10;
contentElement.push(<ul key={key + "more"}>
{(key === "data") ? (null) :
- <span className="collectionTreeView-keyHeader" key={key}>{key}</span>}
- {TreeView.GetChildElements(docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
+ <span className="collectionTreeView-keyHeader" style={{ display: "block", marginTop: "7px" }} key={key}>{key}</span>}
+ <div style={{ display: "block", marginTop: `${spacing}px` }}>
+ {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
+ </div>
</ul >);
} else
bulletType = BulletType.Collapsed;
@@ -179,7 +182,7 @@ class TreeView extends React.Component<TreeViewProps> {
</li>
</div>;
}
- public static GetChildElements(docs: (Doc | Promise<Doc>)[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) {
+ public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) {
return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child =>
<TreeView document={child as Doc} key={(child as Doc)[Id]} deleteDoc={remove} moveDocument={move} dropAction={dropAction} />);
}
@@ -203,12 +206,11 @@ export class CollectionTreeView extends CollectionSubView(Document) {
}
}
render() {
- const children = this.children;
let dropAction = StrCast(this.props.Document.dropAction, "alias") as dropActionType;
- if (!children) {
+ if (!this.children) {
return (null);
}
- let childElements = TreeView.GetChildElements(children, false, this.remove, this.props.moveDocument, dropAction);
+ let childElements = TreeView.GetChildElements(this.children, false, this.remove, this.props.moveDocument, dropAction);
return (
<div id="body" className="collectionTreeView-dropTarget"
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 62b1456cf..d5ce4e1e7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -7,7 +7,7 @@ import { CollectionViewProps } from "../CollectionSubView";
import "./CollectionFreeFormLinksView.scss";
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
-import { Doc, DocListCast } from "../../../../new_fields/Doc";
+import { Doc, DocListCastAsync, DocListCast } from "../../../../new_fields/Doc";
import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types";
import { listSpec } from "../../../../new_fields/Schema";
import { List } from "../../../../new_fields/List";
@@ -20,11 +20,11 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
componentDidMount() {
this._brushReactionDisposer = reaction(
() => {
- let doclist = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []);
- return { doclist: doclist ? doclist : [], xs: doclist instanceof List ? doclist.map(d => d instanceof Doc && d.x) : [] };
+ let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+ return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
},
- async () => {
- let doclist = await DocListCast(this.props.Document[this.props.fieldKey]);
+ () => {
+ 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) => {
@@ -84,7 +84,7 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
}
if (view.props.ContainingCollectionView) {
let collid = view.props.ContainingCollectionView.props.Document[Id];
- Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc).
+ DocListCast(this.props.Document[this.props.fieldKey]).
filter(child =>
child[Id] === collid).map(view =>
DocumentManager.Instance.getDocumentViews(view).map(view =>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1bf39e335..9ace0272a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,3 +1,4 @@
+import * as htmlToImage from "html-to-image";
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Docs } from "../../../documents/Documents";
@@ -14,6 +15,8 @@ import { Doc } from "../../../../new_fields/Doc";
import { NumCast, Cast } from "../../../../new_fields/Types";
import { InkField, StrokeData } from "../../../../new_fields/InkField";
import { List } from "../../../../new_fields/List";
+import { ImageField } from "../../../../new_fields/URLField";
+import { Template, Templates } from "../../Templates";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -30,6 +33,7 @@ interface MarqueeViewProps {
@observer
export class MarqueeView extends React.Component<MarqueeViewProps>
{
+ private _mainCont = React.createRef<HTMLDivElement>();
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@observable _downX: number = 0;
@@ -166,7 +170,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
@undoBatch
@action
- marqueeCommand = (e: KeyboardEvent) => {
+ marqueeCommand = async (e: KeyboardEvent) => {
if (this._commandExecuted) {
return;
}
@@ -224,13 +228,17 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top);
let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" });
+ let dataUrl = await htmlToImage.toPng(this._mainCont.current!, { width: bounds.width, height: bounds.height, quality: 1 });
+ summary.proto!.thumbnail = new ImageField(new URL(dataUrl));
+
+ summary.proto!.templates = new List<string>([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]);
if (e.key === "s" || e.key === "p") {
summary.proto!.maximizeOnRight = true;
newCollection.proto!.summaryDoc = summary;
selected = [newCollection];
}
summary.proto!.summarizedDocs = new List<Doc>(selected);
- summary.proto!.isButton = true;
+ //summary.proto!.isButton = true;
selected.map(summarizedDoc => {
let maxx = NumCast(summarizedDoc.x, undefined);
let maxy = NumCast(summarizedDoc.y, undefined);
@@ -313,17 +321,21 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
@computed
get marqueeDiv() {
- let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- return <div className="marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} >
+ return <div className="marquee" style={{ width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }} >
<span className="marquee-legend" />
</div>;
}
render() {
+ let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
return <div className="marqueeView" style={{ borderRadius: "inherit" }} onClick={this.onClick} onPointerDown={this.onPointerDown}>
- {this.props.children}
- {!this._visible ? (null) : this.marqueeDiv}
+ <div style={{ position: "absolute", transform: `translate(${p[0]}px, ${p[1]}px)` }} >
+ <div ref={this._mainCont} style={{ position: "absolute", transform: `translate(${-p[0]}px, ${-p[1]}px)` }} >
+ {this.props.children}
+ </div>
+ {!this._visible ? null : this.marqueeDiv}
+ </div>
</div>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index b05f2eea2..39d216da0 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -9,10 +9,10 @@ import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schem
import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types";
import { OmitKeys, Utils } from "../../../Utils";
import { SelectionManager } from "../../util/SelectionManager";
-import { Doc, DocListCast, HeightSym } from "../../../new_fields/Doc";
+import { Doc, DocListCastAsync, DocListCast, } from "../../../new_fields/Doc";
import { List } from "../../../new_fields/List";
import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
+import { UndoManager } from "../../util/UndoManager";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
}
@@ -65,7 +65,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
panelWidth = () => this.props.PanelWidth();
panelHeight = () => this.props.PanelHeight();
- toggleMinimized = async () => this.toggleIcon(await DocListCast(this.props.Document.maximizedDocs));
+ toggleMinimized = async () => this.toggleIcon(await DocListCastAsync(this.props.Document.maximizedDocs));
getTransform = (): Transform => this.props.ScreenToLocalTransform()
.translate(-this.X, -this.Y)
.scale(1 / this.contentScaling()).scale(1 / this.zoom)
@@ -132,7 +132,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
let minimizedDoc: Doc | undefined = this.props.Document;
if (!maximizedDocs) {
minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc);
- if (minimizedDoc) maximizedDocs = await DocListCast(minimizedDoc.maximizedDocs);
+ if (minimizedDoc) maximizedDocs = await DocListCastAsync(minimizedDoc.maximizedDocs);
}
if (minimizedDoc && maximizedDocs) {
let minimizedTarget = minimizedDoc;
@@ -176,16 +176,18 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
let altKey = e.altKey;
if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
- let isBullet = (e.target as any).id === "isBullet";
- let isIcon = StrCast(this.props.Document.layout).indexOf("IconBox") !== -1;
- if (BoolCast(this.props.Document.isButton, false) || isBullet) {
- let maximizedDocs = await DocListCast(isBullet ? this.props.Document.subBulletDocs : isIcon ? this.props.Document.maximizedDocs : this.props.Document.summarizedDocs);
- if (maximizedDocs) { // bcz: need a better way to associate behaviors with click events on widget-documents
+ let isExpander = (e.target as any).id === "isExpander";
+ if (BoolCast(this.props.Document.isButton, false) || isExpander) {
+ let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs);
+ let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs);
+ let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs);
+ let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : [])];
+ if (expandedDocs) { // bcz: need a better way to associate behaviors with click events on widget-documents
if ((altKey && !this.props.Document.maximizeOnRight) || (!altKey && this.props.Document.maximizeOnRight)) {
- let dataDocs = await DocListCast(CollectionDockingView.Instance.props.Document.data);
+ let dataDocs = DocListCast(CollectionDockingView.Instance.props.Document.data);
if (dataDocs) {
SelectionManager.DeselectAll();
- maximizedDocs.forEach(maxDoc => {
+ expandedDocs.forEach(maxDoc => {
maxDoc.isMinimized = false;
if (!dataDocs || dataDocs.indexOf(maxDoc) == -1) {
CollectionDockingView.Instance.AddRightSplit(maxDoc);
@@ -195,8 +197,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
});
}
} else {
- this.props.addDocument && maximizedDocs.forEach(async maxDoc => this.props.addDocument!(await maxDoc, false));
- this.toggleIcon(maximizedDocs);
+ this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(await maxDoc, false));
+ this.toggleIcon(expandedDocs);
}
}
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 5aa74c703..90f67db7c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -12,13 +12,13 @@ import { CollectionPDFView } from "../collections/CollectionPDFView";
import { CollectionVideoView } from "../collections/CollectionVideoView";
import { CollectionView } from "../collections/CollectionView";
import { ContextMenu } from "../ContextMenu";
-import { Template, Templates } from "./../Templates";
+import { Template } from "./../Templates";
import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import React = require("react");
-import { Opt, Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc";
+import { Opt, Doc, WidthSym, HeightSym, DocListCastAsync, DocListCast } from "../../../new_fields/Doc";
import { DocComponent } from "../DocComponent";
-import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
import { FieldValue, StrCast, BoolCast, Cast } from "../../../new_fields/Types";
import { List } from "../../../new_fields/List";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
@@ -109,8 +109,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
// bcz: kind of ugly .. setup a reaction to update the title of a summary document's target (maximizedDocs) whenver the summary doc's title changes
this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs, this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""],
- async () => {
- let maxDoc = await DocListCast(this.props.Document.maximizedDocs);
+ () => {
+ let maxDoc = DocListCast(this.props.Document.maximizedDocs);
if (maxDoc && StrCast(this.props.Document.layout).indexOf("IconBox") !== -1) {
this.props.Document.title = (maxDoc && maxDoc.length === 1 ? maxDoc[0].title + ".icon" : "");
}
@@ -145,7 +145,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) {
if (this._mainCont.current) {
- let allConnected = dragSubBullets ? [this.props.Document, ...Cast(this.props.Document.subBulletDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc)] : [this.props.Document];
+ let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])];
const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0);
let dragData = new DragManager.DocumentDragData(allConnected);
const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top);
@@ -169,17 +169,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
SelectionManager.SelectDoc(this, e.ctrlKey);
}
}
- _hitIsBullet = false;
+ _hitExpander = false;
onPointerDown = (e: React.PointerEvent): void => {
this._downX = e.clientX;
this._downY = e.clientY;
if (CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && !this.isSelected()) {
return;
}
- this._hitIsBullet = (e.target && (e.target as any).id === "isBullet") || Cast(this.props.Document.subBulletDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc).length > 0;
+ this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0;
if (e.shiftKey && e.buttons === 1) {
if (this.props.isTopMost) {
- this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitIsBullet);
+ this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitExpander);
} else if (this.props.Document) {
CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e);
}
@@ -197,7 +197,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
document.removeEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
if (!e.altKey && !this.topMost && (!CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 1) || (CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 2)) {
- this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitIsBullet);
+ this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander);
}
}
e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers
@@ -232,6 +232,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
ContextMenu.Instance.clearItems();
SelectionManager.DeselectAll();
}
+
@undoBatch
@action
drop = async (e: Event, de: DragManager.DropEvent) => {
@@ -259,7 +260,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
-
@action
addTemplate = (template: Template) => {
this.templates.push(template.Layout);
@@ -307,7 +307,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
-
isSelected = () => SelectionManager.IsSelected(this);
select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx
index 4bcb4c636..48aecdcd0 100644
--- a/src/client/views/nodes/IconBox.tsx
+++ b/src/client/views/nodes/IconBox.tsx
@@ -2,12 +2,12 @@ import React = require("react");
import { library } from '@fortawesome/fontawesome-svg-core';
import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { computed, observable, runInAction, reaction, IReactionDisposer } from "mobx";
+import { computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
import { FieldView, FieldViewProps } from './FieldView';
import "./IconBox.scss";
import { Cast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { Doc, DocListCast } from "../../../new_fields/Doc";
+import { Doc } from "../../../new_fields/Doc";
import { IconField } from "../../../new_fields/IconField";
import { ContextMenu } from "../ContextMenu";
import Measure from "react-measure";
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 0e9e904a8..f9659a4b2 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,5 +1,5 @@
-import { action, observable } from 'mobx';
+import { action, observable, trace } from 'mobx';
import { observer } from "mobx-react";
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
@@ -157,15 +157,21 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
}
render() {
+ trace();
let field = this.Document[this.props.fieldKey];
let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"];
if (field instanceof ImageField) paths = [field.url.href];
else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href);
- let nativeWidth = FieldValue(this.Document.nativeWidth, 1);
+ let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50);
let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
+ let id = this.props.id;
return (
- <div className={`imageBox-cont${interactive}`} onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
- <img src={paths[Math.min(paths.length, this._photoIndex)]} style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
+ <div id={id} className={`imageBox-cont${interactive}`} onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
+ <img id={id} src={paths[Math.min(paths.length, this._photoIndex)]}
+ style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }}
+ width={nativeWidth}
+ ref={this._imgRef}
+ onLoad={this.onLoad} />
{paths.length > 1 ? this.dots(paths) : (null)}
{this.lightbox(paths)}
</div>);
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 24901913d..7bf13d5f9 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -5,7 +5,7 @@ import { LinkBox } from "./LinkBox";
import { LinkEditor } from "./LinkEditor";
import './LinkMenu.scss';
import React = require("react");
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
import { Cast, FieldValue } from "../../../new_fields/Types";
import { listSpec } from "../../../new_fields/Schema";
import { Id } from "../../../new_fields/RefField";
@@ -31,8 +31,8 @@ export class LinkMenu extends React.Component<Props> {
render() {
//get list of links from document
- let linkFrom = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
- let linkTo = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc);
+ let linkFrom = DocListCast(this.props.docView.props.Document.linkedFromDocs);
+ let linkTo = DocListCast(this.props.docView.props.Document.linkedToDoc);
if (this._editingLink === undefined) {
return (
<div id="linkMenu-container">
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 2ab145fa3..46ccb3e90 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -29,13 +29,17 @@ export const SelfProxy = Symbol("SelfProxy");
export const WidthSym = Symbol("Width");
export const HeightSym = Symbol("Height");
-export function DocListCast(field: FieldResult): Promise<Doc[] | undefined>;
-export function DocListCast(field: FieldResult, defaultValue: Doc[]): Promise<Doc[]>;
-export function DocListCast(field: FieldResult, defaultValue?: Doc[]) {
+export function DocListCastAsync(field: FieldResult): Promise<Doc[] | undefined>;
+export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise<Doc[]>;
+export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) {
const list = Cast(field, listSpec(Doc));
return list ? Promise.all(list) : Promise.resolve(defaultValue);
}
+export function DocListCast(field: FieldResult) {
+ return Cast(field, listSpec(Doc), []).filter(d => d && d instanceof Doc).map(d => d as Doc)
+}
+
@Deserializable("doc").withFields(["id"])
export class Doc extends RefField {
constructor(id?: FieldId, forceSave?: boolean) {