From a37faf30652c6c593923198ad34e54377e670caf Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 5 Jun 2019 08:09:10 -0400 Subject: fixed full screen text bug. cleaned up imports --- src/client/views/nodes/ImageBox.tsx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4c2b73b70..06ecc794b 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,25 +1,25 @@ -import { action, observable, trace } from 'mobx'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faImage } from '@fortawesome/free-solid-svg-icons'; +import { action, observable } 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 +import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { List } from '../../../new_fields/List'; +import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; +import { Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types'; +import { ImageField } from '../../../new_fields/URLField'; import { Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; +import { ContextMenuProps } from '../ContextMenuItem'; +import { DocComponent } from '../DocComponent'; +import { InkingControl } from '../InkingControl'; +import { positionSchema } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); -import { createSchema, makeInterface, listSpec } from '../../../new_fields/Schema'; -import { DocComponent } from '../DocComponent'; -import { positionSchema } from './DocumentView'; -import { FieldValue, Cast, StrCast, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { ImageField } from '../../../new_fields/URLField'; -import { List } from '../../../new_fields/List'; -import { InkingControl } from '../InkingControl'; -import { Doc, WidthSym, HeightSym } from '../../../new_fields/Doc'; -import { faImage } from '@fortawesome/free-solid-svg-icons'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { ContextMenuItemProps, ContextMenuProps } from '../ContextMenuItem'; var path = require('path'); -- cgit v1.2.3-70-g09d2 From 852bd5c7b7e8d6c01ff0e6dbb5cef35f4bfd9617 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 6 Jun 2019 22:49:25 -0400 Subject: added unfreeze for images, pdfs, etc. allows margins. improved rotate for images. added ctrl-drag to resize text. fixed minimizing to work with scaled views --- src/client/views/DocumentDecorations.tsx | 20 +++++++++++++--- .../views/collections/CollectionStackingView.tsx | 13 +++++++++- src/client/views/nodes/DocumentView.tsx | 28 +++++++--------------- src/client/views/nodes/ImageBox.tsx | 14 +++++++---- 4 files changed, 47 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ee76f718d..f22fecb98 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -6,7 +6,7 @@ import { observer } from "mobx-react"; import { Doc } from "../../new_fields/Doc"; import { List } from "../../new_fields/List"; import { listSpec } from "../../new_fields/Schema"; -import { Cast, NumCast, StrCast } from "../../new_fields/Types"; +import { Cast, NumCast, StrCast, BoolCast } from "../../new_fields/Types"; import { emptyFunction, Utils } from "../../Utils"; import { Docs } from "../documents/Documents"; import { DocumentManager } from "../util/DocumentManager"; @@ -443,16 +443,30 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let actualdH = Math.max(height + (dH * scale), 20); doc.x = (doc.x || 0) + dX * (actualdW - width); doc.y = (doc.y || 0) + dY * (actualdH - height); + let proto = Doc.GetProto(doc); + let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight); + if (fixedAspect && (!nwidth || !nheight)) { + proto.nativeWidth = doc.width; + proto.nativeHeight = doc.height; + proto.ignoreAspect = true; + } if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { + if (!fixedAspect) proto.nativeWidth = zoomBasis * actualdW / (doc.width || 1) * NumCast(proto.nativeWidth); doc.width = zoomBasis * actualdW; // doc.zoomBasis = zoomBasis * width / actualdW; + if (fixedAspect) doc.height = nheight / nwidth * doc.width; + else doc.height = zoomBasis * actualdH; + proto.nativeHeight = (doc.height || 0) / doc.width * NumCast(proto.nativeWidth); } else { - doc.width = nwidth / nheight * zoomBasis * actualdH; + if (!fixedAspect) proto.nativeHeight = zoomBasis * actualdH / (doc.height || 1) * NumCast(proto.nativeHeight); + doc.height = zoomBasis * actualdH; //doc.zoomBasis = zoomBasis * height / actualdH; + if (fixedAspect) doc.width = nwidth / nheight * doc.height; + else doc.width = zoomBasis * actualdW; + proto.nativeWidth = (doc.width || 0) / doc.height * NumCast(proto.nativeHeight); } - doc.height = nheight / nwidth * doc.width; } else { doc.width = zoomBasis * actualdW; if (docHeightBefore === doc.height) doc.height = zoomBasis * actualdH; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index af7e02e06..eeae498a6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -11,6 +11,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; +import { ContextMenu } from "../ContextMenu"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -147,12 +148,22 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ); }) } + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ + description: "Toggle multi-column", + event: () => this.props.Document.singleColumn = !BoolCast(this.props.Document.singleColumn, false), icon: "file-pdf" + }); + } + } render() { - let cols = this.singleColumn ? 1 : Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + 2 * this.gridGap)); + let cols = this.singleColumn ? 1 : Math.min(this.childDocs.filter(d => !d.isMinimized).length, + Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + 2 * this.gridGap))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return (
e.stopPropagation()}>
(Docu toggleMinimized = async () => { let minimizedDoc = await Cast(this.props.Document.minimizedDoc, Doc); if (minimizedDoc) { - let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint( + let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint( NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); this.props.collapseToPoint && this.props.collapseToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); } @@ -246,7 +246,7 @@ export class DocumentView extends DocComponent(Docu this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); } } else { - let scrpt = this.props.ScreenToLocalTransform().inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); + let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); this.props.collapseToPoint && this.props.collapseToPoint(scrpt, expandedProtoDocs); } } @@ -374,23 +374,13 @@ export class DocumentView extends DocComponent(Docu } freezeNativeDimensions = (e: React.MouseEvent): void => { - if (NumCast(this.props.Document.nativeWidth)) { - let proto = Doc.GetProto(this.props.Document); - let nw = proto.nativeWidth; - let nh = proto.nativeHeight; - proto.nativeWidth = proto.nativeHeight = undefined; - this.props.Document.width = this.props.Document.frozenWidth; - this.props.Document.height = this.props.Document.frozenHeight; - } - else { - let scale = this.props.ScreenToLocalTransform().Scale * NumCast(this.props.Document.zoomBasis, 1); - let scr = this.screenRect(); - let proto = Doc.GetProto(this.props.Document); - this.props.Document.frozenWidth = this.props.Document.width; - this.props.Document.frozenHeight = this.props.Document.height; - this.props.Document.height = proto.nativeHeight = scr.height * scale; - this.props.Document.width = proto.nativeWidth = scr.width * scale; + let proto = Doc.GetProto(this.props.Document); + if (proto.ignoreAspect === undefined && !proto.nativeWidth) { + proto.nativeWidth = this.props.PanelWidth(); + proto.nativeHeight = this.props.PanelHeight(); + proto.ignoreAspect = true; } + proto.ignoreAspect = !BoolCast(proto.ignoreAspect, false); } @action @@ -412,7 +402,7 @@ export class DocumentView extends DocComponent(Docu subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems }); - cm.addItem({ description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.freezeNativeDimensions, icon: "edit" }); + cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); cm.addItem({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 06ecc794b..0d19508fa 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -136,12 +136,15 @@ export class ImageBox extends DocComponent(ImageD subitems.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); subitems.push({ description: "Rotate", event: action(() => { - this.props.Document.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + let proto = Doc.GetProto(this.props.Document); let nw = this.props.Document.nativeWidth; - this.props.Document.nativeWidth = this.props.Document.nativeHeight; - this.props.Document.nativeHeight = nw; + let nh = this.props.Document.nativeHeight; let w = this.props.Document.width; - this.props.Document.width = this.props.Document.height; + let h = this.props.Document.height; + proto.rotation = (NumCast(this.props.Document.rotation) + 90) % 360; + proto.nativeWidth = nh; + proto.nativeHeight = nw; + this.props.Document.width = h; this.props.Document.height = w; }), icon: "expand-arrows-alt" }); @@ -198,6 +201,7 @@ export class ImageBox extends DocComponent(ImageD let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx let nativeWidth = FieldValue(this.Document.nativeWidth, pw); + let nativeHeight = FieldValue(this.Document.nativeHeight, 0); let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; // this._curSuffix = ""; // if (w > 20) { @@ -211,7 +215,7 @@ export class ImageBox extends DocComponent(ImageD let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; let rotation = NumCast(this.props.Document.rotation, 0); let aspect = (rotation % 180) ? this.props.Document[HeightSym]() / this.props.Document[WidthSym]() : 1; - let shift = (rotation % 180) ? (this.props.Document[HeightSym]() - this.props.Document[WidthSym]() / aspect) / 2 : 0; + let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; return (
Date: Tue, 18 Jun 2019 11:31:46 -0400 Subject: fixed image drag drop when not selected. --- src/client/views/nodes/DocumentView.tsx | 7 +++++-- src/client/views/nodes/ImageBox.tsx | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 942228e71..de6e9f5fa 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; +import { faAlignCenter, faCaretSquareRight, faCompressArrowsAlt, faUnlock, faLock, faExpandArrowsAlt, faLayerGroup, faSquare, faTrash, faConciergeBell, faFolder, faMapPin, faLink, faFingerprint, faCrosshairs, faDesktop } from '@fortawesome/free-solid-svg-icons'; import { action, computed, IReactionDisposer, reaction, trace, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; @@ -48,6 +48,8 @@ library.add(faLink); library.add(faFingerprint); library.add(faCrosshairs); library.add(faDesktop); +library.add(faUnlock); +library.add(faLock); const linkSchema = createSchema({ title: "string", @@ -354,7 +356,7 @@ export class DocumentView extends DocComponent(Docu if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - if (!e.altKey && !this.topMost && e.buttons === 1) { + if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) { this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander); } } @@ -475,6 +477,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Open...", subitems: subitems }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" }); + cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: () => this.props.Document.lockedPosition = BoolCast(this.props.Document.lockedPosition) ? undefined : true, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" }); cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" }); cm.addItem({ description: "Find aliases", event: async () => { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0d19508fa..6b8b64c5f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -86,9 +86,9 @@ export class ImageBox extends DocComponent(ImageD } onPointerDown = (e: React.PointerEvent): void => { - if (e.shiftKey && e.ctrlKey) - - e.stopPropagation(); + if (e.shiftKey && e.ctrlKey) { + e.stopPropagation(); // allows default system drag drop of images with shift+ctrl only + } else e.preventDefault(); // if (Date.now() - this._lastTap < 300) { // if (e.buttons === 1) { // this._downX = e.clientX; -- cgit v1.2.3-70-g09d2 From 13e301dea2f537b67b338cc6a98d3f3b5a8e1f36 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 18 Jun 2019 20:58:32 -0400 Subject: Fixed linter errors --- src/client/northstar/dash-nodes/HistogramBox.tsx | 3 +-- src/client/util/DocumentManager.ts | 6 +++--- src/client/util/DragManager.ts | 4 +++- src/client/util/RichTextSchema.tsx | 10 +++++----- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/ContextMenu.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/MainView.tsx | 7 ++++--- src/client/views/PresentationView.tsx | 4 ++-- src/client/views/collections/CollectionBaseView.tsx | 2 +- src/client/views/collections/CollectionDockingView.tsx | 5 +++-- src/client/views/collections/CollectionPDFView.tsx | 2 +- src/client/views/collections/CollectionSchemaView.tsx | 11 ++++++----- src/client/views/collections/CollectionStackingView.tsx | 4 ++-- src/client/views/collections/CollectionTreeView.tsx | 10 +++++----- .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 12 ++++++------ src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 3 ++- src/client/views/pdf/PDFAnnotationLayer.tsx | 2 +- src/client/views/pdf/PDFMenu.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 4 ++-- src/server/index.ts | 2 +- 27 files changed, 59 insertions(+), 54 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index d7732ee86..a60eaea85 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -125,8 +125,7 @@ export class HistogramBox extends React.Component { let mapped = brushingDocs.map((brush, i) => { brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; let brushed = DocListCast(brush.brushingDocs); - if (!brushed.length) - return null; + if (!brushed.length) return null; return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; }); runInAction(() => this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped.filter(m => m) as { l: Doc, b: Doc }[])); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index ff0c1560b..862395d74 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -35,9 +35,9 @@ export class DocumentManager { let toReturn: DocumentView | null = null; let passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; - for (let i = 0; i < passes.length; i++) { + for (let pass of passes) { DocumentManager.Instance.DocumentViews.map(view => { - if (view.props.Document[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { + if (view.props.Document[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; return; } @@ -45,7 +45,7 @@ export class DocumentManager { if (!toReturn) { DocumentManager.Instance.DocumentViews.map(view => { let doc = view.props.Document.proto; - if (doc && doc[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) { + if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) { toReturn = view; } }); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 89566e777..c3c92daa5 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -282,11 +282,13 @@ export namespace DragManager { // } let set = dragElement.getElementsByTagName('*'); if (dragElement.hasAttribute("style")) (dragElement as any).style.pointerEvents = "none"; - for (let i = 0; i < set.length; i++) + // tslint:disable-next-line: prefer-for-of + for (let i = 0; i < set.length; i++) { if (set[i].hasAttribute("style")) { let s = set[i]; (s as any).style.pointerEvents = "none"; } + } dragDiv.appendChild(dragElement); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index e1e595925..943cdb4d1 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -156,12 +156,12 @@ export const nodes: { [index: string]: NodeSpec } = { title: dom.getAttribute("title"), alt: dom.getAttribute("alt"), width: Math.min(100, Number(dom.getAttribute("width"))), - } + }; } }], toDOM(node) { - const attrs = { style: `width: ${node.attrs.width}` } - return ["video", { ...node.attrs, ...attrs }] + const attrs = { style: `width: ${node.attrs.width}` }; + return ["video", { ...node.attrs, ...attrs }]; } }, @@ -285,7 +285,7 @@ export const marks: { [index: string]: MarkSpec } = { toDOM() { return ['span', { style: 'color: blue' - }] + }]; } }, @@ -536,4 +536,4 @@ schema.nodeFromJSON = (json: any) => { node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice); } return node; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 0a61b7e7d..f2559db74 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -256,7 +256,7 @@ export class TooltipTextMenu { starButton.onclick = () => { let state = this.view.state; this.insertStar(state, this.view.dispatch); - } + }; this.tooltip.appendChild(starButton); } diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index da374455e..eb1937683 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -1,8 +1,8 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; -import { observer } from "mobx-react" -import "./ContextMenu.scss" +import { observer } from "mobx-react"; +import "./ContextMenu.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index ceca940b6..e60f8c86c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -466,7 +466,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.SelectedDocuments().forEach(element => { const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect(); - if (rect.width !== 0 && (dX != 0 || dY != 0 || dW != 0 || dH != 0)) { + if (rect.width !== 0 && (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0)) { let doc = PositionDocument(element.props.Document); let nwidth = doc.nativeWidth || 0; let nheight = doc.nativeHeight || 0; diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 0de880175..b4ad5f4d7 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -40,7 +40,7 @@ export class MainOverlayTextBox extends React.Component this.TextDoc = box.props.Document; let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined); let xf = () => { box.props.ScreenToLocalTransform(); return new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale); }; - this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight, false) || box.props.height === "min-content") + this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight, false) || box.props.height === "min-content"); } else { this.TextDoc = undefined; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fd76cbbd3..7f979cd3b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -237,10 +237,11 @@ export class MainView extends React.Component { } onColorClick = (e: React.MouseEvent) => { - let target = (e.nativeEvent! as any).path[0]; - let parent = (e.nativeEvent! as any).path[1]; - if (target.localName === "input" || parent.localName === "span") + let target = (e.nativeEvent as any).path[0]; + let parent = (e.nativeEvent as any).path[1]; + if (target.localName === "input" || parent.localName === "span") { e.stopPropagation(); + } } diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index d2d41a4ba..1dacbb663 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -40,8 +40,8 @@ class PresentationViewList extends React.Component { //this doc is selected className += " presentationView-selected"; } - let onEnter = (e: React.PointerEvent) => { document.libraryBrush = true; } - let onLeave = (e: React.PointerEvent) => { document.libraryBrush = false; } + let onEnter = (e: React.PointerEvent) => { document.libraryBrush = true; }; + let onLeave = (e: React.PointerEvent) => { document.libraryBrush = false; }; return (
{ @action.bound removeDocument(doc: Doc): boolean { - let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView) + let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); const props = this.props; //TODO This won't create the field if it doesn't already exist diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f2b3528b8..5beb89315 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -347,7 +347,7 @@ export class CollectionDockingView extends React.Component CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv); tab.reactComponents = [upDiv]; tab.element.append(upDiv); @@ -432,8 +432,9 @@ export class DockedFrameRenderer extends React.Component { @observable private _document: Opt; get _stack(): any { let parent = (this.props as any).glContainer.parent.parent; - if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) + if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) { return parent.parent.contentItems[1]; + } return parent; } constructor(props: any) { diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index b62d3f7bb..b2d016934 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -40,7 +40,7 @@ export class CollectionPDFView extends React.Component { // console.log(this.props.Document[HeightSym]()); }, { fireImmediately: true } - ) + ); } public static LayoutString(fieldKey: string = "data") { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 14a7d19d0..faea8d44d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -87,8 +87,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { let columnDocs = DocListCast(schemaDoc.data); if (columnDocs) { let ddoc = columnDocs.find(doc => doc.title === columnName); - if (ddoc) + if (ddoc) { return ddoc; + } } } return this.props.Document; @@ -285,7 +286,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate( - - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth); + - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth) get documentKeysCheckList() { @@ -334,7 +335,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { columns={this.tableColumns} column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }} getTrProps={this.getTrProps} - /> + />; } @computed @@ -360,7 +361,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { addDocTab={this.props.addDocTab} setPreviewScript={this.setPreviewScript} previewScript={this.previewScript} - /> + />; } @action setPreviewScript = (script: string) => { @@ -409,7 +410,7 @@ export class CollectionSchemaPreview extends React.Component this.nativeWidth * this.contentScaling(); private PanelHeight = () => this.nativeHeight * this.contentScaling(); - private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling()) + private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling()); get centeringOffset() { return (this.props.width() - this.nativeWidth * this.contentScaling()) / 2; } @action onPreviewScriptChange = (e: React.ChangeEvent) => { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e1ac3505b..f5ad4ee95 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -101,7 +101,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let childFocus = (doc: Doc) => { doc.libraryBrush = true; this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered. - } + }; return (
doc) { whenActiveChanged={this.props.whenActiveChanged} />
); - }) + }); } onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b13694e9d..3e495b734 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -67,8 +67,8 @@ class TreeView extends React.Component { @undoBatch delete = () => this.props.deleteDoc(this.props.document); @undoBatch openRight = async () => this.props.addDocTab(this.props.document, "openRight"); - @action onMouseEnter = () => { this._isOver = true; } - @action onMouseLeave = () => { this._isOver = false; } + @action onMouseEnter = () => { this._isOver = true; }; + @action onMouseLeave = () => { this._isOver = false; }; onPointerEnter = (e: React.PointerEvent): void => { this.props.active() && (this.props.document.libraryBrush = true); @@ -89,8 +89,8 @@ class TreeView extends React.Component { let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2); let before = x[1] < bounds[1]; let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible); - this._header!.current!.className = "treeViewItem-header" - if (inside && this._bulletType != BulletType.List) this._header!.current!.className += " treeViewItem-header-inside"; + this._header!.current!.className = "treeViewItem-header"; + if (inside && this._bulletType !== BulletType.List) this._header!.current!.className += " treeViewItem-header-inside"; else if (before) this._header!.current!.className += " treeViewItem-header-above"; else if (!before) this._header!.current!.className += " treeViewItem-header-below"; e.stopPropagation(); @@ -192,7 +192,7 @@ class TreeView extends React.Component { if (inside) { let docList = Cast(this.props.document.data, listSpec(Doc)); if (docList !== undefined) { - addDoc = (doc: Doc) => { docList && docList.push(doc); return true; } + addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }; } } let added = false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index c4dd534ed..be75c6c5c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -109,7 +109,7 @@ export class CollectionFreeFormLinksView extends React.Component [ , ...this.views - ]; + ] render() { const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; const easing = () => this.props.Document.panTransformType === "Ease"; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index dedcc3172..05dc6f534 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -321,7 +321,7 @@ export class MarqueeView extends React.Component summary.imageSummary = imageSummary; this.props.addDocument(imageSummary, false); } - }) + }); newCollection.proto!.summaryDoc = summary; selected = [newCollection]; newCollection.x = bounds.left + bounds.width; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f6b1c62ee..858959d81 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -48,7 +48,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.PanelHeight(); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) - .scale(1 / this.contentScaling()).scale(1 / this.zoom); + .scale(1 / this.contentScaling()).scale(1 / this.zoom) animateBetweenIcon = (icon: number[], stime: number, maximizing: boolean) => { this.props.bringToFront(this.props.Document); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7c058d91c..4992669df 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -168,8 +168,8 @@ export class DocumentView extends DocComponent(Docu public static animateBetweenIconFunc = (doc: Doc, width: number, height: number, stime: number, maximizing: boolean, cb?: (progress: number) => void) => { setTimeout(() => { let now = Date.now(); - let progress = now < stime + 200 ? Math.min(1, (now - stime) / 200) : 1 - doc.width = progress === 1 ? width : maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress + let progress = now < stime + 200 ? Math.min(1, (now - stime) / 200) : 1; + doc.width = progress === 1 ? width : maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress; doc.height = progress === 1 ? height : maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress; cb && cb(progress); if (now < stime + 200) { @@ -229,7 +229,7 @@ export class DocumentView extends DocComponent(Docu if (minimizedDoc) { let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint( NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y)); - this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)) + this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs)); } } @@ -372,8 +372,8 @@ export class DocumentView extends DocComponent(Docu this._lastTap = Date.now(); } - deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); } - fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight") }; + deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); }; + fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"); }; makeBtnClicked = (): void => { let doc = Doc.GetProto(this.props.Document); doc.isButton = !BoolCast(doc.isButton, false); @@ -527,7 +527,7 @@ export class DocumentView extends DocComponent(Docu onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; isSelected = () => SelectionManager.IsSelected(this); - @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); } + @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 36d902c4f..df12f261b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -161,7 +161,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe de.data.moveDocument(de.data.draggedDocuments[0], stackDoc, (doc) => { Cast(stackDoc.data, listSpec(Doc))!.push(doc); return true; - }) + }); } } } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6b8b64c5f..f208ce2ce 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -188,8 +188,9 @@ export class ImageBox extends DocComponent(ImageD } @action onError = () => { let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; - if (timeout < 10) + if (timeout < 10) { setTimeout(this.retryPath, Math.min(10000, timeout * 5)); + } } _curSuffix = "_m"; render() { diff --git a/src/client/views/pdf/PDFAnnotationLayer.tsx b/src/client/views/pdf/PDFAnnotationLayer.tsx index e92dcacbf..1f49e0d2f 100644 --- a/src/client/views/pdf/PDFAnnotationLayer.tsx +++ b/src/client/views/pdf/PDFAnnotationLayer.tsx @@ -19,6 +19,6 @@ export class PDFAnnotationLayer extends React.Component {
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 7817e8c26..2ed891131 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -162,6 +162,6 @@ export default class PDFMenu extends React.Component {
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 69372f43b..8c0aaea00 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -198,7 +198,7 @@ class Viewer extends React.Component { { @action getPageImage = async (page: number) => { let handleError = () => this.getRenderedPage(page); - if (this._isPage[page] != "image") { + if (this._isPage[page] !== "image") { this._isPage[page] = "image"; const address = this.props.url; let res = JSON.parse(await rp.get(DocServer.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`))); diff --git a/src/server/index.ts b/src/server/index.ts index 7ef542b01..2901f61ed 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -172,7 +172,7 @@ function LoadPage(file: string, pageNumber: number, res: Response) { canvasContext: canvasAndContext.context, viewport: viewport, canvasFactory: factory - } + }; console.log("read " + pageNumber); page.render(renderContext).promise -- cgit v1.2.3-70-g09d2 From 3b880d7b15b7107049ae27601b9f759b17f7fde9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 18 Jun 2019 22:51:46 -0400 Subject: added initial keyboard shortcuts for adding and moving docs in TreeView. fixed image drag bug. --- src/client/documents/Documents.ts | 3 +- src/client/views/EditableView.tsx | 34 +++++--- .../views/collections/CollectionDockingView.tsx | 1 + .../views/collections/CollectionTreeView.tsx | 96 +++++++++++++++++----- src/client/views/nodes/ImageBox.tsx | 2 +- 5 files changed, 103 insertions(+), 33 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 91d3707f6..fcd1010c6 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -51,7 +51,6 @@ export interface DocumentOptions { panY?: number; page?: number; scale?: number; - baseLayout?: string; layout?: string; templates?: List; viewType?: number; @@ -136,7 +135,7 @@ export namespace Docs { } function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Doc { - return Doc.assign(new Doc(protoId, true), { ...options, title: title, layout: layout, baseLayout: layout }); + return Doc.assign(new Doc(protoId, true), { ...options, title: title, layout: layout }); } function SetInstanceOptions(doc: Doc, options: DocumentOptions, value: U) { const deleg = Doc.MakeDelegate(doc); diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index c946d68e1..a96fca464 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -18,13 +18,17 @@ export interface EditableProps { OnFillDown?(value: string): void; + OnTab?(): void; + /** * The contents to render when not editing */ contents: any; + fontStyle?: string; height?: number; display?: string; oneLine?: boolean; + editing?: boolean } /** @@ -34,40 +38,48 @@ export interface EditableProps { */ @observer export class EditableView extends React.Component { - @observable - editing: boolean = false; + @observable _editing: boolean = false; + + constructor(props: EditableProps) { + super(props); + this._editing = this.props.editing ? true : false; + } @action onKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { + if (e.key === "Tab") { + this.props.OnTab && this.props.OnTab(); + } else if (e.key === "Enter") { if (!e.ctrlKey) { if (this.props.SetValue(e.currentTarget.value)) { - this.editing = false; + this._editing = false; } } else if (this.props.OnFillDown) { this.props.OnFillDown(e.currentTarget.value); - this.editing = false; + this._editing = false; } } else if (e.key === "Escape") { - this.editing = false; + this._editing = false; } } @action onClick = (e: React.MouseEvent) => { - this.editing = true; + this._editing = true; e.stopPropagation(); } render() { - if (this.editing) { - return this.editing = false)} + if (this._editing) { + return this._editing = false)} style={{ display: this.props.display }} />; } else { return ( -
- {this.props.contents} + {this.props.contents}
); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f2b3528b8..bd3020a78 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -467,6 +467,7 @@ export class DockedFrameRenderer extends React.Component { let docHeight = NumCast(this._document!.height); if (NumCast(this._document!.nativeWidth) || !docWidth || !this._panelWidth || !this._panelHeight) return 1; if (StrCast(this._document!.layout).indexOf("Collection") === -1 || + !BoolCast(this._document!.fitToContents, false) || NumCast(this._document!.viewType) !== CollectionViewType.Freeform) return 1; let scaling = Math.max(1, this._panelWidth / docWidth * docHeight > this._panelHeight ? this._panelHeight / docHeight : this._panelWidth / docWidth); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b13694e9d..23efe9f79 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -21,6 +21,7 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { Transform } from '../../util/Transform'; import { SelectionManager } from '../../util/SelectionManager'; +import { emptyFunction } from '../../../Utils'; export interface TreeViewProps { @@ -30,6 +31,7 @@ export interface TreeViewProps { dropAction: "alias" | "copy" | undefined; addDocTab: (doc: Doc, where: string) => void; addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; + indentDocument?: () => void; ScreenToLocalTransform: () => Transform; treeViewId: string; parentKey: string; @@ -114,6 +116,12 @@ class TreeView extends React.Component { } return true; } + @action + indent = () => { + this.props.addDocument(this.props.document); + this.delete(); + } + renderBullet(type: BulletType) { let onClicked = action(() => this._collapsed = !this._collapsed); @@ -124,25 +132,37 @@ class TreeView extends React.Component { } return
{bullet ? : ""}
; } + static loadId = ""; + editableView = (key: string, style?: string) => + ( StrCast(this.props.document[key])} + OnFillDown={(value: string) => { + Doc.GetProto(this.props.document)[key] = value; + let doc = Docs.FreeformDocument([], { title: "untitled" }); + TreeView.loadId = doc[Id]; + this.props.addDocument(doc); + return true; + }} + OnTab={() => this.props.indentDocument && this.props.indentDocument()} + SetValue={(value: string) => { + Doc.GetProto(this.props.document)[key] = value; + return true; + }} + />); + /** * Renders the EditableView title element for placement into the tree. */ renderTitle() { let reference = React.createRef(); let onItemDown = SetupDrag(reference, () => this.props.document, this.move, this.props.dropAction, this.props.treeViewId, true); - let editableView = (titleString: string) => - ( StrCast(this.props.document.title)} - SetValue={(value: string) => { - let target = this.props.document.proto ? this.props.document.proto : this.props.document; - target.title = value; - return true; - }} - />); + let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document.data, listSpec(Doc), []) : []; let openRight = dataDocs && dataDocs.indexOf(this.props.document) !== -1 ? (null) : (
@@ -156,7 +176,7 @@ class TreeView extends React.Component { pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none" }} > - {editableView(StrCast(this.props.document.title))} + {this.editableView("title")} {/* {
} */}
{openRight} @@ -221,6 +241,7 @@ class TreeView extends React.Component { return true; } + @observable _chosenKey: string = "data" _bulletType: BulletType = BulletType.List; render() { let bulletType = BulletType.List; @@ -234,7 +255,21 @@ class TreeView extends React.Component { keys.splice(keys.indexOf("data"), 1); keys.splice(0, 0, "data"); } + let keyList: string[] = []; keys.map(key => { + let docList = Cast(this.props.document[key], listSpec(Doc)); + let doc = Cast(this.props.document[key], Doc); + if (doc instanceof Doc || (docList && (DocListCast(docList).length > 0 || key === "data"))) { + keyList.push(key); + } + }); + let headerElements =
{keyList.map(key => + this._chosenKey = key)} + style={{ display: "inline", marginRight: "3px", marginTop: "7px", background: key === this._chosenKey ? "lightgray" : undefined }}> + {key} + )} +
+ [this._chosenKey].map(key => { let docList = Cast(this.props.document[key], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, key); let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.document, key, doc, addBefore, before); @@ -243,9 +278,10 @@ class TreeView extends React.Component { if (!this._collapsed) { bulletType = BulletType.Collapsible; contentElement.push(
    - {key} + {headerElements}
    {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, key, addDoc, remDoc, this.move, + this.indent, this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active)}
); @@ -274,14 +310,36 @@ class TreeView extends React.Component { add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, + indent: () => void, dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => void, screenToLocalXf: () => Transform, active: () => boolean ) { - return docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)).map(child => - ); + let docList = docs.filter(child => !child.excludeFromLibrary && (key !== "data" || !child.isMinimized)); + return docList.map((child, i) => { + let indent = i == 0 ? undefined : () => { + if (StrCast(docList[i - 1].layout).indexOf("CollectionView") !== -1) { + let fieldKeysub = StrCast(docList[i - 1].layout).split("fieldKey")[1]; + let fieldKey = fieldKeysub.split("\"")[1]; + TreeView.AddDocToList(docList[i - 1], fieldKey, child); + remove(child); + } + } + return + }); } } @@ -321,7 +379,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => TreeView.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before); let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); let childElements = TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.fieldKey, addDoc, this.remove, - moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active); + moveDoc, emptyFunction, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.active); return (
(ImageD let aspect = (rotation % 180) ? this.props.Document[HeightSym]() / this.props.Document[WidthSym]() : 1; let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; return ( -
Date: Fri, 21 Jun 2019 13:13:18 -0400 Subject: lots more template stuff. --- src/client/util/DocumentManager.ts | 6 +- src/client/util/DragManager.ts | 18 ++-- src/client/views/DocumentDecorations.tsx | 35 ++++---- src/client/views/MainOverlayTextBox.tsx | 8 +- .../views/collections/CollectionDockingView.tsx | 100 +++++++++++---------- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 33 +++++-- src/client/views/collections/CollectionView.tsx | 4 +- .../views/collections/ParentDocumentSelector.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 27 +++--- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 43 +++++---- src/client/views/pdf/PDFViewer.tsx | 1 - src/new_fields/Doc.ts | 8 ++ 15 files changed, 174 insertions(+), 119 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 862395d74..8421c902e 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -138,7 +138,7 @@ export class DocumentManager { docContext.panTransformType = "Ease"; targetContextView.props.focus(docDelegate); } else { - (dockFunc || CollectionDockingView.Instance.AddRightSplit)(docContext); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(docContext, docContext); setTimeout(() => { this.jumpToDocument(docDelegate, forceDockFunc, dockFunc, linkPage); }, 10); @@ -147,7 +147,7 @@ export class DocumentManager { const actualDoc = Doc.MakeAlias(docDelegate); actualDoc.libraryBrush = true; if (linkPage !== undefined) actualDoc.curPage = linkPage; - (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc, actualDoc); } } else { let contextView: DocumentView | null; @@ -156,7 +156,7 @@ export class DocumentManager { contextDoc.panTransformType = "Ease"; contextView.props.focus(docDelegate); } else { - (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc); + (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc, contextDoc); setTimeout(() => { this.jumpToDocument(docDelegate, forceDockFunc, dockFunc, linkPage); }, 10); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c3c92daa5..cc83b7346 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,7 +15,8 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); - var dragData = new DragManager.DocumentDragData([await docFunc()]); + let doc = await docFunc(); + var dragData = new DragManager.DocumentDragData([doc], [doc]); dragData.dropAction = dropAction; dragData.moveDocument = moveFunc; dragData.options = options; @@ -31,7 +32,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () if (e.button === 0) { e.stopPropagation(); if (e.shiftKey && CollectionDockingView.Instance) { - CollectionDockingView.Instance.StartOtherDrag([await docFunc()], e); + CollectionDockingView.Instance.StartOtherDrag(e, [await docFunc()]); } else { document.addEventListener("pointermove", onRowMove); document.addEventListener("pointerup", onRowUp); @@ -59,7 +60,8 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n let doc = await Cast(draggedDoc.annotationOn, Doc); if (doc) moddrag.push(doc); } - let dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs); + let linkDocs = moddrag.length ? moddrag : draggedDocs; + let dragData = new DragManager.DocumentDragData(linkDocs, linkDocs); // bcz: dataDocs? DragManager.StartDocumentDrag([dragEle], dragData, x, y, { handlers: { dragComplete: action(emptyFunction), @@ -141,13 +143,15 @@ export namespace DragManager { export type MoveFunction = (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; export class DocumentDragData { - constructor(dragDoc: Doc[]) { + constructor(dragDoc: Doc[], dragDataDocs: Doc[]) { this.draggedDocuments = dragDoc; + this.draggedDataDocs = dragDataDocs; this.droppedDocuments = dragDoc; this.xOffset = 0; this.yOffset = 0; } draggedDocuments: Doc[]; + draggedDataDocs: Doc[]; droppedDocuments: Doc[]; xOffset: number; yOffset: number; @@ -238,6 +242,8 @@ export namespace DragManager { const docs: Doc[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnnotationDragData ? [dragData.dragDocument] : []; + const datadocs: Doc[] = + dragData instanceof DocumentDragData ? dragData.draggedDataDocs : dragData instanceof AnnotationDragData ? [dragData.dragDocument] : []; let dragElements = eles.map(ele => { const w = ele.offsetWidth, h = ele.offsetHeight; @@ -314,12 +320,12 @@ export namespace DragManager { } if (e.shiftKey && CollectionDockingView.Instance) { AbortDrag(); - CollectionDockingView.Instance.StartOtherDrag(docs, { + CollectionDockingView.Instance.StartOtherDrag({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 - }); + }, docs, datadocs); } //TODO: Why can't we use e.movementX and e.movementY? let moveX = e.pageX - lastX; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3a366b4d2..8f02f04d7 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -166,7 +166,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dragDocView = SelectionManager.SelectedDocuments()[0]; const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); const [xoff, yoff] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top); - let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); + let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document), SelectionManager.SelectedDocuments().map(dv => dv.props.DataDoc)); dragData.xOffset = xoff; dragData.yOffset = yoff; dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument; @@ -485,9 +485,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let doc = PositionDocument(element.props.Document); let nwidth = doc.nativeWidth || 0; let nheight = doc.nativeHeight || 0; - let zoomBasis = NumCast(doc.zoomBasis, 1); - let width = (doc.width || 0) / zoomBasis; - let height = (doc.height || (nheight / nwidth * width)) / zoomBasis; + let width = (doc.width || 0); + let height = (doc.height || (nheight / nwidth * width)); let scale = element.props.ScreenToLocalTransform().Scale; let actualdW = Math.max(width + (dW * scale), 20); let actualdH = Math.max(height + (dH * scale), 20); @@ -502,25 +501,27 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } if (nwidth > 0 && nheight > 0) { if (Math.abs(dW) > Math.abs(dH)) { - if (!fixedAspect) proto.nativeWidth = zoomBasis * actualdW / (doc.width || 1) * NumCast(proto.nativeWidth); - doc.width = zoomBasis * actualdW; - // doc.zoomBasis = zoomBasis * width / actualdW; + if (!fixedAspect) { + Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true); + } + doc.width = actualdW; if (fixedAspect) doc.height = nheight / nwidth * doc.width; - else doc.height = zoomBasis * actualdH; - proto.nativeHeight = (doc.height || 0) / doc.width * NumCast(proto.nativeWidth); + else doc.height = actualdH; + Doc.SetInPlace(element.props.Document, "nativeHeight", (doc.height || 0) / doc.width * (doc.nativeWidth || 0), true); } else { - if (!fixedAspect) proto.nativeHeight = zoomBasis * actualdH / (doc.height || 1) * NumCast(proto.nativeHeight); - doc.height = zoomBasis * actualdH; - //doc.zoomBasis = zoomBasis * height / actualdH; + if (!fixedAspect) { + Doc.SetInPlace(element.props.Document, "nativeHeight", actualdH / (doc.height || 1) * (doc.nativeHeight || 0), true); + } + doc.height = actualdH; if (fixedAspect) doc.width = nwidth / nheight * doc.height; - else doc.width = zoomBasis * actualdW; - proto.nativeWidth = (doc.width || 0) / doc.height * NumCast(proto.nativeHeight); + else doc.width = actualdW; + Doc.SetInPlace(element.props.Document, "nativeWidth", (doc.width || 0) / doc.height * (doc.nativeHeight || 0), true); } } else { - dW && (doc.width = zoomBasis * actualdW); - dH && (doc.height = zoomBasis * actualdH); - proto.autoHeight = undefined; + dW && (doc.width = actualdW); + dH && (doc.height = actualdH); + Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true); } } }); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 64271650b..73d59ce31 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -82,10 +82,10 @@ export class MainOverlayTextBox extends React.Component } @action textBoxMove = (e: PointerEvent) => { - if (e.movementX > 1 || e.movementY > 1) { + if ((e.movementX > 1 || e.movementY > 1) && FormattedTextBox.InputBoxOverlay) { document.removeEventListener("pointermove", this.textBoxMove); document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData(FormattedTextBox.InputBoxOverlay ? [FormattedTextBox.InputBoxOverlay.props.Document] : []); + let dragData = new DragManager.DocumentDragData([FormattedTextBox.InputBoxOverlay.props.Document], [FormattedTextBox.InputBoxOverlay.props.DataDoc]); const [left, top] = this._textXf().inverse().transformPoint(0, 0); dragData.xOffset = e.clientX - left; dragData.yOffset = e.clientY - top; @@ -102,9 +102,9 @@ export class MainOverlayTextBox extends React.Component document.removeEventListener('pointerup', this.textBoxUp); } - addDocTab = (doc: Doc, location: string) => { + addDocTab = (doc: Doc, dataDoc: Doc, location: string) => { if (true) { // location === "onRight") { need to figure out stack to add "inTab" - CollectionDockingView.Instance.AddRightSplit(doc); + CollectionDockingView.Instance.AddRightSplit(doc, dataDoc); } } render() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 79a0d18df..89fadab57 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -28,7 +28,7 @@ import { MainView } from '../MainView'; @observer export class CollectionDockingView extends React.Component { public static Instance: CollectionDockingView; - public static makeDocumentConfig(document: Doc, width?: number) { + public static makeDocumentConfig(document: Doc, dataDoc: Doc, width?: number) { return { type: 'react-component', component: 'DocumentFrameRenderer', @@ -36,6 +36,7 @@ export class CollectionDockingView extends React.Component - this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener. + dragDocs.map((dragDoc, i) => + this.AddRightSplit(dragDoc, dragDataDocs ? dragDataDocs[i] : dragDoc, true).contentItems[0].tab._dragListener. onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 })); } @action - public OpenFullScreen(document: Doc) { + public OpenFullScreen(document: Doc, dataDoc: Doc) { let newItemStackConfig = { type: 'stack', - content: [CollectionDockingView.makeDocumentConfig(document)] + content: [CollectionDockingView.makeDocumentConfig(document, dataDoc)] }; var docconfig = this._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, this._goldenLayout); this._goldenLayout.root.contentItems[0].addChild(docconfig); @@ -123,14 +124,14 @@ export class CollectionDockingView extends React.Component { + public AddRightSplit = (document: Doc, dataDoc: Doc, minimize: boolean = false) => { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); } let newItemStackConfig = { type: 'stack', - content: [CollectionDockingView.makeDocumentConfig(document)] + content: [CollectionDockingView.makeDocumentConfig(document, dataDoc)] }; var newContentItem = this._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, this._goldenLayout); @@ -160,12 +161,12 @@ export class CollectionDockingView extends React.Component { + public AddTab = (stack: any, document: Doc, dataDocument: Doc) => { let docs = Cast(this.props.Document.data, listSpec(Doc)); if (docs) { docs.push(document); } - let docContentConfig = CollectionDockingView.makeDocumentConfig(document); + let docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument); var newContentItem = stack.layoutManager.createContentItem(docContentConfig, this._goldenLayout); stack.addChild(newContentItem.contentItems[0], undefined); this.layoutChanged(); @@ -281,14 +282,16 @@ export class CollectionDockingView extends React.Component) => { + DocServer.GetRefField(docid).then(action(async (f: Opt) => { if (f instanceof Doc) { - DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), x, y, + let dataDoc = (datadocid !== docid) ? await DocServer.GetRefField(datadocid) : f; + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f], [dataDoc instanceof Doc ? dataDoc : f]), x, y, { handlers: { dragComplete: emptyFunction, @@ -338,33 +341,34 @@ export class CollectionDockingView extends React.Component { - if (doc instanceof Doc) { - let counter: any = this.htmlToElement(`0
`); - tab.element.append(counter); - let upDiv = document.createElement("span"); - const stack = tab.contentItem.parent; - // shifts the focus to this tab when another tab is dragged over it - tab.element[0].onmouseenter = (e: any) => { - if (!this._isPointerDown) return; - var activeContentItem = tab.header.parent.getActiveContentItem(); - if (tab.contentItem !== activeContentItem) { - tab.header.parent.setActiveContentItem(tab.contentItem); - } - tab.setActive(true); - }; - ReactDOM.render( CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv); - tab.reactComponents = [upDiv]; - tab.element.append(upDiv); - counter.DashDocId = tab.contentItem.config.props.documentId; - tab.reactionDisposer = reaction(() => [doc.linkedFromDocs, doc.LinkedToDocs, doc.title], - () => { - counter.innerHTML = DocListCast(doc.linkedFromDocs).length + DocListCast(doc.linkedToDocs).length; - tab.titleElement[0].textContent = doc.title; - }, { fireImmediately: true }); - tab.titleElement[0].DashDocId = tab.contentItem.config.props.documentId; - } - }); + let doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId) as Doc; + let dataDoc = await DocServer.GetRefField(tab.contentItem.config.props.dataDocumentId) as Doc; + if (doc instanceof Doc && dataDoc instanceof Doc) { + let counter: any = this.htmlToElement(`0
`); + tab.element.append(counter); + let upDiv = document.createElement("span"); + const stack = tab.contentItem.parent; + // shifts the focus to this tab when another tab is dragged over it + tab.element[0].onmouseenter = (e: any) => { + if (!this._isPointerDown) return; + var activeContentItem = tab.header.parent.getActiveContentItem(); + if (tab.contentItem !== activeContentItem) { + tab.header.parent.setActiveContentItem(tab.contentItem); + } + tab.setActive(true); + }; + ReactDOM.render( CollectionDockingView.Instance.AddTab(stack, doc, dataDoc)} />, upDiv); + tab.reactComponents = [upDiv]; + tab.element.append(upDiv); + counter.DashDocId = tab.contentItem.config.props.documentId; + counter.DashDataDocId = tab.contentItem.config.props.dataDocumentId; + tab.reactionDisposer = reaction(() => [doc.linkedFromDocs, doc.LinkedToDocs, doc.title], + () => { + counter.innerHTML = DocListCast(doc.linkedFromDocs).length + DocListCast(doc.linkedToDocs).length; + tab.titleElement[0].textContent = doc.title; + }, { fireImmediately: true }); + tab.titleElement[0].DashDocId = tab.contentItem.config.props.documentId; + } } tab.titleElement[0].Tab = tab; tab.closeElement.off('click') //unbind the current click handler @@ -427,6 +431,7 @@ export class CollectionDockingView extends React.Component { @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; + @observable private _dataDoc: Opt; get _stack(): any { let parent = (this.props as any).glContainer.parent.parent; if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) { @@ -444,7 +450,11 @@ export class DockedFrameRenderer extends React.Component { } constructor(props: any) { super(props); - DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => this._document = f as Doc)); + DocServer.GetRefField(this.props.documentId).then(action((f: Opt) => { + this._document = f as Doc; + if (!this.props.dataDocumentId || this.props.documentId === this.props.dataDocumentId) this._dataDoc = this._document; + })); + if (this.props.dataDocumentId && this.props.documentId !== this.props.dataDocumentId) DocServer.GetRefField(this.props.dataDocumentId).then(action((f: Opt) => this._dataDoc = f as Doc)); } nativeWidth = () => NumCast(this._document!.nativeWidth, this._panelWidth); @@ -481,17 +491,17 @@ export class DockedFrameRenderer extends React.Component { } get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } - addDocTab = (doc: Doc, location: string) => { + addDocTab = (doc: Doc, dataDoc: Doc, location: string) => { if (doc.dockingConfig) { MainView.Instance.openWorkspace(doc); } else if (location === "onRight") { - CollectionDockingView.Instance.AddRightSplit(doc); + CollectionDockingView.Instance.AddRightSplit(doc, dataDoc); } else { - CollectionDockingView.Instance.AddTab(this._stack, doc); + CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc); } } get content() { - if (!this._document) { + if (!this._document || !this._dataDoc) { return (null); } return ( @@ -499,7 +509,7 @@ export class DockedFrameRenderer extends React.Component { style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px) scale(${this.scaleToFitMultiplier}, ${this.scaleToFitMultiplier})` }}> boolean; active: () => boolean; whenActiveChanged: (isActive: boolean) => void; - addDocTab: (document: Doc, where: string) => void; + addDocTab: (document: Doc, dataDoc: Doc, where: string) => void; setPreviewScript: (script: string) => void; previewScript?: string; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 18d6751c6..83a7c9e3a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -26,6 +26,8 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); import { FormattedTextBox } from '../nodes/FormattedTextBox'; +import { ImageField } from '../../../new_fields/URLField'; +import { ImageBox } from '../nodes/ImageBox'; export interface TreeViewProps { @@ -35,7 +37,7 @@ export interface TreeViewProps { deleteDoc: (doc: Doc) => boolean; moveDocument: DragManager.MoveFunction; dropAction: "alias" | "copy" | undefined; - addDocTab: (doc: Doc, where: string) => void; + addDocTab: (doc: Doc, dataDoc: Doc, where: string) => void; panelWidth: () => number; panelHeight: () => number; addDocument: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean; @@ -73,7 +75,7 @@ class TreeView extends React.Component { } @undoBatch delete = () => this.props.deleteDoc(this.props.document); - @undoBatch openRight = async () => this.props.addDocTab(this.props.document, "onRight"); + @undoBatch openRight = async () => this.props.addDocTab(this.props.document, this.props.dataDoc, "onRight"); onPointerDown = (e: React.PointerEvent) => e.stopPropagation(); onPointerEnter = (e: React.PointerEvent): void => { @@ -148,6 +150,25 @@ class TreeView extends React.Component { SetValue={(value: string) => { let res = (Doc.GetProto(this.props.document)[key] = value) ? true : true; + if (value.startsWith(">>")) { + let metaKey = value.slice(2, value.length); + let collection = this.props.containingCollection; + Doc.GetProto(collection)[metaKey] = new ImageField("http://www.cs.brown.edu/~bcz/face.gif"); + let template = Doc.MakeAlias(collection); + template.title = metaKey; + template.embed = true; + template.layout = ImageBox.LayoutString(metaKey); + template.x = 0; + template.y = 0; + template.nativeWidth = 300; + template.nativeHeight = 300; + template.width = 300; + template.height = 300; + template.isTemplate = true; + template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); + Doc.AddDocToList(collection, "data", template); + this.delete(); + } if (value.startsWith(">")) { let metaKey = value.slice(1, value.length); let collection = this.props.containingCollection; @@ -236,10 +257,10 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.props.document)) }); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.KVPDocument(this.props.document, { width: 300, height: 300 }), "onRight"), icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }, icon: "layer-group" }); if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { - ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab"), icon: "folder" }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight"), icon: "caret-square-right" }); + ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.props.dataDoc, "inTab"), icon: "folder" }); + ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.props.dataDoc, "onRight"), icon: "caret-square-right" }); if (DocumentManager.Instance.getDocumentViews(this.props.document).length) { ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) }); } @@ -339,7 +360,7 @@ class TreeView extends React.Component { remove: ((doc: Doc) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, - addDocTab: (doc: Doc, where: string) => void, + addDocTab: (doc: Doc, dataDoc: Doc, where: string) => void, screenToLocalXf: () => Transform, outerXf: () => { translateX: number, translateY: number }, active: () => boolean, diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 89e5ad74c..10e6fb885 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -18,6 +18,7 @@ import { Doc } from '../../../new_fields/Doc'; import { FormattedTextBox } from '../nodes/FormattedTextBox'; import { Docs } from '../../documents/Documents'; import { List } from '../../../new_fields/List'; +import { ImageField } from '../../../new_fields/URLField'; export const COLLECTION_BORDER_WIDTH = 2; library.add(faTh); @@ -63,8 +64,9 @@ export class CollectionView extends React.Component { let otherdoc = Docs.TextDocument({ width: 100, height: 50, title: "applied template" }); Doc.GetProto(otherdoc).description = "THIS DESCRIPTION IS REALLY IMPORTANT!"; Doc.GetProto(otherdoc).summary = "THIS SUMMARY IS MEANINGFUL!"; + Doc.GetProto(otherdoc).photo = new ImageField("http://www.cs.brown.edu/~bcz/snowbeast.JPG"); Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); - this.props.addDocTab && this.props.addDocTab(otherdoc, "onRight"); + this.props.addDocTab && this.props.addDocTab(otherdoc, otherdoc, "onRight"); }), icon: "project-diagram" }); } diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index f11af04a3..fa7058d5a 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -9,7 +9,7 @@ import { CollectionDockingView } from "./CollectionDockingView"; import { NumCast } from "../../../new_fields/Types"; import { CollectionViewType } from "./CollectionBaseView"; -type SelectorProps = { Document: Doc, addDocTab(doc: Doc, location: string): void }; +type SelectorProps = { Document: Doc, addDocTab(doc: Doc, dataDoc: Doc, location: string): void }; @observer export class SelectorContextMenu extends React.Component { @observable private _docs: { col: Doc, target: Doc }[] = []; @@ -43,7 +43,7 @@ export class SelectorContextMenu extends React.Component { col.panX = newPanX; col.panY = newPanY; } - this.props.addDocTab(col, "inTab"); + this.props.addDocTab(col, col, "inTab"); // bcz: dataDoc? }; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index da50d0b53..08f58dcd6 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -81,7 +81,7 @@ export interface DocumentViewProps { parentActive: () => boolean; whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc) => void; - addDocTab: (doc: Doc, where: string) => void; + addDocTab: (doc: Doc, dataDoc: Doc, where: string) => void; animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; } @@ -212,8 +212,9 @@ export class DocumentView extends DocComponent(Docu startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) { if (this._mainCont.current) { let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; + let alldataConnected = [this.props.DataDoc, ...(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); + let dragData = new DragManager.DocumentDragData(allConnected, alldataConnected); const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.xOffset = xoff; @@ -268,7 +269,7 @@ export class DocumentView extends DocComponent(Docu let altKey = e.altKey; let ctrlKey = e.ctrlKey; if (this._doubleTap && !this.props.isTopMost) { - this.props.addDocTab(this.props.Document, "inTab"); + this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = false; } @@ -311,7 +312,7 @@ export class DocumentView extends DocComponent(Docu if (dataDocs) { expandedDocs.forEach(maxDoc => (!CollectionDockingView.Instance.CloseRightSplit(Doc.GetProto(maxDoc)) && - this.props.addDocTab(getDispDoc(maxDoc), maxLocation))); + this.props.addDocTab(getDispDoc(maxDoc), getDispDoc(maxDoc), maxLocation))); } } else { let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); @@ -334,7 +335,7 @@ export class DocumentView extends DocComponent(Docu 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, document => this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey ? 1 : 0], targetContext); + DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, document => this.props.addDocTab(document, document, maxLocation), linkedFwdPage[altKey ? 1 : 0], targetContext); } } } @@ -345,7 +346,7 @@ export class DocumentView extends DocComponent(Docu this._downY = e.clientY; this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; if (e.shiftKey && e.buttons === 1 && CollectionDockingView.Instance) { - CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); + CollectionDockingView.Instance.StartOtherDrag(e, [Doc.MakeAlias(this.props.Document)], [this.props.DataDoc]); e.stopPropagation(); } else { if (this.active) e.stopPropagation(); // events stop at the lowest document that is active. @@ -376,7 +377,7 @@ export class DocumentView extends DocComponent(Docu } deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); }; - fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"); }; + fieldsClicked = (): void => { let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }; makeBtnClicked = (): void => { let doc = Doc.GetProto(this.props.Document); doc.isButton = !BoolCast(doc.isButton, false); @@ -390,7 +391,7 @@ export class DocumentView extends DocComponent(Docu } } fullScreenClicked = (): void => { - CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(Doc.MakeCopy(this.props.Document, false)); + CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(Doc.MakeAlias(this.props.Document), this.props.DataDoc); SelectionManager.DeselectAll(); } @@ -473,10 +474,10 @@ export class DocumentView extends DocComponent(Docu const cm = ContextMenu.Instance; let subitems: ContextMenuProps[] = []; subitems.push({ description: "Open Full Screen", event: this.fullScreenClicked, icon: "desktop" }); - subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "inTab"), icon: "folder" }); - subitems.push({ description: "Open Tab Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" }); - subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, "onRight"), icon: "caret-square-right" }); - subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Tab Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); @@ -486,7 +487,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), "onRight"); + this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), Docs.SchemaDocument(["title"], aliases, {}), "onRight"); // bcz: dataDoc? }, icon: "search" }); cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document), icon: "crosshairs" }); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 35608af86..8879da55f 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -36,7 +36,7 @@ export interface FieldViewProps { isTopMost: boolean; selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; - addDocTab: (document: Doc, where: string) => void; + addDocTab: (document: Doc, dataDoc: Doc, where: string) => void; removeDocument?: (document: Doc) => boolean; moveDocument?: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; ScreenToLocalTransform: () => Transform; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f59af226d..39444fd6a 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -270,7 +270,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; if (this._linkClicked) { DocServer.GetRefField(this._linkClicked).then(f => { - (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, "inTab")); + (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, document => this.props.addDocTab(document, document, "inTab")); }); e.stopPropagation(); e.preventDefault(); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index f56a2d926..241a593b0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,13 +1,13 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faImage } from '@fortawesome/free-solid-svg-icons'; -import { action, observable } from 'mobx'; +import { action, observable, computed } 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 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; import { List } from '../../../new_fields/List'; import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; -import { Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types'; +import { Cast, FieldValue, NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; import { ImageField } from '../../../new_fields/URLField'; import { Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; @@ -36,7 +36,7 @@ const ImageDocument = makeInterface(pageSchema, positionSchema); @observer export class ImageBox extends DocComponent(ImageDocument) { - public static LayoutString() { return FieldView.LayoutString(ImageBox); } + public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject = React.createRef(); private _downX: number = 0; private _downY: number = 0; @@ -46,6 +46,8 @@ export class ImageBox extends DocComponent(ImageD private dropDisposer?: DragManager.DragDropDisposer; + @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + protected createDropTarget = (ele: HTMLDivElement) => { if (this.dropDisposer) { @@ -66,19 +68,24 @@ export class ImageBox extends DocComponent(ImageD drop = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { de.data.droppedDocuments.forEach(action((drop: Doc) => { - let layout = StrCast(drop.backgroundLayout); - if (layout.indexOf(ImageBox.name) !== -1) { - let imgData = this.props.Document[this.props.fieldKey]; - if (imgData instanceof ImageField) { - Doc.SetOnPrototype(this.props.Document, "data", new List([imgData])); - } - let imgList = Cast(this.props.Document[this.props.fieldKey], listSpec(ImageField), [] as any[]); - if (imgList) { - let field = drop.data; - if (field instanceof ImageField) imgList.push(field); - else if (field instanceof List) imgList.concat(field); - } + if (this.dataDoc !== this.props.Document && drop.data instanceof ImageField) { + this.dataDoc[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); + } else { + let layout = StrCast(drop.backgroundLayout); + if (layout.indexOf(ImageBox.name) !== -1) { + let imgData = this.dataDoc[this.props.fieldKey]; + if (imgData instanceof ImageField) { + Doc.SetOnPrototype(this.dataDoc, this.props.fieldKey, new List([imgData])); + } + let imgList = Cast(this.dataDoc[this.props.fieldKey], listSpec(ImageField), [] as any[]); + if (imgList) { + let field = drop.data; + if (field instanceof ImageField) imgList.push(field); + else if (field instanceof List) imgList.concat(field); + } + e.stopPropagation(); + } } })); // de.data.removeDocument() bcz: need to implement @@ -206,7 +213,7 @@ export class ImageBox extends DocComponent(ImageD let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; // this._curSuffix = ""; // if (w > 20) { - let field = this.Document[this.props.fieldKey]; + let field = this.dataDoc[this.props.fieldKey]; // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; @@ -214,8 +221,8 @@ export class ImageBox extends DocComponent(ImageD else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); // } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; - let rotation = NumCast(this.props.Document.rotation, 0); - let aspect = (rotation % 180) ? this.props.Document[HeightSym]() / this.props.Document[WidthSym]() : 1; + let rotation = NumCast(this.dataDoc.rotation, 0); + let aspect = (rotation % 180) ? this.dataDoc[HeightSym]() / this.dataDoc[WidthSym]() : 1; let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; return (
{ this._isPage[page] = "page"; this._visibleElements[page] = ( Date: Fri, 21 Jun 2019 22:46:24 -0400 Subject: fixes to allow collections to be template fields --- src/client/views/DocumentDecorations.tsx | 21 +++++++ .../views/collections/CollectionBaseView.tsx | 45 +++++--------- src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 71 ++++++++++++++-------- src/client/views/collections/CollectionView.tsx | 7 +++ .../collectionFreeForm/CollectionFreeFormView.tsx | 5 +- src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/ImageBox.tsx | 2 +- 8 files changed, 96 insertions(+), 60 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8f02f04d7..bdc814546 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -26,6 +26,7 @@ import { Template, Templates } from "./Templates"; import React = require("react"); import { URLField } from '../../new_fields/URLField'; import { templateLiteral } from 'babel-types'; +import { CollectionViewType } from './collections/CollectionBaseView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -74,6 +75,26 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (text[0] === '#') { this._fieldKey = text.slice(1, text.length); this._title = this.selectionTitle; + } else if (text.startsWith(">>>")) { + let metaKey = text.slice(3, text.length); + let collection = SelectionManager.SelectedDocuments()[0].props.ContainingCollectionView!.props.Document; + Doc.GetProto(collection)[metaKey] = new List([ + Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), + Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }), + ]); + let template = Doc.MakeAlias(collection); + template.title = metaKey; + template.embed = true; + template.layout = CollectionView.LayoutString(metaKey); + template.viewType = CollectionViewType.Freeform; + template.x = 0; + template.y = 0; + template.width = 300; + template.height = 300; + template.isTemplate = true; + template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); + Doc.AddDocToList(collection, "data", template); + SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document)); } else if (text[0] === ">") { let metaKey = text.slice(1, text.length); let first = SelectionManager.SelectedDocuments()[0].props.Document!; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 038a73626..75bdf755c 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -5,7 +5,7 @@ import { Doc, DocListCast, Opt } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { listSpec } from '../../../new_fields/Schema'; -import { Cast, FieldValue, NumCast, PromiseValue, StrCast } from '../../../new_fields/Types'; +import { Cast, FieldValue, NumCast, PromiseValue, StrCast, BoolCast } from '../../../new_fields/Types'; import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; @@ -60,6 +60,8 @@ export class CollectionBaseView extends React.Component { } } + @computed get dataDoc() { return (BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document); } + active = (): boolean => { var isSelected = this.props.isSelected(); var topMost = this.props.isTopMost; @@ -102,30 +104,21 @@ export class CollectionBaseView extends React.Component { @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { - let props = this.props; - var curPage = NumCast(props.Document.curPage, -1); + var curPage = NumCast(this.props.Document.curPage, -1); Doc.GetProto(doc).page = curPage; if (curPage >= 0) { - Doc.GetProto(doc).annotationOn = props.Document; + Doc.GetProto(doc).annotationOn = this.props.Document; } allowDuplicates = true; - if (!this.createsCycle(doc, props.Document)) { + if (!this.createsCycle(doc, this.dataDoc)) { //TODO This won't create the field if it doesn't already exist - const value = Cast(props.Document[props.fieldKey], listSpec(Doc)); - let alreadyAdded = true; + const value = Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc)); if (value !== undefined) { if (allowDuplicates || !value.some(v => v instanceof Doc && v[Id] === doc[Id])) { - alreadyAdded = false; value.push(doc); } } else { - alreadyAdded = false; - Doc.SetOnPrototype(this.props.Document, this.props.fieldKey, new List([doc])); - } - // set the ZoomBasis only if hasn't already been set -- bcz: maybe set/resetting the ZoomBasis should be a parameter to addDocument? - if (!alreadyAdded && (this.collectionViewType === CollectionViewType.Freeform || this.collectionViewType === CollectionViewType.Invalid)) { - let zoom = NumCast(this.props.Document.scale, 1); - // Doc.GetProto(doc).zoomBasis = zoom; + Doc.SetOnPrototype(this.dataDoc, this.props.fieldKey, new List([doc])); } return true; } @@ -136,22 +129,12 @@ export class CollectionBaseView extends React.Component { removeDocument(doc: Doc): boolean { let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const props = this.props; //TODO This won't create the field if it doesn't already exist - const value = Cast(props.Document[props.fieldKey], listSpec(Doc), []); - let index = -1; - for (let i = 0; i < value.length; i++) { - let v = value[i]; - if (v instanceof Doc && v[Id] === doc[Id]) { - index = i; - break; - } - } - PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => { - if (annotationOn === props.Document) { - doc.annotationOn = undefined; - } - }); + const value = Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), []); + let index = value.reduce((p, v, i) => (v instanceof Doc && v[Id] === doc[Id]) ? i : p, -1); + PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => + annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined) + ); if (index !== -1) { value.splice(index, 1); @@ -165,7 +148,7 @@ export class CollectionBaseView extends React.Component { @action.bound moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean { - if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { + if (Doc.AreProtosEqual(this.dataDoc, targetCollection)) { return true; } if (this.removeDocument(doc)) { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 699bddc7c..a887d8ec8 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -4,7 +4,7 @@ import CursorField from "../../../new_fields/CursorField"; import { Doc, DocListCast, Opt } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast, PromiseValue } from "../../../new_fields/Types"; +import { Cast, PromiseValue, BoolCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { RouteStore } from "../../../server/RouteStore"; import { DocServer } from "../../DocServer"; @@ -48,7 +48,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get childDocs() { //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 DocListCast(this.props.Document[this.props.fieldKey]); + return DocListCast((BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document)[this.props.fieldKey]); } @action diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 83a7c9e3a..05252f632 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -28,6 +28,8 @@ import React = require("react"); import { FormattedTextBox } from '../nodes/FormattedTextBox'; import { ImageField } from '../../../new_fields/URLField'; import { ImageBox } from '../nodes/ImageBox'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionView } from './CollectionView'; export interface TreeViewProps { @@ -150,42 +152,63 @@ class TreeView extends React.Component { SetValue={(value: string) => { let res = (Doc.GetProto(this.props.document)[key] = value) ? true : true; - if (value.startsWith(">>")) { - let metaKey = value.slice(2, value.length); + if (value.startsWith(">>>")) { + let metaKey = value.slice(3, value.length); let collection = this.props.containingCollection; - Doc.GetProto(collection)[metaKey] = new ImageField("http://www.cs.brown.edu/~bcz/face.gif"); + Doc.GetProto(collection)[metaKey] = new List([ + Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), + Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }), + ]); let template = Doc.MakeAlias(collection); template.title = metaKey; template.embed = true; - template.layout = ImageBox.LayoutString(metaKey); + template.layout = CollectionView.LayoutString(metaKey); + template.viewType = CollectionViewType.Freeform; template.x = 0; template.y = 0; - template.nativeWidth = 300; - template.nativeHeight = 300; template.width = 300; template.height = 300; template.isTemplate = true; template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); Doc.AddDocToList(collection, "data", template); this.delete(); - } - if (value.startsWith(">")) { - let metaKey = value.slice(1, value.length); - let collection = this.props.containingCollection; - Doc.GetProto(collection)[metaKey] = "-empty field-"; - let template = Doc.MakeAlias(collection); - template.title = metaKey; - template.embed = true; - template.layout = FormattedTextBox.LayoutString(metaKey); - template.x = 0; - template.y = 0; - template.width = 100; - template.height = 50; - template.isTemplate = true; - template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); - Doc.AddDocToList(collection, "data", template); - this.delete(); - } + } else + if (value.startsWith(">>")) { + let metaKey = value.slice(2, value.length); + let collection = this.props.containingCollection; + Doc.GetProto(collection)[metaKey] = new ImageField("http://www.cs.brown.edu/~bcz/face.gif"); + let template = Doc.MakeAlias(collection); + template.title = metaKey; + template.embed = true; + template.layout = ImageBox.LayoutString(metaKey); + template.x = 0; + template.y = 0; + template.nativeWidth = 300; + template.nativeHeight = 300; + template.width = 300; + template.height = 300; + template.isTemplate = true; + template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); + Doc.AddDocToList(collection, "data", template); + this.delete(); + } else + if (value.startsWith(">")) { + let metaKey = value.slice(1, value.length); + let collection = this.props.containingCollection; + Doc.GetProto(collection)[metaKey] = "-empty field-"; + let template = Doc.MakeAlias(collection); + template.title = metaKey; + template.embed = true; + template.layout = FormattedTextBox.LayoutString(metaKey); + template.x = 0; + template.y = 0; + template.width = 100; + template.height = 50; + template.isTemplate = true; + template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); + Doc.AddDocToList(collection, "data", template); + this.delete(); + } return res; }} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 10e6fb885..872cb3f1c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -66,6 +66,13 @@ export class CollectionView extends React.Component { Doc.GetProto(otherdoc).summary = "THIS SUMMARY IS MEANINGFUL!"; Doc.GetProto(otherdoc).photo = new ImageField("http://www.cs.brown.edu/~bcz/snowbeast.JPG"); Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); + Doc.GetProto(otherdoc).publication = new List([ + Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }), + Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), + Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), + Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), + Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }), + ]); this.props.addDocTab && this.props.addDocTab(otherdoc, otherdoc, "onRight"); }), icon: "project-diagram" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 5c2ea3ef0..20a9a172c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -45,6 +45,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } + @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } public get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey === "annotations"; } @@ -163,7 +164,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); - let ink = Cast(this.props.Document.ink, InkField); + let ink = Cast(this.dataDoc.ink, InkField); if (ink && ink.inkData) { ink.inkData.forEach((value: StrokeData, key: string) => { let bounds = InkingCanvas.StrokeRect(value); @@ -296,7 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getDocumentViewProps(layoutDoc: Doc): DocumentViewProps { return { - DataDoc: this.props.DataDoc !== this.props.Document ? this.props.DataDoc : layoutDoc, + DataDoc: this.props.DataDoc !== this.props.Document && !BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : layoutDoc, Document: layoutDoc, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 08f58dcd6..1a92d7152 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -536,6 +536,7 @@ export class DocumentView extends DocComponent(Docu @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } @computed get contents() { + console.log("dv = " + this.props.Document.title + " " + this.props.DataDoc.title); return ( ); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 241a593b0..008a09130 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -68,7 +68,7 @@ export class ImageBox extends DocComponent(ImageD drop = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { de.data.droppedDocuments.forEach(action((drop: Doc) => { - if (this.dataDoc !== this.props.Document && drop.data instanceof ImageField) { + if (/*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { this.dataDoc[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); } else { -- cgit v1.2.3-70-g09d2 From 46c51661acb042ed2779d26a6a8305ec15bec25b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 25 Jun 2019 20:18:06 -0400 Subject: cleaned up version of templates with annotations. --- .../views/collections/CollectionBaseView.tsx | 11 ++++----- src/client/views/collections/CollectionSubView.tsx | 6 +++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 10 +------- src/client/views/nodes/ImageBox.tsx | 4 ++-- src/new_fields/Doc.ts | 27 ++++++++++++++-------- 5 files changed, 30 insertions(+), 28 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 13c4a33a8..22e8259e7 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -1,16 +1,16 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Opt } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { listSpec } from '../../../new_fields/Schema'; -import { Cast, FieldValue, NumCast, PromiseValue, StrCast, BoolCast } from '../../../new_fields/Types'; +import { BoolCast, Cast, NumCast, PromiseValue } from '../../../new_fields/Types'; +import { DocumentManager } from '../../util/DocumentManager'; import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import './CollectionBaseView.scss'; -import { DocumentManager } from '../../util/DocumentManager'; export enum CollectionViewType { Invalid, @@ -36,7 +36,6 @@ export interface CollectionViewProps extends FieldViewProps { contentRef?: React.Ref; } - @observer export class CollectionBaseView extends React.Component { @observable private static _safeMode = false; @@ -75,10 +74,10 @@ export class CollectionBaseView extends React.Component { } @computed get extDoc() { - return this.dataDoc && this.props.fieldExt && this.dataDoc[this.props.fieldKey + "_ext"] instanceof Doc ? this.dataDoc[this.props.fieldKey + "_ext"] as Doc : this.dataDoc; + return Doc.extDoc(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } @computed get extField() { - return this.dataDoc && this.props.fieldExt && this.dataDoc[this.props.fieldKey + "_ext"] instanceof Doc ? this.props.fieldExt : this.props.fieldKey; + return Doc.extField(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } @action.bound diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index caf6aa0c9..1b1f765ed 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -45,13 +45,15 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } + @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } @computed get extDoc() { - return this.props.DataDoc && this.props.fieldExt && this.props.DataDoc[this.props.fieldKey + "_ext"] instanceof Doc ? this.props.DataDoc[this.props.fieldKey + "_ext"] as Doc : this.props.DataDoc; + return Doc.extDoc(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } @computed get extField() { - return this.props.DataDoc && this.props.fieldExt && this.props.DataDoc[this.props.fieldKey + "_ext"] instanceof Doc ? this.props.fieldExt : this.props.fieldKey; + return Doc.extField(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } + get childDocs() { //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) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9f4daf38d..7489af1aa 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -47,7 +47,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } - @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } @computed get nativeWidth() { return this.Document.nativeWidth || 0; } @computed get nativeHeight() { return this.Document.nativeHeight || 0; } public get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldExt === "annotations"; } @@ -371,10 +370,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); } - @computed get extDoc() { - return this.dataDoc && this.props.fieldExt && this.dataDoc[this.props.fieldKey + "_ext"] instanceof Doc ? this.dataDoc[this.props.fieldKey + "_ext"] as Doc : this.dataDoc; - } - private childViews = () => [ , ...this.views @@ -382,10 +377,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { render() { const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; const easing = () => this.props.Document.panTransformType === "Ease"; - if (this.dataDoc && this.props.fieldExt && this.dataDoc[this.props.fieldKey + "_ext"] === undefined) { - console.log("Timeout " + this.dataDoc.title + " " + this.props.fieldKey); - setTimeout(() => Doc.MakeFieldExtension(this.dataDoc, this.props.fieldKey), 0); - } + if (this.props.fieldExt) Doc.UpdateFieldExtension(this.dataDoc, this.props.fieldKey); return (
(ImageD if (de.data instanceof DragManager.DocumentDragData) { de.data.droppedDocuments.forEach(action((drop: Doc) => { if (/*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { - this.dataDoc[this.props.fieldKey] = new ImageField(drop.data.url); + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); } else { let layout = StrCast(drop.backgroundLayout); if (layout.indexOf(ImageBox.name) !== -1) { let imgData = this.dataDoc[this.props.fieldKey]; if (imgData instanceof ImageField) { - Doc.SetOnPrototype(this.dataDoc, this.props.fieldKey, new List([imgData])); + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new List([imgData]); } let imgList = Cast(this.dataDoc[this.props.fieldKey], listSpec(ImageField), [] as any[]); if (imgList) { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 621f87981..675278ed5 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -224,7 +224,7 @@ export namespace Doc { // gets the document's prototype or returns the document if it is a prototype export function GetProto(doc: Doc) { - return Doc.GetT(doc, "isPrototype", "boolean", true) || doc.isTemplate ? doc : (doc.proto || doc); + return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc); } export function allKeys(doc: Doc): string[] { @@ -249,16 +249,25 @@ export namespace Doc { return true; } - export function MakeFieldExtension(doc: Doc, fieldKey: string) { - let fieldExtension = new Doc(doc[Id] + fieldKey, true); - fieldExtension.title = "Extension of " + doc.title + "'s field:" + fieldKey; - let proto: Doc | undefined = doc; - while (proto && !Doc.IsPrototype(proto)) { - proto = proto.proto; + export function extDoc(doc: Doc, fieldKey: string, fieldExt: string) { + return doc && fieldExt && doc[fieldKey + "_ext"] instanceof Doc ? doc[fieldKey + "_ext"] as Doc : doc; + } + export function extField(doc: Doc, fieldKey: string, fieldExt: string) { + return doc && fieldExt && doc[fieldKey + "_ext"] instanceof Doc ? fieldExt : fieldKey; + } + export function UpdateFieldExtension(doc: Doc, fieldKey: string) { + if (doc && doc[fieldKey + "_ext"] === undefined) { + setTimeout(() => { + let fieldExtension = new Doc(doc[Id] + fieldKey, true); + fieldExtension.title = "Extension of " + doc.title + "'s field:" + fieldKey; + let proto: Doc | undefined = doc; + while (proto && !Doc.IsPrototype(proto)) { + proto = proto.proto; + } + (proto ? proto : doc)[fieldKey + "_ext"] = fieldExtension; + }, 0); } - (proto ? proto : doc)[fieldKey + "_ext"] = fieldExtension; } - export function MakeAlias(doc: Doc) { if (!GetT(doc, "isPrototype", "boolean", true)) { return Doc.MakeCopy(doc); -- cgit v1.2.3-70-g09d2 From 24d835913f919d99df56303982c38a441ac57e59 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 25 Jun 2019 21:17:42 -0400 Subject: more cleanup --- src/client/views/DocumentDecorations.tsx | 7 ++-- .../views/collections/CollectionBaseView.tsx | 4 +- src/client/views/collections/CollectionSubView.tsx | 11 ++---- .../views/collections/CollectionTreeView.tsx | 43 +--------------------- src/client/views/collections/CollectionView.tsx | 5 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 +- 9 files changed, 19 insertions(+), 59 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9ce68d200..e8ea7d5fc 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -82,10 +82,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let collectionKey = field.props.ContainingCollectionView!.props.fieldKey; let collectionKeyProp = `fieldKey={"${collectionKey}"}`; - let collectionAnoKeyProp = `fieldKey={"annotations"}`; let metaKey = text.slice(1, text.length); let metaKeyProp = `fieldKey={"${metaKey}"}`; - let metaAnoKeyProp = `fieldKey={"${metaKey}"} fieldExt={"annotations"}`; let template = Doc.MakeAlias(field.props.Document); template.proto = collection; @@ -95,10 +93,13 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> template.embed = true; template.isTemplate = true; template.templates = new List([Templates.TitleBar(metaKey)]); - template.layout = StrCast(field.props.Document.layout).replace(collectionKeyProp, metaKeyProp); if (field.props.Document.backgroundLayout) { + let metaAnoKeyProp = `fieldKey={"${metaKey}"} fieldExt={"annotations"}`; + let collectionAnoKeyProp = `fieldKey={"annotations"}`; template.layout = StrCast(field.props.Document.layout).replace(collectionAnoKeyProp, metaAnoKeyProp); template.backgroundLayout = StrCast(field.props.Document.backgroundLayout).replace(collectionKeyProp, metaKeyProp); + } else { + template.layout = StrCast(field.props.Document.layout).replace(collectionKeyProp, metaKeyProp); } Doc.AddDocToList(collection, collectionKey, template); SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document)); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 22e8259e7..4ef84ac66 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -59,7 +59,7 @@ export class CollectionBaseView extends React.Component { } } - @computed get dataDoc() { return (BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document); } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } active = (): boolean => { var isSelected = this.props.isSelected(); @@ -104,7 +104,7 @@ export class CollectionBaseView extends React.Component { let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); //TODO This won't create the field if it doesn't already exist - const value = Cast(this.dataDoc[this.props.fieldKey], listSpec(Doc), []); + const value = Cast(this.extDoc[this.extField], listSpec(Doc), []); let index = value.reduce((p, v, i) => (v instanceof Doc && v[Id] === doc[Id]) ? i : p, -1); PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined) diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1b1f765ed..f1f1d9127 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -45,14 +45,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } - @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } - - @computed get extDoc() { - return Doc.extDoc(this.dataDoc, this.props.fieldKey, this.props.fieldExt); - } - @computed get extField() { - return Doc.extField(this.dataDoc, this.props.fieldKey, this.props.fieldExt); - } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get extDoc() { return Doc.extDoc(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } + @computed get extField() { return Doc.extField(this.dataDoc, this.props.fieldKey, this.props.fieldExt); } get childDocs() { //TODO tfs: This might not be what we want? diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f5f323269..eeacb02e8 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -89,7 +89,7 @@ class TreeView extends React.Component { return keyList.length ? keyList[0] : "data"; } - @computed get dataDoc() { return (BoolCast(this.props.document.isTemplate) ? this.props.dataDoc : this.props.document); } + @computed get dataDoc() { return BoolCast(this.props.document.isTemplate) ? this.props.dataDoc : this.props.document; } protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); @@ -171,45 +171,7 @@ class TreeView extends React.Component { height={36} fontStyle={style} GetValue={() => StrCast(this.props.document[key])} - SetValue={(value: string) => { - let res = (Doc.GetProto(this.dataDoc)[key] = value) ? true : true; - - if (value.startsWith(">")) { - let metaKey = value.slice(value.startsWith(">>>") ? 3 : value.startsWith(">>") ? 2 : 1, value.length); - let collection = this.props.containingCollection; - let template = Doc.MakeAlias(collection); - template.title = metaKey; - template.embed = true; - template.x = 0; - template.y = 0; - template.width = 300; - template.height = 300; - template.isTemplate = true; - template.templates = new List([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]); - if (value.startsWith(">>>")) { // Collection - Doc.GetProto(collection)[metaKey] = new List([ - Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }), - Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }), - ]); - template.layout = CollectionView.LayoutString(metaKey); - template.viewType = CollectionViewType.Freeform; - } else if (value.startsWith(">>")) { // Image - Doc.GetProto(collection)[metaKey] = new ImageField("http://www.cs.brown.edu/~bcz/face.gif"); - template.layout = ImageBox.LayoutString(metaKey); - template.nativeWidth = 300; - template.nativeHeight = 300; - } else if (value.startsWith(">")) { // Text - Doc.GetProto(collection)[metaKey] = "-empty field-"; - template.layout = FormattedTextBox.LayoutString(metaKey); - template.width = 100; - template.height = 50; - } - Doc.AddDocToList(collection, "data", template); - this.delete(); - } - - return res; - }} + SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true} OnFillDown={(value: string) => { Doc.GetProto(this.dataDoc)[key] = value; let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); @@ -456,7 +418,6 @@ export class CollectionTreeView extends CollectionSubView(Document) { outerXf = () => Utils.GetScreenTransform(this._mainEle!); onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {}); - @computed get dataDoc() { return (BoolCast(this.props.DataDoc.isTemplate) ? this.props.DataDoc : this.props.Document); } render() { let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ab1dbc499..a133eacb1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -58,7 +58,10 @@ export class CollectionView extends React.Component { ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems }); ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => { - let otherdoc = Docs.TextDocument({ width: 100, height: 50, title: "applied template" }); + let otherdoc = new Doc(); + otherdoc.width = 100; + otherdoc.height = 50; + Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")"; Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document); this.props.addDocTab && this.props.addDocTab(otherdoc, otherdoc, "onRight"); }), icon: "project-diagram" diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7489af1aa..cbd9e3de3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -298,7 +298,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getDocumentViewProps(layoutDoc: Doc): DocumentViewProps { return { - DataDoc: this.props.DataDoc !== this.props.Document && !BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : layoutDoc, + DataDoc: BoolCast(this.props.Document.isTemplate) ? layoutDoc : this.props.DataDoc, Document: layoutDoc, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index c18bc8f22..0a1a86226 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -110,7 +110,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } dispatchTransaction = (tx: Transaction) => { if (this._editorView) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 09bf21228..0da774db1 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -46,7 +46,7 @@ export class ImageBox extends DocComponent(ImageD private dropDisposer?: DragManager.DragDropDisposer; - @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } protected createDropTarget = (ele: HTMLDivElement) => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 61789bb30..f8bf5faf3 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -27,7 +27,7 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _alt = false; @observable private _scrollY: number = 0; - @computed get dataDoc() { return this.props.DataDoc && BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } private _reactionDisposer?: IReactionDisposer; -- cgit v1.2.3-70-g09d2 From 084dd6d9b0ad51133025ba6bd2702fc44b1b6c31 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 26 Jun 2019 12:56:22 -0400 Subject: fixes to datadoc usage. fixed tree view for textboxes. --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/MainView.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 10 +-- src/client/views/collections/CollectionSubView.tsx | 5 +- .../views/collections/CollectionTreeView.tsx | 81 +++++++++++----------- .../collectionFreeForm/CollectionFreeFormView.tsx | 9 +-- src/client/views/nodes/DocumentView.tsx | 19 ++--- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/new_fields/Doc.ts | 2 +- 13 files changed, 75 insertions(+), 69 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b9537fca6..557db3639 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -176,7 +176,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dragDocView = SelectionManager.SelectedDocuments()[0]; const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); const [xoff, yoff] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top); - let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document), SelectionManager.SelectedDocuments().map(dv => dv.props.DataDoc)); + let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document), SelectionManager.SelectedDocuments().map(dv => dv.props.DataDoc ? dv.props.DataDoc : dv.props.Document)); dragData.xOffset = xoff; dragData.yOffset = yoff; dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index d26e24748..e48de27d7 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -203,7 +203,7 @@ export class MainView extends React.Component { let mainCont = this.mainContainer; let content = !mainCont ? (null) : { } } - @computed get dataDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } + @computed get dataDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc ? this.props.DataDoc : this.props.Document : this.props.Document, this.props.fieldKey, this.props.fieldExt); } @computed get dataField() { return this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; } active = (): boolean => { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 796882724..a8061f9f1 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -437,15 +437,16 @@ export class CollectionSchemaPreview extends React.Component this.nativeWidth * this.contentScaling(); - private PanelHeight = () => this.nativeHeight * this.contentScaling(); + private PanelWidth = () => this.nativeWidth ? this.nativeWidth * this.contentScaling() : this.props.width(); + private PanelHeight = () => this.nativeHeight ? this.nativeHeight * this.contentScaling() : this.props.height(); private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling()); - get centeringOffset() { return (this.props.width() - this.nativeWidth * this.contentScaling()) / 2; } + get centeringOffset() { return this.nativeWidth ? (this.props.width() - this.nativeWidth * this.contentScaling()) / 2 : 0; } @action onPreviewScriptChange = (e: React.ChangeEvent) => { this.props.setPreviewScript(e.currentTarget.value); } render() { + let self = this; let input = this.props.previewScript === undefined ? (null) :
; @@ -462,7 +463,8 @@ export class CollectionSchemaPreview extends React.Component(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } - @computed get dataDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } - @computed get dataField() { return this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; } + @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } get childDocs() { //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 DocListCast((BoolCast(this.props.Document.isTemplate) ? this.dataDoc : this.props.Document)[this.dataField]); + return DocListCast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); } @action diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index d33a4786c..a8324eba2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -29,7 +29,7 @@ import React = require("react"); export interface TreeViewProps { document: Doc; - dataDoc: Doc; + dataDoc?: Doc; containingCollection: Doc; deleteDoc: (doc: Doc) => boolean; moveDocument: DragManager.MoveFunction; @@ -66,14 +66,14 @@ class TreeView extends React.Component { @observable _collapsed: boolean = true; @computed get fieldKey() { - let keys = Array.from(Object.keys(this.dataDoc)); - if (this.dataDoc.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.dataDoc.proto))); + let keys = Array.from(Object.keys(this.resolvedDataDoc)); + if (this.resolvedDataDoc.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto))); while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } let keyList: string[] = []; keys.map(key => { - let docList = Cast(this.dataDoc[key], listSpec(Doc)); + let docList = Cast(this.resolvedDataDoc[key], listSpec(Doc)); if (docList && docList.length > 0) { keyList.push(key); } @@ -85,7 +85,7 @@ class TreeView extends React.Component { return keyList.length ? keyList[0] : "data"; } - @computed get dataDoc() { return BoolCast(this.props.document.isTemplate) ? this.props.dataDoc : this.props.document; } + @computed get resolvedDataDoc() { return BoolCast(this.props.document.isTemplate) && this.props.dataDoc ? this.props.dataDoc : this.props.document; } protected createTreeDropTarget = (ele: HTMLDivElement) => { this._treedropDisposer && this._treedropDisposer(); @@ -94,7 +94,7 @@ class TreeView extends React.Component { } } - @undoBatch delete = () => this.props.deleteDoc(this.dataDoc); + @undoBatch delete = () => this.props.deleteDoc(this.resolvedDataDoc); @undoBatch openRight = async () => this.props.addDocTab(this.props.document, this.props.document, "onRight"); onPointerDown = (e: React.PointerEvent) => e.stopPropagation(); @@ -126,7 +126,7 @@ class TreeView extends React.Component { @action remove = (document: Document, key: string): boolean => { - let children = Cast(this.dataDoc[key], listSpec(Doc), []); + let children = Cast(this.resolvedDataDoc[key], listSpec(Doc), []); if (children.indexOf(document) !== -1) { children.splice(children.indexOf(document), 1); return true; @@ -142,8 +142,8 @@ class TreeView extends React.Component { indent = () => this.props.addDocument(this.props.document) && this.delete() renderBullet() { - let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc)); - let doc = Cast(this.dataDoc[this.fieldKey], Doc); + let docList = Cast(this.resolvedDataDoc[this.fieldKey], listSpec(Doc)); + let doc = Cast(this.resolvedDataDoc[this.fieldKey], Doc); let isDoc = doc instanceof Doc || docList; return
this._collapsed = !this._collapsed)}> {} @@ -161,15 +161,15 @@ class TreeView extends React.Component { editableView = (key: string, style?: string) => ( StrCast(this.props.document[key])} - SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true} + SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc)[key] = value) ? true : true} OnFillDown={(value: string) => { - Doc.GetProto(this.dataDoc)[key] = value; + Doc.GetProto(this.resolvedDataDoc)[key] = value; let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); TreeView.loadId = doc[Id]; return this.props.addDocument(doc); @@ -178,13 +178,13 @@ class TreeView extends React.Component { />) @computed get keyList() { - let keys = Array.from(Object.keys(this.dataDoc)); - if (this.dataDoc.proto instanceof Doc) { - keys.push(...Array.from(Object.keys(this.dataDoc.proto))); + let keys = Array.from(Object.keys(this.resolvedDataDoc)); + if (this.resolvedDataDoc.proto instanceof Doc) { + keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto))); while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } - let keyList: string[] = keys.reduce((l, key) => Cast(this.dataDoc[key], listSpec(Doc)) ? [...l, key] : l, [] as string[]); - keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && keyList.push(key)); + let keyList: string[] = keys.reduce((l, key) => Cast(this.resolvedDataDoc[key], listSpec(Doc)) ? [...l, key] : l, [] as string[]); + keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key)); if (keyList.indexOf(this.fieldKey) !== -1) { keyList.splice(keyList.indexOf(this.fieldKey), 1); } @@ -196,7 +196,7 @@ class TreeView extends React.Component { */ renderTitle() { let reference = React.createRef(); - let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); + let onItemDown = SetupDrag(reference, () => this.resolvedDataDoc, this.move, this.props.dropAction, this.props.treeViewId, true); let headerElements = ( { {this._chosenKey} ); let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : []; - let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : ( + let openRight = dataDocs && dataDocs.indexOf(this.resolvedDataDoc) !== -1 ? (null) : (
); @@ -229,13 +229,13 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.dataDoc)) }); + ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.resolvedDataDoc)) }); ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }, icon: "layer-group" }); if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { - ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.dataDoc, "inTab"), icon: "folder" }); - ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.dataDoc, "onRight"), icon: "caret-square-right" }); - if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) { - ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.dataDoc).map(view => view.props.focus(this.props.document)) }); + ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" }); + ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" }); + if (DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).length) { + ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).map(view => view.props.focus(this.props.document)) }); } ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)) }); } else { @@ -252,9 +252,9 @@ class TreeView extends React.Component { let before = x[1] < bounds[1]; let inside = x[0] > bounds[0] + 75 || (!before && !this._collapsed); if (de.data instanceof DragManager.DocumentDragData) { - let addDoc = (doc: Doc) => this.props.addDocument(doc, this.dataDoc, before); + let addDoc = (doc: Doc) => this.props.addDocument(doc, this.resolvedDataDoc, before); if (inside) { - let docList = Cast(this.dataDoc.data, listSpec(Doc)); + let docList = Cast(this.resolvedDataDoc.data, listSpec(Doc)); if (docList !== undefined) { addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }; } @@ -262,10 +262,10 @@ class TreeView extends React.Component { e.stopPropagation(); let movedDocs = (de.data.options === this.props.treeViewId ? de.data.draggedDocuments : de.data.droppedDocuments); return (de.data.dropAction || de.data.userDropAction) ? - de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.dataDoc, before) || added, false) + de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before) || added, false) : (de.data.moveDocument) ? - movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.dataDoc, addDoc) || added, false) - : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.dataDoc, before), false); + movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.resolvedDataDoc, addDoc) || added, false) + : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before), false); } return false; } @@ -280,22 +280,23 @@ class TreeView extends React.Component { render() { let contentElement: (JSX.Element | null) = null; - let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc)); + let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc)); let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey); - let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before); - let doc = Cast(this.dataDoc[this._chosenKey], Doc); + let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.resolvedDataDoc, this._chosenKey, doc, addBefore, before); + let doc = Cast(this.resolvedDataDoc[this._chosenKey], Doc); let docWidth = () => NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5; if (!this._collapsed) { if (!this.props.document.embed) { contentElement =
    - {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.dataDoc, this._chosenKey, addDoc, remDoc, this.move, + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.props.dataDoc, this._chosenKey, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth)}
; } else { + console.log("PW = " + this.props.panelWidth()); contentElement =
{ docs: Doc[], treeViewId: string, containingCollection: Doc, - dataDoc: Doc, + dataDoc: Doc | undefined, key: string, add: (doc: Doc, relativeTo?: Doc, before?: boolean) => boolean, remove: ((doc: Doc) => boolean), @@ -412,6 +413,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } + @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } + outerXf = () => Utils.GetScreenTransform(this._mainEle!); onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {}); @@ -428,11 +431,11 @@ export class CollectionTreeView extends CollectionSubView(Document) { onDrop={this.onTreeDrop} ref={this.createTreeDropTarget}> StrCast(this.props.DataDoc.title)} - SetValue={(value: string) => (Doc.GetProto(this.props.DataDoc).title = value) ? true : true} + GetValue={() => StrCast(this.resolvedDataDoc.title)} + SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true} OnFillDown={(value: string) => { Doc.GetProto(this.props.Document).title = value; let doc = Docs.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List([Templates.Title.Layout]) }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a3ca02941..6672b3a07 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -163,7 +163,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); - let ink = Cast(this.dataDoc.ink, InkField); + let ink = Cast(this.extensionDoc.ink, InkField); if (ink && ink.inkData) { ink.inkData.forEach((value: StrokeData, key: string) => { let bounds = InkingCanvas.StrokeRect(value); @@ -295,8 +295,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { getDocumentViewProps(layoutDoc: Doc): DocumentViewProps { + let datadoc = BoolCast(this.props.Document.isTemplate) || this.props.DataDoc === this.props.Document ? undefined : this.props.DataDoc; return { - DataDoc: BoolCast(this.props.Document.isTemplate) ? layoutDoc : this.props.DataDoc, + DataDoc: datadoc, Document: layoutDoc, addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, @@ -375,7 +376,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { render() { const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; const easing = () => this.props.Document.panTransformType === "Ease"; - if (this.props.fieldExt) Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); + if (this.props.fieldExt) Doc.UpdateDocumentExtensionForField(this.extensionDoc, this.props.fieldKey); return (
- + {this.childViews} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9c3479ec2..eb4f56af1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -67,7 +67,7 @@ const LinkDoc = makeInterface(linkSchema); export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Doc; - DataDoc: Doc; + DataDoc?: Doc; addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean; removeDocument?: (doc: Doc) => boolean; moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; @@ -209,10 +209,11 @@ export class DocumentView extends DocComponent(Docu e.stopPropagation(); } + get dataDoc() { return this.props.DataDoc ? this.props.DataDoc : this.props.Document; } startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) { if (this._mainCont.current) { let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; - let alldataConnected = [this.props.DataDoc, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; + let alldataConnected = [this.dataDoc, ...(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, alldataConnected); const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); @@ -271,7 +272,7 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth) { let fullScreenAlias = Doc.MakeAlias(this.props.Document); fullScreenAlias.templates = new List(); - this.props.addDocTab(fullScreenAlias, this.props.DataDoc, "inTab"); + this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); this.props.Document.libraryBrush = false; } @@ -348,7 +349,7 @@ export class DocumentView extends DocComponent(Docu this._downY = e.clientY; this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; if (e.shiftKey && e.buttons === 1 && CollectionDockingView.Instance) { - CollectionDockingView.Instance.StartOtherDrag(e, [Doc.MakeAlias(this.props.Document)], [this.props.DataDoc]); + CollectionDockingView.Instance.StartOtherDrag(e, [Doc.MakeAlias(this.props.Document)], [this.dataDoc]); e.stopPropagation(); } else { if (this.active) e.stopPropagation(); // events stop at the lowest document that is active. @@ -393,7 +394,7 @@ export class DocumentView extends DocComponent(Docu } } fullScreenClicked = (): void => { - CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(Doc.MakeAlias(this.props.Document), this.props.DataDoc); + CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(Doc.MakeAlias(this.props.Document), this.dataDoc); SelectionManager.DeselectAll(); } @@ -476,10 +477,10 @@ export class DocumentView extends DocComponent(Docu const cm = ContextMenu.Instance; let subitems: ContextMenuProps[] = []; subitems.push({ description: "Open Full Screen", event: this.fullScreenClicked, icon: "desktop" }); - subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab"), icon: "folder" }); - subitems.push({ description: "Open Tab Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" }); - subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight"), icon: "caret-square-right" }); - subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Tab", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.dataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Tab Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Right", event: () => this.props.addDocTab && this.props.addDocTab(this.props.Document, this.dataDoc, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" }); subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" }); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 8a481144e..55f61ddff 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -30,7 +30,7 @@ export interface FieldViewProps { fieldExt: string; ContainingCollectionView: Opt; Document: Doc; - DataDoc: Doc; + DataDoc?: Doc; isSelected: () => boolean; select: (isCtrlPressed: boolean) => void; renderDepth: number; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0a1a86226..e1a496574 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -110,15 +110,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } dispatchTransaction = (tx: Transaction) => { if (this._editorView) { const state = this._editorView.state.apply(tx); this._editorView.updateState(state); this._applyingChange = true; - Doc.SetOnPrototype(this.dataDoc, this.props.fieldKey, new RichTextField(JSON.stringify(state.toJSON()))); - Doc.SetOnPrototype(this.dataDoc, this.props.fieldKey + "_text", state.doc.textBetween(0, state.doc.content.size, "\n\n")); + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON())); + Doc.GetProto(this.dataDoc)[this.props.fieldKey + "_text"] = state.doc.textBetween(0, state.doc.content.size, "\n\n"); this._applyingChange = false; let title = StrCast(this.dataDoc.title); if (title && title.startsWith("-") && this._editorView) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0da774db1..0e6c1ee19 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -46,7 +46,7 @@ export class ImageBox extends DocComponent(ImageD private dropDisposer?: DragManager.DragDropDisposer; - @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } protected createDropTarget = (ele: HTMLDivElement) => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index f8bf5faf3..b863ee4fc 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -27,7 +27,7 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _alt = false; @observable private _scrollY: number = 0; - @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) ? this.props.DataDoc : this.props.Document; } + @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } private _reactionDisposer?: IReactionDisposer; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 8825bc13a..ddbbc1436 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -178,7 +178,7 @@ export namespace Doc { export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { let hasProto = doc.proto instanceof Doc; let onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; - let onProto = Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; + let onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; if (onDeleg || !hasProto || (!onProto && !defaultProto)) doc[key] = value; else doc.proto![key] = value; -- cgit v1.2.3-70-g09d2 From 07f68d5692609a6128716f2b9f1effa2a09013b2 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 27 Jun 2019 09:25:32 -0400 Subject: restored ink width control. changed dropping image on image to swap image only if Alt is pressed. --- src/client/views/InkingControl.tsx | 5 ++--- src/client/views/MainView.tsx | 1 - src/client/views/nodes/ImageBox.tsx | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 18128f72c..ec228ce98 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,5 +1,5 @@ import { observable, action, computed } from "mobx"; -import { CirclePicker, ColorResult } from 'react-color'; +import { ColorResult } from 'react-color'; import React = require("react"); import { observer } from "mobx-react"; import "./InkingControl.scss"; @@ -8,7 +8,6 @@ import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-s import { SelectionManager } from "../util/SelectionManager"; import { InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; -import { InkingCanvas } from "./InkingCanvas"; library.add(faPen, faHighlighter, faEraser, faBan); @@ -18,7 +17,7 @@ export class InkingControl extends React.Component { @observable private _selectedTool: InkTool = InkTool.None; @observable private _selectedColor: string = "rgb(244, 67, 54)"; @observable private _selectedWidth: string = "25"; - @observable private _open: boolean = false; + @observable public _open: boolean = false; constructor(props: Readonly<{}>) { super(props); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 462ea1594..6290d8985 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -404,7 +404,6 @@ export class MainView extends React.Component { {this.nodesMenu()} {this.miscButtons} -
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0e6c1ee19..37e7a46a1 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -68,7 +68,7 @@ export class ImageBox extends DocComponent(ImageD drop = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { de.data.droppedDocuments.forEach(action((drop: Doc) => { - if (/*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { + if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); } else { -- cgit v1.2.3-70-g09d2 From eb9448e37be256b1c554be68cfb43dd7da44b0af Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 27 Jun 2019 10:04:33 -0400 Subject: fixed issues with dropping images onto images --- src/client/views/nodes/ImageBox.tsx | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 37e7a46a1..5c00d9d44 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -4,7 +4,7 @@ import { action, observable, computed } 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 -import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; +import { Doc, HeightSym, WidthSym, DocListCast } from '../../../new_fields/Doc'; import { List } from '../../../new_fields/List'; import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; import { Cast, FieldValue, NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; @@ -63,6 +63,7 @@ export class ImageBox extends DocComponent(ImageD console.log("IMPLEMENT ME PLEASE"); } + @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "Alternates"); } @undoBatch drop = (e: Event, de: DragManager.DropEvent) => { @@ -72,19 +73,17 @@ export class ImageBox extends DocComponent(ImageD Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); } else { - let layout = StrCast(drop.backgroundLayout); - if (layout.indexOf(ImageBox.name) !== -1) { - let imgData = this.dataDoc[this.props.fieldKey]; - if (imgData instanceof ImageField) { - Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new List([imgData]); + if (this.extensionDoc !== this.dataDoc) { + let layout = StrCast(drop.backgroundLayout); + if (layout.indexOf(ImageBox.name) !== -1) { + let imgData = this.extensionDoc.Alternates; + if (!imgData) { + Doc.GetProto(this.extensionDoc).Alternates = new List([]); + } + let imgList = Cast(this.extensionDoc.Alternates, listSpec(Doc), [] as any[]); + imgList && imgList.push(drop); + e.stopPropagation(); } - let imgList = Cast(this.dataDoc[this.props.fieldKey], listSpec(ImageField), [] as any[]); - if (imgList) { - let field = drop.data; - if (field instanceof ImageField) imgList.push(field); - else if (field instanceof List) imgList.concat(field); - } - e.stopPropagation(); } } })); @@ -213,24 +212,28 @@ export class ImageBox extends DocComponent(ImageD let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; // this._curSuffix = ""; // if (w > 20) { + let alts = DocListCast(this.extensionDoc.Alternates); + let altpaths: string[] = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url)); let field = this.dataDoc[this.props.fieldKey]; // if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s"; // else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m"; // else if (this._largeRetryCount < 10) this._curSuffix = "_l"; if (field instanceof ImageField) paths = [this.choosePath(field.url)]; - else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => this.choosePath((p as ImageField).url)); + paths.push(...altpaths); // } let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; let rotation = NumCast(this.dataDoc.rotation, 0); let aspect = (rotation % 180) ? this.dataDoc[HeightSym]() / this.dataDoc[WidthSym]() : 1; let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; + Doc.UpdateDocumentExtensionForField(this.extensionDoc, this.props.fieldKey); + let srcpath = paths[Math.min(paths.length, this._photoIndex)]; return (
Date: Fri, 28 Jun 2019 03:00:30 -0400 Subject: added expansion of templates on demand --- package.json | 2 +- src/client/views/DocumentDecorations.tsx | 7 ++++ .../views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 5 ++- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 7 +++- src/client/views/nodes/ImageBox.tsx | 44 ++++++++++++++++------ src/new_fields/Doc.ts | 13 +++++++ 8 files changed, 64 insertions(+), 18 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/package.json b/package.json index dc829a045..51d1bab5d 100644 --- a/package.json +++ b/package.json @@ -196,4 +196,4 @@ "uuid": "^3.3.2", "xoauth2": "^1.2.0" } -} \ No newline at end of file +} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index db10007f4..fdfff86db 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -85,11 +85,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let metaKey = text.slice(1, text.length); let metaKeyProp = `fieldKey={"${metaKey}"}`; + let layoutProto = Doc.GetProto(field.props.Document); let template = Doc.MakeAlias(field.props.Document); template.proto = collection; template.title = metaKey; template.nativeWidth = Cast(field.nativeWidth, "number"); template.nativeHeight = Cast(field.nativeHeight, "number"); + template.width = NumCast(field.props.Document.width); + template.height = NumCast(field.props.Document.height); + template.panX = NumCast(field.props.Document.panX); + template.panY = NumCast(field.props.Document.panY); + template.x = NumCast(field.props.Document.x); + template.y = NumCast(field.props.Document.y); template.embed = true; template.isTemplate = true; template.templates = new List([Templates.TitleBar(metaKey)]); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5c80fbd38..ccd0e92af 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -233,7 +233,7 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.resolvedDataDoc)) }); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }, icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" }); if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 15185ecb0..128525a48 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -28,6 +28,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); + export const panZoomSchema = createSchema({ panX: "number", panY: "number", @@ -334,11 +335,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return 1; } - getDocumentViewProps(layoutDoc: Doc): DocumentViewProps { let datadoc = BoolCast(this.props.Document.isTemplate) || this.props.DataDoc === this.props.Document ? undefined : this.props.DataDoc; if (Cast(layoutDoc.layout, Doc) instanceof Doc) { // if this document is using a template to render, then set the dataDoc for the template to be this document datadoc = layoutDoc; + } else if (datadoc && datadoc !== layoutDoc) { // if this view has a dataDocument and it's not the same as the view document + // then map the view document to an instance of itself (ie, expand the template). This allows the view override the template's properties and be referenceable as document. + layoutDoc = Doc.expandTemplateLayout(layoutDoc, datadoc); } return { DataDoc: datadoc, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4ac43ef4d..2ee694225 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -393,7 +393,7 @@ export class DocumentView extends DocComponent(Docu } deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); }; - fieldsClicked = (): void => { let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }; + fieldsClicked = (): void => { let kvp = Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.dataDoc, "onRight"); }; makeBtnClicked = (): void => { let doc = Doc.GetProto(this.props.Document); doc.isButton = !BoolCast(doc.isButton, false); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 55f61ddff..7c8509722 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -18,6 +18,8 @@ import { ImageBox } from "./ImageBox"; import { PDFBox } from "./PDFBox"; import { VideoBox } from "./VideoBox"; import { Id } from "../../../new_fields/FieldSymbols"; +import { BoolCast, Cast } from "../../../new_fields/Types"; +import { DarpaDatasetDoc } from "../../northstar/model/idea/idea"; // @@ -28,6 +30,7 @@ import { Id } from "../../../new_fields/FieldSymbols"; export interface FieldViewProps { fieldKey: string; fieldExt: string; + leaveNativeSize?: boolean; ContainingCollectionView: Opt; Document: Doc; DataDoc?: Doc; @@ -72,7 +75,7 @@ export class FieldView extends React.Component { return ; } else if (field instanceof ImageField) { - return ; + return ; } else if (field instanceof IconField) { return ; @@ -86,7 +89,7 @@ export class FieldView extends React.Component { return

{field.date.toLocaleString()}

; } else if (field instanceof Doc) { - return

{field.title + " + " + field[Id]}

; + return

{field.title + " : id= " + field[Id]}

; // let returnHundred = () => 100; // return ( // ; @@ -41,7 +43,6 @@ export class ImageBox extends DocComponent(ImageD private _downX: number = 0; private _downY: number = 0; private _lastTap: number = 0; - @observable private _photoIndex: number = 0; @observable private _isOpen: boolean = false; private dropDisposer?: DragManager.DragDropDisposer; @@ -115,20 +116,21 @@ export class ImageBox extends DocComponent(ImageD e.stopPropagation(); } + @action lightbox = (images: string[]) => { if (this._isOpen) { return ( this._isOpen = false )} onMovePrevRequest={action(() => - this._photoIndex = (this._photoIndex + images.length - 1) % images.length + this.Document.curPage = ((this.Document.curPage || 0) + images.length - 1) % images.length )} onMoveNextRequest={action(() => - this._photoIndex = (this._photoIndex + 1) % images.length + this.Document.curPage = ((this.Document.curPage || 0) + 1) % images.length )} />); } @@ -160,7 +162,6 @@ export class ImageBox extends DocComponent(ImageD @action onDotDown(index: number) { - this._photoIndex = index; this.Document.curPage = index; } @@ -170,7 +171,7 @@ export class ImageBox extends DocComponent(ImageD let left = (nativeWidth - paths.length * dist) / 2; return paths.map((p, i) =>
-
{ e.stopPropagation(); this.onDotDown(i); }} /> +
{ e.stopPropagation(); this.onDotDown(i); }} />
); } @@ -199,6 +200,22 @@ export class ImageBox extends DocComponent(ImageD } } _curSuffix = "_m"; + + resize(srcpath: string, layoutdoc: Doc) { + requestImageSize(window.origin + RouteStore.corsProxy + "/" + srcpath) + .then((size: any) => { + let aspect = size.height / size.width; + if (layoutdoc[HeightSym]() / layoutdoc[WidthSym]() != aspect) { + setTimeout(action(() => { + layoutdoc.height = layoutdoc[WidthSym]() * aspect; + layoutdoc.nativeHeight = size.height; + layoutdoc.nativeWidth = size.width; + }), 0); + } + }) + .catch((err: any) => console.log(err)); + } + render() { // let transform = this.props.ScreenToLocalTransform().inverse(); let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50; @@ -212,6 +229,7 @@ export class ImageBox extends DocComponent(ImageD let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"]; // this._curSuffix = ""; // if (w > 20) { + Doc.UpdateDocumentExtensionForField(this.extensionDoc, this.props.fieldKey); let alts = DocListCast(this.extensionDoc.Alternates); let altpaths: string[] = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url)); let field = this.dataDoc[this.props.fieldKey]; @@ -225,8 +243,10 @@ export class ImageBox extends DocComponent(ImageD let rotation = NumCast(this.dataDoc.rotation, 0); let aspect = (rotation % 180) ? this.dataDoc[HeightSym]() / this.dataDoc[WidthSym]() : 1; let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; - Doc.UpdateDocumentExtensionForField(this.extensionDoc, this.props.fieldKey); - let srcpath = paths[Math.min(paths.length, this._photoIndex)]; + let srcpath = paths[Math.min(paths.length, this.Document.curPage || 0)]; + + if (!this.props.Document.ignoreAspect && !this.props.leaveNativeSize) this.resize(srcpath, this.props.Document); + return (
(ImageD key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys src={srcpath} style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }} - // style={{ objectFit: (this._photoIndex === 0 ? undefined : "contain") }} + // style={{ objectFit: (this.Document.curPage === 0 ? undefined : "contain") }} width={nativeWidth} ref={this._imgRef} onError={this.onError} /> diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index b0184dd4e..d552ddd2d 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -280,6 +280,19 @@ export namespace Doc { return new Doc; } + export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc: Doc) { + let expandedTemplateLayout = templateLayoutDoc["_expanded_" + dataDoc[Id]]; + if (expandedTemplateLayout instanceof Doc) { + return expandedTemplateLayout; + } + if (expandedTemplateLayout === undefined) + setTimeout(() => { + templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc); + (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title; + }, 0); + return templateLayoutDoc; + } + export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc { const copy = new Doc; Object.keys(doc).forEach(key => { -- cgit v1.2.3-70-g09d2 From 09042b933c843d24a715e8c58414976133b19e41 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 28 Jun 2019 14:28:47 -0400 Subject: fixed template application to create expanded documents --- src/client/views/DocumentDecorations.tsx | 55 ++++++++++------------ .../views/collections/CollectionSchemaView.tsx | 14 +++++- .../views/collections/CollectionStackingView.tsx | 12 +++-- .../views/collections/CollectionTreeView.tsx | 18 ++++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 41 +++++++++++----- src/client/views/nodes/FormattedTextBox.tsx | 8 +++- src/client/views/nodes/ImageBox.tsx | 2 +- src/new_fields/Doc.ts | 10 +++- 8 files changed, 101 insertions(+), 59 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fdfff86db..76c2d71e8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -26,6 +26,7 @@ import { Template, Templates } from "./Templates"; import React = require("react"); import { RichTextField } from '../../new_fields/RichTextField'; import { LinkManager } from '../util/LinkManager'; +import { ObjectField } from '../../new_fields/ObjectField'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -77,39 +78,31 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this._fieldKey = text.slice(1, text.length); this._title = this.selectionTitle; } else if (text.startsWith(">")) { - let field = SelectionManager.SelectedDocuments()[0]; - let collection = field.props.ContainingCollectionView!.props.Document; - - let collectionKey = field.props.ContainingCollectionView!.props.fieldKey; - let collectionKeyProp = `fieldKey={"${collectionKey}"}`; + let fieldTemplateView = SelectionManager.SelectedDocuments()[0]; + SelectionManager.DeselectAll(); + let fieldTemplate = fieldTemplateView.props.Document; + let docTemplate = fieldTemplateView.props.ContainingCollectionView!.props.Document; let metaKey = text.slice(1, text.length); - let metaKeyProp = `fieldKey={"${metaKey}"}`; - - let layoutProto = Doc.GetProto(field.props.Document); - let template = Doc.MakeAlias(field.props.Document); - template.proto = collection; - template.title = metaKey; - template.nativeWidth = Cast(field.nativeWidth, "number"); - template.nativeHeight = Cast(field.nativeHeight, "number"); - template.width = NumCast(field.props.Document.width); - template.height = NumCast(field.props.Document.height); - template.panX = NumCast(field.props.Document.panX); - template.panY = NumCast(field.props.Document.panY); - template.x = NumCast(field.props.Document.x); - template.y = NumCast(field.props.Document.y); - template.embed = true; - template.isTemplate = true; - template.templates = new List([Templates.TitleBar(metaKey)]); - if (field.props.Document.backgroundLayout) { - let metaAnoKeyProp = `fieldKey={"${metaKey}"} fieldExt={"annotations"}`; - let collectionAnoKeyProp = `fieldKey={"annotations"}`; - template.layout = StrCast(field.props.Document.layout).replace(collectionAnoKeyProp, metaAnoKeyProp); - template.backgroundLayout = StrCast(field.props.Document.backgroundLayout).replace(collectionKeyProp, metaKeyProp); - } else { - template.layout = StrCast(field.props.Document.layout).replace(collectionKeyProp, metaKeyProp); + + // 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(collection, collectionKey, template); - SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document)); + let nw = Cast(fieldTemplate.nativeWidth, "number"); + let nh = Cast(fieldTemplate.nativeHeight, "number"); + + 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([Templates.TitleBar(metaKey)]); + fieldTemplate.proto = Doc.GetProto(docTemplate); } else { if (SelectionManager.SelectedDocuments().length > 0) { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 98bf513bb..5562676e9 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -349,12 +349,22 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
; } + @computed get previewPanel() { + // let layoutDoc = this.previewDocument; + // let resolvedDataDoc = (layoutDoc !== this.props.DataDoc) ? this.props.DataDoc : undefined; + // if (layoutDoc && !(Cast(layoutDoc.layout, Doc) instanceof Doc) && + // resolvedDataDoc && resolvedDataDoc !== layoutDoc) { + // // ... so change the layout to be an expanded view of the template layout. This allows the view override the template's properties and be referenceable as its own document. + // layoutDoc = Doc.expandTemplateLayout(layoutDoc, resolvedDataDoc); + // } + + let layoutDoc = this.previewDocument ? Doc.expandTemplateLayout(this.previewDocument, this.props.DataDoc) : undefined; return
doc) { @@ -66,17 +67,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { get singleColumnChildren() { let children = this.childDocs.filter(d => !d.isMinimized); return children.map((d, i) => { + let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); let dref = React.createRef(); - let dxf = () => this.getDocTransform(d, dref.current!).scale(this.columnWidth / d[WidthSym]()); + let dxf = () => this.getDocTransform(layoutDoc, dref.current!).scale(this.columnWidth / d[WidthSym]()); let width = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; - let height = () => this.singleColDocHeight(d); + let height = () => this.singleColDocHeight(layoutDoc); return
{ let keys = Array.from(Object.keys(this.resolvedDataDoc)); if (this.resolvedDataDoc.proto instanceof Doc) { keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto))); - while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } - let keyList: string[] = keys.reduce((l, key) => Cast(this.resolvedDataDoc[key], listSpec(Doc)) ? [...l, key] : l, [] as string[]); + let keyList: string[] = keys.reduce((l, key) => { + let listspec = DocListCast(this.resolvedDataDoc[key]); + if (listspec && listspec.length) + return [...l, key]; + return l; + }, [] as string[]); keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key)); if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links"); if (keyList.indexOf(this.fieldKey) !== -1) { keyList.splice(keyList.indexOf(this.fieldKey), 1); } keyList.splice(0, 0, this.fieldKey); - return keyList; + return keyList.filter((item, index) => keyList.indexOf(item) >= index); } /** * Renders the EditableView title element for placement into the tree. @@ -322,14 +326,14 @@ class TreeView extends React.Component { this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)} ; } else { - console.log("PW = " + this.props.panelWidth()); - contentElement =
+ let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc); + contentElement =
); + prev.push(); } } return prev; @@ -419,7 +438,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } private childViews = () => [ - , + , ...this.views ] render() { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 2a45aeb43..ba6808737 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -211,7 +211,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined; return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`; }, - field => this._editorView && !this._applyingChange && + field => this._editorView && !this._applyingChange && this.props.Document[this.props.fieldKey] instanceof RichTextField && this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field))) ); this.setupEditor(config, this.dataDoc, this.props.fieldKey); @@ -247,6 +247,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this.props.selectOnLoad) { if (!this.props.isOverlay) this.props.select(false); else this._editorView!.focus(); + this.tryUpdateHeight(); } } @@ -382,6 +383,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (!this._undoTyping) { this._undoTyping = UndoManager.StartBatch("undoTyping"); } + this.tryUpdateHeight(); + } + + @action + tryUpdateHeight() { if (this.props.isOverlay && this.props.Document.autoHeight) { let xf = this._ref.current!.getBoundingClientRect(); let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 378b13b0d..06bf65f73 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -205,7 +205,7 @@ export class ImageBox extends DocComponent(ImageD requestImageSize(window.origin + RouteStore.corsProxy + "/" + srcpath) .then((size: any) => { let aspect = size.height / size.width; - if (layoutdoc[HeightSym]() / layoutdoc[WidthSym]() != aspect) { + if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) { setTimeout(action(() => { layoutdoc.height = layoutdoc[WidthSym]() * aspect; layoutdoc.nativeHeight = size.height; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index d552ddd2d..27dcfba08 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -280,7 +280,15 @@ export namespace Doc { return new Doc; } - export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc: Doc) { + export function expandTemplateLayout(templateLayoutDoc: Doc, dataDoc?: Doc) { + let resolvedDataDoc = (templateLayoutDoc !== dataDoc) ? dataDoc : undefined; + if (!dataDoc || !(templateLayoutDoc && !(Cast(templateLayoutDoc.layout, Doc) instanceof Doc) && resolvedDataDoc && resolvedDataDoc !== templateLayoutDoc)) { + return templateLayoutDoc; + } + // if we have a data doc that doesn't match the layout, then we're rendering a template. + // ... which means we change the layout to be an expanded view of the template layout. + // This allows the view override the template's properties and be referenceable as its own document. + let expandedTemplateLayout = templateLayoutDoc["_expanded_" + dataDoc[Id]]; if (expandedTemplateLayout instanceof Doc) { return expandedTemplateLayout; -- cgit v1.2.3-70-g09d2 From d236da11dcd635440eecb897a195df8ade4ca7b0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 4 Jul 2019 18:20:54 -0400 Subject: added dropping and reordering within Stacking views. needs GUI feedback. --- src/client/util/DragManager.ts | 2 +- .../views/collections/CollectionStackingView.tsx | 58 +++++++++++++++++++++- src/client/views/collections/CollectionSubView.tsx | 9 +++- src/client/views/nodes/ImageBox.tsx | 4 +- 4 files changed, 68 insertions(+), 5 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d4b1bc8f4..ce1f9d890 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -448,7 +448,7 @@ export namespace DragManager { x: e.x, y: e.y, data: dragData, - mods: e.altKey ? "AltKey" : "" + mods: e.altKey ? "AltKey" : e.ctrlKey ? "CtrlKey" : "" } }) ); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b10907937..6b4eddec9 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -11,6 +11,8 @@ import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { resolve } from "bluebird"; +import { undoBatch } from "../../util/UndoManager"; +import { DragManager } from "../../util/DragManager"; @observer export class CollectionStackingView extends CollectionSubView(doc => doc) { @@ -96,8 +98,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
; }); } + docXfs: any[] = [] @computed get children() { + this.docXfs.length = 0; return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { let aspect = d.nativeHeight ? NumCast(d.nativeWidth) / NumCast(d.nativeHeight) : undefined; let dref = React.createRef(); @@ -105,6 +109,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let width = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => aspect ? width() / aspect : d[HeightSym](); let rowSpan = Math.ceil((height() + this.gridGap) / (this._gridSize + this.gridGap)); + this.docXfs.push({ dxf: dxf, width: width, height: height }); return (
doc) { }); } } + + @undoBatch + @action + drop = (e: Event, de: DragManager.DropEvent) => { + let targInd = -1; + let where = [de.x, de.y]; + if (de.data instanceof DragManager.DocumentDragData) { + this.docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }) + } + if (super.drop(e, de)) { + if (targInd !== -1) { + let newDoc = de.data.droppedDocuments[0]; + let docs = this.childDocList; + if (docs) { + let srcInd = docs.indexOf(newDoc); + docs.splice(srcInd, 1); + docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); + } + } + } + return false; + } + @undoBatch + @action + onDrop = (e: React.DragEvent): void => { + let where = [e.clientX, e.clientY]; + let targInd = -1; + this.docXfs.map((cd, i) => { + let pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap); + let pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height()); + if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) { + targInd = i; + } + }) + super.onDrop(e, {}, () => { + if (targInd !== -1) { + let newDoc = this.childDocs[this.childDocs.length - 1]; + let docs = this.childDocList; + if (docs) { + docs.splice(docs.length - 1, 1); + docs.splice(targInd, 0, newDoc); + } + } + }); + } render() { let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.childDocs.filter(d => !d.isMinimized).length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; return ( -
e.stopPropagation()} > +
e.stopPropagation()} >
(schemaCtor: (doc: Doc) => T) { //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) return DocListCast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); } + get childDocList() { + //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((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc)); + } @action protected async setCursorPosition(position: [number, number]) { @@ -145,7 +150,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch @action - protected onDrop(e: React.DragEvent, options: DocumentOptions): void { + protected onDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) { if (e.ctrlKey) { e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl return; @@ -255,7 +260,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { } if (promises.length) { - Promise.all(promises).finally(() => batch.end()); + Promise.all(promises).finally(() => { completed && completed(); batch.end(); }); } else { batch.end(); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 06bf65f73..dd4e4262d 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -73,7 +73,7 @@ export class ImageBox extends DocComponent(ImageD if (de.mods === "AltKey" && /*this.dataDoc !== this.props.Document &&*/ drop.data instanceof ImageField) { Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(drop.data.url); e.stopPropagation(); - } else { + } else if (de.mods === "CtrlKey") { if (this.extensionDoc !== this.dataDoc) { let layout = StrCast(drop.backgroundLayout); if (layout.indexOf(ImageBox.name) !== -1) { @@ -205,6 +205,8 @@ export class ImageBox extends DocComponent(ImageD requestImageSize(window.origin + RouteStore.corsProxy + "/" + srcpath) .then((size: any) => { let aspect = size.height / size.width; + let rotation = NumCast(this.dataDoc.rotation) % 180; + if (rotation === 90 || rotation === 270) aspect = 1 / aspect; if (Math.abs(layoutdoc[HeightSym]() / layoutdoc[WidthSym]() - aspect) > 0.01) { setTimeout(action(() => { layoutdoc.height = layoutdoc[WidthSym]() * aspect; -- cgit v1.2.3-70-g09d2 From ad87140f4a52984d754c06fcb55e66a0cc935ce2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 4 Jul 2019 23:18:13 -0400 Subject: fixed shift-dragging of documents --- src/client/util/DragManager.ts | 1 - src/client/views/DocumentDecorations.tsx | 1 - src/client/views/collections/CollectionDockingView.tsx | 3 --- src/client/views/collections/CollectionSchemaView.tsx | 1 - src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 1 - src/client/views/search/SearchItem.tsx | 1 - 7 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 2fd83ae56..f9492f452 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -41,7 +41,6 @@ export function SetupDrag( let onItemDown = async (e: React.PointerEvent) => { if (e.button === 0) { e.stopPropagation(); - e.preventDefault(); if (e.shiftKey && CollectionDockingView.Instance) { e.persist(); CollectionDockingView.Instance.StartOtherDrag(e, [await docFunc()]); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c7990647a..48b89ff4e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -172,7 +172,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onBackgroundMove); document.addEventListener("pointerup", this.onBackgroundUp); e.stopPropagation(); - e.preventDefault(); } @action diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f146ec62b..19d07ecdc 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -321,9 +321,6 @@ export class CollectionDockingView extends React.Component doc) { onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) { if (this.props.isSelected()) e.stopPropagation(); - else e.preventDefault(); } } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index dd4e4262d..5da52f4c2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -95,7 +95,7 @@ export class ImageBox extends DocComponent(ImageD onPointerDown = (e: React.PointerEvent): void => { if (e.shiftKey && e.ctrlKey) { e.stopPropagation(); // allows default system drag drop of images with shift+ctrl only - } else e.preventDefault(); + } // if (Date.now() - this._lastTap < 300) { // if (e.buttons === 1) { // this._downX = e.clientX; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1239b498f..264d3c1f7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -119,7 +119,6 @@ export class VideoBox extends DocComponent(VideoD }); } onPointerDown = (e: React.PointerEvent) => { - e.preventDefault(); e.stopPropagation(); } diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 606ac4e85..51f0ed607 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -231,7 +231,6 @@ export class SearchItem extends React.Component { onPointerDown = (e: React.PointerEvent) => { e.stopPropagation(); - // e.preventDefault(); const doc = Doc.IsPrototype(this.props.doc) ? Doc.MakeDelegate(this.props.doc) : this.props.doc; DragManager.StartDocumentDrag([e.currentTarget], new DragManager.DocumentDragData([doc], []), e.clientX, e.clientY, { handlers: { dragComplete: emptyFunction }, -- cgit v1.2.3-70-g09d2 From aedd283fb9f9eff4145e27658bc6647982256032 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 5 Jul 2019 00:34:19 -0400 Subject: beginning implementation of key value tags for all imported documents --- src/client/documents/Documents.ts | 12 +- .../util/Import & Export/DirectoryImportBox.scss | 0 .../util/Import & Export/DirectoryImportBox.tsx | 181 +++++++++++++++++++++ src/client/util/Import & Export/ImageImporter.tsx | 67 -------- src/client/util/Import & Export/ImportBox.tsx | 134 --------------- src/client/util/request-image-size.js | 6 +- src/client/views/MainView.tsx | 1 - src/client/views/collections/CollectionSubView.tsx | 4 +- src/client/views/nodes/DocumentContentsView.tsx | 4 +- src/client/views/nodes/ImageBox.tsx | 4 +- 10 files changed, 198 insertions(+), 215 deletions(-) create mode 100644 src/client/util/Import & Export/DirectoryImportBox.scss create mode 100644 src/client/util/Import & Export/DirectoryImportBox.tsx delete mode 100644 src/client/util/Import & Export/ImageImporter.tsx delete mode 100644 src/client/util/Import & Export/ImportBox.tsx (limited to 'src/client/views/nodes/ImageBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5d637dd3a..26b5498a2 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -36,7 +36,7 @@ import { UndoManager } from "../util/UndoManager"; import { RouteStore } from "../../server/RouteStore"; import { LinkManager } from "../util/LinkManager"; import { DocumentManager } from "../util/DocumentManager"; -import ImportBox from "../util/Import & Export/ImportBox"; +import DirectoryImportBox from "../util/Import & Export/DirectoryImportBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -180,7 +180,7 @@ export namespace Docs { } function CreateImportPrototype(): Doc { - let importProto = setupPrototypeOptions(importProtoId, "IMPORT_PROTO", ImportBox.LayoutString(), { x: 0, y: 0, width: 600, height: 600, type: DocTypes.IMPORT }); + let importProto = setupPrototypeOptions(importProtoId, "IMPORT_PROTO", DirectoryImportBox.LayoutString(), { x: 0, y: 0, width: 600, height: 600, type: DocTypes.IMPORT }); return importProto; } @@ -347,7 +347,7 @@ export namespace Docs { return CreateInstance(collProto, new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } - export async function getDocumentFromType(type: string, path: string, options: DocumentOptions, addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean): Promise> { + export async function getDocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { let ctor: ((path: string, options: DocumentOptions) => (Doc | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { ctor = Docs.ImageDocument; @@ -370,17 +370,17 @@ export namespace Docs { if (path.includes(window.location.hostname)) { let s = path.split('/'); let id = s[s.length - 1]; - DocServer.GetRefField(id).then(field => { + return 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; - addDocument && addDocument(alias, false); + return alias; } + return undefined; }); - return undefined; } ctor = Docs.WebDocument; options = { height: options.width, ...options, title: path, nativeWidth: undefined }; diff --git a/src/client/util/Import & Export/DirectoryImportBox.scss b/src/client/util/Import & Export/DirectoryImportBox.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx new file mode 100644 index 000000000..2d77f6ae6 --- /dev/null +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -0,0 +1,181 @@ +import "fs"; +import React = require("react"); +import { Doc } from "../../../new_fields/Doc"; +import { DocServer } from "../../DocServer"; +import { RouteStore } from "../../../server/RouteStore"; +import { action, observable, runInAction } from "mobx"; +import { FieldViewProps, FieldView } from "../../views/nodes/FieldView"; +import Measure, { ContentRect } from "react-measure"; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faArrowUp, faTag, faFileExcel } from '@fortawesome/free-solid-svg-icons'; +import { Docs, DocumentOptions } from "../../documents/Documents"; +import { EditableView } from "../../views/EditableView"; + +export default class DirectoryImportBox extends React.Component { + private selector = React.createRef(); + @observable private top = 0; + @observable private left = 0; + private dimensions = 50; + + @observable private key = "Key"; + @observable private value = "Value"; + + public static LayoutString() { return FieldView.LayoutString(DirectoryImportBox); } + + constructor(props: FieldViewProps) { + super(props); + library.add(faArrowUp, faTag); + } + + updateKey = (newKey: string) => { + runInAction(() => this.key = newKey); + console.log("KEY ", this.key); + return true; + } + + updateValue = (newValue: string) => { + runInAction(() => this.value = newValue); + console.log("VALUE ", this.value); + return true; + } + + handleSelection = async (e: React.ChangeEvent) => { + let promises: Promise[] = []; + let docs: Doc[] = []; + + let files = e.target.files; + if (!files || files.length === 0) return; + + let directory = (files.item(0) as any).webkitRelativePath.split("/", 1); + + for (let i = 0; i < files.length; i++) { + let uploaded_file = files.item(i); + + if (!uploaded_file) { + continue; + } + + let formData = new FormData(); + formData.append('file', uploaded_file); + let dropFileName = uploaded_file ? uploaded_file.name : "-empty-"; + let type = uploaded_file.type; + + let prom = fetch(DocServer.prepend(RouteStore.upload), { + method: 'POST', + body: formData + }).then(async (res: Response) => { + (await res.json()).map(action((file: any) => { + let path = DocServer.prepend(file); + console.log(path); + let docPromise = Docs.getDocumentFromType(type, path, { nativeWidth: 300, width: 300, title: dropFileName }); + docPromise.then(doc => doc && docs.push(doc)); + })); + }); + promises.push(prom); + } + + await Promise.all(promises); + + let doc = this.props.Document; + let options: DocumentOptions = { title: `Import of ${directory}`, width: 500, height: 500, x: Doc.GetT(doc, "x", "number"), y: Doc.GetT(doc, "y", "number") }; + let parent = this.props.ContainingCollectionView; + if (parent) { + let importContainer = Docs.StackingDocument(docs, options); + Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer); + this.props.removeDocument && this.props.removeDocument(doc); + } + } + + componentDidMount() { + this.selector.current!.setAttribute("directory", ""); + this.selector.current!.setAttribute("webkitdirectory", ""); + } + + @action + preserveCentering = (rect: ContentRect) => { + let bounds = rect.offset!; + if (bounds.width === 0 || bounds.height === 0) { + return; + } + let offset = this.dimensions / 2; + this.left = bounds.width / 2 - offset; + this.top = bounds.height / 2 - offset; + } + + render() { + let dimensions = 50; + let keyValueStyle = { paddingLeft: 5, width: "50%" }; + return ( + + {({ measureRef }) => +
+ +