From f6c15087d30f27c15b3b6304af58c93c65536131 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 29 Aug 2019 14:50:22 -0400 Subject: changed linkFollowBox creation approach. fixed target contexts to add link default. --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7631ecc6c..c9c394960 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -8,7 +8,6 @@ import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView" import "./DocumentView.scss"; import React = require("react"); import { Doc } from "../../../new_fields/Doc"; -import { returnEmptyString } from "../../../Utils"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { x?: number; -- cgit v1.2.3-70-g09d2 From 0fea8592b5bd790334d0557c3ef30eb03973c601 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 6 Sep 2019 23:19:21 -0400 Subject: changed sub-menu pop up location. added rotation jitter --- src/client/views/ContextMenuItem.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 ++++++++++---- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 4 +++- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 90f7be33f..1a0839060 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -89,7 +89,7 @@ export class ContextMenuItem extends React.Component +
{this._items.map(prop => )}
; return ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4f6055260..2df2a3464 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -152,6 +152,7 @@ export namespace PivotView { y={pos.y} width={pos.width} height={pos.height} + jitterRotation={NumCast(target.props.Document.jitterRotation)} {...target.getChildDocumentViewProps(doc)} />, bounds: { @@ -797,6 +798,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (pair.layout && !(pair.data instanceof Promise)) { prev.push({ ele: , bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } @@ -912,10 +914,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }); layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" }); layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); - layoutItems.push({ description: "1: Note", event: () => this.createText("Note", "yellow"), icon: "eye" }); - layoutItems.push({ description: "2: Idea", event: () => this.createText("Idea", "pink"), icon: "eye" }); - layoutItems.push({ description: "3: Topic", event: () => this.createText("Topic", "lightBlue"), icon: "eye" }); - layoutItems.push({ description: "4: Person", event: () => this.createText("Person", "lightGreen"), icon: "eye" }); + layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); + + let noteItems: ContextMenuProps[] = []; + noteItems.push({ description: "1: Note", event: () => this.createText("Note", "yellow"), icon: "eye" }); + noteItems.push({ description: "2: Idea", event: () => this.createText("Idea", "pink"), icon: "eye" }); + noteItems.push({ description: "3: Topic", event: () => this.createText("Topic", "lightBlue"), icon: "eye" }); + noteItems.push({ description: "4: Person", event: () => this.createText("Person", "lightGreen"), icon: "eye" }); + layoutItems.push({ description: "Add Note ...", subitems: noteItems, icon: "eye" }) ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" }); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c9c394960..f07584b4f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -8,12 +8,14 @@ import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView" import "./DocumentView.scss"; import React = require("react"); import { Doc } from "../../../new_fields/Doc"; +import { random } from "animejs"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { x?: number; y?: number; width?: number; height?: number; + jitterRotation: number; } const schema = createSchema({ @@ -27,7 +29,7 @@ const FreeformDocument = makeInterface(schema, positionSchema); @observer export class CollectionFreeFormDocumentView extends DocComponent(FreeformDocument) { - @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) scale(${this.zoom}) `; } + @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg) scale(${this.zoom}) `; } @computed get X() { return this.props.x !== undefined ? this.props.x : this.Document.x || 0; } @computed get Y() { return this.props.y !== undefined ? this.props.y : this.Document.y || 0; } @computed get width(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } -- cgit v1.2.3-70-g09d2 From 3865ccd688015d92c8c551bf78ee2a9b6ece5500 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 9 Sep 2019 15:40:49 -0400 Subject: added local overlay for free form views. added start of minimap. --- src/client/views/OverlayView.tsx | 4 +++- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 ++++++++++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 23 ++++++++++++++++++---- src/client/views/nodes/DocumentView.tsx | 2 -- src/server/index.ts | 2 +- 5 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index fe06e4440..da4b71e5c 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -197,7 +197,9 @@ export class OverlayView extends React.Component { render() { return (
- {this._elements} +
+ {this._elements} +
{this.overlayDocs}
); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2df2a3464..2ec2b0671 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -3,7 +3,7 @@ import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; import { action, computed, IReactionDisposer, observable, reaction, trace } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCastAsync, Field, FieldResult, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; +import { Doc, DocListCastAsync, Field, FieldResult, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { createSchema, makeInterface } from "../../../../new_fields/Schema"; @@ -225,8 +225,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return bounds; } + @computed get actualContentBounds() { + return this.fitToBox && !this.isAnnotationOverlay ? this.ComputeContentBounds(this.elements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!)) : undefined; + } + @computed get contentBounds() { - let bounds = this.fitToBox && !this.isAnnotationOverlay ? this.ComputeContentBounds(this.elements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!)) : undefined; + let bounds = this.actualContentBounds; let res = { panX: bounds ? (bounds.x + bounds.r) / 2 : this.Document.panX || 0, panY: bounds ? (bounds.y + bounds.b) / 2 : this.Document.panY || 0, @@ -775,7 +779,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const initScript = this.Document.arrangeInit; const script = this.Document.arrangeScript; let state: any = undefined; - const docs = this.childDocs; + let docs = this.childDocs; + let overlayDocs = DocListCast(this.props.Document.localOverlays); + overlayDocs && docs.push(...overlayDocs); let elements: ViewDefResult[] = []; if (initScript) { const initResult = initScript.script.run({ docs, collection: this.Document }); @@ -967,6 +973,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } render() { + this.props.Document.fitX = this.actualContentBounds && this.actualContentBounds.x; + this.props.Document.fitY = this.actualContentBounds && this.actualContentBounds.y; + this.props.Document.fitW = this.actualContentBounds && (this.actualContentBounds.r - this.actualContentBounds.x); + this.props.Document.fitH = this.actualContentBounds && (this.actualContentBounds.b - this.actualContentBounds.y); const easing = () => this.props.Document.panTransformType === "Ease"; Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); return ( diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f07584b4f..c059ff50d 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,7 +1,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; +import { BoolCast, FieldValue, NumCast, StrCast, Cast } from "../../../new_fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView"; @@ -77,6 +77,21 @@ export class CollectionFreeFormDocumentView extends DocComponent this.clusterColor; render() { + let txf = this.transform; + let w = this.width; + let h = this.height; + let renderScript = this.Document.renderScript; + if (renderScript) { + let someView = Cast(this.Document.someView, Doc); + let minimap = Cast(this.Document.minimap, Doc); + if (someView instanceof Doc && minimap instanceof Doc) { + let x = (NumCast(someView.panX) - NumCast(someView.width) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap.width) - NumCast(minimap.width) / 2; + let y = (NumCast(someView.panY) - NumCast(someView.height) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap.height) - NumCast(minimap.height) / 2; + w = NumCast(someView.width) / NumCast(someView.scale) / NumCast(minimap.fitW) * NumCast(minimap.width); + h = NumCast(someView.height) / NumCast(someView.scale) / NumCast(minimap.fitH) * NumCast(minimap.height); + txf = `translate(${x}px,${y}px)`; + } + } const hasPosition = this.props.x !== undefined || this.props.y !== undefined; return (
(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith(" { console.log("reading " + page); - let viewport = page.getViewport({scale: 1}); + let viewport = page.getViewport(1 as any); let canvasAndContext = factory.create(viewport.width, viewport.height); let renderContext = { canvasContext: canvasAndContext.context, -- cgit v1.2.3-70-g09d2 From 9608245db4ba8cca6054a0641f2eb2bd2032eba6 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 10 Sep 2019 15:55:51 -0400 Subject: fixed up some stuff with portals and added a ButtonBox menu item for running scripts over a collection --- src/client/views/ContextMenuItem.tsx | 2 +- src/client/views/InkingControl.tsx | 2 +- src/client/views/ScriptBox.tsx | 15 +++++++++++++-- src/client/views/collections/CollectionBaseView.tsx | 4 ++++ src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 11 +++++++---- src/client/views/nodes/DocumentView.tsx | 12 +++++++++--- src/new_fields/Doc.ts | 3 ++- 7 files changed, 37 insertions(+), 12 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 1a0839060..0366a6a30 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -89,7 +89,7 @@ export class ContextMenuItem extends React.Component +
{this._items.map(prop => )}
; return ( diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 519792308..aa573f16b 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -64,7 +64,7 @@ export class InkingControl extends React.Component { closest = i; } } - cp[closest] = "rgb(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + ")"; + cp[closest] = "rgba(" + color.rgb.r + "," + color.rgb.g + "," + color.rgb.b + "," + color.rgb.a + ")"; view.props.ContainingCollectionView.props.Document.colorPalette = new List(cp); targetDoc.backgroundColor = cp[closest]; } else diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 2b862a81e..7afba5e01 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -66,13 +66,24 @@ export class ScriptBox extends React.Component {
); } - public static EditClickScript(doc: Doc, fieldKey: string) { + public static EditClickScript(doc: Doc, fieldKey: string, prewrapper?: string, postwrapper?: string) { let overlayDisposer: () => void = emptyFunction; const script = ScriptCast(doc[fieldKey]); let originalText: string | undefined = undefined; - if (script) originalText = script.script.originalScript; + if (script) { + originalText = script.script.originalScript; + if (prewrapper && originalText.startsWith(prewrapper)) { + originalText = originalText.substr(prewrapper.length); + } + if (postwrapper && originalText.endsWith(postwrapper)) { + originalText = originalText.substr(0, originalText.length - postwrapper.length); + } + } // tslint:disable-next-line: no-unnecessary-callback-wrapper let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + if (prewrapper) { + text = prewrapper + text + (postwrapper ? postwrapper : ""); + } const script = CompileScript(text, { params: { this: Doc.name }, typecheck: false, diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index b6ed6aaa0..bd8d56851 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -12,6 +12,7 @@ import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import './CollectionBaseView.scss'; import { DateField } from '../../../new_fields/DateField'; +import { DocumentType } from '../../documents/DocumentTypes'; export enum CollectionViewType { Invalid, @@ -103,6 +104,9 @@ export class CollectionBaseView extends React.Component { if (this.props.fieldExt) { // bcz: fieldExt !== undefined means this is an overlay layer Doc.GetProto(doc).annotationOn = this.props.Document; } + if (doc.type === DocumentType.BUTTON) { + doc.collectionContext = this.props.Document; // used by docList() function in Doc.ts so that buttons can iterate over the documents in their collection + } allowDuplicates = true; let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document; let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c059ff50d..9692dd8a9 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -99,10 +99,13 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Into Background", event: this.makeBackground, icon: this.props.Document.lockedPosition ? "unlock" : "lock" }); makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Into Button", event: this.makeBtnClicked, icon: "concierge-bell" }); makes.push({ description: "OnClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick") }); + makes.push({ description: "OnClick foreach doc", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick", "docList(this.collectionContext.data).map(d => {", "});\n") }); makes.push({ description: "Into Portal", event: () => { - let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" }); - DocUtils.MakeLink(this.props.Document, portal, undefined, this.props.Document.title + ".portal"); - this.makeBtnClicked(); + if (!DocListCast(this.props.Document.links).find(doc => { + if (Cast(doc.anchor2, Doc) instanceof Doc && (Cast(doc.anchor2, Doc) as Doc)!.title === this.props.Document.title + ".portal") return true; + return false; + })) { + let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" }); + DocUtils.MakeLink(this.props.Document, portal, undefined, this.props.Document.title + ".portal"); + Doc.GetProto(this.props.Document).isButton = true; + } }, icon: "window-restore" }); makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" }); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index e3d7cc9ed..ccb8f4aa2 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -685,4 +685,5 @@ export namespace Doc { Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`; }); Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); -Scripting.addGlobal(function aliasDocs(field: any) { return new List(field.map((d: any) => Doc.MakeAlias(d))); }); \ No newline at end of file +Scripting.addGlobal(function aliasDocs(field: any) { return new List(field.map((d: any) => Doc.MakeAlias(d))); }); +Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From edec708b4396cd3b21ea22296812d5014b1359db Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 10 Sep 2019 22:18:46 -0400 Subject: got rid of zoomBasis remnants. cleaned up (just a little bit) renderScript stuff in colelctionfreeformdocumentview --- src/client/views/DocumentDecorations.tsx | 3 +- .../views/collections/ParentDocumentSelector.tsx | 4 +- .../CollectionFreeFormLinkView.tsx | 8 ++-- .../CollectionFreeFormLinksView.tsx | 4 +- src/client/views/linking/LinkFollowBox.tsx | 12 +++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 50 +++++++++++----------- src/client/views/search/SearchBox.tsx | 1 - src/client/views/search/SearchItem.tsx | 4 +- src/scraping/buxton/scraper.py | 1 - 9 files changed, 41 insertions(+), 46 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 94aab8b2f..773ab8b9f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -397,8 +397,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } moveIconDoc(iconDoc: Doc) { let selView = SelectionManager.SelectedDocuments()[0]; - let zoom = NumCast(selView.props.Document.zoomBasis, 1); - let where = (selView.props.ScreenToLocalTransform()).scale(selView.props.ContentScaling()).scale(1 / zoom). + let where = (selView.props.ScreenToLocalTransform()).scale(selView.props.ContentScaling()). transformPoint(this._minimizedX - 12, this._minimizedY - 12); iconDoc.x = where[0] + NumCast(selView.props.Document.x); iconDoc.y = where[1] + NumCast(selView.props.Document.y); diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 17111af58..d8475a467 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -38,8 +38,8 @@ export class SelectorContextMenu extends React.Component { return () => { col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col; if (NumCast(col.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(target.x) + NumCast(target.width) / NumCast(target.zoomBasis, 1) / 2; - const newPanY = NumCast(target.y) + NumCast(target.height) / NumCast(target.zoomBasis, 1) / 2; + const newPanX = NumCast(target.x) + NumCast(target.width) / 2; + const newPanY = NumCast(target.y) + NumCast(target.height) / 2; col.panX = newPanX; col.panY = newPanY; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 6af87b138..790c6694b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -39,10 +39,10 @@ export class CollectionFreeFormLinkView extends React.Component)[]) => field.findIndex(brush => { diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index d5ed01f53..f8807641b 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -180,8 +180,8 @@ export class LinkFollowBox extends React.Component { openColFullScreen = (options: { context: Doc }) => { if (LinkFollowBox.destinationDoc) { if (NumCast(options.context.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; + const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / 2; + const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / 2; options.context.panX = newPanX; options.context.panY = newPanY; } @@ -209,8 +209,8 @@ export class LinkFollowBox extends React.Component { if (LinkFollowBox.destinationDoc) { options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context; if (NumCast(options.context.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; + const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / 2; + const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / 2; options.context.panX = newPanX; options.context.panY = newPanY; } @@ -286,8 +286,8 @@ export class LinkFollowBox extends React.Component { if (LinkFollowBox.destinationDoc) { options.context = Doc.IsPrototype(options.context) ? Doc.MakeDelegate(options.context) : options.context; if (NumCast(options.context.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; - const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / NumCast(LinkFollowBox.destinationDoc.zoomBasis, 1) / 2; + const newPanX = NumCast(LinkFollowBox.destinationDoc.x) + NumCast(LinkFollowBox.destinationDoc.width) / 2; + const newPanY = NumCast(LinkFollowBox.destinationDoc.y) + NumCast(LinkFollowBox.destinationDoc.height) / 2; options.context.panX = newPanX; options.context.panY = newPanY; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 9692dd8a9..eb7ab64f8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -19,7 +19,6 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { } const schema = createSchema({ - zoomBasis: "number", zIndex: "number", }); @@ -29,22 +28,36 @@ const FreeformDocument = makeInterface(schema, positionSchema); @observer export class CollectionFreeFormDocumentView extends DocComponent(FreeformDocument) { - @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg) scale(${this.zoom}) `; } - @computed get X() { return this.props.x !== undefined ? this.props.x : this.Document.x || 0; } - @computed get Y() { return this.props.y !== undefined ? this.props.y : this.Document.y || 0; } - @computed get width(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } - @computed get height(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.props.height !== undefined ? this.props.height : this.Document.height || 0; } - @computed get zoom(): number { return 1 / FieldValue(this.Document.zoomBasis, 1); } + @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } + @computed get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } + @computed get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } + @computed get width(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } + @computed get height(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.Document.height || 0; } @computed get nativeWidth(): number { return FieldValue(this.Document.nativeWidth, 0); } @computed get nativeHeight(): number { return FieldValue(this.Document.nativeHeight, 0); } @computed get scaleToOverridingWidth() { return this.width / NumCast(this.props.Document.width, this.width); } + @computed get renderScriptDim() { + if (this.Document.renderScript) { + let someView = Cast(this.Document.someView, Doc); + let minimap = Cast(this.Document.minimap, Doc); + if (someView instanceof Doc && minimap instanceof Doc) { + let x = (NumCast(someView.panX) - NumCast(someView.width) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap.width) - NumCast(minimap.width) / 2; + let y = (NumCast(someView.panY) - NumCast(someView.height) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap.height) - NumCast(minimap.height) / 2; + let w = NumCast(someView.width) / NumCast(someView.scale) / NumCast(minimap.fitW) * NumCast(minimap.width); + let h = NumCast(someView.height) / NumCast(someView.scale) / NumCast(minimap.fitH) * NumCast(minimap.height); + return { x: x, y: y, width: w, height: h }; + } + } + return undefined; + } + contentScaling = () => this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) - .scale(1 / this.contentScaling()).scale(1 / this.zoom / this.scaleToOverridingWidth) + .scale(1 / this.contentScaling()).scale(1 / this.scaleToOverridingWidth) animateBetweenIcon = (icon: number[], stime: number, maximizing: boolean) => { this.props.bringToFront(this.props.Document); @@ -77,21 +90,6 @@ export class CollectionFreeFormDocumentView extends DocComponent this.clusterColor; render() { - let txf = this.transform; - let w = this.width; - let h = this.height; - let renderScript = this.Document.renderScript; - if (renderScript) { - let someView = Cast(this.Document.someView, Doc); - let minimap = Cast(this.Document.minimap, Doc); - if (someView instanceof Doc && minimap instanceof Doc) { - let x = (NumCast(someView.panX) - NumCast(someView.width) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap.width) - NumCast(minimap.width) / 2; - let y = (NumCast(someView.panY) - NumCast(someView.height) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap.height) - NumCast(minimap.height) / 2; - w = NumCast(someView.width) / NumCast(someView.scale) / NumCast(minimap.fitW) * NumCast(minimap.width); - h = NumCast(someView.height) / NumCast(someView.scale) / NumCast(minimap.fitH) * NumCast(minimap.height); - txf = `translate(${x}px,${y}px)`; - } - } const hasPosition = this.props.x !== undefined || this.props.y !== undefined; return (
1000) { x = 0; diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 30e0454f3..c56d093fa 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -71,8 +71,8 @@ export class SelectorContextMenu extends React.Component { return () => { col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col; if (NumCast(col.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) { - const newPanX = NumCast(target.x) + NumCast(target.width) / NumCast(target.zoomBasis, 1) / 2; - const newPanY = NumCast(target.y) + NumCast(target.height) / NumCast(target.zoomBasis, 1) / 2; + const newPanX = NumCast(target.x) + NumCast(target.width) / 2; + const newPanY = NumCast(target.y) + NumCast(target.height) / 2; col.panX = newPanX; col.panY = newPanY; } diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index 807216ef1..a9256073b 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -88,7 +88,6 @@ def write_collection(parse_results, display_fields, storage_key, viewType=2): "height": 600, "panX": 0, "panY": 0, - "zoomBasis": 1, "zIndex": 2, "libraryBrush": False, "viewType": viewType -- cgit v1.2.3-70-g09d2 From 186d7aed7b99b1373e99b51cfe0c88c8167c8290 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 11 Sep 2019 22:52:07 -0400 Subject: fixed some template issues specifically for self-templates. --- src/client/views/DocumentDecorations.tsx | 22 +++++++++++++------- .../views/collections/CollectionBaseView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 24 ++++++++++++++-------- src/client/views/nodes/DocumentView.tsx | 6 +++--- src/client/views/nodes/FormattedTextBox.tsx | 3 +-- src/new_fields/Doc.ts | 5 ++--- 6 files changed, 37 insertions(+), 25 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fe409d9a6..814d718be 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -30,6 +30,7 @@ import { MetadataEntryMenu } from './MetadataEntryMenu'; import { ImageBox } from './nodes/ImageBox'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; +import { ObjectField } from '../../new_fields/ObjectField'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -145,13 +146,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let fieldTemplateView = SelectionManager.SelectedDocuments()[0]; SelectionManager.DeselectAll(); let fieldTemplate = fieldTemplateView.props.Document; - let docTemplate = fieldTemplateView.props.ContainingCollectionView!.props.Document; - let metaKey = text.startsWith(">>") ? text.slice(2, text.length) : text.slice(1, text.length); - let proto = Doc.GetProto(docTemplate); - Doc.MakeTemplate(fieldTemplate, metaKey, proto); - if (text.startsWith(">>")) { - proto.detailedLayout = proto.layout; - proto.miniLayout = ImageBox.LayoutString(metaKey); + let containerView = fieldTemplateView.props.ContainingCollectionView; + if (containerView) { + let docTemplate = containerView.props.Document; + let metaKey = text.startsWith(">>") ? text.slice(2, text.length) : text.slice(1, text.length); + let proto = Doc.GetProto(docTemplate); + if (metaKey !== containerView.props.fieldKey && containerView.props.DataDoc) { + const fd = fieldTemplate.data; + fd instanceof ObjectField && (Doc.GetProto(containerView.props.DataDoc)[metaKey] = ObjectField.MakeCopy(fd)); + } + Doc.MakeTemplate(fieldTemplate, metaKey, proto); + if (text.startsWith(">>")) { + proto.detailedLayout = proto.layout; + proto.miniLayout = ImageBox.LayoutString(metaKey); + } } } else { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 5829f0626..b7036b3ff 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -127,7 +127,7 @@ export class CollectionBaseView extends React.Component { let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document; let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; let value = Cast(targetDataDoc[targetField], listSpec(Doc), []); - let index = value.reduce((p, v, i) => (v instanceof Doc && v[Id] === doc[Id]) ? i : p, -1); + let index = value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined)); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index eb7ab64f8..07dd1cae7 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -74,10 +74,10 @@ export class CollectionFreeFormDocumentView extends DocComponent { - let br = StrCast(this.props.Document.layout instanceof Doc ? this.props.Document.layout.borderRounding : this.props.Document.borderRounding); + let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); if (br.endsWith("%")) { let percent = Number(br.substr(0, br.length - 1)) / 100; - let nativeDim = Math.min(NumCast(this.props.Document.nativeWidth), NumCast(this.props.Document.nativeHeight)); + let nativeDim = Math.min(NumCast(this.layoutDoc.nativeWidth), NumCast(this.layoutDoc.nativeHeight)); let minDim = percent * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight())); return minDim; } @@ -89,6 +89,12 @@ export class CollectionFreeFormDocumentView extends DocComponent this.clusterColor; + get layoutDoc() { + // if this document's layout field contains a document (ie, a rendering template), then we will use that + // to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string. + return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; + } + render() { const hasPosition = this.props.x !== undefined || this.props.y !== undefined; return ( @@ -98,15 +104,15 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu let docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: StrCast(this.Document.title) + "layout", width: NumCast(this.props.Document.width) + 20, height: Math.max(100, NumCast(this.props.Document.height) + 45) }); let metaKey = "data"; let proto = Doc.GetProto(docTemplate); - Doc.MakeTemplate(fieldTemplate, metaKey, proto, true); + Doc.MakeTemplate(fieldTemplate, metaKey, proto); - Doc.ApplyTemplateTo(docTemplate, this.props.Document, undefined, true); + Doc.ApplyTemplateTo(docTemplate, this.props.Document, undefined, false); } @undoBatch @@ -634,7 +634,7 @@ export class DocumentView extends DocComponent(Docu let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : []; makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Into Background", event: this.makeBackground, icon: this.props.Document.lockedPosition ? "unlock" : "lock" }); makes.push({ description: "Custom Document View", event: this.makeCustomViewClicked, icon: "concierge-bell" }); - makes.push({ description: "Metadata Field View", event: () => this.props.ContainingCollectionView && Doc.MakeTemplate(this.props.Document, StrCast(this.props.Document.title), this.props.ContainingCollectionView.props.Document, true), icon: "concierge-bell" }) + makes.push({ description: "Metadata Field View", event: () => this.props.ContainingCollectionView && Doc.MakeTemplate(this.props.Document, StrCast(this.props.Document.title), this.props.ContainingCollectionView.props.Document), icon: "concierge-bell" }) makes.push({ description: "Into Portal", event: this.makeIntoPortal, icon: "window-restore" }); makes.push({ description: this.layoutDoc.ignoreClick ? "Selectable" : "Unselectable", event: () => this.layoutDoc.ignoreClick = !this.layoutDoc.ignoreClick, icon: this.layoutDoc.ignoreClick ? "unlock" : "lock" }); !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 194026a08..0ea36cdc2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -289,8 +289,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) !== "") { - if (this.props.DataDoc) this.props.DataDoc.layout = draggedDoc; - else this.props.Document.layout = draggedDoc; + this.props.Document.layout = draggedDoc; draggedDoc.isTemplate = true; e.stopPropagation(); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index d4b784cac..e94b9f1eb 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -459,7 +459,7 @@ export namespace Doc { } if (expandedTemplateLayout === undefined) { setTimeout(() => dataDoc[expandedLayoutFieldKey] === undefined && - (dataDoc[expandedLayoutFieldKey] = !BoolCast(templateLayoutDoc.suppressTemplateInstance) ? Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]") : templateLayoutDoc), 0); + (dataDoc[expandedLayoutFieldKey] = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]")), 0); } return undefined; // use the templateLayout when it's not a template or the expandedTemplate is pending. } @@ -558,7 +558,7 @@ export namespace Doc { } } - export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc, suppressTemplateFlag?: boolean) { + export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); let fieldLayoutDoc = fieldTemplate; @@ -576,7 +576,6 @@ export namespace Doc { fieldTemplate.templateField = metaKey; fieldTemplate.title = metaKey; fieldTemplate.isTemplate = true; - fieldTemplate.suppressTemplateInstance = suppressTemplateFlag; fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout; fieldTemplate.backgroundLayout = backgroundLayout; /* move certain layout properties from the original data doc to the template layout to avoid -- cgit v1.2.3-70-g09d2 From 47ca25c49d7d9f1fee22b256f86e296dac42b47b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 12 Sep 2019 21:42:07 -0400 Subject: cleaned up rulerProvider a bit and added menu item to turn it on. --- src/client/views/DocumentDecorations.tsx | 13 +++++---- src/client/views/InkingControl.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 31 +++++++--------------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 3 +++ src/client/views/nodes/DocumentView.tsx | 12 ++++++--- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- 7 files changed, 31 insertions(+), 36 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6451fdf5e..4ab2ade8e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -424,23 +424,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onRadiusMove); document.addEventListener("pointerup", this.onRadiusUp); } - if (!this._isMoving) { - SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). - map(d => d.borderRounding = "0%"); - } } onRadiusMove = (e: PointerEvent): void => { this._isMoving = true; let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1])); - SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). - map(d => d.borderRounding = `${Math.min(100, dist)}%`); + dist = dist < 3 ? 0 : dist; + let usingRule = false; SelectionManager.SelectedDocuments().map(dv => { let cv = dv.props.ContainingCollectionView; let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); let heading = NumCast(dv.props.Document.heading); - cv && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleRounding_" + heading] = StrCast(dv.props.Document.borderRounding)); + ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`); + usingRule = usingRule || (ruleProvider && heading ? true : false); }) + !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). + map(d => d.borderRounding = `${Math.min(100, dist)}%`); e.stopPropagation(); e.preventDefault(); } diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index aa573f16b..867735c0b 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -73,7 +73,7 @@ export class InkingControl extends React.Component { let cv = view.props.ContainingCollectionView; let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); let parback = cv && StrCast(cv.props.Document.backgroundColor); - cv && parback && ((ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); + cv && parback && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); // if (parback && cv && parback.indexOf("rgb") !== -1) { // let parcol = Utils.fromRGBAstr(parback); // let hsl = Utils.RGBToHSL(parcol.r, parcol.g, parcol.b); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 24f2a60a9..9a8ae3535 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -262,27 +262,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (heading === 0) { let sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 : DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0); - heading = NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); + heading = !sorted.length ? 1 : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); } newBox.heading = heading; - PromiseValue(Cast(this.props.Document.ruleProvider, Doc)).then(ruleProvider => { - if (!ruleProvider) ruleProvider = this.props.Document; - // saturation shift - // let col = NumCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - // let back = Utils.fromRGBAstr(StrCast(this.props.Document.backgroundColor)); - // let hsl = Utils.RGBToHSL(back.r, back.g, back.b); - // let newcol = { h: hsl.h, s: hsl.s + col, l: hsl.l }; - // col && (Doc.GetProto(newBox).backgroundColor = Utils.toRGBAstr(Utils.HSLtoRGB(newcol.h, newcol.s, newcol.l))); - // OR transparency set - let col = StrCast(ruleProvider["ruleColor_" + NumCast(newBox.heading)]); - (newBox.backgroundColor === newBox.defaultBackgroundColor) && col && (Doc.GetProto(newBox).backgroundColor = col); - - let round = StrCast(ruleProvider["ruleRounding_" + NumCast(newBox.heading)]); - round && (Doc.GetProto(newBox).borderRounding = round); - newBox.ruleProvider = ruleProvider; - this.addDocument(newBox, false); - }); + if (Cast(this.props.Document.ruleProvider, Doc) as Doc) { + newBox.ruleProvider = Doc.GetProto(Cast(this.props.Document.ruleProvider, Doc) as Doc); + } + this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { this.props.addDocument(newBox, false); @@ -898,7 +885,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { let layoutItems: ContextMenuProps[] = []; - if (this.childDocs.some(d => d.isTemplate)) { + if (this.childDocs.some(d => BoolCast(d.isTemplate))) { layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); @@ -913,9 +900,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, icon: !this.props.Document.useClusters ? "braille" : "braille" }); - this.props.Document.useClusters && layoutItems.push({ - description: `${this.props.Document.clusterOverridesDefaultBackground ? "Use Default Backgrounds" : "Clusters Override Defaults"}`, - event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground, + layoutItems.push({ + description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, + event: () => this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider, icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard" }); layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index fe48a3485..4308497a1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -356,7 +356,7 @@ export class MarqueeView extends React.Component this.props.addLiveTextDocument(summary); } else { - newCollection.ruleProvider = this.props.container.props.Document; + newCollection.ruleProvider = this.props.container.props.Document.isRuleProvider ? this.props.container.props.Document : this.props.container.props.Document.ruleProvider; this.props.addDocument(newCollection, false); this.props.selectDocuments([newCollection]); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 07dd1cae7..082e5c5e3 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -74,7 +74,10 @@ export class CollectionFreeFormDocumentView extends DocComponent { + let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); + br = !br && ruleRounding ? ruleRounding : br; if (br.endsWith("%")) { let percent = Number(br.substr(0, br.length - 1)) / 100; let nativeDim = Math.min(NumCast(this.layoutDoc.nativeWidth), NumCast(this.layoutDoc.nativeHeight)); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3f0b62511..7b9ed12a7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -793,9 +793,15 @@ export class DocumentView extends DocComponent(Docu render() { - let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ? + let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleColor = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(this.props.Document.heading)]) : undefined; + let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; + let colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; + let clusterCol = this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground; + + let backgroundColor = this.layoutDoc.isBackground || (clusterCol && !colorSet) ? this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : - StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); + ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; @@ -811,7 +817,7 @@ export class DocumentView extends DocComponent(Docu } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith(" diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 444b91b28..658e2a04d 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -284,8 +284,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe e.stopPropagation(); } else if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; - if (draggedDoc && draggedDoc.type === DocumentType.TEXT && StrCast(draggedDoc.layout) !== "") { - this.props.Document.layout = draggedDoc; + if (draggedDoc && draggedDoc.type === DocumentType.TEXT) { + this.props.Document.layout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; draggedDoc.isTemplate = true; e.stopPropagation(); } -- cgit v1.2.3-70-g09d2 From 233893698083cbcfcf39ddad8b57049aeb1ba842 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 13 Sep 2019 14:18:55 -0400 Subject: refactored how ruleProvider's work. overloaded custom template for creating metadata fields --- src/client/util/RichTextRules.ts | 8 +++---- src/client/util/TooltipTextMenu.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 11 ++------- src/client/views/InkingControl.tsx | 5 ++-- src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/MainView.tsx | 2 ++ src/client/views/TemplateMenu.tsx | 16 ++++++------- .../views/collections/CollectionDockingView.tsx | 1 + .../views/collections/CollectionSchemaView.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 27 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 2 -- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 13 +++++++---- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/FormattedTextBox.tsx | 2 +- .../views/presentationview/PresentationElement.tsx | 1 + src/client/views/search/SearchItem.tsx | 1 + src/new_fields/Doc.ts | 2 +- 19 files changed, 51 insertions(+), 51 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index c0c62463a..c727eec73 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -61,7 +61,7 @@ export const inpRules = { new RegExp(/^#([0-9]+)\s$/), (state, match, start, end) => { let size = Number(match[1]); - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { (Cast(FormattedTextBox.InputBoxOverlay!.props.Document, Doc) as Doc).heading = Number(match[1]); @@ -74,7 +74,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "center"; @@ -88,7 +88,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "left"; @@ -100,7 +100,7 @@ export const inpRules = { (state, match, start, end) => { let node = (state.doc.resolve(start) as any).nodeAfter; let sm = state.storedMarks || undefined; - let ruleProvider = Cast(FormattedTextBox.InputBoxOverlay!.props.Document.ruleProvider, Doc) as Doc; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleAlign_" + heading] = "right"; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index c376b6f86..84d045e6f 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -496,7 +496,7 @@ export class TooltipTextMenu { if (markType.name[0] === 'p') { let size = this.fontSizeToNum.get(markType); if (size) { this.updateFontSizeDropdown(String(size) + " pt"); } - let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let ruleProvider = this.editorProps.ruleProvider; let heading = NumCast(this.editorProps.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleSize_" + heading] = size; @@ -505,7 +505,7 @@ export class TooltipTextMenu { else { let fontName = this.fontStylesToName.get(markType); if (fontName) { this.updateFontStyleDropdown(fontName); } - let ruleProvider = Cast(this.editorProps.Document.ruleProvider, Doc) as Doc; + let ruleProvider = this.editorProps.ruleProvider; let heading = NumCast(this.editorProps.Document.heading); if (ruleProvider && heading) { ruleProvider["ruleFont_" + heading] = fontName; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6d63e8f73..ebdf2a749 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -365,14 +365,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { let docViews = SelectionManager.ViewsSortedVertically(); let topDocView = docViews[0]; - let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); - if (ind !== -1) { - topDocView.templates.splice(ind, 1); - topDocView.props.Document.subBulletDocs = undefined; - } else { - topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } } this._removeIcon = false; @@ -439,7 +432,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let usingRule = false; SelectionManager.SelectedDocuments().map(dv => { let cv = dv.props.ContainingCollectionView; - let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); + let ruleProvider = cv && cv.props.ruleProvider; let heading = NumCast(dv.props.Document.heading); ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`); usingRule = usingRule || (ruleProvider && heading ? true : false); diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 867735c0b..86d0fc0be 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -71,9 +71,8 @@ export class InkingControl extends React.Component { targetDoc.backgroundColor = this._selectedColor; if (view.props.Document.heading) { let cv = view.props.ContainingCollectionView; - let ruleProvider = cv && (Cast(cv.props.Document.ruleProvider, Doc) as Doc); - let parback = cv && StrCast(cv.props.Document.backgroundColor); - cv && parback && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); + let ruleProvider = cv && (Cast(cv.props.ruleProvider, Doc) as Doc); + cv && (Doc.GetProto(ruleProvider ? ruleProvider : cv.props.Document)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb)); // if (parback && cv && parback.indexOf("rgb") !== -1) { // let parcol = Utils.fromRGBAstr(parback); // let hsl = Utils.RGBToHSL(parcol.r, parcol.g, parcol.b); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index c3a2cb214..71fb2707d 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -72,7 +72,6 @@ export class MainOverlayTextBox extends React.Component if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } - this._textAutoHeight = autoHeight; this.TextFieldKey = textFieldKey!; let txf = tx ? tx : () => Transform.Identity(); this._textXf = txf; @@ -143,6 +142,7 @@ export class MainOverlayTextBox extends React.Component Document={FormattedTextBox.InputBoxOverlay.props.Document} DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc} onClick={undefined} + ruleProvider={this._textBox ? this._textBox.props.ruleProvider : undefined} ChromeHeight={this.ChromeHeight} isSelected={returnTrue} select={emptyFunction} renderDepth={0} ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b64986084..2cec1c052 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -322,6 +322,7 @@ export class MainView extends React.Component { addDocTab={emptyFunction} pinToPres={emptyFunction} onClick={undefined} + ruleProvider={undefined} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} @@ -385,6 +386,7 @@ export class MainView extends React.Component { addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} removeDocument={undefined} + ruleProvider={undefined} onClick={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 0ef1a137d..060191e29 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -51,16 +51,16 @@ export class TemplateMenu extends React.Component { @observable private _hidden: boolean = true; dragRef = React.createRef(); - constructor(props: TemplateMenuProps) { - super(props); - } - toggleCustom = (e: React.MouseEvent): void => { this.props.docs.map(dv => { - if (dv.Document.type !== DocumentType.COL && dv.Document.type !== DocumentType.TEMPLATE) { - dv.makeCustomViewClicked(); - } else if (dv.Document.nativeLayout) { - dv.makeNativeViewClicked(); + if (dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.DataDoc) { + Doc.MakeMetadataFieldTemplate(dv.props.Document, dv.props.ContainingCollectionView.props.DataDoc) + } else { + if (dv.Document.type !== DocumentType.COL && dv.Document.type !== DocumentType.TEMPLATE) { + dv.makeCustomViewClicked(); + } else if (dv.Document.nativeLayout) { + dv.makeNativeViewClicked(); + } } }); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index fb8b0c41b..166fa0811 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -631,6 +631,7 @@ export class DockedFrameRenderer extends React.Component { bringToFront={emptyFunction} addDocument={undefined} removeDocument={undefined} + ruleProvider={undefined} ContentScaling={this.contentScaling} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9d83aa6c1..dca1d7c1d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -995,6 +995,7 @@ export class CollectionSchemaPreview extends React.Component(schemaCtor: (doc: Doc) => T) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9a8ae3535..4a3e5039a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -257,18 +257,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); private addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed - let heading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); - heading = heading === 0 || this.childDocs.length === 0 ? 1 : heading === 1 ? 2 : 0; + let maxHeading = this.childDocs.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0); + let heading = maxHeading === 0 || this.childDocs.length === 0 ? 1 : maxHeading === 1 ? 2 : 0; if (heading === 0) { let sorted = this.childDocs.filter(d => d.type === DocumentType.TEXT && d.data_ext instanceof Doc && d.data_ext.lastModified).sort((a, b) => DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date > DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? 1 : DateCast((Cast(a.data_ext, Doc) as Doc).lastModified).date < DateCast((Cast(b.data_ext, Doc) as Doc).lastModified).date ? -1 : 0); - heading = !sorted.length ? 1 : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); - } - newBox.heading = heading; - - if (Cast(this.props.Document.ruleProvider, Doc) as Doc) { - newBox.ruleProvider = Doc.GetProto(Cast(this.props.Document.ruleProvider, Doc) as Doc); + heading = !sorted.length ? Math.max(1, maxHeading) : NumCast(sorted[sorted.length - 1].heading) === 1 ? 2 : NumCast(sorted[sorted.length - 1].heading); } + !this.props.Document.isRuleProvider && (newBox.heading = heading); this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { @@ -698,6 +694,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, + ruleProvider: this.props.Document.isRuleProvider && childLayout.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider, onClick: this.props.onClick, ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform, renderDepth: this.props.renderDepth + 1, @@ -723,6 +720,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { addDocument: this.props.addDocument, removeDocument: this.props.removeDocument, moveDocument: this.props.moveDocument, + ruleProvider: this.props.ruleProvider, onClick: this.props.onClick, ScreenToLocalTransform: this.getTransform, renderDepth: this.props.renderDepth, @@ -817,6 +815,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (pair.layout && !(pair.data instanceof Promise)) { prev.push({ ele: , @@ -873,6 +872,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } + autoFormat = () => { + this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider; + this.childDocs.map(child => child.heading = undefined); + } + analyzeStrokes = async () => { let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); if (!data) { @@ -900,11 +904,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, icon: !this.props.Document.useClusters ? "braille" : "braille" }); - layoutItems.push({ - description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, - event: () => this.props.Document.isRuleProvider = !this.props.Document.isRuleProvider, - icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard" - }); + layoutItems.push({ description: `${this.props.Document.isRuleProvider ? "Stop Auto Format" : "Auto Format"}`, event: this.autoFormat, icon: !this.props.Document.isRuleProvider ? "chalkboard" : "chalkboard" }); layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" }); layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" }); @@ -1034,7 +1034,6 @@ class CollectionFreeFormOverlayView extends React.Component boolean }> { @computed get backgroundView() { - let props = this.props; return (); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 4308497a1..e46e8cb88 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -329,7 +329,6 @@ export class MarqueeView extends React.Component selected = [newCollection]; newCollection.x = bounds.left + bounds.width; summary.proto!.subBulletDocs = new List(selected); - summary.templates = new List([Templates.Bullet.Layout]); let container = Docs.Create.FreeformDocument([summary, newCollection], { x: bounds.left, y: bounds.top, width: 300, height: 200, chromeStatus: "disabled", title: "-summary-" }); container.viewType = CollectionViewType.Stacking; container.autoHeight = true; @@ -356,7 +355,6 @@ export class MarqueeView extends React.Component this.props.addLiveTextDocument(summary); } else { - newCollection.ruleProvider = this.props.container.props.Document.isRuleProvider ? this.props.container.props.Document : this.props.container.props.Document.ruleProvider; this.props.addDocument(newCollection, false); this.props.selectDocuments([newCollection]); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 082e5c5e3..4872a7aa1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -74,7 +74,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { - let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleProvider = this.props.ruleProvider; let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); br = !br && ruleRounding ? ruleRounding : br; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0816cb813..cc04c5a9f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import * as fa from '@fortawesome/free-solid-svg-icons'; -import { action, computed, IReactionDisposer, reaction, runInAction, trace, observable } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; import { Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; @@ -9,12 +9,13 @@ import { List } from "../../../new_fields/List"; import { ObjectField } from "../../../new_fields/ObjectField"; import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema"; import { ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../new_fields/Types"; +import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { RouteStore } from '../../../server/RouteStore'; import { emptyFunction, returnTrue, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from "../../documents/Documents"; +import { DocumentType } from '../../documents/DocumentTypes'; import { ClientUtils } from '../../util/ClientUtils'; import { DictationManager } from '../../util/DictationManager'; import { DocumentManager } from "../../util/DocumentManager"; @@ -35,12 +36,10 @@ import { MainView } from '../MainView'; import { OverlayView } from '../OverlayView'; import { ScriptBox } from '../ScriptBox'; import { ScriptingRepl } from '../ScriptingRepl'; -import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import { FormattedTextBox } from './FormattedTextBox'; import React = require("react"); -import { DocumentType } from '../../documents/DocumentTypes'; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? library.add(fa.faTrash); @@ -89,6 +88,7 @@ export interface DocumentViewProps { renderDepth: number; showOverlays?: (doc: Doc) => { title?: string, caption?: string }; ContentScaling: () => number; + ruleProvider: Doc | undefined; PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Doc, willZoom: boolean, scale?: number) => void; @@ -470,6 +470,9 @@ export class DocumentView extends DocComponent(Docu this.props.Document.type === DocumentType.VID ? Docs.Create.VideoDocument("http://www.cs.brown.edu", options) : Docs.Create.ImageDocument("http://www.cs.brown.edu", options); + fieldTemplate.backgroundColor = StrCast(this.props.Document.backgroundColor); + fieldTemplate.heading = 1; + let docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: StrCast(this.Document.title) + "layout", width: NumCast(this.props.Document.width) + 20, height: Math.max(100, NumCast(this.props.Document.height) + 45) }); let proto = Doc.GetProto(docTemplate); Doc.MakeMetadataFieldTemplate(fieldTemplate, proto); @@ -800,7 +803,7 @@ export class DocumentView extends DocComponent(Docu render() { - let ruleProvider = this.props.Document.ruleProvider as Doc; + let ruleProvider = this.props.ruleProvider; let ruleColor = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(this.props.Document.heading)]) : undefined; let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; let colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d9774303b..943d181d6 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -30,6 +30,7 @@ export interface FieldViewProps { leaveNativeSize?: boolean; fitToBox?: boolean; ContainingCollectionView: Opt; + ruleProvider: Doc | undefined; Document: Doc; DataDoc?: Doc; onClick?: ScriptField; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d39291743..a0dc054cf 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -458,7 +458,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._rulesReactionDisposer = reaction(() => { - let ruleProvider = Cast(this.props.Document.ruleProvider, Doc); + let ruleProvider = this.props.ruleProvider; let heading = NumCast(this.props.Document.heading); if (ruleProvider instanceof Doc) { return { diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 80aa25f48..7be44faf6 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -351,6 +351,7 @@ export default class PresentationElement extends React.Component { Document={this.props.doc} addDocument={returnFalse} removeDocument={returnFalse} + ruleProvider={undefined} ScreenToLocalTransform={Transform.Identity} addDocTab={returnFalse} pinToPres={returnFalse} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 1a3d689bb..5b22a62a1 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -560,7 +560,7 @@ export namespace Doc { export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) - let metadataFieldName = StrCast(fieldTemplate.title); + let metadataFieldName = StrCast(fieldTemplate.title).replace(/^-/, ""); let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); let fieldLayoutDoc = fieldTemplate; if (fieldTemplate.layout instanceof Doc) { -- cgit v1.2.3-70-g09d2 From f428ac2621f123661a937405764058f27a9feefd Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 16 Sep 2019 09:49:25 -0400 Subject: fixed boxShadows for backgrounds and activeDocuments() for freeformviews/marquees --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6b2b79261..5d5d9de9e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -283,7 +283,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return this.childDocs.filter(doc => { var page = NumCast(doc.page, -1); return page === curPage || page === -1; - }); + }).map(doc => Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, doc).layout); } @computed get fieldExtensionDoc() { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 4872a7aa1..865eb27d5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -109,9 +109,8 @@ export class CollectionFreeFormDocumentView extends DocComponent Date: Tue, 17 Sep 2019 11:26:54 -0400 Subject: lots of code cleanup in collectionFreeFormDocumentView and DocumentView --- src/Utils.ts | 5 + src/client/views/DocumentDecorations.tsx | 3 +- src/client/views/GlobalKeyHandler.ts | 2 +- .../views/collections/CollectionDockingView.tsx | 5 + .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../document_templates/image_card/ImageCard.tsx | 3 - src/client/views/linking/LinkFollowBox.tsx | 2 - .../nodes/CollectionFreeFormDocumentView.scss | 5 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 48 ++-- src/client/views/nodes/DocumentView.scss | 42 +++ src/client/views/nodes/DocumentView.tsx | 286 ++++++++++----------- src/client/views/nodes/ImageBox.tsx | 5 +- 12 files changed, 215 insertions(+), 193 deletions(-) create mode 100644 src/client/views/nodes/CollectionFreeFormDocumentView.scss (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 3921a49c3..415023ac4 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -37,6 +37,7 @@ export class Utils { public static prepend(extension: string): string { return window.location.origin + extension; } + public static CorsProxy(url: string): string { return this.prepend(RouteStore.corsProxy + "/") + encodeURIComponent(url); } @@ -239,6 +240,10 @@ export function timenow() { return now.toLocaleDateString() + ' ' + h + ':' + m + ' ' + ampm; } +export function percent2frac(percent: string) { + return Number(percent.substr(0, percent.length - 1)) / 100; +} + export function numberRange(num: number) { return Array.from(Array(num)).map((v, i) => i); } export function returnTrue() { return true; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 240abaf6b..7829bd7f1 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -16,7 +16,7 @@ import { undoBatch, UndoManager } from "../util/UndoManager"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { CollectionView } from "./collections/CollectionView"; import './DocumentDecorations.scss'; -import { DocumentView, PositionDocument } from "./nodes/DocumentView"; +import { DocumentView } from "./nodes/DocumentView"; import { FieldView } from "./nodes/FieldView"; import { FormattedTextBox, GoogleRef } from "./nodes/FormattedTextBox"; import { IconBox } from "./nodes/IconBox"; @@ -34,6 +34,7 @@ import { ObjectField } from '../../new_fields/ObjectField'; import { DocServer } from '../DocServer'; import { CompileScript } from '../util/Scripting'; import { ComputedField } from '../../new_fields/ScriptField'; +import { PositionDocument } from './nodes/CollectionFreeFormDocumentView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index f9ee22f61..ba125d6e5 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -166,7 +166,7 @@ export default class KeyManager { break; case "o": let target = SelectionManager.SelectedDocuments()[0]; - target && target.fullScreenClicked(); + target && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(target) break; case "r": preventDefault = false; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index bf55dba31..a350cfcc5 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -86,6 +86,7 @@ export class CollectionDockingView extends React.Component { @@ -169,6 +171,7 @@ export class CollectionDockingView extends React.Component { let docs = Cast(this.props.Document.data, listSpec(Doc)); @@ -207,6 +210,8 @@ export class CollectionDockingView extends React.Component { Doc.GetProto(document).lastOpened = new DateField; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e2d9bbb33..f32843d98 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -862,7 +862,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let layoutItems: ContextMenuProps[] = []; if (this.childDocs.some(d => BoolCast(d.isTemplate))) { - layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" }); + layoutItems.push({ description: "Template Layout Instance", event: () => this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" }); } layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: async () => this.Document.fitToBox = !this.fitToBox, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); diff --git a/src/client/views/document_templates/image_card/ImageCard.tsx b/src/client/views/document_templates/image_card/ImageCard.tsx index 9931515f3..868afc423 100644 --- a/src/client/views/document_templates/image_card/ImageCard.tsx +++ b/src/client/views/document_templates/image_card/ImageCard.tsx @@ -1,8 +1,5 @@ import * as React from 'react'; -import { DocComponent } from '../../DocComponent'; import { FieldViewProps } from '../../nodes/FieldView'; -import { createSchema, makeInterface } from '../../../../new_fields/Schema'; -import { createInterface } from 'readline'; import { ImageBox } from '../../nodes/ImageBox'; export default class ImageCard extends React.Component { diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index f8807641b..b1c6c367f 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -172,7 +172,6 @@ export class LinkFollowBox extends React.Component { if (LinkFollowBox.destinationDoc) { let view: DocumentView | null = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc); view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view); - SelectionManager.DeselectAll(); } } @@ -188,7 +187,6 @@ export class LinkFollowBox extends React.Component { let view = DocumentManager.Instance.getDocumentView(options.context); view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view); this.highlightDoc(); - SelectionManager.DeselectAll(); } } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss new file mode 100644 index 000000000..c0d9e1267 --- /dev/null +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss @@ -0,0 +1,5 @@ +.collectionFreeFormDocumentView-container { + transform-origin: left top; + position: absolute; + background-color: transparent; +} \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 865eb27d5..9f0bd736d 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,11 +1,12 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { BoolCast, FieldValue, NumCast, StrCast, Cast } from "../../../new_fields/Types"; +import { FieldValue, NumCast, StrCast, Cast } from "../../../new_fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; -import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView"; -import "./DocumentView.scss"; +import { percent2frac } from "../../../Utils" +import { DocumentView, DocumentViewProps, documentSchema } from "./DocumentView"; +import "./CollectionFreeFormDocumentView.scss"; import React = require("react"); import { Doc } from "../../../new_fields/Doc"; import { random } from "animejs"; @@ -17,30 +18,31 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { height?: number; jitterRotation: number; } - -const schema = createSchema({ +const positionSchema = createSchema({ zIndex: "number", + x: "number", + y: "number", + z: "number", }); -//TODO Types: The import order is wrong, so positionSchema is undefined -type FreeformDocument = makeInterface<[typeof schema, typeof positionSchema]>; -const FreeformDocument = makeInterface(schema, positionSchema); +export type PositionDocument = makeInterface<[typeof documentSchema, typeof positionSchema]>; +export const PositionDocument = makeInterface(documentSchema, positionSchema); @observer -export class CollectionFreeFormDocumentView extends DocComponent(FreeformDocument) { +export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } @computed get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } @computed get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } - @computed get width(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } - @computed get height(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.Document.height || 0; } - @computed get nativeWidth(): number { return FieldValue(this.Document.nativeWidth, 0); } - @computed get nativeHeight(): number { return FieldValue(this.Document.nativeHeight, 0); } - @computed get scaleToOverridingWidth() { return this.width / NumCast(this.props.Document.width, this.width); } + @computed get width() { return this.Document.willMaximize ? 0 : this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } + @computed get height() { return this.Document.willMaximize ? 0 : this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.Document.height || 0; } + @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } + @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } + @computed get scaleToOverridingWidth() { return this.width / FieldValue(this.Document.width, this.width); } @computed get renderScriptDim() { if (this.Document.renderScript) { - let someView = Cast(this.Document.someView, Doc); - let minimap = Cast(this.Document.minimap, Doc); + let someView = Cast(this.props.Document.someView, Doc); + let minimap = Cast(this.props.Document.minimap, Doc); if (someView instanceof Doc && minimap instanceof Doc) { let x = (NumCast(someView.panX) - NumCast(someView.width) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap.width) - NumCast(minimap.width) / 2; let y = (NumCast(someView.panY) - NumCast(someView.height) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap.height) - NumCast(minimap.height) / 2; @@ -52,7 +54,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? this.width / this.nativeWidth : 1; + contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); getTransform = (): Transform => this.props.ScreenToLocalTransform() @@ -74,15 +76,12 @@ export class CollectionFreeFormDocumentView extends DocComponent { - let ruleProvider = this.props.ruleProvider; - let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; - let br = StrCast(this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout.borderRounding : this.props.Document.borderRounding); + let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; + let br = StrCast(((this.layoutDoc.layout as Doc) || this.Document).borderRounding); br = !br && ruleRounding ? ruleRounding : br; if (br.endsWith("%")) { - let percent = Number(br.substr(0, br.length - 1)) / 100; let nativeDim = Math.min(NumCast(this.layoutDoc.nativeWidth), NumCast(this.layoutDoc.nativeHeight)); - let minDim = percent * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight())); - return minDim; + return percent2frac(br) * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight())); } return undefined; } @@ -103,9 +102,6 @@ export class CollectionFreeFormDocumentView extends DocComponent number; } -const schema = createSchema({ - layout: "string", +export const documentSchema = createSchema({ + layout: "string", // should also allow Doc but that can't be expressed in the schema + title: "string", nativeWidth: "number", nativeHeight: "number", backgroundColor: "string", opacity: "number", hidden: "boolean", onClick: ScriptField, -}); - -export const positionSchema = createSchema({ - nativeWidth: "number", - nativeHeight: "number", + willMaximize: "boolean", + ignoreAspect: "boolean", + autoHeight: "boolean", + isTemplate: "boolean", + isButton: "boolean", + isBackground: "boolean", + ignoreClick: "boolean", + type: "string", + maximizeLocation: "string", + lockedPosition: "boolean", + excludeFromLibrary: "boolean", width: "number", height: "number", - x: "number", - y: "number", - z: "number", + borderRounding: "string", + fitToBox: "boolean", + searchFields: "string", + heading: "number", + showCaption: "string", + showTitle: "string" }); -export type PositionDocument = makeInterface<[typeof positionSchema]>; -export const PositionDocument = makeInterface(positionSchema); - -type Document = makeInterface<[typeof schema]>; -const Document = makeInterface(schema); +type Document = makeInterface<[typeof documentSchema]>; +const Document = makeInterface(documentSchema); @observer export class DocumentView extends DocComponent(Document) { @@ -259,7 +266,7 @@ export class DocumentView extends DocComponent(Docu if (e.nativeEvent.cancelBubble) return; // || SelectionManager.IsSelected(this)) -- bcz: needed because EditableView may stopPropagation which won't apparently stop this event from firing. if (this.onClickHandler && this.onClickHandler.script) { e.stopPropagation(); - this.onClickHandler.script.run({ this: this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }); + this.onClickHandler.script.run({ this: this.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }); e.preventDefault(); return; } @@ -268,23 +275,18 @@ export class DocumentView extends DocComponent(Docu if (this._doubleTap && this.props.renderDepth) { e.stopPropagation(); let fullScreenAlias = Doc.MakeAlias(this.props.Document); - fullScreenAlias.templates = new List(); Doc.UseDetailLayout(fullScreenAlias); - fullScreenAlias.showCaption = true; + fullScreenAlias.showCaption = "caption"; this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab"); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } - else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] && + else if (!this.Document.ignoreClick && CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { - if (BoolCast(this.props.Document.ignoreClick)) { - return; - } e.stopPropagation(); SelectionManager.SelectDoc(this, e.ctrlKey); - let isExpander = (e.target as any).id === "isExpander"; - if (BoolCast(this.props.Document.isButton) || this.props.Document.type === DocumentType.BUTTON || isExpander) { + if (this.Document.isButton || this.Document.type === DocumentType.BUTTON) { let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs); let linkedDocs = LinkManager.Instance.getAllRelatedLinks(this.props.Document); @@ -292,12 +294,12 @@ export class DocumentView extends DocComponent(Docu expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs; expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; // let expandedDocs = [ ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),]; - if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents + if (expandedDocs.length) { SelectionManager.DeselectAll(); - let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace"); + let maxLocation = StrCast(this.Document.maximizeLocation, "inPlace"); let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target); if (altKey || ctrlKey) { - maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace")); + maxLocation = this.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace")); if (!maxLocation || maxLocation === "inPlace") { let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !d.isMinimized, false); @@ -379,8 +381,8 @@ export class DocumentView extends DocComponent(Docu document.removeEventListener("pointermove", this.onPointerMove); } else if (!e.cancelBubble && this.active) { - if (!this.props.Document.excludeFromLibrary && (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3)) { - if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) { + if (!this.Document.excludeFromLibrary && (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3)) { + if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.Document.lockedPosition)) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); @@ -400,39 +402,33 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } - @undoBatch - fieldsClicked = (): void => { - let kvp = Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }); - this.props.addDocTab(kvp, this.dataDoc, "onRight"); - } - @undoBatch makeNativeViewClicked = (): void => { makeNativeView(this.props.Document); } @undoBatch makeCustomViewClicked = (): void => { - this.props.Document.nativeLayout = this.props.Document.layout; - this.props.Document.nativeType = this.props.Document.type; - this.props.Document.nonCustomAutoHeight = this.props.Document.autoHeight; - this.props.Document.nonCustomWidth = this.props.Document.width; - this.props.Document.nonCustomHeight = this.props.Document.height; - this.props.Document.nonCustomNativeWidth = this.props.Document.nativeWidth; - this.props.Document.nonCustomNativeHeight = this.props.Document.nativeHeight; - this.props.Document.nonCustomIgnoreAspect = this.props.Document.ignoreAspect; + this.props.Document.nativeLayout = this.Document.layout; + this.props.Document.nativeType = this.Document.type; + this.props.Document.nonCustomAutoHeight = this.Document.autoHeight; + this.props.Document.nonCustomWidth = this.Document.width; + this.props.Document.nonCustomHeight = this.Document.height; + this.props.Document.nonCustomNativeWidth = this.Document.nativeWidth; + this.props.Document.nonCustomNativeHeight = this.Document.nativeHeight; + this.props.Document.nonCustomIgnoreAspect = this.Document.ignoreAspect; PromiseValue(Cast(this.props.Document.customLayout, Doc)).then(custom => { if (custom) { - this.props.Document.type = DocumentType.TEMPLATE; + this.Document.type = DocumentType.TEMPLATE; this.props.Document.layout = custom; - !custom.nativeWidth && (this.props.Document.nativeWidth = 0); - !custom.nativeHeight && (this.props.Document.nativeHeight = 0); - !custom.nativeWidth && (this.props.Document.ignoreAspect = true); - this.props.Document.autoHeight = this.props.Document.autoHeight; - this.props.Document.width = this.props.Document.customWidth; - this.props.Document.height = this.props.Document.customHeight; - this.props.Document.nativeWidth = this.props.Document.customNativeWidth; - this.props.Document.nativeHeight = this.props.Document.customNativeHeight; - this.props.Document.ignoreAspect = this.props.Document.ignoreAspect; + !custom.nativeWidth && (this.Document.nativeWidth = 0); + !custom.nativeHeight && (this.Document.nativeHeight = 0); + !custom.nativeWidth && (this.Document.ignoreAspect = true); + this.Document.autoHeight = BoolCast(this.Document.customAutoHeight); + this.Document.width = NumCast(this.props.Document.customWidth); + this.Document.height = NumCast(this.props.Document.customHeight); + this.Document.nativeWidth = NumCast(this.props.Document.customNativeWidth); + this.Document.nativeHeight = NumCast(this.props.Document.customNativeHeight); + this.Document.ignoreAspect = BoolCast(this.Document.customIgnoreAspect); this.props.Document.customAutoHeight = undefined; this.props.Document.customWidth = undefined; this.props.Document.customHeight = undefined; @@ -440,21 +436,21 @@ export class DocumentView extends DocComponent(Docu this.props.Document.customNativeHeight = undefined; this.props.Document.customIgnoreAspect = undefined; } else { - let options = { title: "data", width: NumCast(this.props.Document.width), x: -NumCast(this.props.Document.width) / 2, y: -NumCast(this.props.Document.height) / 2, }; - let fieldTemplate = this.props.Document.type === DocumentType.TEXT ? Docs.Create.TextDocument(options) : - this.props.Document.type === DocumentType.VID ? Docs.Create.VideoDocument("http://www.cs.brown.edu", options) : + let options = { title: "data", width: (this.Document.width || 0), x: -(this.Document.width || 0) / 2, y: - (this.Document.height || 0) / 2, }; + let fieldTemplate = this.Document.type === DocumentType.TEXT ? Docs.Create.TextDocument(options) : + this.Document.type === DocumentType.VID ? Docs.Create.VideoDocument("http://www.cs.brown.edu", options) : Docs.Create.ImageDocument("http://www.cs.brown.edu", options); - fieldTemplate.backgroundColor = StrCast(this.props.Document.backgroundColor); + fieldTemplate.backgroundColor = this.Document.backgroundColor; fieldTemplate.heading = 1; fieldTemplate.autoHeight = true; - let docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: StrCast(this.Document.title) + "layout", width: NumCast(this.props.Document.width) + 20, height: Math.max(100, NumCast(this.props.Document.height) + 45) }); + let docTemplate = Docs.Create.FreeformDocument([fieldTemplate], { title: this.Document.title + "layout", width: (this.Document.width || 0) + 20, height: Math.max(100, (this.Document.height || 0) + 45) }); let proto = Doc.GetProto(docTemplate); Doc.MakeMetadataFieldTemplate(fieldTemplate, proto, true); Doc.ApplyTemplateTo(docTemplate, this.props.Document, undefined, false); - Doc.GetProto(this.dataDoc || this.props.Document).customLayout = this.props.Document.layout; + Doc.GetProto(this.dataDoc || this.props.Document).customLayout = this.Document.layout; } }); } @@ -468,21 +464,6 @@ export class DocumentView extends DocComponent(Docu } else { doc.isButton = true; } - - // if (doc.isButton) { - // if (!doc.nativeWidth) { - // doc.nativeWidth = this.props.Document[WidthSym](); - // doc.nativeHeight = this.props.Document[HeightSym](); - // } - // } else { - // doc.nativeWidth = doc.nativeHeight = undefined; - // } - } - - @undoBatch - public fullScreenClicked = (): void => { - CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this); - SelectionManager.DeselectAll(); } @undoBatch @@ -543,10 +524,10 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action freezeNativeDimensions = (): void => { - let proto = this.props.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document); - this.props.Document.autoHeight = proto.autoHeight = false; - proto.ignoreAspect = !BoolCast(proto.ignoreAspect); - if (!BoolCast(proto.ignoreAspect) && !proto.nativeWidth) { + let proto = this.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document); + proto.autoHeight = this.Document.autoHeight = false; + proto.ignoreAspect = !proto.ignoreAspect; + if (!proto.ignoreAspect && !proto.nativeWidth) { proto.nativeWidth = this.props.PanelWidth(); proto.nativeHeight = this.props.PanelHeight(); } @@ -555,12 +536,12 @@ export class DocumentView extends DocComponent(Docu @action makeIntoPortal = (): void => { if (!DocListCast(this.props.Document.links).find(doc => { - if (Cast(doc.anchor2, Doc) instanceof Doc && (Cast(doc.anchor2, Doc) as Doc)!.title === this.props.Document.title + ".portal") return true; + if (Cast(doc.anchor2, Doc) instanceof Doc && (Cast(doc.anchor2, Doc) as Doc)!.title === this.Document.title + ".portal") return true; return false; })) { - let portalID = (this.props.Document.title + ".portal").replace(/^-/, "").replace(/\([0-9]*\)$/, ""); + let portalID = (this.Document.title + ".portal").replace(/^-/, "").replace(/\([0-9]*\)$/, ""); DocServer.GetRefField(portalID).then(existingPortal => { - let portal = existingPortal instanceof Doc ? existingPortal : Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: portalID }); + let portal = existingPortal instanceof Doc ? existingPortal : Docs.Create.FreeformDocument([], { width: (this.Document.width || 0) + 10, height: this.Document.height || 0, title: portalID }); DocUtils.MakeLink(this.props.Document, portal, undefined, portalID); Doc.GetProto(this.props.Document).isButton = true; }) @@ -618,15 +599,14 @@ 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.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" }); + subitems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this), icon: "desktop" }); + subitems.push({ description: "Open Tab ", event: () => this.props.addDocTab(this.props.Document, this.dataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Right ", event: () => this.props.addDocTab(this.props.Document, this.dataDoc, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Alias Tab ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "inTab"), icon: "folder" }); + subitems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" }); + subitems.push({ description: "Open Fields ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group" }); cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" }); - let existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); let onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); @@ -643,7 +623,7 @@ export class DocumentView extends DocComponent(Docu }, icon: "window-restore" }); onClicks.push({ description: this.layoutDoc.ignoreClick ? "Select" : "Do Nothing", event: () => this.layoutDoc.ignoreClick = !this.layoutDoc.ignoreClick, icon: this.layoutDoc.ignoreClick ? "unlock" : "lock" }); - onClicks.push({ description: this.props.Document.isButton || this.props.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); + onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" }); onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) }); onClicks.push({ description: "Edit onClick Foreach Doc Script", icon: "edit", event: (obj: any) => { @@ -655,20 +635,20 @@ export class DocumentView extends DocComponent(Docu let existing = ContextMenu.Instance.findByDescription("Layout..."); let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; - layoutItems.push({ description: this.props.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.props.Document.lockedPosition ? "unlock" : "lock" }); + layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.Document.lockedPosition ? "unlock" : "lock" }); if (this.props.DataDoc) { layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc!), icon: "concierge-bell" }) } layoutItems.push({ description: `${this.layoutDoc.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.layoutDoc.chromeStatus = (this.layoutDoc.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); layoutItems.push({ description: `${this.layoutDoc.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" }); - layoutItems.push({ description: this.props.Document.ignoreAspect || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); + layoutItems.push({ description: this.Document.ignoreAspect || !this.Document.nativeWidth || !this.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); layoutItems.push({ description: this.layoutDoc.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.layoutDoc.lockedPosition) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); - if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) { + if (this.props.Document.detailedLayout && !this.Document.isTemplate) { layoutItems.push({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" }); } - if (this.props.Document.type !== DocumentType.COL && this.props.Document.type !== DocumentType.TEMPLATE) { + if (this.Document.type !== DocumentType.COL && this.Document.type !== DocumentType.TEMPLATE) { layoutItems.push({ description: "Use Custom Layout", event: this.makeCustomViewClicked, icon: "concierge-bell" }); } else if (this.props.Document.nativeLayout) { layoutItems.push({ description: "Use Native Layout", event: this.makeNativeViewClicked, icon: "concierge-bell" }); @@ -700,7 +680,7 @@ export class DocumentView extends DocComponent(Docu } }); - cm.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, StrCast(this.props.Document.title), this.props.addDocument, this.props.removeDocument), icon: "file" }); + cm.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.Document, this.Document.title || "", this.props.addDocument, this.props.removeDocument), icon: "file" }); cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" }); type User = { email: string, userDocumentId: string }; let usersMenu: ContextMenuProps[] = []; @@ -780,7 +760,7 @@ export class DocumentView extends DocComponent(Docu select={this.select} onClick={this.onClickHandler} layoutKey={"layout"} - fitToBox={BoolCast(this.props.Document.fitToBox) ? true : this.props.fitToBox} + fitToBox={this.Document.fitToBox ? true : this.props.fitToBox} DataDoc={this.dataDoc} />); } @@ -796,55 +776,66 @@ export class DocumentView extends DocComponent(Docu return (showTitle ? 25 : 0) + 1;// bcz: why 8?? } - get layoutDoc() { + get layoutDoc(): Document { // if this document's layout field contains a document (ie, a rendering template), then we will use that // to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string. - return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; + return Document(this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document); } - render() { - let ruleProvider = this.props.ruleProvider; - let ruleColor = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(this.props.Document.heading)]) : undefined; - let ruleRounding = ruleProvider ? StrCast(Doc.GetProto(ruleProvider)["ruleRounding_" + NumCast(this.props.Document.heading)]) : undefined; - let colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; - let clusterCol = this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground; - - let backgroundColor = this.layoutDoc.isBackground || (clusterCol && !colorSet) ? + const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined; + const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; + const colorSet = this.layoutDoc.backgroundColor !== this.layoutDoc.defaultBackgroundColor; + const clusterCol = this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground; + const backgroundColor = this.layoutDoc.isBackground || (clusterCol && !colorSet) ? this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); - let foregroundColor = StrCast(this.layoutDoc.color); - var nativeWidth = this.props.Document.willMaximize ? 0 : this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; - var nativeHeight = this.props.Document.willMaximize ? 0 : BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; - let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; - let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle); - let showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : StrCast(this.layoutDoc.showCaption); - let templates = Cast(this.layoutDoc.templates, listSpec("string")); - if (!showOverlays && templates instanceof List) { - templates.map(str => { - if (!showTitle && str.indexOf("{props.Document.title}") !== -1) showTitle = "title"; - if (!showCaption && str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption"; - }); - } - let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith(" - {StrCast(this.props.Document.search_fields)} + + const nativeWidth = this.Document.willMaximize ? 0 : this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; + const nativeHeight = this.Document.willMaximize ? 0 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; + const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; + const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.layoutDoc.showTitle; + const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.layoutDoc.showCaption; + const showTextTitle = showTitle && StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined; + const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); + const borderRounding = this.Document.borderRounding || ruleRounding; + const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree; + const searchHighlight = (!this.Document.searchFields ? (null) : +
+ {this.Document.searchFields} +
); + const captionView = (!showCaption ? (null) : +
+ +
); + const titleView = (!showTitle ? (null) : +
+ StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle])} + SetValue={(value: string) => ((this.layoutDoc.isTemplate ? this.layoutDoc : Doc.GetProto(this.layoutDoc))[showTitle] = value) ? true : true} + />
); return (
(Docu onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave} > {!showTitle && !showCaption ? - this.props.Document.search_fields ?
- {this.contents} - {searchHighlight} -
: - this.contents : -
-
+ this.Document.searchFields ? + (
+ {this.contents} + {searchHighlight} +
) + : + this.contents + : +
+
{this.contents}
- {!showTitle ? (null) : -
- StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle!])} - SetValue={(value: string) => ((this.layoutDoc.isTemplate ? this.layoutDoc : Doc.GetProto(this.layoutDoc))[showTitle!] = value) ? true : true} - /> -
- } - {!showCaption ? (null) : -
- -
- } + {titleView} + {captionView} {searchHighlight}
} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 95f304641..beccce9dd 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -376,7 +376,6 @@ export class ImageBox extends DocComponent(ImageD // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight()); // let w = bptX - sptX; - 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[] = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; @@ -402,11 +401,11 @@ export class ImageBox extends DocComponent(ImageD if (!this.props.Document.ignoreAspect && !this.props.leaveNativeSize) this.resize(srcpath, this.props.Document); return ( -
- Date: Tue, 17 Sep 2019 15:30:02 -0400 Subject: cleaning up icon animations --- .../views/collections/CollectionStackingView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 60 +++++++++------- src/client/views/nodes/DocumentView.tsx | 82 +++++++++------------- src/new_fields/Doc.ts | 10 ++- 4 files changed, 80 insertions(+), 74 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0a96676e3..14a9dc9d9 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -163,7 +163,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ; } getDocHeight(d?: Doc) { - if (!d || d.willMaximize) return 0; + if (!d) return 0; let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); if (!d.ignoreAspect && nw && nh) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 9f0bd736d..19d4a6784 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,6 +1,6 @@ -import { computed } from "mobx"; +import { computed, action, observable, reaction, IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FieldValue, NumCast, StrCast, Cast } from "../../../new_fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; @@ -8,7 +8,7 @@ import { percent2frac } from "../../../Utils" import { DocumentView, DocumentViewProps, documentSchema } from "./DocumentView"; import "./CollectionFreeFormDocumentView.scss"; import React = require("react"); -import { Doc } from "../../../new_fields/Doc"; +import { Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; import { random } from "animejs"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @@ -30,11 +30,12 @@ export const PositionDocument = makeInterface(documentSchema, positionSchema); @observer export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { + _disposer: IReactionDisposer | undefined = undefined; @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } - @computed get X() { return this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } - @computed get Y() { return this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } - @computed get width() { return this.Document.willMaximize ? 0 : this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.Document.width || 0; } - @computed get height() { return this.Document.willMaximize ? 0 : this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.Document.height || 0; } + @computed get X() { return this._animx !== undefined ? this._animx : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } + @computed get Y() { return this._animy !== undefined ? this._animy : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } + @computed get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.Document[WidthSym](); } + @computed get height() { return this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.Document[HeightSym](); } @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } @computed get scaleToOverridingWidth() { return this.width / FieldValue(this.Document.width, this.width); } @@ -54,26 +55,35 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.Document.iconTarget, + () => { + const icon = this.props.Document.iconTarget ? Array.from(Cast(this.props.Document.iconTarget, listSpec("number"))!) : undefined; + if (icon) { + let target = this.props.ScreenToLocalTransform().transformPoint(icon[0], icon[1]); + if (icon[2] === 1) { + this._animx = target[0]; + this._animy = target[1]; + } + setTimeout(action(() => { + this._animx = icon[2] === 1 ? this.Document.x : target[0]; + this._animy = icon[2] === 1 ? this.Document.y : target[1]; + }), 25); + } else { + this._animx = this._animy = undefined; + } + }, { fireImmediately: true }); + } + contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) - .scale(1 / this.contentScaling()).scale(1 / this.scaleToOverridingWidth) - - animateBetweenIcon = (icon: number[], stime: number, maximizing: boolean) => { - this.props.bringToFront(this.props.Document); - let targetPos = [this.Document.x || 0, this.Document.y || 0]; - let iconPos = this.props.ScreenToLocalTransform().transformPoint(icon[0], icon[1]); - DocumentView.animateBetweenIconFunc(this.props.Document, - this.Document.width || 0, this.Document.height || 0, stime, maximizing, (progress: number) => { - let pval = maximizing ? - [iconPos[0] + (targetPos[0] - iconPos[0]) * progress, iconPos[1] + (targetPos[1] - iconPos[1]) * progress] : - [targetPos[0] + (iconPos[0] - targetPos[0]) * progress, targetPos[1] + (iconPos[1] - targetPos[1]) * progress]; - this.Document.x = progress === 1 ? targetPos[0] : pval[0]; - this.Document.y = progress === 1 ? targetPos[1] : pval[1]; - }); - } + .scale(1 / this.contentScaling()).scale(1 / this.scaleToOverridingWidth); borderRounding = () => { let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; @@ -97,6 +107,9 @@ export class CollectionFreeFormDocumentView extends DocComponent
); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f58587066..37c38cc04 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -102,7 +102,7 @@ export interface DocumentViewProps { zoomToScale: (scale: number) => void; backgroundColor: (doc: Doc) => string | undefined; getScale: () => number; - animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; + animateBetweenIcon?: (maximize: boolean, target: number[]) => void; ChromeHeight?: () => number; } @@ -115,7 +115,6 @@ export const documentSchema = createSchema({ opacity: "number", hidden: "boolean", onClick: ScriptField, - willMaximize: "boolean", ignoreAspect: "boolean", autoHeight: "boolean", isTemplate: "boolean", @@ -148,7 +147,6 @@ export class DocumentView extends DocComponent(Docu private _hitTemplateDrag = false; private _mainCont = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; - private _animateToIconDisposer?: IReactionDisposer; public get ContentDiv() { return this._mainCont.current; } @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } @@ -161,35 +159,9 @@ export class DocumentView extends DocComponent(Docu handlers: { drop: this.drop.bind(this) } }); } - this._animateToIconDisposer = reaction(() => this.Document.isIconAnimating, (values) => - (values instanceof List) && this.animateBetweenIcon(values, values[2], values[3] ? true : false) - , { fireImmediately: true }); DocumentManager.Instance.DocumentViews.push(this); } - animateBetweenIcon = (iconPos: number[], startTime: number, maximizing: boolean) => { - this.props.animateBetweenIcon ? this.props.animateBetweenIcon(iconPos, startTime, maximizing) : - DocumentView.animateBetweenIconFunc(this.props.Document, this.Document.width || 0, this.Document.height || 0, startTime, maximizing); - } - - 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; - doc.height = progress === 1 ? height : maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress; - cb && cb(progress); - if (now < stime + 200) { - DocumentView.animateBetweenIconFunc(doc, width, height, stime, maximizing, cb); - } - else { - doc.isMinimized = !maximizing; - doc.isIconAnimating = undefined; - } - doc.willMaximize = false; - }, - 2); - } @action componentDidUpdate() { this._dropDisposer && this._dropDisposer(); @@ -201,7 +173,6 @@ export class DocumentView extends DocComponent(Docu } @action componentWillUnmount() { - this._animateToIconDisposer && this._animateToIconDisposer(); this._dropDisposer && this._dropDisposer(); DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } @@ -235,30 +206,45 @@ export class DocumentView extends DocComponent(Docu } } - static _undoBatch?: UndoManager.Batch = undefined; @action public collapseTargetsToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => { SelectionManager.DeselectAll(); if (expandedDocs) { - if (!DocumentView._undoBatch) { - DocumentView._undoBatch = UndoManager.StartBatch("iconAnimating"); - } let isMinimized: boolean | undefined; expandedDocs.map(maximizedDoc => { - let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); - if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { - if (isMinimized === undefined) { - isMinimized = BoolCast(maximizedDoc.isMinimized); + if (isMinimized === undefined) { + isMinimized = BoolCast(maximizedDoc.isMinimized); + } + let w = NumCast(maximizedDoc.width); + let h = NumCast(maximizedDoc.height); + let iconAnimating = maximizedDoc.isIconAnimating ? Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!) : undefined; + if (isMinimized || (iconAnimating && iconAnimating.length && iconAnimating[0] === 0)) { + // MAXIMIZE DOC + if (maximizedDoc.isMinimized) { + maximizedDoc.isIconAnimating = new List([0, 0]); + maximizedDoc.isMinimized = false; } - maximizedDoc.willMaximize = isMinimized; - maximizedDoc.isMinimized = false; - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); + maximizedDoc.iconTarget = new List([...scrpt, 1]); + setTimeout(() => { + maximizedDoc.isIconAnimating = new List([w, h]); + setTimeout(() => { + if (maximizedDoc.isIconAnimating && Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!)[0] !== 0) { + maximizedDoc.isIconAnimating = undefined; + } + }, 750); + }, 0); + } else { + maximizedDoc.iconTarget = new List([...scrpt, 0]); + // MINIMIZE DOC + maximizedDoc.isIconAnimating = new List([0, 0]); + setTimeout(() => { + if (maximizedDoc.isIconAnimating && Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!)[0] === 0) { + maximizedDoc.isMinimized = true; + maximizedDoc.isIconAnimating = undefined; + } + }, 750); } }); - setTimeout(() => { - DocumentView._undoBatch && DocumentView._undoBatch.end(); - DocumentView._undoBatch = undefined; - }, 500); } } @@ -791,8 +777,8 @@ export class DocumentView extends DocComponent(Docu this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) : ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc); - const nativeWidth = this.Document.willMaximize ? 0 : this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; - const nativeHeight = this.Document.willMaximize ? 0 : this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; + const nativeWidth = this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; + const nativeHeight = this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined; const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.layoutDoc.showTitle; const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.layoutDoc.showCaption; @@ -800,6 +786,7 @@ export class DocumentView extends DocComponent(Docu const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.Document.borderRounding || ruleRounding; const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree; + const iconAnimating = this.Document.isIconAnimating ? Array.from(Cast(this.Document.isIconAnimating, listSpec("number"))!) : undefined; const searchHighlight = (!this.Document.searchFields ? (null) :
{this.Document.searchFields} @@ -830,6 +817,7 @@ export class DocumentView extends DocComponent(Docu
NumCast(this[SelfProxy].width); // bcz: is this the right way to access width/height? it didn't work with : this.width - public [HeightSym] = () => NumCast(this[SelfProxy].height); + public [WidthSym] = () => { + let iconAnimating = this[SelfProxy].isIconAnimating ? Array.from(Cast(this[SelfProxy].isIconAnimating, listSpec("number"))!) : undefined; + return iconAnimating ? iconAnimating[0] : NumCast(this[SelfProxy].width); + } + public [HeightSym] = () => { + let iconAnimating = this[SelfProxy].isIconAnimating ? Array.from(Cast(this[SelfProxy].isIconAnimating, listSpec("number"))!) : undefined; + return iconAnimating ? iconAnimating[1] : NumCast(this[SelfProxy].height); + } [ToScriptString]() { return "invalid"; -- cgit v1.2.3-70-g09d2 From 3e6f24e4ac4a4b64620d8c9f614f214f8f1c7b94 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 17 Sep 2019 19:47:05 -0400 Subject: cleanup for animating document icon collapse/expand - still need to fix for docs without native dimensions. lots of lint fixes. --- src/Utils.ts | 17 ++--- src/client/documents/Documents.ts | 4 +- src/client/util/ProsemirrorExampleTransfer.ts | 4 +- src/client/util/RichTextRules.ts | 6 +- src/client/util/RichTextSchema.tsx | 14 ++-- src/client/util/TooltipTextMenu.tsx | 4 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/OverlayView.tsx | 1 + src/client/views/ScriptBox.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 ++-- src/client/views/nodes/ButtonBox.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 35 ++++------ src/client/views/nodes/DocumentView.tsx | 75 +++++++++------------- src/client/views/nodes/FormattedTextBox.tsx | 6 +- src/client/views/nodes/ImageBox.tsx | 8 +-- src/client/views/nodes/PDFBox.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- src/new_fields/Doc.ts | 12 ++-- .../authentication/models/current_user_utils.ts | 2 +- 23 files changed, 99 insertions(+), 129 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 415023ac4..65eb3cffd 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -115,28 +115,23 @@ export class Utils { // Calculate hue // No difference - if (delta == 0) - h = 0; + if (delta === 0) h = 0; // Red is max - else if (cmax == r) - h = ((g - b) / delta) % 6; + else if (cmax === r) h = ((g - b) / delta) % 6; // Green is max - else if (cmax == g) - h = (b - r) / delta + 2; + else if (cmax === g) h = (b - r) / delta + 2; // Blue is max - else - h = (r - g) / delta + 4; + else h = (r - g) / delta + 4; h = Math.round(h * 60); // Make negative hues positive behind 360° - if (h < 0) - h += 360; // Calculate lightness + if (h < 0) h += 360; // Calculate lightness l = (cmax + cmin) / 2; // Calculate saturation - s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); + s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); // Multiply l and s by 100 // s = +(s * 100).toFixed(1); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 673acfbaf..206e2c4f1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -631,8 +631,8 @@ export namespace DocUtils { LinkManager.Instance.deleteLink(link); LinkManager.Instance.addLink(link); } - }) - }) + }); + }); } } }); diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 1d2d33800..3e3d3155c 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -97,7 +97,7 @@ export default function buildKeymap>(schema: S, mapKeys?: tx2.doc.descendants((node: any, offset: any, index: any) => { if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) { let path = (tx2.doc.resolve(offset) as any).path; - let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && (c as any).type === schema.nodes.ordered_list ? 1 : 0), 0); + let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && c.type === schema.nodes.ordered_list ? 1 : 0), 0); if (node.type === schema.nodes.ordered_list) depth++; tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: node.attrs.mapStyle, bulletStyle: depth }, node.marks); } @@ -145,7 +145,7 @@ export default function buildKeymap>(schema: S, mapKeys?: marks && tx.ensureMarks(marks.filter((val: any) => val.type !== schema.marks.metadata && val.type !== schema.marks.metadataKey && val.type !== schema.marks.metadataVal)); marks && tx.setStoredMarks(marks.filter((val: any) => val.type !== schema.marks.metadata && val.type !== schema.marks.metadataKey && val.type !== schema.marks.metadataVal)); return tx; - } + }; bind("Enter", (state: EditorState, dispatch: (tx: Transaction) => void) => { var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); if (!splitListItem(schema.nodes.list_item)(state, (tx3: Transaction) => dispatch(tx3))) { diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index c727eec73..cd37ea0bb 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -20,7 +20,7 @@ export const inpRules = { /^1\.\s$/, schema.nodes.ordered_list, () => { - return ({ mapStyle: "decimal", bulletStyle: 1 }) + return ({ mapStyle: "decimal", bulletStyle: 1 }); }, (match: any, node: any) => { return node.childCount + node.attrs.order === +match[1]; @@ -33,7 +33,7 @@ export const inpRules = { schema.nodes.ordered_list, // match => { () => { - return ({ mapStyle: "alpha", bulletStyle: 1 }) + return ({ mapStyle: "alpha", bulletStyle: 1 }); // return ({ order: +match[1] }) }, (match: any, node: any) => { @@ -67,7 +67,7 @@ export const inpRules = { (Cast(FormattedTextBox.InputBoxOverlay!.props.Document, Doc) as Doc).heading = Number(match[1]); return state.tr.deleteRange(start, end); } - return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: Number(match[1]) })) + return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: Number(match[1]) })); }), new InputRule( new RegExp(/^\^\^\s$/), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index f027a4bf7..ba4b92a25 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -349,8 +349,9 @@ export const marks: { [index: string]: MarkSpec } = { let style = getComputedStyle(p); if (style.textDecoration === "underline") return null; if (p.parentElement.outerHTML.indexOf("text-decoration: underline") !== -1 && - p.parentElement.outerHTML.indexOf("text-decoration-style: dotted") !== -1) + p.parentElement.outerHTML.indexOf("text-decoration-style: dotted") !== -1) { return null; + } } return false; } @@ -371,10 +372,9 @@ export const marks: { [index: string]: MarkSpec } = { getAttrs: (p: any) => { if (typeof (p) !== "string") { let style = getComputedStyle(p); - if (style.textDecoration === "underline") - return null; - if (p.parentElement.outerHTML.indexOf("text-decoration-style:line") !== -1) + if (style.textDecoration === "underline" || p.parentElement.outerHTML.indexOf("text-decoration-style:line") !== -1) { return null; + } } return false; } @@ -633,11 +633,11 @@ export class ImageResizeView { DocumentManager.Instance.jumpToDocument(jumpToDoc, e.ctrlKey, false, document => addDocTab(document, undefined, location ? location : "inTab")); } else { DocumentManager.Instance.jumpToDocument(linkDoc, e.ctrlKey, false, document => addDocTab(document, undefined, location ? location : "inTab")); - } e.ctrlKey + } } }); } - } + }; this._handle.onpointerdown = function (e: any) { e.preventDefault(); e.stopPropagation(); @@ -776,7 +776,7 @@ export class FootnoteView { this.innerView.updateState(state); if (!tr.getMeta("fromOutside")) { - let outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1) + let outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1); for (let i = 0; i < transactions.length; i++) { let steps = transactions[i].steps; for (let j = 0; j < steps.length; j++) { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 84d045e6f..5764af282 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -523,12 +523,12 @@ export class TooltipTextMenu { tx2.doc.descendants((node: any, offset: any, index: any) => { if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) { let path = (tx2.doc.resolve(offset) as any).path; - let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && (c as any).type === schema.nodes.ordered_list ? 1 : 0), 0); + let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && c.type === schema.nodes.ordered_list ? 1 : 0), 0); if (node.type === schema.nodes.ordered_list) depth++; tx2.setNodeMarkup(offset, node.type, { mapStyle: style, bulletStyle: depth }, node.marks); } }); - }; + } //remove all node typeand apply the passed-in one to the selected text changeToNodeType = (nodeType: NodeType | undefined, view: EditorView) => { //remove oldif (nodeType) { //add new diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7829bd7f1..9a2105467 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -439,7 +439,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let heading = NumCast(dv.props.Document.heading); ruleProvider && heading && (Doc.GetProto(ruleProvider)["ruleRounding_" + heading] = `${Math.min(100, dist)}%`); usingRule = usingRule || (ruleProvider && heading ? true : false); - }) + }); !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)). map(d => d.borderRounding = `${Math.min(100, dist)}%`); e.stopPropagation(); diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index ba125d6e5..59229418d 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -166,7 +166,7 @@ export default class KeyManager { break; case "o": let target = SelectionManager.SelectedDocuments()[0]; - target && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(target) + target && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(target); break; case "r": preventDefault = false; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index da4b71e5c..15faea3cd 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -172,6 +172,7 @@ export class OverlayView extends React.Component { ChromeHeight={returnZero} isSelected={returnFalse} select={emptyFunction} + ruleProvider={undefined} layoutKey={"layout"} bringToFront={emptyFunction} addDocument={undefined} diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 8f06cf770..8ef9f3be6 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -98,7 +98,7 @@ export class ScriptBox extends React.Component { // tslint:disable-next-line: no-unnecessary-callback-wrapper let params: string[] = []; let setParams = (p: string[]) => params.splice(0, params.length, ...p); - let scriptingBox = overlayDisposer()} onSave={(text, onError) => { + let scriptingBox = { if (prewrapper) { text = prewrapper + text + (postwrapper ? postwrapper : ""); } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 548f663ec..5f4742834 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -99,7 +99,7 @@ export class CollectionView extends React.Component { subItems.push({ description: "Stacking (AutoHeight)", event: () => { this.props.Document.viewType = CollectionViewType.Stacking; - this.props.Document.autoHeight = true + this.props.Document.autoHeight = true; }, icon: "ellipsis-v" }); subItems.push({ description: "Masonry", event: () => this.props.Document.viewType = CollectionViewType.Masonry, icon: "columns" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 03ac012b4..8d392d764 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -24,9 +24,9 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss" import { ContextMenu } from "../../ContextMenu"; import { ContextMenuProps } from "../../ContextMenuItem"; import { InkingCanvas } from "../../InkingCanvas"; -import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; +import { CollectionFreeFormDocumentView, positionSchema } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps, positionSchema } from "../../nodes/DocumentView"; +import { DocumentViewProps, documentSchema } from "../../nodes/DocumentView"; import { pageSchema } from "../../nodes/ImageBox"; import { OverlayElementOptions, OverlayView } from "../../OverlayView"; import PDFMenu from "../../pdf/PDFMenu"; @@ -176,8 +176,8 @@ export namespace PivotView { } -type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof positionSchema, typeof pageSchema]>; -const PanZoomDocument = makeInterface(panZoomSchema, positionSchema, pageSchema); +type PanZoomDocument = makeInterface<[typeof panZoomSchema, typeof documentSchema, typeof positionSchema, typeof pageSchema]>; +const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSchema, pageSchema); @observer export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @@ -341,7 +341,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.bringToFront(d); }); - de.data.droppedDocuments.length == 1 && this.updateCluster(de.data.droppedDocuments[0]); + de.data.droppedDocuments.length === 1 && this.updateCluster(de.data.droppedDocuments[0]); } } else if (de.data instanceof DragManager.AnnotationDragData) { @@ -473,7 +473,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // choose a cluster color from a palette let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"]; clusterColor = colors[cluster % colors.length]; - let set = this.sets.length > cluster ? this.sets[cluster].filter(s => s.backgroundColor && (s.backgroundColor != s.defaultBackgroundColor)) : undefined; + let set = this.sets.length > cluster ? this.sets[cluster].filter(s => s.backgroundColor && (s.backgroundColor !== s.defaultBackgroundColor)) : undefined; // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document set && set.filter(s => !s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor)); set && set.filter(s => s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor)); @@ -848,7 +848,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { Doc.GetProto(this.props.Document)["ruleColor_" + NumCast(headingLayout.heading)] = headingLayout.backgroundColor; } }) - ) + ); } analyzeStrokes = async () => { diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index 68d3b8ae1..eebf6c167 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -49,7 +49,7 @@ export class ButtonBox extends DocComponent(Butt funcs.push({ description: "Clear Script Params", event: () => { let params = Cast(this.props.Document.buttonParams, listSpec("string")); - params && params.map(p => this.props.Document[p] = undefined) + params && params.map(p => this.props.Document[p] = undefined); }, icon: "trash" }); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 19d4a6784..bade3f8c1 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,10 +1,10 @@ -import { computed, action, observable, reaction, IReactionDisposer } from "mobx"; +import { computed, action, observable, reaction, IReactionDisposer, trace } from "mobx"; import { observer } from "mobx-react"; import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FieldValue, NumCast, StrCast, Cast } from "../../../new_fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; -import { percent2frac } from "../../../Utils" +import { percent2frac } from "../../../Utils"; import { DocumentView, DocumentViewProps, documentSchema } from "./DocumentView"; import "./CollectionFreeFormDocumentView.scss"; import React = require("react"); @@ -18,7 +18,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { height?: number; jitterRotation: number; } -const positionSchema = createSchema({ +export const positionSchema = createSchema({ zIndex: "number", x: "number", y: "number", @@ -32,8 +32,8 @@ export const PositionDocument = makeInterface(documentSchema, positionSchema); export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { _disposer: IReactionDisposer | undefined = undefined; @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } - @computed get X() { return this._animx !== undefined ? this._animx : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } - @computed get Y() { return this._animy !== undefined ? this._animy : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } + @computed get X() { return this._animPos !== undefined ? this._animPos[0] : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.Document.x || 0; } + @computed get Y() { return this._animPos !== undefined ? this._animPos[1] : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.Document.y || 0; } @computed get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.Document[WidthSym](); } @computed get height() { return this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.Document[HeightSym](); } @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } @@ -59,22 +59,10 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.Document.iconTarget, + this._disposer = reaction(() => [this.props.Document.animateToPos, this.props.Document.isAnimating], () => { - const icon = this.props.Document.iconTarget ? Array.from(Cast(this.props.Document.iconTarget, listSpec("number"))!) : undefined; - if (icon) { - let target = this.props.ScreenToLocalTransform().transformPoint(icon[0], icon[1]); - if (icon[2] === 1) { - this._animx = target[0]; - this._animy = target[1]; - } - setTimeout(action(() => { - this._animx = icon[2] === 1 ? this.Document.x : target[0]; - this._animy = icon[2] === 1 ? this.Document.y : target[1]; - }), 25); - } else { - this._animx = this._animy = undefined; - } + const target = this.props.Document.animateToPos ? Array.from(Cast(this.props.Document.animateToPos, listSpec("number"))!) : undefined; + this._animPos = !target ? undefined : target[2] ? [this.Document.x || 0, this.Document.y || 0] : this.props.ScreenToLocalTransform().transformPoint(target[0], target[1]); }, { fireImmediately: true }); } @@ -83,7 +71,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.scaleToOverridingWidth); + .scale(1 / this.contentScaling()).scale(1 / this.scaleToOverridingWidth) borderRounding = () => { let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; @@ -107,8 +95,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu @action public collapseTargetsToPoint = (scrpt: number[], expandedDocs: Doc[] | undefined): void => { SelectionManager.DeselectAll(); - if (expandedDocs) { - let isMinimized: boolean | undefined; - expandedDocs.map(maximizedDoc => { - if (isMinimized === undefined) { - isMinimized = BoolCast(maximizedDoc.isMinimized); + expandedDocs && expandedDocs.map(expDoc => { + if (expDoc.isMinimized || expDoc.isAnimating === "min") { // MAXIMIZE DOC + if (expDoc.isMinimized) { // docs are never actaully at the minimized location. so when we unminimize one, we have to set our overrides to make it look like it was at the minimize location + expDoc.isMinimized = false; + expDoc.animateToPos = new List([...scrpt, 0]); + expDoc.animateToDimensions = new List([0, 0]); } - let w = NumCast(maximizedDoc.width); - let h = NumCast(maximizedDoc.height); - let iconAnimating = maximizedDoc.isIconAnimating ? Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!) : undefined; - if (isMinimized || (iconAnimating && iconAnimating.length && iconAnimating[0] === 0)) { - // MAXIMIZE DOC - if (maximizedDoc.isMinimized) { - maximizedDoc.isIconAnimating = new List([0, 0]); - maximizedDoc.isMinimized = false; + setTimeout(() => { + expDoc.isAnimating = "max"; + expDoc.animateToPos = new List([0, 0, 1]); + expDoc.animateToDimensions = new List([NumCast(expDoc.width), NumCast(expDoc.height)]); + setTimeout(() => expDoc.isAnimating === "max" && (expDoc.isAnimating = expDoc.animateToPos = expDoc.animateToDimensions = undefined), 600); + }, 0); + } else { // MINIMIZE DOC + expDoc.isAnimating = "min"; + expDoc.animateToPos = new List([...scrpt, 0]); + expDoc.animateToDimensions = new List([0, 0]); + setTimeout(() => { + if (expDoc.isAnimating === "min") { + expDoc.isMinimized = true; + expDoc.isAnimating = expDoc.animateToPos = expDoc.animateToDimensions = undefined; } - maximizedDoc.iconTarget = new List([...scrpt, 1]); - setTimeout(() => { - maximizedDoc.isIconAnimating = new List([w, h]); - setTimeout(() => { - if (maximizedDoc.isIconAnimating && Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!)[0] !== 0) { - maximizedDoc.isIconAnimating = undefined; - } - }, 750); - }, 0); - } else { - maximizedDoc.iconTarget = new List([...scrpt, 0]); - // MINIMIZE DOC - maximizedDoc.isIconAnimating = new List([0, 0]); - setTimeout(() => { - if (maximizedDoc.isIconAnimating && Array.from(Cast(maximizedDoc.isIconAnimating, listSpec("number"))!)[0] === 0) { - maximizedDoc.isMinimized = true; - maximizedDoc.isIconAnimating = undefined; - } - }, 750); - } - }); - } + }, 600); + } + }); } onClick = async (e: React.MouseEvent) => { @@ -530,14 +518,14 @@ export class DocumentView extends DocComponent(Docu let portal = existingPortal instanceof Doc ? existingPortal : Docs.Create.FreeformDocument([], { width: (this.Document.width || 0) + 10, height: this.Document.height || 0, title: portalID }); DocUtils.MakeLink(this.props.Document, portal, undefined, portalID); Doc.GetProto(this.props.Document).isButton = true; - }) + }); } } @undoBatch @action toggleCustomView = (): void => { if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.DataDoc) { - Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.DataDoc) + Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.DataDoc); } else { if (this.Document.type !== DocumentType.COL && this.Document.type !== DocumentType.TEMPLATE) { this.makeCustomViewClicked(); @@ -623,7 +611,7 @@ export class DocumentView extends DocComponent(Docu let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; layoutItems.push({ description: this.Document.isBackground ? "As Foreground" : "As Background", event: this.makeBackground, icon: this.Document.lockedPosition ? "unlock" : "lock" }); if (this.props.DataDoc) { - layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc!), icon: "concierge-bell" }) + layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc!), icon: "concierge-bell" }); } layoutItems.push({ description: `${this.layoutDoc.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.layoutDoc.chromeStatus = (this.layoutDoc.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); layoutItems.push({ description: `${this.layoutDoc.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" }); @@ -786,7 +774,6 @@ export class DocumentView extends DocComponent(Docu const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.Document.borderRounding || ruleRounding; const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree; - const iconAnimating = this.Document.isIconAnimating ? Array.from(Cast(this.Document.isIconAnimating, listSpec("number"))!) : undefined; const searchHighlight = (!this.Document.searchFields ? (null) :
{this.Document.searchFields} @@ -817,7 +804,7 @@ export class DocumentView extends DocComponent(Docu
{ doc.nonCustomNativeWidth = undefined; doc.nonCustomNativeHeight = undefined; doc.nonCustomIgnoreAspect = undefined; -} +}; let makeCustomView = (doc: any): void => { doc.nativeLayout = doc.layout; doc.nativeType = doc.type; @@ -911,7 +898,7 @@ let makeCustomView = (doc: any): void => { doc.customNativeHeight = undefined; doc.customIgnoreAspect = undefined; } -} +}; Scripting.addGlobal(function toggleDetail(doc: any) { if (doc.type !== DocumentType.COL && doc.type !== DocumentType.TEMPLATE) { makeCustomView(doc); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 77e29632e..1c946aa78 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -182,9 +182,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument); if (linkDoc) { (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc; } else DocUtils.MakeLink(this.dataDoc, this.dataDoc[key] as Doc, undefined, "Ref:" + value, undefined, undefined, id, true); - }) + }); }); - }) + }); this.linkOnDeselect.clear(); } @@ -195,7 +195,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let range = tx.selection.$from.blockRange(tx.selection.$to); let text = range ? tx.doc.textBetween(range.start, range.end) : ""; let textEndSelection = tx.selection.to; - for (; textEndSelection < range!.end && text[textEndSelection - range!.start] != " "; textEndSelection++) { } + for (; textEndSelection < range!.end && text[textEndSelection - range!.start] !== " "; textEndSelection++) { } text = text.substr(0, textEndSelection - range!.start); text = text.split(" ")[text.split(" ").length - 1]; let split = text.split("::"); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index beccce9dd..42307ee02 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -23,7 +23,7 @@ import { ContextMenu } from "../../views/ContextMenu"; import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from '../DocComponent'; import { InkingControl } from '../InkingControl'; -import { positionSchema } from './DocumentView'; +import { documentSchema } from './DocumentView'; import FaceRectangles from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; @@ -50,8 +50,8 @@ declare class MediaRecorder { constructor(e: any); } -type ImageDocument = makeInterface<[typeof pageSchema, typeof positionSchema]>; -const ImageDocument = makeInterface(pageSchema, positionSchema); +type ImageDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>; +const ImageDocument = makeInterface(pageSchema, documentSchema); @observer export class ImageBox extends DocComponent(ImageDocument) { @@ -220,7 +220,7 @@ export class ImageBox extends DocComponent(ImageD let modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" }); modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" }); - !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" }) + !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: modes, icon: "hand-point-right" }); ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs, icon: "asterisk" }); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index df35b603c..31e8f122b 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -14,14 +14,14 @@ import { CompileScript } from '../../util/Scripting'; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; import { PDFViewer } from "../pdf/PDFViewer"; -import { positionSchema } from "./DocumentView"; +import { documentSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); -type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; -const PdfDocument = makeInterface(positionSchema, pageSchema); +type PdfDocument = makeInterface<[typeof documentSchema, typeof pageSchema]>; +const PdfDocument = makeInterface(documentSchema, pageSchema); export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === KeyCodes.BACKSPACE) e.stopPropagation(); }; @observer diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 96f011eff..a696f255d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -14,7 +14,7 @@ import { ContextMenuProps } from "../ContextMenuItem"; import { DocComponent } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; -import { positionSchema } from "./DocumentView"; +import { documentSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./VideoBox.scss"; @@ -25,8 +25,8 @@ import { Doc } from "../../../new_fields/Doc"; import { ScriptField } from "../../../new_fields/ScriptField"; var path = require('path'); -type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; -const VideoDocument = makeInterface(positionSchema, pageSchema); +type VideoDocument = makeInterface<[typeof documentSchema, typeof pageSchema]>; +const VideoDocument = makeInterface(documentSchema, pageSchema); library.add(faVideo); diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index eeb2531a2..34e3b0931 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -58,7 +58,7 @@ class RegionAnnotation extends React.Component { runInAction(() => this._brushed = brushed); } } - ) + ); } componentWillUnmount() { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7bc1d3507..c508935f2 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -81,7 +81,7 @@ export class PDFViewer extends React.Component { return annotations.filter(anno => { let run = this._script.run({ this: anno }); return run.success ? run.result : true; - }) + }); } @computed get nonDocAnnotations() { diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 614babd3c..0cf1208d7 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -144,12 +144,12 @@ export class Doc extends RefField { private [Self] = this; private [SelfProxy]: any; public [WidthSym] = () => { - let iconAnimating = this[SelfProxy].isIconAnimating ? Array.from(Cast(this[SelfProxy].isIconAnimating, listSpec("number"))!) : undefined; - return iconAnimating ? iconAnimating[0] : NumCast(this[SelfProxy].width); + let animDims = this[SelfProxy].animateToDimensions ? Array.from(Cast(this[SelfProxy].animateToDimensions, listSpec("number"))!) : undefined; + return animDims ? animDims[0] : NumCast(this[SelfProxy].width); } public [HeightSym] = () => { - let iconAnimating = this[SelfProxy].isIconAnimating ? Array.from(Cast(this[SelfProxy].isIconAnimating, listSpec("number"))!) : undefined; - return iconAnimating ? iconAnimating[1] : NumCast(this[SelfProxy].height); + let animDims = this[SelfProxy].animateToDimensions ? Array.from(Cast(this[SelfProxy].animateToDimensions, listSpec("number"))!) : undefined; + return animDims ? animDims[1] : NumCast(this[SelfProxy].height); } [ToScriptString]() { @@ -334,7 +334,7 @@ export namespace Doc { } export function IndexOf(toFind: Doc, list: Doc[]) { - return list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)) + return list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); } export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { if (target[key] === undefined) { @@ -419,7 +419,7 @@ export namespace Doc { export function MakeAlias(doc: Doc) { let alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc) : Doc.MakeDelegate(doc); if (alias.layout instanceof Doc) { - alias.layout = Doc.MakeAlias(alias.layout as Doc); + alias.layout = Doc.MakeAlias(alias.layout); } let aliasNumber = Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1; let script = `return renameAlias(self, ${aliasNumber})`; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index af5774ebe..8cac8550c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -59,7 +59,7 @@ export class CurrentUserUtils { noteTypes.excludeFromLibrary = true; doc.noteTypes = noteTypes; } - PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(vals => DocListCast(vals))); + PromiseValue(Cast(doc.noteTypes, Doc)).then(noteTypes => noteTypes && PromiseValue(noteTypes.data).then(DocListCast)); if (doc.recentlyClosed === undefined) { const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 }); recentlyClosed.excludeFromLibrary = true; -- cgit v1.2.3-70-g09d2 From 75e0134298242edc18be5b0460ef74c7a37aa467 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 17 Sep 2019 20:30:38 -0400 Subject: final fixes for icon animations? --- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index bade3f8c1..d05e39e2b 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -110,7 +110,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu
Date: Fri, 20 Sep 2019 15:11:30 -0400 Subject: simplified script execution api a little. fixed dataDoc() related stuff in various Box's. fixed some template stuff. --- src/client/util/Scripting.ts | 8 ++-- src/client/util/SelectionManager.ts | 4 ++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/ScriptingRepl.tsx | 20 ++++---- src/client/views/TemplateMenu.tsx | 11 ++++- .../views/collections/CollectionBaseView.tsx | 4 +- .../views/collections/CollectionSchemaCells.tsx | 10 ++-- src/client/views/collections/CollectionSubView.tsx | 40 ++++++---------- .../views/collections/CollectionTreeView.tsx | 13 +---- .../collectionFreeForm/CollectionFreeFormView.tsx | 56 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 14 ++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 29 +++++++---- src/client/views/nodes/DragBox.tsx | 8 ++-- src/client/views/nodes/FormattedTextBox.tsx | 7 ++- src/client/views/nodes/ImageBox.tsx | 6 +-- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 22 ++++----- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/pdf/PDFAnnotationLayer.scss | 6 --- src/client/views/pdf/PDFAnnotationLayer.tsx | 21 -------- src/client/views/pdf/PDFViewer.tsx | 17 ++----- src/debug/Repl.tsx | 8 +--- src/new_fields/Doc.ts | 6 +-- src/new_fields/ScriptField.ts | 5 +- 25 files changed, 136 insertions(+), 189 deletions(-) delete mode 100644 src/client/views/pdf/PDFAnnotationLayer.scss delete mode 100644 src/client/views/pdf/PDFAnnotationLayer.tsx (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx') diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 1d0916ac0..ff4451824 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -19,6 +19,7 @@ export interface ScriptSucccess { export interface ScriptError { success: false; error: any; + result: any; } export type ScriptResult = ScriptSucccess | ScriptError; @@ -27,7 +28,7 @@ export interface CompiledScript { readonly compiled: true; readonly originalScript: string; readonly options: Readonly; - run(args?: { [name: string]: any }): ScriptResult; + run(args?: { [name: string]: any }, onError?: (res: any) => void, errorVal?: any): ScriptResult; } export interface CompileError { @@ -100,7 +101,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an // let params: any[] = [Docs, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let { capturedVariables = {} } = options; - let run = (args: { [name: string]: any } = {}): ScriptResult => { + let run = (args: { [name: string]: any } = {}, onError?: (e: any) => void, errorVal?: any): ScriptResult => { let argsArray: any[] = []; for (let name of customParams) { if (name === "this") { @@ -127,7 +128,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an if (batch) { batch.end(); } - return { success: false, error }; + onError && onError(error); + return { success: false, error, result: errorVal }; } }; return { compiled: true, run, originalScript, options }; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 9efef888d..4c97a1056 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -24,6 +24,10 @@ export namespace SelectionManager { manager.SelectedDocuments.push(docView); // console.log(manager.SelectedDocuments); docView.props.whenActiveChanged(true); + } else if (!ctrlPressed && manager.SelectedDocuments.length > 1) { + manager.SelectedDocuments.map(dv => dv !== docView && dv.props.whenActiveChanged(false)); + manager.SelectedDocuments = [docView]; + FormattedTextBox.InputBoxOverlay = undefined; } } @action diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 6c29a2dc7..b482e3298 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -339,7 +339,7 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], let templates: Map = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => - templates.set(template, this.props.views.reduce((checked, doc) => checked || (doc.props.Document["show" + template.Name] ? true : false), false as boolean))); + templates.set(template, this.props.views.reduce((checked, doc) => checked || doc.getLayoutPropStr("show" + template.Name) ? true : false, false as boolean))); return (
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index e05195ca0..1eb380e0b 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -135,19 +135,17 @@ export class ScriptingRepl extends React.Component { this.commands.push({ command: this.commandString, result: script.errors }); return; } - const result = script.run({ args: this.args }); - if (!result.success) { - this.commands.push({ command: this.commandString, result: result.error.toString() }); - return; - } - this.commands.push({ command: this.commandString, result: result.result }); - this.commandsHistory.push(this.commandString); + const result = script.run({ args: this.args }, e => this.commands.push({ command: this.commandString, result: e.toString() })); + if (result.success) { + this.commands.push({ command: this.commandString, result: result.result }); + this.commandsHistory.push(this.commandString); - this.maybeScrollToBottom(); + this.maybeScrollToBottom(); - this.commandString = ""; - this.commandBuffer = ""; - this.historyIndex = -1; + this.commandString = ""; + this.commandBuffer = ""; + this.historyIndex = -1; + } break; } case "ArrowUp": { diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index bfb8168e4..e4ef8313d 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -98,7 +98,14 @@ export class TemplateMenu extends React.Component { @undoBatch @action clearTemplates = (event: React.MouseEvent) => { - Templates.TemplateList.map(template => this.props.docs.map(d => d.Document["show" + template.Name] = undefined)); + Templates.TemplateList.forEach(template => this.props.docs.forEach(d => d.Document["show" + template.Name] = undefined)); + ["backgroundColor", "borderRounding", "width", "height"].forEach(field => this.props.docs.forEach(d => { + if (d.Document.isTemplate && d.props.DataDoc) { + d.Document[field] = undefined; + } else if (d.Document["default" + field[0].toUpperCase() + field.slice(1)] !== undefined) { + d.Document[field] = Doc.GetProto(d.Document)[field] = undefined; + } + })); } @action @@ -128,7 +135,7 @@ export class TemplateMenu extends React.Component {
this.toggleTemplateActivity()}>+
    {templateMenu} - {/* */} + {}
); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 0399371ff..56d12bd84 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -79,7 +79,7 @@ export class CollectionBaseView extends React.Component { } } - @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 dataDoc() { return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? 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; } active = (): boolean => { @@ -94,7 +94,7 @@ export class CollectionBaseView extends React.Component { this.props.whenActiveChanged(isActive); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); } @action.bound addDocument(doc: Doc, allowDuplicates: boolean = false): boolean { diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 0306d415c..4dac27e60 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -238,13 +238,11 @@ export class CollectionSchemaCell extends React.Component { return this.applyToDoc(props.Document, this.props.row, this.props.col, script.run); }} OnFillDown={async (value: string) => { - let script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - if (!script.compiled) { - return; + const script = CompileScript(value, { requiredType: type, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + if (script.compiled) { + DocListCast(this.props.Document[this.props.fieldKey]). + forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, script.run)); } - const run = script.run; - const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); - val && val.forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, run)); }} />
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 804bfa2b2..774e6b1b9 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -40,6 +40,8 @@ export interface SubCollectionViewProps extends CollectionViewProps { export function CollectionSubView(schemaCtor: (doc: Doc) => T) { class CollectionSubView extends DocComponent(schemaCtor) { private dropDisposer?: DragManager.DragDropDisposer; + private _childLayoutDisposer?: IReactionDisposer; + protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer && this.dropDisposer(); if (ele) { @@ -50,8 +52,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this.createDropTarget(ele); } - _childLayoutDisposer?: IReactionDisposer; - componentDidMount() { this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], async (args) => args[1] instanceof Doc && @@ -62,35 +62,25 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { this._childLayoutDisposer && this._childLayoutDisposer(); } - @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); } + // The data field for rendeing this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. + // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through + // to its children which may be templates. + // The name of the data field comes from fieldExt if it's an extension, or fieldKey otherwise. + @computed get dataField() { + return Doc.fieldExtensionDoc(this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt)[this.props.fieldExt || this.props.fieldKey]; + } get childLayoutPairs() { return this.childDocs.map(cd => Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, cd)).filter(pair => pair.layout).map(pair => ({ layout: pair.layout!, data: pair.data! })); } - 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) - let docs = DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]); - let viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); - if (viewSpecScript) { - let script = viewSpecScript.script; - docs = docs.filter(d => { - let res = script.run({ doc: d }); - if (res.success) { - return res.result; - } - else { - console.log(res.error); - } - }); - } - return docs; - } 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(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc)); + return Cast(this.dataField, listSpec(Doc)); + } + get childDocs() { + let docs = DocListCast(this.dataField); + const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); + return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; } @action diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 08d87c7b2..e5313f68c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -425,18 +425,9 @@ class TreeView extends React.Component { preventTreeViewOpen: boolean, renderedIds: string[] ) { - let viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); + const viewSpecScript = Cast(containingCollection.viewSpecScript, ScriptField); if (viewSpecScript) { - let script = viewSpecScript.script; - docs = docs.filter(d => { - let res = script.run({ doc: d }); - if (res.success) { - return res.result; - } - else { - console.log(res.error); - } - }); + docs = docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } let ascending = Cast(containingCollection.sortAscending, "boolean", null); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7383c5551..36e62842c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -156,6 +156,7 @@ export namespace PivotView { y={pos.y} width={pos.width} height={pos.height} + transition={"transform 1s"} jitterRotation={NumCast(target.props.Document.jitterRotation)} {...target.getChildDocumentViewProps(doc)} />, @@ -183,11 +184,9 @@ const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSch export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _lastX: number = 0; private _lastY: number = 0; - private _inkKey = "ink"; // the document key used to store ink annotation strokes private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } - - get parentScaling() { + private get parentScaling() { return (this.props as any).ContentScaling && this.fitToBox && !this.isAnnotationOverlay ? (this.props as any).ContentScaling() : 1; } @@ -264,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } @computed get fieldExtensionDoc() { - return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); + return Doc.fieldExtensionDoc(this.props.DataDoc || this.props.Document, this.props.fieldKey); } intersectRect(r1: { left: number, top: number, width: number, height: number }, @@ -700,10 +699,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - getCalculatedPositions(script: ScriptField, params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, state?: any } { - const result = script.script.run(params); - return !result.success ? {} : result.result !== undefined ? result.result : - { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(params.doc.width, "number"), height: Cast(params.doc.height, "number") }; + getCalculatedPositions(params: { doc: Doc, index: number, collection: Doc, docs: Doc[], state: any }): { x?: number, y?: number, z?: number, width?: number, height?: number, transition?: string, state?: any } { + const script = this.Document.arrangeScript; + const result = script && script.script.run(params, console.log); + if (result && result.success) { + return { ...result, transition: "transform 1s" }; + } + return { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(params.doc.width, "number"), height: Cast(params.doc.height, "number") }; } viewDefsToJSX = (views: any[]) => { @@ -745,12 +747,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (this.Document.usePivotLayout) return PivotView.elements(this); let curPage = FieldValue(this.Document.curPage, -1); const initScript = this.Document.arrangeInit; - const script = this.Document.arrangeScript; let state: any = undefined; let pairs = this.childLayoutPairs; let elements: ViewDefResult[] = []; if (initScript) { - const initResult = initScript.script.run({ docs: pairs.map(pair => pair.layout), collection: this.Document }); + const initResult = initScript.script.run({ docs: pairs.map(pair => pair.layout), collection: this.Document }, console.log); if (initResult.success) { const result = initResult.result; const { state: scriptState, views } = result; @@ -760,23 +761,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } let docviews = pairs.reduce((prev, pair) => { var page = NumCast(pair.layout.page, -1); - if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { - let minim = BoolCast(pair.layout.isMinimized); - if (minim === undefined || !minim) { - const pos = script ? this.getCalculatedPositions(script, { doc: pair.layout, index: prev.length, collection: this.Document, docs: pairs.map(pair => pair.layout), state }) : - { x: Cast(pair.layout.x, "number"), y: Cast(pair.layout.y, "number"), z: Cast(pair.layout.z, "number"), width: Cast(pair.layout.width, "number"), height: Cast(pair.layout.height, "number") }; - state = pos.state === undefined ? state : pos.state; - if (pair.layout && !(pair.data instanceof Promise)) { - prev.push({ - ele: , - bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) } - }); - } - } + if (!pair.layout.isMinimized && ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1)) { + const pos = this.getCalculatedPositions({ doc: pair.layout, index: prev.length, collection: this.Document, docs: pairs.map(pair => pair.layout), state }); + state = pos.state === undefined ? state : pos.state; + prev.push({ + ele: , + bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: pos.width || 0, height: pos.height || 0 } + }); } return prev; }, elements); @@ -838,7 +833,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } analyzeStrokes = async () => { - let data = Cast(this.fieldExtensionDoc[this._inkKey], InkField); + let data = Cast(this.fieldExtensionDoc.ink, InkField); if (data) { CognitiveServices.Inking.Appliers.ConcatenateHandwriting(this.fieldExtensionDoc, ["inkAnalysis", "handwriting"], data.inkData); } @@ -932,12 +927,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } render() { + // update the actual dimensions of the collection so that they can inquired (e.g., by a minimap) this.props.Document.fitX = this.actualContentBounds && this.actualContentBounds.x; this.props.Document.fitY = this.actualContentBounds && this.actualContentBounds.y; this.props.Document.fitW = this.actualContentBounds && (this.actualContentBounds.r - this.actualContentBounds.x); this.props.Document.fitH = this.actualContentBounds && (this.actualContentBounds.b - this.actualContentBounds.y); + // if fieldExt is set, then children will be stored in the extension document for the fieldKey. + // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document + Doc.UpdateDocumentExtensionForField(this.props.DataDoc || this.props.Document, this.props.fieldKey); const easing = () => this.props.Document.panTransformType === "Ease"; - Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey); return (
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 18d0fea8c..bbea4a555 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -228,18 +228,14 @@ export class MarqueeView extends React.Component return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } - get ink() { - let container = this.props.container.props.Document; - let containerKey = this.props.container.props.fieldKey; - let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); - return Cast(extensionDoc.ink, InkField); + get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored. + let cprops = this.props.container.props; + return Cast(Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink, InkField); } set ink(value: InkField | undefined) { - let container = Doc.GetProto(this.props.container.props.Document); - let containerKey = this.props.container.props.fieldKey; - let extensionDoc = Doc.resolvedFieldDataDoc(container, containerKey, "true"); - extensionDoc.ink = value; + let cprops = this.props.container.props; + Doc.fieldExtensionDoc(cprops.Document, cprops.fieldKey).ink = value; } @undoBatch diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d05e39e2b..9685f9bca 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,6 +17,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { width?: number; height?: number; jitterRotation: number; + transition?: string; } export const positionSchema = createSchema({ zIndex: "number", @@ -98,7 +99,6 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler && this.onClickHandler.script) { - this.onClickHandler.script.run({ this: this.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }); + this.onClickHandler.script.run({ this: this.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); } else if (this.Document.isButton) { SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered. this.buttonClick(e.altKey, e.ctrlKey); @@ -569,32 +569,45 @@ export class DocumentView extends DocComponent(Docu }); } + + // the document containing the view layout information - will be the Document itself unless the Document has + // a layout field. In that case, all layout information comes from there unless overriden by Document + get layoutDoc(): Document { + return Document(this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document); + } + + // does Document set a layout prop + setsLayoutProp = (prop: string) => this.props.Document[prop] !== this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)]; + // get the a layout prop by first choosing the prop from Document, then falling back to the layout doc otherwise. + getLayoutPropStr = (prop: string) => StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]); + getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]); + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }; chromeHeight = () => { let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.Document.showTitle); - return (showTitle ? 25 : 0) + 1;// bcz: why 8?? + return (showTitle ? 25 : 0) + 1; } render() { const ruleColor = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleColor_" + this.Document.heading]) : undefined; const ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; - const colorSet = this.Document.backgroundColor !== this.Document.defaultBackgroundColor; + const colorSet = this.setsLayoutProp("backgroundColor"); const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground; const backgroundColor = this.Document.isBackground || (clusterCol && !colorSet) ? - this.props.backgroundColor(this.Document) || StrCast(this.Document.backgroundColor) : - ruleColor && !colorSet ? ruleColor : StrCast(this.Document.backgroundColor) || this.props.backgroundColor(this.Document); + this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) : + ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document); const nativeWidth = this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; const nativeHeight = this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; - const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.Document.showTitle; - const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.Document.showCaption; + const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle"); + const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption"); const showTextTitle = showTitle && StrCast(this.Document.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); - const borderRounding = this.Document.borderRounding || ruleRounding; + const borderRounding = this.getLayoutPropStr("borderRounding") || ruleRounding; const localScale = this.props.ScreenToLocalTransform().Scale * fullDegree; const searchHighlight = (!this.Document.searchFields ? (null) :
diff --git a/src/client/views/nodes/DragBox.tsx b/src/client/views/nodes/DragBox.tsx index 2d1a98df2..6c3db18c4 100644 --- a/src/client/views/nodes/DragBox.tsx +++ b/src/client/views/nodes/DragBox.tsx @@ -51,11 +51,9 @@ export class DragBox extends DocComponent(DragDocu const onDragStart = this.Document.onDragStart; e.stopPropagation(); e.preventDefault(); - let res = onDragStart ? onDragStart.script.run({ this: this.props.Document }) : undefined; - let doc = res !== undefined && res.success ? - res.result as Doc : - Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" }); - doc && DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); + let res = onDragStart && onDragStart.script.run({ this: this.props.Document }).result; + let doc = (res as Doc) || Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" }); + DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); } e.stopPropagation(); e.preventDefault(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 031929bbd..eb4718581 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -142,10 +142,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); } - - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } // this should be internal to prosemirror, but is needed // here to make sure that footnote view nodes in the overlay editor @@ -641,7 +640,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let annotations = DocListCast(region.annotations); annotations.forEach(anno => anno.target = this.props.Document); - let fieldExtDoc = Doc.resolvedFieldDataDoc(doc, "data", "true"); + let fieldExtDoc = Doc.fieldExtensionDoc(doc, "data"); let targetAnnotations = DocListCast(fieldExtDoc.annotations); if (targetAnnotations) { targetAnnotations.push(region); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 3cb64aa40..624593245 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -63,9 +63,9 @@ export class ImageBox extends DocComponent(ImageD @observable private _isOpen: boolean = false; private dropDisposer?: DragManager.DragDropDisposer; + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } - + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } protected createDropTarget = (ele: HTMLDivElement) => { if (this.dropDisposer) { @@ -81,8 +81,6 @@ export class ImageBox extends DocComponent(ImageD console.log("IMPLEMENT ME PLEASE"); } - @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "Alternates"); } - @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8fcd44f46..3a9318469 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -76,7 +76,7 @@ export class KeyValueBox extends React.Component { } else if (type === "script") { field = new ScriptField(script); } else { - let res = script.run({ this: target }); + let res = script.run({ this: target }, console.log); if (!res.success) return false; field = res.result; } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index c8534ed0d..37bf6dbb7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -31,11 +31,9 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _alt = false; @observable private _pdf: Opt; - @computed get containingCollectionDocument() { return this.props.ContainingCollectionDoc; } - @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } + @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } - - @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document); } private _mainCont: React.RefObject = React.createRef(); private _reactionDisposer?: IReactionDisposer; @@ -96,7 +94,7 @@ export class PDFBox extends DocComponent(PdfDocumen @action setPanY = (y: number) => { - this.containingCollectionDocument && (this.containingCollectionDocument.panY = y); + this.props.ContainingCollectionDoc && (this.props.ContainingCollectionDoc.panY = y); } @action @@ -113,7 +111,7 @@ export class PDFBox extends DocComponent(PdfDocumen private resetFilters = () => { this._keyValue = this._valueValue = ""; - this._scriptValue = "return true"; + this._scriptValue = ""; this._keyRef.current && (this._keyRef.current.value = ""); this._valueRef.current && (this._valueRef.current.value = ""); this._scriptRef.current && (this._scriptRef.current.value = ""); @@ -127,7 +125,7 @@ export class PDFBox extends DocComponent(PdfDocumen return !this.props.active() ? (null) : (
e.stopPropagation()}>
  • +
  • ; @@ -520,12 +521,8 @@ export class MainView extends React.Component { /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @computed get miscButtons() { - let logoutRef = React.createRef(); - return [ this.isSearchVisible ?
    : null, -
    -
    ]; } diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 0e7e0afa7..6f5abd05b 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -1,8 +1,5 @@ @import "../../views/globalCssVariables.scss"; -.collectiondockingview-content { - height: 100%; -} .lm_active .messageCounter{ color:white; background: #999999; @@ -21,7 +18,7 @@ .collectiondockingview-container { width: 100%; - height: 100%; + height:100%; border-style: solid; border-width: $COLLECTION_BORDER_WIDTH; position: absolute; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index b6bc4b4ba..b047e77a8 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -32,6 +32,7 @@ import React = require("react"); import { ButtonSelector } from './ParentDocumentSelector'; import { DocumentType } from '../../documents/DocumentTypes'; library.add(faFile); +const _global = (window /* browser */ || global /* node */) as any; @observer export class CollectionDockingView extends React.Component { @@ -534,12 +535,11 @@ interface DockedFrameProps { } @observer export class DockedFrameRenderer extends React.Component { - _mainCont: HTMLDivElement | undefined = undefined; + _mainCont: HTMLDivElement | null = null; @observable private _panelWidth = 0; @observable private _panelHeight = 0; @observable private _document: Opt; @observable private _dataDoc: Opt; - @observable private _isActive: boolean = false; get _stack(): any { @@ -577,6 +577,13 @@ export class DockedFrameRenderer extends React.Component { } componentDidMount() { + let observer = new _global.ResizeObserver(action((entries: any) => { + for (let entry of entries) { + this._panelWidth = entry.contentRect.width; + this._panelHeight = entry.contentRect.height; + } + })); + observer.observe(this.props.glContainer._element[0]); this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged); this.props.glContainer.on("tab", this.onActiveContentItemChanged); this.onActiveContentItemChanged(); @@ -595,15 +602,16 @@ export class DockedFrameRenderer extends React.Component { } } - panelWidth = () => this._document!.ignoreAspect ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth())); - panelHeight = () => this._document!.ignoreAspect ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), this.nativeHeight())); + panelWidth = () => this._document!.ignoreAspect || this._document!.fitWidth ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth())); + panelHeight = () => this._document!.ignoreAspect || this._document!.fitWidth ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), this.nativeHeight())); - nativeWidth = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0; - nativeHeight = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0; + nativeWidth = () => !this._document!.ignoreAspect && !this._document!.fitWidth ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0; + nativeHeight = () => !this._document!.ignoreAspect && !this._document!.fitWidth ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0; contentScaling = () => { if (this._document!.type === DocumentType.PDF) { - if (this._panelHeight / NumCast(this._document!.nativeHeight) > this._panelWidth / NumCast(this._document!.nativeWidth)) { + if ((this._document && this._document.fitWidth) || + this._panelHeight / NumCast(this._document!.nativeHeight) > this._panelWidth / NumCast(this._document!.nativeWidth)) { return this._panelWidth / NumCast(this._document!.nativeWidth); } else { return this._panelHeight / NumCast(this._document!.nativeHeight); @@ -639,13 +647,10 @@ export class DockedFrameRenderer extends React.Component { return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc); } } - @computed get docView() { - if (!this._document) { - return (null); - } - let resolvedDataDoc = this._document.layout instanceof Doc ? this._document : this._dataDoc; - return { getScale={returnOne} />; } - @computed get content() { - return ( -
    { - this._mainCont = ref; - if (ref) { - this._panelWidth = Number(getComputedStyle(ref).width!.replace("px", "")); - this._panelHeight = Number(getComputedStyle(ref).height!.replace("px", "")); - } - })} - style={{ transform: `translate(${this.previewPanelCenteringOffset}px, 0px)` }}> - {this.docView} -
    ); - } - render() { - if (!this._isActive || !this._document) return null; - let theContent = this.content; - return !this._document ? (null) : - { this._panelWidth = r.offset.width; this._panelHeight = r.offset.height; })}> - {({ measureRef }) =>
    - {theContent} -
    } -
    ; + return (!this._isActive || !this._document) ? (null) : + (
    this._mainCont = ref} + style={{ + transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`, + height: this._document && this._document.fitWidth ? undefined : "100%" + }}> + {this.docView(this._document)} +
    ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 721732774..4b260d111 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -401,27 +401,34 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } } SelectionManager.DeselectAll(); - const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2; - const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2; - const newState = HistoryUtil.getState(); - newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; - HistoryUtil.pushState(newState); - - let savedState = { px: this.Document.panX, py: this.Document.panY, s: this.Document.scale, pt: this.Document.panTransformType }; - - this.setPan(newPanX, newPanY); - this.Document.panTransformType = "Ease"; - this.props.focus(this.props.Document); - willZoom && this.setScaleToZoom(doc, scale); - - afterFocus && setTimeout(() => { - if (afterFocus && afterFocus()) { - this.Document.panX = savedState.px; - this.Document.panY = savedState.py; - this.Document.scale = savedState.s; - this.Document.panTransformType = savedState.pt; - } - }, 1000); + if (this.props.Document.scrollHeight) { + let annotOn = Cast(doc.annotationOn, Doc) as Doc; + let offset = annotOn && (NumCast(annotOn.height) / 2); + this.props.Document.scrollY = NumCast(doc.y) - offset; + } else { + const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2; + const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2; + const newState = HistoryUtil.getState(); + newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; + HistoryUtil.pushState(newState); + + let savedState = { px: this.Document.panX, py: this.Document.panY, s: this.Document.scale, pt: this.Document.panTransformType }; + + this.setPan(newPanX, newPanY); + this.Document.panTransformType = "Ease"; + this.props.focus(this.props.Document); + willZoom && this.setScaleToZoom(doc, scale); + + afterFocus && setTimeout(() => { + if (afterFocus && afterFocus()) { + this.Document.panX = savedState.px; + this.Document.panY = savedState.py; + this.Document.scale = savedState.s; + this.Document.panTransformType = savedState.pt; + } + }, 1000); + } + } setScaleToZoom = (doc: Doc, scale: number = 0.5) => { @@ -449,7 +456,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { PanelHeight: childLayout[HeightSym], ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, - ContainingCollectionDoc: this.props.ContainingCollectionDoc, + ContainingCollectionDoc: this.props.Document, focus: this.focusDocument, backgroundColor: this.getClusterColor, parentActive: this.props.active, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 44611869e..82193aefa 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -188,16 +188,13 @@ export class MarqueeView extends React.Component @action onPointerUp = (e: PointerEvent): void => { if (!this.props.container.props.active()) this.props.selectDocuments([this.props.container.props.Document]); - // console.log("pointer up!"); if (this._visible) { - // console.log("visible"); let mselect = this.marqueeSelect(); if (!e.shiftKey) { SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document); } this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]); } - //console.log("invisible"); this.cleanupInteractions(true); if (e.altKey) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c3d2c9e51..c4fed200f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -77,7 +77,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { let ruleRounding = this.props.ruleProvider ? StrCast(this.props.ruleProvider["ruleRounding_" + this.Document.heading]) : undefined; - let ld = this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout as Doc : undefined; + let ld = this.layoutDoc.layout instanceof Doc ? this.layoutDoc.layout : undefined; let br = StrCast((ld || this.props.Document).borderRounding); br = !br && ruleRounding ? ruleRounding : br; if (br.endsWith("%")) { @@ -100,7 +100,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.dataProvider ? this.dataProvider.width : this.panelWidth(); + finalPanelWidth = () => this.dataProvider ? this.dataProvider.width : this.panelWidth(); finalPanelHeight = () => this.dataProvider ? this.dataProvider.height : this.panelHeight(); render() { @@ -124,7 +124,7 @@ export class CollectionFreeFormDocumentView extends DocComponent
    diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6ee88f834..bd702c6a2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -223,15 +223,18 @@ export class DocumentView extends DocComponent(Docu else if (linkedDocs.length) { SelectionManager.DeselectAll(); let first = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor1 as Doc, this.props.Document) && !d.anchor1anchored); + let second = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor2 as Doc, this.props.Document) && !d.anchor2anchored); let firstUnshown = first.filter(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); + let secondUnshown = second.filter(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0); if (firstUnshown.length) first = [firstUnshown[0]]; - let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : [expandedDocs[0], expandedDocs[0]]; + if (secondUnshown.length) second = [secondUnshown[0]]; + let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : second.length ? [second[0].anchor1 as Doc, second[0].anchor1 as Doc] : undefined; // @TODO: shouldn't always follow target context let linkedFwdContextDocs = [first.length ? await (first[0].targetContext) as Doc : undefined, undefined]; let linkedFwdPage = [first.length ? NumCast(first[0].anchor2Page, undefined) : undefined, undefined]; - if (!linkedFwdDocs.some(l => l instanceof Promise)) { + if (linkedFwdDocs && !linkedFwdDocs.some(l => l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab"); let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionDoc) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined; DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, @@ -601,7 +604,7 @@ export class DocumentView extends DocComponent(Docu ruleColor && !colorSet ? ruleColor : StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document); const nativeWidth = this.nativeWidth > 0 && !this.Document.ignoreAspect ? `${this.nativeWidth}px` : "100%"; - const nativeHeight = this.Document.ignoreAspect ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : nativeWidth !== "100%" ? nativeWidth : "100%"; + const nativeHeight = this.Document.ignoreAspect || this.props.Document.fitWidth ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : nativeWidth !== "100%" ? nativeWidth : "100%"; const showOverlays = this.props.showOverlays ? this.props.showOverlays(this.Document) : undefined; const showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : this.getLayoutPropStr("showTitle"); const showCaption = showOverlays && "caption" in showOverlays ? showOverlays.caption : this.getLayoutPropStr("showCaption"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 923dd1544..565fb0505 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -815,6 +815,40 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); } + let ctrlKey = e.ctrlKey; + if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { + e.preventDefault(); + } + } + + onPointerUp = (e: React.PointerEvent): void => { + FormattedTextBoxComment.textBox = this; + if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { + e.stopPropagation(); + } + } + + @action + onFocused = (e: React.FocusEvent): void => { + document.removeEventListener("keypress", this.recordKeyHandler); + document.addEventListener("keypress", this.recordKeyHandler); + this.tryUpdateHeight(); + if (!this.props.isOverlay) { + FormattedTextBox.InputBoxOverlay = this; + } else { + if (this._ref.current) { + this._ref.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; + } + } + } + onPointerWheel = (e: React.WheelEvent): void => { + // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time + if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { + e.stopPropagation(); + } + } + + onClick = (e: React.MouseEvent): void => { let ctrlKey = e.ctrlKey; if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) { let href = (e.target as any).href; @@ -829,8 +863,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); if (node) { let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link); - href = link && link.attrs.href; - location = link && link.attrs.location; + if (link && !(link.attrs.docref && link.attrs.title)) { // bcz: getting hacky. this indicates that we clicked on a PDF excerpt quotation. In this case, we don't want to follow the link (we follow only the actual hyperlink for the quotation which is handled above). + href = link && link.attrs.href; + location = link && link.attrs.location; + } } if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { @@ -848,7 +884,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return; } } - if (targetContext) { + if (targetContext && (!jumpToDoc || targetContext !== await jumpToDoc.annotationOn)) { DocumentManager.Instance.jumpToDocument(targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); } else if (jumpToDoc) { DocumentManager.Instance.jumpToDocument(jumpToDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); @@ -870,39 +906,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { - e.preventDefault(); - } - } - - onPointerUp = (e: React.PointerEvent): void => { - FormattedTextBoxComment.textBox = this; - if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { - e.stopPropagation(); - } - } - - @action - onFocused = (e: React.FocusEvent): void => { - document.removeEventListener("keypress", this.recordKeyHandler); - document.addEventListener("keypress", this.recordKeyHandler); - this.tryUpdateHeight(); - if (!this.props.isOverlay) { - FormattedTextBox.InputBoxOverlay = this; - } else { - if (this._ref.current) { - this._ref.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; - } - } - } - onPointerWheel = (e: React.WheelEvent): void => { - // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time - if (this.props.isSelected() || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { - e.stopPropagation(); - } - } - - onClick = (e: React.MouseEvent): void => { // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. if (this.props.isSelected() && e.nativeEvent.offsetX < 40) { let pos = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 624593245..004f50590 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -38,6 +38,7 @@ library.add(faFileAudio, faAsterisk); export const pageSchema = createSchema({ curPage: "number", + fitWidth: "boolean" }); interface Window { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 0fcbaaa7c..fe71e76fd 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -20,6 +20,9 @@ import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); import { undoBatch } from '../../util/UndoManager'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { ContextMenu } from '../ContextMenu'; +import { Utils } from '../../../Utils'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -58,7 +61,7 @@ export class PDFBox extends DocComponent(PdfDocumen this.Document.nativeWidth = nw * 96 / 72; this.Document.nativeHeight = this.Document.nativeHeight ? nw * 96 / 72 * oldaspect : nh * 96 / 72; } - this.Document.height = this.Document[WidthSym]() * (nh / nw); + !this.Document.fitWidth && !this.Document.ignoreAspect && (this.Document.height = this.Document[WidthSym]() * (nh / nw)); } public search(string: string, fwd: boolean) { this._pdfViewer && this._pdfViewer.search(string, fwd); } @@ -165,14 +168,23 @@ export class PDFBox extends DocComponent(PdfDocumen
    ); } + specificContextMenu = (e: React.MouseEvent): void => { + const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); + let funcs: ContextMenuProps[] = []; + pdfUrl && funcs.push({ description: "Copy path", event: () => Utils.CopyText(pdfUrl.url.pathname), icon: "expand-arrows-alt" }); + funcs.push({ description: "Toggle Fit Width " + (this.Document.fitWidth ? "Off" : "On"), event: () => this.Document.fitWidth = !this.Document.fitWidth, icon: "expand-arrows-alt" }); + + ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); + } + render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); let classname = "pdfBox-cont" + (InkingControl.Instance.selectedTool || !this.active ? "" : "-interactive"); return (!(pdfUrl instanceof PdfField) || !this._pdf ?
    {`pdf, ${this.dataDoc[this.props.fieldKey]}, not found`}
    : -
    { +
    { let hit = document.elementFromPoint(e.clientX, e.clientY); - if (hit && hit.localName === "span" && this.props.isSelected()) { + if (hit && hit.localName === "span" && this.props.isSelected()) { // drag selecting text stops propagation e.button === 0 && e.stopPropagation(); } }}> @@ -182,7 +194,7 @@ export class PDFBox extends DocComponent(PdfDocumen Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling} addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} pinToPres={this.props.pinToPres} addDocument={this.props.addDocument} - ScreenToLocalTransform={this.props.ScreenToLocalTransform} + ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select} isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged} fieldKey={this.props.fieldKey} fieldExtensionDoc={this.extensionDoc} /> {this.settingsPanel()} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 5ad4ffd48..13fd8ea98 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -9,14 +9,12 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, returnOne, Utils } from "../../../Utils"; +import smoothScroll, { Utils, emptyFunction, returnOne } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { CompiledScript, CompileScript } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; -import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; -import Annotation from "./Annotation"; import PDFMenu from "./PDFMenu"; import "./PDFViewer.scss"; import React = require("react"); @@ -24,7 +22,8 @@ import * as rp from "request-promise"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; -import { SelectionManager } from "../../util/SelectionManager"; +import Annotation from "./Annotation"; +import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer"); const pdfjsLib = require("pdfjs-dist"); @@ -41,6 +40,7 @@ interface IViewerProps { PanelWidth: () => number; PanelHeight: () => number; ContentScaling: () => number; + select: (isCtrlPressed: boolean) => void; renderDepth: number; isSelected: () => boolean; loaded: (nw: number, nh: number, np: number) => void; @@ -106,11 +106,20 @@ export class PDFViewer extends React.Component { // file address of the pdf this._coverPath = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/".length, this.props.url.length - ".pdf".length)}-${NumCast(this.props.Document.curPage, 1)}.PNG`))); runInAction(() => this._showWaiting = this._showCover = true); - this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => { - this.setupPdfJsViewer(); - this._selectionReactionDisposer && this._selectionReactionDisposer(); - this._selectionReactionDisposer = undefined; - }) + this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => this.setupPdfJsViewer()); + this._reactionDisposer = reaction( + () => this.props.Document.scrollY, + (scrollY) => { + if (scrollY !== undefined) { + if (this._showCover || this._showWaiting) { + this.setupPdfJsViewer(); + } + this._mainCont.current && smoothScroll(1000, this._mainCont.current, NumCast(this.props.Document.scrollY) || 0); + this.props.Document.scrollY = undefined; + } + }, + { fireImmediately: true } + ); } componentWillUnmount = () => { @@ -153,12 +162,14 @@ export class PDFViewer extends React.Component { i === this.props.pdf.numPages - 1 && this.props.loaded((page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]), (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]), i); })))); - Doc.GetProto(this.props.Document).scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0); + Doc.GetProto(this.props.Document).scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72; } } @action setupPdfJsViewer = async () => { + this._selectionReactionDisposer && this._selectionReactionDisposer(); + this._selectionReactionDisposer = undefined; this._showWaiting = true; this.props.setPdfViewer(this); await this.initialLoad(); @@ -180,10 +191,6 @@ export class PDFViewer extends React.Component { }), { fireImmediately: true } ); - this._reactionDisposer = reaction( - () => this.props.Document.panY, - () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.props.Document.panY) || 0, behavior: "auto" }) - ); document.removeEventListener("copy", this.copy); document.addEventListener("copy", this.copy); @@ -228,10 +235,9 @@ export class PDFViewer extends React.Component { annoDocs.push(annoDoc); annoDoc.isButton = true; anno.remove(); - // this.props.addDocument && this.props.addDocument(annoDoc, false); mainAnnoDoc = annoDoc; + mainAnnoDocProto = Doc.GetProto(mainAnnoDoc); mainAnnoDocProto.y = annoDoc.y; - mainAnnoDocProto = Doc.GetProto(annoDoc); } else { this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => value.map(anno => { let annoDoc = new Doc(); @@ -381,7 +387,7 @@ export class PDFViewer extends React.Component { this._downX = e.clientX; this._downY = e.clientY; if (NumCast(this.props.Document.scale, 1) !== 1) return; - if (e.button !== 0 && this.active()) { + if ((e.button !== 0 || e.altKey) && this.active()) { this._setPreviewCursor && this._setPreviewCursor(e.clientX, e.clientY, true); } this._marqueeing = false; @@ -638,18 +644,15 @@ export class PDFViewer extends React.Component { } @computed get annotationLayer() { - trace(); return
    {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) => )}
    ; } @computed get pdfViewerDiv() { - trace(); return
    ; } @computed get standinViews() { - trace(); return <> {this._showCover ? this.getCoverImage() : (null)} {this._showWaiting ? : (null)} @@ -710,7 +713,7 @@ class PdfViewerMarquee extends React.Component { width: `${this.props.width()}px`, height: `${this.props.height()}px`, border: `${this.props.width() === 0 ? "" : "2px dashed black"}` }}> -
    +
    ; } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 1b3c8b0b0..79b73aba8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -344,7 +344,7 @@ export namespace Doc { let list = Cast(target[key], listSpec(Doc)); if (list) { if (allowDuplicates !== true) { - let pind = list.reduce((l, d, i) => d instanceof Doc && Doc.AreProtosEqual(d, doc) ? i : l, -1); + let pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1); if (pind !== -1) { list.splice(pind, 1); } -- cgit v1.2.3-70-g09d2