From 8790670f8e2173dd2a578500b3f03ad08ef793f2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 30 Sep 2019 20:56:10 -0400 Subject: switching presentatons to be colllections --- src/client/views/collections/CollectionTreeView.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index e5313f68c..a133e2c51 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,12 +1,13 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt, faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'; +import { faAngleRight, faArrowsAltH, faBell, faCamera, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faExpand, faMinus, faPlus, faTrash, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable, trace, untracked } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, WidthSym, Opt, Field } from '../../../new_fields/Doc'; +import { Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { Document, listSpec } from '../../../new_fields/Schema'; +import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types'; import { emptyFunction, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -17,18 +18,16 @@ import { SelectionManager } from '../../util/SelectionManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; +import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; +import { KeyValueBox } from '../nodes/KeyValueBox'; import { Templates } from '../Templates'; import { CollectionViewType } from './CollectionBaseView'; -import { CollectionDockingView } from './CollectionDockingView'; import { CollectionSchemaPreview } from './CollectionSchemaView'; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); -import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; -import { KeyValueBox } from '../nodes/KeyValueBox'; -import { ContextMenuProps } from '../ContextMenuItem'; export interface TreeViewProps { @@ -250,8 +249,8 @@ class TreeView extends React.Component { } docWidth = () => { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); - if (aspect) return Math.min(this.props.document[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 5)); - return NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5; + if (aspect) return Math.min(this.props.document[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20)); + return NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20; } docHeight = () => { let bounds = this.boundsOfCollectionDocument; @@ -331,6 +330,7 @@ class TreeView extends React.Component { width={this.docWidth} height={this.docHeight} getTransform={this.docTransform} + CollectionDoc={this.props.containingCollection} CollectionView={undefined} addDocument={emptyFunction as any} moveDocument={this.props.moveDocument} -- cgit v1.2.3-70-g09d2 From 2a393bd745667fa920d105bf69827c75dc687f08 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 1 Oct 2019 01:33:57 -0400 Subject: final updates to presentation view to improve layout. fixes for chromeHeight --- .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 6 ++-- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 19 +++++++---- .../views/collections/CollectionViewChromes.tsx | 3 +- src/client/views/nodes/PresBox.tsx | 10 ++++-- .../views/presentationview/PresElementBox.scss | 14 ++++++-- .../views/presentationview/PresElementBox.tsx | 38 ++++++++++------------ 8 files changed, 52 insertions(+), 42 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index d83530d4f..246546c9e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -573,7 +573,7 @@ export class DockedFrameRenderer extends React.Component { //add this new doc to props.Document let curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; if (curPres) { - let pinDoc = Docs.Create.PresElementBoxDocument(); + let pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); Doc.GetProto(pinDoc).target = doc; Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.target instanceof Doc) && this.target.title.toString()'); const data = Cast(curPres.data, listSpec(Doc)); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cb272ef1c..c7060f110 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -203,9 +203,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { - // bcz: this is here for now to account for the presentation stacking view being offset from the document top in PresBox's. Should generalize this somehow. - let offsethack = Number(this._masonryGridRef && this._masonryGridRef.parentElement!.parentElement!.offsetTop); - let where = [de.x, de.y - offsethack]; + let where = [de.x, de.y]; let targInd = -1; let plusOne = false; if (de.data instanceof DragManager.DocumentDragData) { @@ -285,7 +283,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); return this.props.ScreenToLocalTransform(). - translate(offset[0], offset[1]). + translate(offset[0], offset[1] + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)). scale(NumCast(doc.width, 1) / this.columnWidth); } masonryChildren(docs: Doc[]) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a133e2c51..6ce5d8e20 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -81,7 +81,7 @@ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); - get defaultExpandedView() { return this.childDocs ? this.fieldKey : "fields"; } + get defaultExpandedView() { return this.childDocs ? this.fieldKey : this.props.document.defaultExpandedView ? StrCast(this.props.document.defaultExpandedView) : ""; } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state @computed get treeViewOpen() { return (BoolCast(this.props.document.treeViewOpen) && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = c; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 6eb444dde..534246326 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -50,20 +50,25 @@ export class CollectionView extends React.Component { this._reactionDisposer && this._reactionDisposer(); } + // bcz: Argh? What's the height of the collection chomes?? + chromeHeight = () => { + return (this.props.ChromeHeight ? this.props.ChromeHeight() : 0) + (this.props.Document.chromeStatus === "enabled" ? -60 : 0); + } + private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (this.isAnnotationOverlay ? CollectionViewType.Freeform : type) { - case CollectionViewType.Schema: return (); + case CollectionViewType.Schema: return (); // currently cant think of a reason for collection docking view to have a chrome. mind may change if we ever have nested docking views -syip - case CollectionViewType.Docking: return (); - case CollectionViewType.Tree: return (); - case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } - case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } - case CollectionViewType.Pivot: { this.props.Document.freeformLayoutEngine = "pivot"; return (); } + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); + case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (); } + case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (); } + case CollectionViewType.Pivot: { this.props.Document.freeformLayoutEngine = "pivot"; return (); } case CollectionViewType.Freeform: default: this.props.Document.freeformLayoutEngine = undefined; - return (); + return (); } return (null); } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 47b300efc..23001f0f5 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -10,7 +10,6 @@ import { ScriptField } from "../../../new_fields/ScriptField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Utils, emptyFunction } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; -import { CompileScript } from "../../util/Scripting"; import { undoBatch } from "../../util/UndoManager"; import { EditableView } from "../EditableView"; import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss"; @@ -375,7 +374,7 @@ export class CollectionViewBaseChrome extends React.Component +
{this.props.Document.minimizedView ? (null) :
- +
}
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index 51f2d2ab8..34c170be2 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -1,10 +1,12 @@ .presElementBox-item { padding: 10px; display: inline-block; + background-color: #eeeeee; pointer-events: all; width: 100%; outline-color: maroon; outline-style: dashed; + border-radius: 12px; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; @@ -40,9 +42,10 @@ box-shadow: black 2px 2px 5px; } - -.presElementBox-icon { +.presElementBox-closeIcon { float: right; + border-radius: 20px; + transform:scale(0.7); } .presElementBox-interaction { @@ -57,12 +60,17 @@ .presElementBox-name { font-size: 15px; + position: absolute; display: inline-block; + width: calc(100% - 45px); + text-overflow: ellipsis; + overflow: hidden; + white-space: pre; } .presElementBox-embedded { position: relative; - margin-top: 15; + margin-top: 30; } .presElementBox-embeddedMask { diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 0e3d8bb7f..fb9474cde 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -31,7 +31,6 @@ library.add(faArrowDown); export class PresElementBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(PresElementBox); } - private _embedHeight = 100; @computed get myIndex() { return DocListCast(this.presentationDoc[this.presentationFieldKey]).indexOf(this.props.Document); } @computed get presentationDoc() { return this.props.Document.presBox as Doc; } @@ -43,9 +42,9 @@ export class PresElementBox extends React.Component { @computed get fadeButton() { return BoolCast(this.props.Document.fadeButton); } @computed get hideAfterButton() { return BoolCast(this.props.Document.hideAfterButton); } @computed get groupButton() { return BoolCast(this.props.Document.groupButton); } - @computed get embedInline() { return BoolCast(this.props.Document.embedOpen); } + @computed get embedOpen() { return BoolCast(this.props.Document.embedOpen); } - set embedInline(value: boolean) { this.props.Document.embedOpen = value; } + set embedOpen(value: boolean) { this.props.Document.embedOpen = value; } set showButton(val: boolean) { this.props.Document.showButton = val; } set navButton(val: boolean) { this.props.Document.navButton = val; } set hideTillShownButton(val: boolean) { this.props.Document.hideTillShownButton = val; } @@ -162,7 +161,7 @@ export class PresElementBox extends React.Component { * presentation element. */ renderEmbeddedInline = () => { - if (!this.embedInline || !(this.props.Document.target instanceof Doc)) { + if (!this.embedOpen || !(this.props.Document.target instanceof Doc)) { return (null); } @@ -171,7 +170,7 @@ export class PresElementBox extends React.Component { let scale = () => 175 / NumCast(this.props.Document.nativeWidth, 175); return (
{ let treecontainer = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.viewType === CollectionViewType.Tree; let className = "presElementBox-item" + (this.currentIndex === this.myIndex ? " presElementBox-selected" : ""); + let pbi = "presElementBox-interaction"; return (
p.focus(p.Document)}> + style={{ outlineWidth: Doc.IsBrushed(p.Document.target as Doc) ? `1px` : "0px", }} + onClick={e => { p.focus(p.Document); e.stopPropagation(); }}> {treecontainer ? (null) : <> {`${this.myIndex + 1}. ${p.Document.title}`} - +
} - - - - - - - - -
+ + + + + + + + +
{this.renderEmbeddedInline()}
); -- cgit v1.2.3-70-g09d2 From 9e1234abe64d289927122ad641e3bcaf0b9eaf6e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 1 Oct 2019 02:54:03 -0400 Subject: bugs, bugs. this time with fittobox when called from schema view which was passing width and height as functions, not values. switched to PanelWidth and PanelHeight --- .../views/collections/CollectionSchemaView.tsx | 32 +++++++++++----------- .../views/collections/CollectionStackingView.tsx | 4 +-- .../views/collections/CollectionTreeView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +-- src/client/views/nodes/PresBox.tsx | 4 +-- .../views/presentationview/PresElementBox.tsx | 22 ++++++--------- 6 files changed, 33 insertions(+), 37 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 77d86b2fa..59cce7386 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -163,8 +163,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { childDocs={this.childDocs} renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} - width={this.previewWidth} - height={this.previewHeight} + PanelWidth={this.previewWidth} + PanelHeight={this.previewHeight} getTransform={this.getPreviewTransform} CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document} CollectionView={this.props.CollectionView} @@ -904,8 +904,8 @@ interface CollectionSchemaPreviewProps { childDocs?: Doc[]; renderDepth: number; fitToBox?: boolean; - width: () => number; - height: () => number; + PanelWidth: () => number; + PanelHeight: () => number; ruleProvider: Doc | undefined; focus?: (doc: Doc) => void; showOverlays?: (doc: Doc) => { title?: string, caption?: string }; @@ -928,12 +928,12 @@ interface CollectionSchemaPreviewProps { export class CollectionSchemaPreview extends React.Component{ private dropDisposer?: DragManager.DragDropDisposer; _mainCont?: HTMLDivElement; - private get nativeWidth() { return NumCast(this.props.Document!.nativeWidth, this.props.width()); } - private get nativeHeight() { return NumCast(this.props.Document!.nativeHeight, this.props.height()); } + private get nativeWidth() { return NumCast(this.props.Document!.nativeWidth, this.props.PanelWidth()); } + private get nativeHeight() { return NumCast(this.props.Document!.nativeHeight, this.props.PanelHeight()); } private contentScaling = () => { - let wscale = this.props.width() / (this.nativeWidth ? this.nativeWidth : this.props.width()); - if (wscale * this.nativeHeight > this.props.height()) { - return this.props.height() / (this.nativeHeight ? this.nativeHeight : this.props.height()); + let wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth()); + if (wscale * this.nativeHeight > this.props.PanelHeight()) { + return this.props.PanelHeight() / (this.nativeHeight ? this.nativeHeight : this.props.PanelHeight()); } return wscale; } @@ -962,10 +962,10 @@ export class CollectionSchemaPreview extends React.Component this.nativeWidth ? this.nativeWidth * this.contentScaling() : this.props.width(); - private PanelHeight = () => this.nativeHeight ? this.nativeHeight * this.contentScaling() : this.props.height(); + private PanelWidth = () => this.nativeWidth ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); + private PanelHeight = () => this.nativeHeight ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling()); - get centeringOffset() { return this.nativeWidth ? (this.props.width() - this.nativeWidth * this.contentScaling()) / 2 : 0; } + get centeringOffset() { return this.nativeWidth ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; } @action onPreviewScriptChange = (e: React.ChangeEvent) => { this.props.setPreviewScript(e.currentTarget.value); @@ -987,15 +987,15 @@ export class CollectionSchemaPreview extends React.Component
; return (
- {!this.props.Document || !this.props.width ? (null) : ( + style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}> + {!this.props.Document || !this.props.PanelWidth ? (null) : (
doc) { ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} fitToBox={this.props.fitToBox} onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler} - width={width} - height={height} + PanelWidth={width} + PanelHeight={height} getTransform={finalDxf} focus={this.props.focus} CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 6ce5d8e20..ffd1f9170 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -327,8 +327,8 @@ class TreeView extends React.Component { showOverlays={this.noOverlays} ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider} fitToBox={this.boundsOfCollectionDocument !== undefined} - width={this.docWidth} - height={this.docHeight} + PanelWidth={this.docWidth} + PanelHeight={this.docHeight} getTransform={this.docTransform} CollectionDoc={this.props.containingCollection} CollectionView={undefined} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6fc809f7f..27b9a06f5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -745,8 +745,8 @@ class CollectionFreeFormViewPannableContents extends React.Component otherwise, reactions won't fire - return
+ const zoom = this.props.zoomScaling(); + return
{this.props.children}
; } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 66608fb8d..f44ca99b9 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -47,7 +47,7 @@ export class PresBox extends React.Component { Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.target instanceof Doc) && this.target.title.toString()'); value.splice(i, 1, pinDoc); } - }) + }); } }); } @@ -343,7 +343,7 @@ export class PresBox extends React.Component { doc.presBox = this.props.Document; doc.presBoxKey = this.props.fieldKey; doc.collapsedHeight = hgt; - doc.height = ComputedField.MakeFunction("this.collapsedHeight + Number(this.embedOpen ? 100:0)") + doc.height = ComputedField.MakeFunction("this.collapsedHeight + Number(this.embedOpen ? 100:0)"); let curScale = NumCast(doc.viewScale, null); if (curScale === undefined) { doc.viewScale = 1; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index fb9474cde..de3242d32 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -15,6 +15,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import "./PresElementBox.scss"; import React = require("react"); +import { CollectionSchemaPreview } from '../collections/CollectionSchemaView'; library.add(faArrowUp); @@ -173,28 +174,23 @@ export class PresElementBox extends React.Component { height: propDocHeight === 0 ? NumCast(this.props.Document.height) - NumCast(this.props.Document.collapsedHeight) : propDocHeight * scale(), width: propDocWidth === 0 ? "auto" : propDocWidth * scale(), }}> - this.props.PanelWidth() - 20} + PanelHeight={() => 100} + setPreviewScript={emptyFunction} + getTransform={Transform.Identity} + active={this.props.active} + moveDocument={this.props.moveDocument!} renderDepth={1} - PanelWidth={() => 350} - PanelHeight={() => 90} focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnFalse} whenActiveChanged={returnFalse} - bringToFront={emptyFunction} - zoomToScale={emptyFunction} - getScale={returnOne} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - ContentScaling={scale} />
-- cgit v1.2.3-70-g09d2 From 9427474b473d70974784a1517a1be902fb8d18ee Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 2 Oct 2019 18:26:55 -0400 Subject: many fixes to pdfs, linking, annotations, presentations. --- src/client/documents/Documents.ts | 24 ++-- src/client/util/DocumentManager.ts | 125 +++++++++++---------- src/client/util/RichTextSchema.tsx | 9 +- src/client/util/SharingManager.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 9 +- .../views/collections/CollectionDockingView.tsx | 10 +- src/client/views/collections/CollectionSubView.tsx | 1 + .../views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 10 +- src/client/views/linking/LinkFollowBox.tsx | 11 +- src/client/views/nodes/DocumentView.tsx | 44 ++------ src/client/views/nodes/FormattedTextBox.tsx | 79 ++++++------- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/PDFBox.tsx | 17 ++- src/client/views/nodes/PresBox.tsx | 24 ++-- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/pdf/Annotation.tsx | 17 ++- src/client/views/pdf/PDFMenu.tsx | 6 +- src/client/views/pdf/PDFViewer.tsx | 72 +++++------- .../views/presentationview/PresElementBox.tsx | 32 +++--- src/new_fields/Doc.ts | 2 + 21 files changed, 224 insertions(+), 276 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4d9698532..2d323ea4b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -653,32 +653,30 @@ export namespace DocUtils { } }); } - export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", sourceContext?: Doc, id?: string, anchored1?: boolean) { - let sv = DocumentManager.Instance.getDocumentView(source); - if (sv && sv.props.ContainingCollectionDoc === target) return; - if (target === CurrentUserUtils.UserDocument) return undefined; + export function MakeLink(source: {doc:Doc,ctx?:Doc}, target: {doc:Doc,ctx?:Doc}, title: string = "", description: string = "", id?: string, anchored1?: boolean) { + let sv = DocumentManager.Instance.getDocumentView(source.doc); + if (sv && sv.props.ContainingCollectionDoc === target.doc) return; + if (target.doc === CurrentUserUtils.UserDocument) return undefined; let linkDocProto = new Doc(id, true); UndoManager.RunInBatch(() => { linkDocProto.type = DocumentType.LINK; - linkDocProto.targetContext = targetContext; - linkDocProto.sourceContext = sourceContext; - linkDocProto.title = title === "" ? source.title + " to " + target.title : title; + linkDocProto.targetContext = target.ctx; + linkDocProto.sourceContext = source.ctx; + linkDocProto.title = title === "" ? source.doc.title + " to " + target.doc.title : title; linkDocProto.linkDescription = description; - linkDocProto.anchor1 = source; - linkDocProto.anchor1Page = source.curPage; + linkDocProto.anchor1 = source.doc; linkDocProto.anchor1Groups = new List([]); linkDocProto.anchor1anchored = anchored1; - linkDocProto.anchor2 = target; - linkDocProto.anchor2Page = target.curPage; + linkDocProto.anchor2 = target.doc; linkDocProto.anchor2Groups = new List([]); LinkManager.Instance.addLink(linkDocProto); - Doc.GetProto(source).links = ComputedField.MakeFunction("links(this)"); - Doc.GetProto(target).links = ComputedField.MakeFunction("links(this)"); + Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(this)"); + Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(this)"); }, "make link"); return linkDocProto; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 4e6968f08..4ebcdf83c 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,7 +1,7 @@ import { action, computed, observable } from 'mobx'; import { Doc, DocListCastAsync } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; -import { Cast, NumCast } from '../../new_fields/Types'; +import { Cast, NumCast, StrCast } from '../../new_fields/Types'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionPDFView } from '../views/collections/CollectionPDFView'; import { CollectionVideoView } from '../views/collections/CollectionVideoView'; @@ -56,9 +56,9 @@ export class DocumentManager { return this.getDocumentViewsById(doc[Id]); } - public getDocumentViewById(id: string, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { + public getDocumentViewById(id: string, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | undefined { - let toReturn: DocumentView | null = null; + let toReturn: DocumentView | undefined; let passes = preferredCollection ? [preferredCollection, undefined] : [undefined]; for (let pass of passes) { @@ -81,10 +81,14 @@ export class DocumentManager { return toReturn; } - public getDocumentView(toFind: Doc, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | null { + public getDocumentView(toFind: Doc, preferredCollection?: CollectionView | CollectionPDFView | CollectionVideoView): DocumentView | undefined { return this.getDocumentViewById(toFind[Id], preferredCollection); } + public getFirstDocumentView(toFind: Doc): DocumentView | undefined { + const views = this.getDocumentViews(toFind); + return views.length ? views[0] : undefined; + } public getDocumentViews(toFind: Doc): DocumentView[] { let toReturn: DocumentView[] = []; @@ -127,72 +131,70 @@ export class DocumentManager { return pairs; } - - @undoBatch - public jumpToDocument = async (docDelegate: Doc, willZoom: boolean, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number, docContext?: Doc): Promise => { - let doc = Doc.GetProto(docDelegate); - const contextDoc = await Cast(doc.annotationOn, Doc); - if (contextDoc) { - contextDoc.scrollY = NumCast(doc.y) - NumCast(contextDoc.height) / 2 * 72 / 96; - } - - let docView: DocumentView | null; - // using forceDockFunc as a flag for splitting linked to doc to the right...can change later if needed - if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) { - Doc.BrushDoc(docView.props.Document); - if (linkPage !== undefined) docView.props.Document.curPage = linkPage; - UndoManager.RunInBatch(() => docView!.props.focus(docView!.props.Document, willZoom), "focus"); + public jumpToDocument = async (targetDoc: Doc, willZoom: boolean, dockFunc?: (doc: Doc) => void, docContext?: Doc, closeContextIfNotFound: boolean = false): Promise => { + const docView = DocumentManager.Instance.getFirstDocumentView(targetDoc); + const annotatedDoc = await Cast(targetDoc.annotationOn, Doc); + if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? + annotatedDoc && docView.props.focus(annotatedDoc, false); + docView.props.focus(targetDoc, willZoom); } else { - if (!contextDoc) { - let docs = docContext ? await DocListCastAsync(docContext.data) : undefined; - let found = false; - // bcz: this just searches within the context for the target -- perhaps it should recursively search through all children? - docs && docs.map(d => found = found || Doc.AreProtosEqual(d, docDelegate)); - if (docContext && found) { - let targetContextView: DocumentView | null; - - if (!forceDockFunc && docContext && (targetContextView = DocumentManager.Instance.getDocumentView(docContext))) { - docContext.panTransformType = "Ease"; - targetContextView.props.focus(docDelegate, willZoom); - } else { - (dockFunc || CollectionDockingView.AddRightSplit)(docContext, undefined); - setTimeout(() => { - let dv = DocumentManager.Instance.getDocumentView(docContext); - dv && this.jumpToDocument(docDelegate, willZoom, forceDockFunc, - doc => dv!.props.focus(dv!.props.Document, true, 1, () => dv!.props.addDocTab(doc, undefined, "inPlace")), - linkPage); - }, 1050); - } - } else { - const actualDoc = Doc.MakeAlias(docDelegate); - Doc.BrushDoc(actualDoc); - if (linkPage !== undefined) actualDoc.curPage = linkPage; - (dockFunc || CollectionDockingView.AddRightSplit)(actualDoc, undefined); - } + const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; + const contextDoc = contextDocs && contextDocs.find(doc => Doc.AreProtosEqual(doc, targetDoc)) ? docContext : undefined; + const targetDocContext = (annotatedDoc ? annotatedDoc : contextDoc); + + if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default + (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); } else { - let contextView: DocumentView | null; - Doc.BrushDoc(docDelegate); - let contextViews = DocumentManager.Instance.getDocumentViews(contextDoc); - if (!forceDockFunc && contextViews.length) { - contextView = contextViews[0]; - SelectionManager.SelectDoc(contextView, false); // force unrendered annotations to be created - contextDoc.panTransformType = "Ease"; + const targetDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext); + if (targetDocContextView) { // we have a context view and aren't forced to create a new one ... focus on the context + targetDocContext.panTransformType = "Ease"; + targetDocContext.scrollY = 0; + targetDocContextView.props.focus(targetDocContextView.props.Document, willZoom); + + // now find the target document within the context setTimeout(() => { - SelectionManager.DeselectDoc(contextView!); - docView = DocumentManager.Instance.getDocumentView(docDelegate); - docView && contextView!.props.focus(contextView!.props.Document, willZoom); - docView && UndoManager.RunInBatch(() => docView!.props.focus(docView!.props.Document, willZoom), "focus"); + const retryDocView = DocumentManager.Instance.getDocumentView(targetDoc); + if (retryDocView) { + retryDocView.props.focus(targetDoc, willZoom); // focus on the target if it now exists in the context + } else { + if (closeContextIfNotFound && targetDocContextView.props.removeDocument) targetDocContextView.props.removeDocument(targetDocContextView.props.Document); + (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); // otherwise create a new view of the target + } }, 0); - } else { - (dockFunc || CollectionDockingView.AddRightSplit)(contextDoc, undefined); + } else { // there's no context view so we need to create one first and try again + targetDocContext.scrollY = 0; + (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext, undefined); setTimeout(() => { - this.jumpToDocument(docDelegate, willZoom, forceDockFunc, dockFunc, linkPage); - }, 1000); + const foundTargetDocContextView = DocumentManager.Instance.getDocumentView(targetDocContext); + if (foundTargetDocContextView) { // we should always find a target context here.... + this.jumpToDocument(targetDoc, willZoom, dockFunc, undefined, true); // so call jump to doc again and if the doc isn't found, it will be created. + } + }, 2000); // the long timeout gives the context view a chance to create its children. think pdf's which need to be activated to render their annotations. } } } } + public async FollowLink(doc: Doc, focus: (doc: Doc, maxLocation: string) => void, zoom: boolean = false, reverse: boolean = false, currentContext?: Doc) { + let linkDocs = LinkManager.Instance.getAllRelatedLinks(doc); + SelectionManager.DeselectAll(); + let firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) && !linkDoc.anchor1anchored); + let secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) && !linkDoc.anchor2anchored); + const firstDocWithoutView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); + const secondDocWithoutView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0); + let first = firstDocWithoutView ? [firstDocWithoutView] : firstDocs; + let second = secondDocWithoutView ? [secondDocWithoutView] : secondDocs; + let linkFollowDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : second.length ? [second[0].anchor1 as Doc, second[0].anchor2 as Doc] : undefined; + let linkFollowDocContexts = first.length ? [await (first[0].targetContext) as Doc, await (first[0].sourceContext) as Doc] : second.length ? [await (second[0].sourceContext) as Doc, await (second[0].targetContext) as Doc] : [undefined, undefined]; + if (linkFollowDocs && !linkFollowDocs.some(l => l instanceof Promise)) { + let maxLocation = StrCast(linkFollowDocs[0].maximizeLocation, "inTab"); + let targetContext = !Doc.AreProtosEqual(linkFollowDocContexts[reverse ? 1 : 0], currentContext) ? linkFollowDocContexts[reverse ? 1 : 0] : undefined; + DocumentManager.Instance.jumpToDocument(linkFollowDocs[reverse ? 1 : 0], zoom, + // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards + (doc: Doc) => focus(doc, maxLocation), targetContext); + } + } + @action zoomIntoScale = (docDelegate: Doc, scale: number) => { let docView = DocumentManager.Instance.getDocumentView(Doc.GetProto(docDelegate)); @@ -202,8 +204,7 @@ export class DocumentManager { getScaleOfDocView = (docDelegate: Doc) => { let doc = Doc.GetProto(docDelegate); - let docView: DocumentView | null; - docView = DocumentManager.Instance.getDocumentView(doc); + const docView = DocumentManager.Instance.getDocumentView(doc); if (docView) { return docView.props.getScale(); } else { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 64821d8db..49bd93942 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -627,17 +627,16 @@ export class ImageResizeView { let jumpToDoc = await Cast(linkDoc.anchor2, Doc); if (jumpToDoc) { if (DocumentManager.Instance.getDocumentView(jumpToDoc)) { - - DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((jumpToDoc === linkDoc.anchor2 ? linkDoc.anchor2Page : linkDoc.anchor1Page))); + DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey); return; } } if (targetContext) { - DocumentManager.Instance.jumpToDocument(targetContext, e.ctrlKey, false, document => addDocTab(document, undefined, location ? location : "inTab")); + DocumentManager.Instance.jumpToDocument(targetContext, e.ctrlKey, document => addDocTab(document, undefined, location ? location : "inTab")); } else if (jumpToDoc) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, e.ctrlKey, false, document => addDocTab(document, undefined, location ? location : "inTab")); + DocumentManager.Instance.jumpToDocument(jumpToDoc, e.ctrlKey, document => addDocTab(document, undefined, location ? location : "inTab")); } else { - DocumentManager.Instance.jumpToDocument(linkDoc, e.ctrlKey, false, document => addDocTab(document, undefined, location ? location : "inTab")); + DocumentManager.Instance.jumpToDocument(linkDoc, e.ctrlKey, document => addDocTab(document, undefined, location ? location : "inTab")); } } }); diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index f427e40b1..1cde2aa8e 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -192,7 +192,7 @@ export default class SharingManager extends React.Component<{}> { onClick={() => { let context: Opt; if (this.targetDoc && this.targetDocView && (context = this.targetDocView.props.ContainingCollectionView)) { - DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, undefined, undefined, context.props.Document); + DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, context.props.Document); } }} onPointerEnter={action(() => { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index e928887e2..38d050e5c 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -5,7 +5,7 @@ import { Doc, DocListCast } from '../../../new_fields/Doc'; import { Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { listSpec } from '../../../new_fields/Schema'; -import { BoolCast, Cast, NumCast, PromiseValue, StrCast } from '../../../new_fields/Types'; +import { BoolCast, Cast, NumCast, PromiseValue, StrCast, FieldValue } from '../../../new_fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from '../ContextMenu'; @@ -130,8 +130,11 @@ export class CollectionBaseView extends React.Component { let value = Cast(targetDataDoc[targetField], listSpec(Doc), []); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? 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)); + PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn => { + if (Doc.AreProtosEqual(annotationOn, FieldValue(Cast(this.dataDoc.extendsDoc, Doc)))) { + Doc.GetProto(doc).annotationOn = undefined; + } + }); if (index !== -1) { value.splice(index, 1); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 98aff41d3..14e513157 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -574,8 +574,8 @@ export class DockedFrameRenderer extends React.Component { let curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; if (curPres) { let pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); - Doc.GetProto(pinDoc).target = doc; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.target instanceof Doc) && this.target.title.toString()'); + Doc.GetProto(pinDoc).presentationTargetDoc = doc; + Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title.toString()'); const data = Cast(curPres.data, listSpec(Doc)); if (data) { data.push(pinDoc); @@ -614,8 +614,8 @@ export class DockedFrameRenderer extends React.Component { } } - 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())); + panelWidth = () => this._document && this._document.maxWidth ? Math.min(Math.max(NumCast(this._document.width), NumCast(this._document.nativeWidth)), this._panelWidth) : this._panelWidth; + panelHeight = () => this._panelHeight; 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; @@ -644,7 +644,7 @@ export class DockedFrameRenderer extends React.Component { } return Transform.Identity(); } - get previewPanelCenteringOffset() { return this.nativeWidth() && !BoolCast(this._document!.ignoreAspect) ? (this._panelWidth - this.nativeWidth() / this.ScreenToLocalTransform().Scale) / 2 : 0; } + get previewPanelCenteringOffset() { return this.nativeWidth() && !this._document!.ignoreAspect ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; } addDocTab = (doc: Doc, dataDoc: Opt, location: string) => { SelectionManager.DeselectAll(); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 155f2718b..28d1eb384 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -31,6 +31,7 @@ export interface CollectionViewProps extends FieldViewProps { moveDocument: (document: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean; PanelWidth: () => number; PanelHeight: () => number; + VisibleHeight?: () => number; chromeCollapsed: boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ffd1f9170..882a0f144 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -217,7 +217,7 @@ class TreeView extends React.Component { if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.document; - DocUtils.MakeLink(sourceDoc, destDoc); + DocUtils.MakeLink({doc:sourceDoc}, {doc:destDoc}); e.stopPropagation(); } if (de.data instanceof DragManager.DocumentDragData) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index eb40e0bcb..4bdede48a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -403,8 +403,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { SelectionManager.DeselectAll(); if (this.props.Document.scrollHeight) { let annotOn = Cast(doc.annotationOn, Doc) as Doc; - let offset = annotOn && (NumCast(annotOn.height) / 2 * 72 / 96); - this.props.Document.scrollY = NumCast(doc.y) - offset; + if (!annotOn) { + this.props.focus(doc); + } else { + let contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn.height); + let offset = annotOn && (contextHgt / 2 * 96 / 72); + 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; @@ -416,6 +421,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.setPan(newPanX, newPanY); this.Document.panTransformType = "Ease"; + Doc.BrushDoc(this.props.Document); this.props.focus(this.props.Document); willZoom && this.setScaleToZoom(doc, scale); diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx index 72fff8e53..53b720a9e 100644 --- a/src/client/views/linking/LinkFollowBox.tsx +++ b/src/client/views/linking/LinkFollowBox.tsx @@ -171,7 +171,7 @@ export class LinkFollowBox extends React.Component { @undoBatch openFullScreen = () => { if (LinkFollowBox.destinationDoc) { - let view: DocumentView | null = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc); + let view = DocumentManager.Instance.getDocumentView(LinkFollowBox.destinationDoc); view && CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(view); } } @@ -250,10 +250,10 @@ export class LinkFollowBox extends React.Component { let dockingFunc = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); }; if (LinkFollowBox.destinationDoc === LinkFollowBox.linkDoc.anchor2 && targetContext) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, async document => dockingFunc(document), undefined, targetContext); + DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, async document => dockingFunc(document), targetContext); } else if (LinkFollowBox.destinationDoc === LinkFollowBox.linkDoc.anchor1 && sourceContext) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, document => dockingFunc(sourceContext!)); + DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, document => dockingFunc(sourceContext!)); if (LinkFollowBox.sourceDoc && LinkFollowBox.destinationDoc) { if (guid) { let views = DocumentManager.Instance.getDocumentViews(jumpToDoc); @@ -264,12 +264,11 @@ export class LinkFollowBox extends React.Component { } } else if (DocumentManager.Instance.getDocumentView(jumpToDoc)) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, undefined, undefined, - NumCast((LinkFollowBox.destinationDoc === LinkFollowBox.linkDoc.anchor2 ? LinkFollowBox.linkDoc.anchor2Page : LinkFollowBox.linkDoc.anchor1Page))); + DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom); } else { - DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, dockingFunc); + DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, dockingFunc); } this.highlightDoc(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a903f8fe2..3273abc1d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -206,7 +206,7 @@ export class DocumentView extends DocComponent(Docu buttonClick = async (altKey: boolean, ctrlKey: boolean) => { let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs); - let linkedDocs = LinkManager.Instance.getAllRelatedLinks(this.props.Document); + let linkDocs = LinkManager.Instance.getAllRelatedLinks(this.props.Document); let expandedDocs: Doc[] = []; expandedDocs = maximizedDocs ? [...maximizedDocs, ...expandedDocs] : expandedDocs; expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs; @@ -223,28 +223,10 @@ export class DocumentView extends DocComponent(Docu expandedDocs.forEach(maxDoc => (!this.props.addDocTab(maxDoc, undefined, "close") && this.props.addDocTab(maxDoc, undefined, maxLocation))); } } - 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]]; - 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 && !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, - // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards - doc => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)), - linkedFwdPage[altKey ? 1 : 0], targetContext); - } + else if (linkDocs.length) { + DocumentManager.Instance.FollowLink(this.props.Document, + (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)), + ctrlKey, altKey, this.props.ContainingCollectionDoc); } } @@ -352,15 +334,9 @@ export class DocumentView extends DocComponent(Docu if (de.data instanceof DragManager.AnnotationDragData) { /// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner e.stopPropagation(); - let sourceDoc = de.data.annotationDocument; - let targetDoc = this.props.Document; - let annotations = await DocListCastAsync(sourceDoc.annotations); - sourceDoc.linkedToDoc = true; - de.data.targetContext = this.props.ContainingCollectionDoc; - targetDoc.targetContext = de.data.targetContext; - annotations && annotations.forEach(anno => anno.target = targetDoc); - - DocUtils.MakeLink(sourceDoc, targetDoc, this.props.ContainingCollectionDoc, `Link from ${StrCast(sourceDoc.title)}`); + (de.data as any).linkedToDoc = true; + + DocUtils.MakeLink({ doc: de.data.annotationDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, `Link from ${StrCast(de.data.annotationDocument.title)}`); } if (de.data instanceof DragManager.DocumentDragData && de.data.applyAsTemplate) { Doc.ApplyTemplateTo(de.data.draggedDocuments[0], this.props.Document); @@ -371,7 +347,7 @@ export class DocumentView extends DocComponent(Docu // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true); // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView); de.data.linkSourceDocument !== this.props.Document && - (de.data.linkDocument = DocUtils.MakeLink(de.data.linkSourceDocument, this.props.Document, this.props.ContainingCollectionDoc, undefined, "in-text link being created")); // TODODO this is where in text links get passed + (de.data.linkDocument = DocUtils.MakeLink({ doc: de.data.linkSourceDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, "in-text link being created")); // TODODO this is where in text links get passed } } @@ -407,7 +383,7 @@ export class DocumentView extends DocComponent(Docu 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.Document.width || 0) + 10, height: this.Document.height || 0, title: portalID }); - DocUtils.MakeLink(this.props.Document, portal, undefined, portalID); + DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, portalID, "portal link"); this.Document.isButton = true; }); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 449f56b16..749886d9a 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -9,7 +9,7 @@ import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark, ResolvedPos } import { EditorState, Plugin, Transaction, TextSelection, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { DateField } from '../../../new_fields/DateField'; -import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Opt, WidthSym, DocListCastAsync } from "../../../new_fields/Doc"; import { Copy, Id } from '../../../new_fields/FieldSymbols'; import { List } from '../../../new_fields/List'; import { RichTextField } from "../../../new_fields/RichTextField"; @@ -230,7 +230,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, width: 500, height: 500 }, value); 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); + else DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: this.dataDoc[key] as Doc }, "Ref:" + value, "link to named target", id, true); }); }); }); @@ -342,7 +342,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let model: NodeType = [".mov", ".mp4"].includes(url) ? schema.nodes.video : schema.nodes.image; let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y }); this._editorView!.dispatch(this._editorView!.state.tr.insert(pos!.pos, model.create({ src: url, docid: target[Id] }))); - DocUtils.MakeLink(this.dataDoc, target, undefined, "ImgRef:" + target.title, undefined, undefined, target[Id]); + DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "ImgRef:" + target.title); this.tryUpdateHeight(); e.stopPropagation(); } else if (de.data instanceof DragManager.DocumentDragData) { @@ -667,55 +667,42 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => { let cbe = event as ClipboardEvent; - let docId: string; - let regionId: string; - if (!cbe.clipboardData) { - return false; - } - let linkId: string; - docId = cbe.clipboardData.getData("dash/pdfOrigin"); - regionId = cbe.clipboardData.getData("dash/pdfRegion"); - if (!docId || !regionId) { - return false; - } - - DocServer.GetRefField(docId).then(doc => { - DocServer.GetRefField(regionId).then(region => { - if (!(doc instanceof Doc) || !(region instanceof Doc)) { - return; - } - - let annotations = DocListCast(region.annotations); - annotations.forEach(anno => anno.target = this.props.Document); - let fieldExtDoc = Doc.fieldExtensionDoc(doc, "data"); - let targetAnnotations = DocListCast(fieldExtDoc.annotations); - if (targetAnnotations) { - targetAnnotations.push(region); - fieldExtDoc.annotations = new List(targetAnnotations); - } + const pdfDocId = cbe.clipboardData && cbe.clipboardData.getData("dash/pdfOrigin"); + const pdfRegionId = cbe.clipboardData && cbe.clipboardData.getData("dash/pdfRegion"); + if (pdfDocId && pdfRegionId) { + DocServer.GetRefField(pdfDocId).then(pdfDoc => { + DocServer.GetRefField(pdfRegionId).then(pdfRegion => { + if ((pdfDoc instanceof Doc) && (pdfRegion instanceof Doc)) { + setTimeout(async () => { + let targetAnnotations = await DocListCastAsync(Doc.fieldExtensionDoc(pdfDoc, "data").annotations);// bcz: NO... this assumes the pdf is using its 'data' field. need to have the PDF's view handle updating its own annotations + targetAnnotations && targetAnnotations.push(pdfRegion); + }); - let link = DocUtils.MakeLink(this.props.Document, region, doc); - if (link) { - cbe.clipboardData!.setData("dash/linkDoc", link[Id]); - linkId = link[Id]; - let frag = addMarkToFrag(slice.content, (node: Node) => addLinkMark(node, StrCast(doc.title))); - slice = new Slice(frag, slice.openStart, slice.openEnd); - var tr = view.state.tr.replaceSelection(slice); - view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste")); - } + let link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "note on " + pdfDoc.title, "pasted PDF link"); + if (link) { + cbe.clipboardData!.setData("dash/linkDoc", link[Id]); + let linkId = link[Id]; + let frag = addMarkToFrag(slice.content, (node: Node) => addLinkMark(node, StrCast(pdfDoc.title), linkId)); + slice = new Slice(frag, slice.openStart, slice.openEnd); + var tr = view.state.tr.replaceSelection(slice); + view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste")); + } + } + }); }); - }); + return true; + } + return false; - return true; function addMarkToFrag(frag: Fragment, marker: (node: Node) => Node) { const nodes: Node[] = []; frag.forEach(node => nodes.push(marker(node))); return Fragment.fromArray(nodes); } - function addLinkMark(node: Node, title: string) { + function addLinkMark(node: Node, title: string, linkId: string) { if (!node.isText) { - const content = addMarkToFrag(node.content, (node: Node) => addLinkMark(node, title)); + const content = addMarkToFrag(node.content, (node: Node) => addLinkMark(node, title, linkId)); return node.copy(content); } const marks = [...node.marks]; @@ -879,16 +866,16 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (jumpToDoc) { if (DocumentManager.Instance.getDocumentView(jumpToDoc)) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((jumpToDoc === linkDoc.anchor2 ? linkDoc.anchor2Page : linkDoc.anchor1Page))); + DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey); return; } } if (targetContext && (!jumpToDoc || targetContext !== await jumpToDoc.annotationOn)) { - DocumentManager.Instance.jumpToDocument(jumpToDoc || targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), undefined, targetContext); + DocumentManager.Instance.jumpToDocument(jumpToDoc || targetContext, ctrlKey, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), targetContext); } else if (jumpToDoc) { - DocumentManager.Instance.jumpToDocument(jumpToDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); + DocumentManager.Instance.jumpToDocument(jumpToDoc, ctrlKey, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); } else { - DocumentManager.Instance.jumpToDocument(linkDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); + DocumentManager.Instance.jumpToDocument(linkDoc, ctrlKey, document => this.props.addDocTab(document, undefined, location ? location : "inTab")); } } }); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9e9fe1324..fe4f75cad 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -299,7 +299,7 @@ export class ImageBox extends DocComponent(ImageD let rotation = NumCast(this.dataDoc.rotation) % 180; let realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size; let aspect = realsize.height / realsize.width; - if (layoutdoc.nativeHeight !== 0 && layoutdoc.nativeWidth !== 0 && (Math.abs(NumCast(layoutdoc.height) - realsize.height) > 1 || Math.abs(NumCast(layoutdoc.width) - realsize.width) > 1)) { + if (layoutdoc.nativeHeight !== 0 && layoutdoc.nativeWidth !== 0 && (Math.abs(1 - NumCast(layoutdoc.nativeHeight) / NumCast(layoutdoc.nativeWidth) / (realsize.height / realsize.width)) > 0.1)) { setTimeout(action(() => { layoutdoc.height = layoutdoc[WidthSym]() * aspect; layoutdoc.nativeHeight = realsize.height; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 617b580dd..88cd2cdc4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -57,11 +57,8 @@ export class PDFBox extends DocComponent(PdfDocumen } loaded = (nw: number, nh: number, np: number) => { this.dataDoc.numPages = np; - if (!this.Document.nativeWidth || !this.Document.nativeHeight || !this.Document.scrollHeight) { - let oldaspect = (this.Document.nativeHeight || 0) / (this.Document.nativeWidth || 1); - this.Document.nativeWidth = nw * 96 / 72; - this.Document.nativeHeight = this.Document.nativeHeight ? nw * 96 / 72 * oldaspect : nh * 96 / 72; - } + this.Document.nativeWidth = nw * 96 / 72; + this.Document.nativeHeight = nh * 96 / 72; !this.Document.fitWidth && !this.Document.ignoreAspect && (this.Document.height = this.Document[WidthSym]() * (nh / nw)); } @@ -177,12 +174,14 @@ export class PDFBox extends DocComponent(PdfDocumen ContextMenu.Instance.addItem({ description: "Pdf Funcs...", subitems: funcs, icon: "asterisk" }); } + _initialScale: number | undefined; render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); let classname = "pdfBox-cont" + (InkingControl.Instance.selectedTool || !this.active ? "" : "-interactive"); let noPdf = !(pdfUrl instanceof PdfField) || !this._pdf; - if (!noPdf && (this.props.isSelected() || this.props.ScreenToLocalTransform().Scale < 2.5)) this._everActive = true; - return (!this._everActive ? + if (this._initialScale === undefined) this._initialScale = this.props.ScreenToLocalTransform().Scale; + if (this.props.isSelected() || this.props.Document.scrollY !== undefined) this._everActive = true; + return (noPdf || (!this._everActive && this.props.ScreenToLocalTransform().Scale > 2.5) ?
{` ${this.props.Document.title}`} @@ -203,11 +202,11 @@ export class PDFBox extends DocComponent(PdfDocumen setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView} renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling} - addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} + addDocTab={this.props.addDocTab} GoToPage={this.gotoPage} focus={this.props.focus} pinToPres={this.props.pinToPres} addDocument={this.props.addDocument} ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select} isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged} - fieldKey={this.props.fieldKey} fieldExtensionDoc={this.extensionDoc} startupLive={this.props.ScreenToLocalTransform().Scale < 2.5 ? true : false} /> + fieldKey={this.props.fieldKey} fieldExtensionDoc={this.extensionDoc} startupLive={this._initialScale < 2.5 ? true : false} /> {this.settingsPanel()}
); } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index f44ca99b9..180ed9032 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -43,8 +43,8 @@ export class PresBox extends React.Component { value.forEach((item, i) => { if (item instanceof Doc && item.type !== DocumentType.PRESELEMENT) { let pinDoc = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent" }); - Doc.GetProto(pinDoc).target = item; - Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.target instanceof Doc) && this.target.title.toString()'); + Doc.GetProto(pinDoc).presentationTargetDoc = item; + Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.presentationTargetDoc instanceof Doc) && this.presentationTargetDoc.title.toString()'); value.splice(i, 1, pinDoc); } }); @@ -124,13 +124,13 @@ export class PresBox extends React.Component { this.childDocs.forEach((doc, ind) => { //the order of cases is aligned based on priority if (doc.hideTillShownButton && ind <= index) { - (doc.target as Doc).opacity = 1; + (doc.presentationTargetDoc as Doc).opacity = 1; } if (doc.hideAfterButton && ind < index) { - (doc.target as Doc).opacity = 0; + (doc.presentationTargetDoc as Doc).opacity = 0; } if (doc.fadeButton && ind < index) { - (doc.target as Doc).opacity = 0.5; + (doc.presentationTargetDoc as Doc).opacity = 0.5; } }); } @@ -145,13 +145,13 @@ export class PresBox extends React.Component { //the order of cases is aligned based on priority if (key.hideAfterButton && ind >= index) { - (key.target as Doc).opacity = 1; + (key.presentationTargetDoc as Doc).opacity = 1; } if (key.fadeButton && ind >= index) { - (key.target as Doc).opacity = 1; + (key.presentationTargetDoc as Doc).opacity = 1; } if (key.hideTillShownButton && ind > index) { - (key.target as Doc).opacity = 0; + (key.presentationTargetDoc as Doc).opacity = 0; } }); } @@ -162,7 +162,7 @@ export class PresBox extends React.Component { * te option open, navigates to that element. */ navigateToElement = async (curDoc: Doc, fromDocIndex: number) => { - let fromDoc = this.childDocs[fromDocIndex].target as Doc; + let fromDoc = this.childDocs[fromDocIndex].presentationTargetDoc as Doc; let docToJump = curDoc; let willZoom = false; @@ -190,7 +190,7 @@ export class PresBox extends React.Component { //docToJump stayed same meaning, it was not in the group or was the last element in the group if (docToJump === curDoc) { //checking if curDoc has navigation open - let target = await curDoc.target as Doc; + let target = await curDoc.presentationTargetDoc as Doc; if (curDoc.navButton) { DocumentManager.Instance.jumpToDocument(target, false); } else if (curDoc.showButton) { @@ -210,8 +210,8 @@ export class PresBox extends React.Component { let curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(await docToJump.target as Doc, willZoom); - let newScale = DocumentManager.Instance.getScaleOfDocView(await curDoc.target as Doc); + await DocumentManager.Instance.jumpToDocument(await docToJump.presentationTargetDoc as Doc, willZoom); + let newScale = DocumentManager.Instance.getScaleOfDocView(await curDoc.presentationTargetDoc as Doc); curDoc.viewScale = newScale; //saving the scale that user was on if (curScale !== 1) { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index b7d9a1eab..573197117 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -129,7 +129,7 @@ export class VideoBox extends DocComponent(VideoD width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-" }); this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.addDocument && this.props.ContainingCollectionView.props.addDocument(imageSummary, false); - DocUtils.MakeLink(imageSummary, this.props.Document); + DocUtils.MakeLink({doc:imageSummary}, {doc: this.props.Document}, "snapshot from " + this.props.Document.title, "video frame snapshot"); } }); } diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 3ed85f6a5..f7f52b3ef 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,7 +1,7 @@ import React = require("react"); import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, WidthSym, Opt } from "../../../new_fields/Doc"; +import { Doc, DocListCast, HeightSym, WidthSym, Opt, DocListCastAsync } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; @@ -14,6 +14,7 @@ interface IAnnotationProps { fieldExtensionDoc: Doc; addDocTab: (document: Doc, dataDoc: Opt, where: string) => boolean; pinToPres: (document: Doc) => void; + focus: (doc: Doc) => void; } export default class Annotation extends React.Component { @@ -60,6 +61,7 @@ class RegionAnnotation extends React.Component { } componentWillUnmount() { + this._brushDisposer && this._brushDisposer(); this._reactionDisposer && this._reactionDisposer(); } @@ -94,14 +96,11 @@ class RegionAnnotation extends React.Component { PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); } else if (e.button === 0) { - let targetDoc = await Cast(this.props.document.target, Doc); - if (targetDoc) { - let context = await Cast(targetDoc.targetContext, Doc); - if (context) { - DocumentManager.Instance.jumpToDocument(targetDoc, false, false, - ((doc) => this.props.addDocTab(targetDoc!, undefined, e.ctrlKey ? "onRight" : "inTab")), - undefined, undefined); - } + let annoGroup = await Cast(this.props.document.group, Doc); + if (annoGroup) { + DocumentManager.Instance.FollowLink(annoGroup, + (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "onRight" : "inTab"), + false, false, undefined); } } } diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 2202351ee..e62542014 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -31,7 +31,7 @@ export default class PDFMenu extends React.Component { @observable public Pinned: boolean = false; public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = emptyFunction; - public Highlight: (d: Doc | undefined, color: string) => void = emptyFunction; + public Highlight: (color: string) => void = emptyFunction; public Delete: () => void = emptyFunction; public Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; public AddTag: (key: string, value: string) => boolean = returnFalse; @@ -156,11 +156,11 @@ export default class PDFMenu extends React.Component { @action highlightClicked = (e: React.MouseEvent) => { if (!this.Pinned) { - this.Highlight(undefined, "#f4f442"); + this.Highlight("#f4f442"); } else { this.Highlighting = !this.Highlighting; - this.Highlight(undefined, "#f4f442"); + this.Highlight("#f4f442"); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 33226eac4..20dfc4d8c 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -10,7 +10,6 @@ import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; 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"; @@ -44,6 +43,7 @@ interface IViewerProps { select: (isCtrlPressed: boolean) => void; startupLive: boolean; renderDepth: number; + focus: (doc: Doc) => void; isSelected: () => boolean; loaded: (nw: number, nh: number, np: number) => void; active: () => boolean; @@ -108,7 +108,8 @@ 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.props.isSelected() && SelectionManager.SelectedDocuments().length === 1 && this.setupPdfJsViewer(), { fireImmediately: this.props.startupLive }); + this.props.startupLive && this.setupPdfJsViewer(); + this._selectionReactionDisposer = reaction(() => this.props.isSelected(), () => (this.props.isSelected() && SelectionManager.SelectedDocuments().length === 1) && this.setupPdfJsViewer(), { fireImmediately: true }); this._reactionDisposer = reaction( () => this.props.Document.scrollY, (scrollY) => { @@ -136,19 +137,11 @@ export class PDFViewer extends React.Component { if (this.props.active() && e.clipboardData) { e.clipboardData.setData("text/plain", this._selectionText); e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]); - e.clipboardData.setData("dash/pdfRegion", this.makeAnnotationDocument(undefined, "#0390fc")[Id]); + e.clipboardData.setData("dash/pdfRegion", this.makeAnnotationDocument("#0390fc")[Id]); e.preventDefault(); } } - paste = (e: ClipboardEvent) => { - if (e.clipboardData && e.clipboardData.getData("dash/pdfOrigin") === this.props.Document[Id]) { - let linkDocId = e.clipboardData.getData("dash/linkDoc"); - linkDocId && DocServer.GetRefField(linkDocId).then(async (link) => - (link instanceof Doc) && (Doc.GetProto(link).anchor2 = this.makeAnnotationDocument(await Cast(Doc.GetProto(link), Doc), "#0390fc", false))); - } - } - setSelectionText = (text: string) => this._selectionText = text; @action @@ -194,13 +187,6 @@ export class PDFViewer extends React.Component { { fireImmediately: true } ); - document.removeEventListener("copy", this.copy); - document.addEventListener("copy", this.copy); - document.addEventListener("pagesinit", action(() => { - this.pdfViewer.currentScaleValue = this._zoomed = 1; - this.gotoPage(NumCast(this.props.Document.curPage, 1)); - })); - document.addEventListener("pagerendered", action(() => this._showCover = this._showWaiting = false)); this.createPdfViewer(); } @@ -212,6 +198,13 @@ export class PDFViewer extends React.Component { } return; } + document.removeEventListener("copy", this.copy); + document.addEventListener("copy", this.copy); + document.addEventListener("pagesinit", action(() => { + this.pdfViewer.currentScaleValue = this._zoomed = 1; + this.gotoPage(NumCast(this.props.Document.curPage, 1)); + })); + document.addEventListener("pagerendered", action(() => this._showCover = this._showWaiting = false)); var pdfLinkService = new PDFJSViewer.PDFLinkService(); let pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, @@ -229,19 +222,18 @@ export class PDFViewer extends React.Component { } @action - makeAnnotationDocument = (sourceDoc: Doc | undefined, color: string, createLink: boolean = true): Doc => { + makeAnnotationDocument = (color: string): Doc => { let mainAnnoDoc = Docs.Create.InstanceFromProto(new Doc(), "", {}); let mainAnnoDocProto = Doc.GetProto(mainAnnoDoc); let annoDocs: Doc[] = []; let minY = Number.MAX_VALUE; - if (this._savedAnnotations.size() === 1 && this._savedAnnotations.values()[0].length === 1 && !createLink) { + if (this._savedAnnotations.size() === 1 && this._savedAnnotations.values()[0].length === 1) { let anno = this._savedAnnotations.values()[0][0]; let annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: "rgba(255, 0, 0, 0.1)", title: "Annotation on " + StrCast(this.props.Document.title) }); if (anno.style.left) annoDoc.x = parseInt(anno.style.left); if (anno.style.top) annoDoc.y = parseInt(anno.style.top); if (anno.style.height) annoDoc.height = parseInt(anno.style.height); if (anno.style.width) annoDoc.width = parseInt(anno.style.width); - annoDoc.target = sourceDoc; annoDoc.group = mainAnnoDoc; annoDoc.color = color; annoDoc.type = AnnotationTypes.Region; @@ -258,7 +250,6 @@ export class PDFViewer extends React.Component { if (anno.style.top) annoDoc.y = parseInt(anno.style.top); if (anno.style.height) annoDoc.height = parseInt(anno.style.height); if (anno.style.width) annoDoc.width = parseInt(anno.style.width); - annoDoc.target = sourceDoc; annoDoc.group = mainAnnoDoc; annoDoc.color = color; annoDoc.type = AnnotationTypes.Region; @@ -272,9 +263,6 @@ export class PDFViewer extends React.Component { } mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title); mainAnnoDocProto.annotationOn = this.props.Document; - if (sourceDoc && createLink) { - DocUtils.MakeLink(sourceDoc, mainAnnoDocProto, undefined, `Annotation from ${StrCast(this.props.Document.title)}`); - } this._savedAnnotations.clear(); this.Index = -1; return mainAnnoDoc; @@ -529,7 +517,7 @@ export class PDFViewer extends React.Component { } if (PDFMenu.Instance.Highlighting) { - this.highlight(undefined, "goldenrod"); + this.highlight("goldenrod"); } else { PDFMenu.Instance.StartDrag = this.startDrag; @@ -540,9 +528,9 @@ export class PDFViewer extends React.Component { } @action - highlight = (targetDoc: Doc | undefined, color: string) => { + highlight = (color: string) => { // creates annotation documents for current highlights - let annotationDoc = this.makeAnnotationDocument(targetDoc, color, false); + let annotationDoc = this.makeAnnotationDocument(color); Doc.AddDocToList(this.props.fieldExtensionDoc, this.props.fieldExt, annotationDoc); return annotationDoc; } @@ -555,20 +543,14 @@ export class PDFViewer extends React.Component { startDrag = (e: PointerEvent, ele: HTMLElement): void => { e.preventDefault(); e.stopPropagation(); - let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" }); - targetDoc.targetPage = this.getPageFromScroll(this._marqueeY); - let annotationDoc = this.highlight(undefined, "red"); - annotationDoc.linkedToDoc = false; + let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "Note linked to " + this.props.Document.title }); + let annotationDoc = this.highlight("red"); let dragData = new DragManager.AnnotationDragData(this.props.Document, annotationDoc, targetDoc); DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, { handlers: { - dragComplete: () => { - if (!annotationDoc.linkedToDoc) { - let annotations = DocListCast(annotationDoc.annotations); - annotations && annotations.forEach(anno => anno.target = targetDoc); - DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(this.props.Document.title)}`); - } - } + dragComplete: () => !(dragData as any).linkedToDoc && + DocUtils.MakeLink({ doc: annotationDoc }, { doc: dragData.dropDocument, ctx: dragData.targetContext }, `Annotation from ${StrCast(this.props.Document.title)}`, "link from PDF") + }, hideSource: false }); @@ -602,6 +584,7 @@ export class PDFViewer extends React.Component { @action.bound removeDocument(doc: Doc): boolean { + Doc.GetProto(doc).annotationOn = undefined; //TODO This won't create the field if it doesn't already exist let targetDataDoc = this.props.fieldExtensionDoc; let targetField = this.props.fieldExt; @@ -634,10 +617,10 @@ export class PDFViewer extends React.Component { getCoverImage = () => { if (!this.props.Document[HeightSym]() || !this.props.Document.nativeHeight) { - setTimeout(() => { + setTimeout((() => { this.props.Document.height = this.props.Document[WidthSym]() * this._coverPath.height / this._coverPath.width; this.props.Document.nativeHeight = nativeWidth * this._coverPath.height / this._coverPath.width; - }, 0); + }).bind(this), 0); } let nativeWidth = NumCast(this.props.Document.nativeWidth); let nativeHeight = NumCast(this.props.Document.nativeHeight); @@ -659,7 +642,7 @@ export class PDFViewer extends React.Component { @computed get annotationLayer() { return
{this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) => - )} + )}
; } @computed get pdfViewerDiv() { @@ -686,7 +669,8 @@ export class PDFViewer extends React.Component { setPreviewCursor={this.setPreviewCursor} PanelHeight={() => NumCast(this.props.Document.scrollHeight, NumCast(this.props.Document.nativeHeight))} PanelWidth={() => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : NumCast(this.props.Document.nativeWidth)} - focus={emptyFunction} + VisibleHeight={() => this.props.PanelHeight() / this.props.ContentScaling() * 72 / 96} + focus={this.props.focus} isSelected={this.props.isSelected} select={emptyFunction} active={this.active} @@ -694,7 +678,7 @@ export class PDFViewer extends React.Component { whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} - addDocument={(doc: Doc, allow: boolean | undefined) => { Doc.AddDocToList(this.props.fieldExtensionDoc, this.props.fieldExt, doc); return true; }} + addDocument={(doc: Doc, allow: boolean | undefined) => { Doc.GetProto(doc).annotationOn = this.props.Document; Doc.AddDocToList(this.props.fieldExtensionDoc, this.props.fieldExt, doc); return true; }} CollectionView={this.props.ContainingCollectionView} ScreenToLocalTransform={this.scrollXf} ruleProvider={undefined} diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index de3242d32..daf000dc7 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -63,13 +63,11 @@ export class PresElementBox extends React.Component { this.hideTillShownButton = !this.hideTillShownButton; if (!this.hideTillShownButton) { if (this.myIndex >= this.currentIndex) { - (this.props.Document.target as Doc).opacity = 1; + (this.props.Document.presentationTargetDoc as Doc).opacity = 1; } } else { - if (this.presentationDoc.presStatus) { - if (this.myIndex > this.currentIndex) { - (this.props.Document.target as Doc).opacity = 0; - } + if (this.presentationDoc.presStatus && this.myIndex > this.currentIndex) { + (this.props.Document.presentationTargetDoc as Doc).opacity = 0; } } } @@ -85,14 +83,12 @@ export class PresElementBox extends React.Component { this.hideAfterButton = !this.hideAfterButton; if (!this.hideAfterButton) { if (this.myIndex <= this.currentIndex) { - (this.props.Document.target as Doc).opacity = 1; + (this.props.Document.presentationTargetDoc as Doc).opacity = 1; } } else { if (this.fadeButton) this.fadeButton = false; - if (this.presentationDoc.presStatus) { - if (this.myIndex < this.currentIndex) { - (this.props.Document.target as Doc).opacity = 0; - } + if (this.presentationDoc.presStatus && this.myIndex < this.currentIndex) { + (this.props.Document.presentationTargetDoc as Doc).opacity = 0; } } } @@ -108,14 +104,12 @@ export class PresElementBox extends React.Component { this.fadeButton = !this.fadeButton; if (!this.fadeButton) { if (this.myIndex <= this.currentIndex) { - (this.props.Document.target as Doc).opacity = 1; + (this.props.Document.presentationTargetDoc as Doc).opacity = 1; } } else { this.hideAfterButton = false; - if (this.presentationDoc.presStatus) { - if (this.myIndex < this.currentIndex) { - (this.props.Document.target as Doc).opacity = 0.5; - } + if (this.presentationDoc.presStatus && (this.myIndex < this.currentIndex)) { + (this.props.Document.presentationTargetDoc as Doc).opacity = 0.5; } } } @@ -162,7 +156,7 @@ export class PresElementBox extends React.Component { * presentation element. */ renderEmbeddedInline = () => { - if (!this.embedOpen || !(this.props.Document.target instanceof Doc)) { + if (!this.embedOpen || !(this.props.Document.presentationTargetDoc instanceof Doc)) { return (null); } @@ -175,8 +169,8 @@ export class PresElementBox extends React.Component { width: propDocWidth === 0 ? "auto" : propDocWidth * scale(), }}> { let pbi = "presElementBox-interaction"; return (
{ p.focus(p.Document); e.stopPropagation(); }}> {treecontainer ? (null) : <> diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index aeffc81c4..58304cebb 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -665,10 +665,12 @@ export namespace Doc { export function BrushDoc(doc: Doc) { brushManager.BrushedDoc.set(doc, true); brushManager.BrushedDoc.set(Doc.GetDataDoc(doc), true); + return doc; } export function UnBrushDoc(doc: Doc) { brushManager.BrushedDoc.delete(doc); brushManager.BrushedDoc.delete(Doc.GetDataDoc(doc)); + return doc; } export class HighlightBrush { -- cgit v1.2.3-70-g09d2 From 9505eda799fdf3b0cd2e6bde2d80c18731caee2c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 10 Oct 2019 21:36:26 -0400 Subject: switching sidebar to a stacking view... --- src/client/views/DocComponent.tsx | 3 ++- src/client/views/collections/CollectionDockingView.tsx | 16 +++++++++------- src/client/views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 6 ++++-- src/server/authentication/models/current_user_utils.ts | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 93e852bef..2c5992259 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -21,7 +21,8 @@ interface DocAnnotatableProps { fieldKey: string; fieldExt: string; whenActiveChanged: (isActive: boolean) => void; - isSelected: () => boolean, renderDepth: number + isSelected: () => boolean; + renderDepth: number; } export function DocAnnotatableComponent

(schemaCtor: (doc: Doc) => T) { class Component extends React.Component

{ diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index fe805a980..1f78c8c97 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -37,7 +37,8 @@ const _global = (window /* browser */ || global /* node */) as any; @observer export class CollectionDockingView extends React.Component { - @observable public static Instance: CollectionDockingView; + @observable public static Instances: CollectionDockingView[] = []; + @computed public static get Instance() { return CollectionDockingView.Instances[0]; } public static makeDocumentConfig(document: Doc, dataDoc: Doc | undefined, width?: number) { return { type: 'react-component', @@ -65,7 +66,7 @@ export class CollectionDockingView extends React.Component CollectionDockingView.Instance = this); + runInAction(() => !CollectionDockingView.Instances ? CollectionDockingView.Instances = [this] : CollectionDockingView.Instances.push(this)); //Why is this here? (window as any).React = React; (window as any).ReactDOM = ReactDOM; @@ -317,13 +318,14 @@ export class CollectionDockingView extends React.Component this._goldenLayout = null); + this._goldenLayout && this._goldenLayout.destroy(); + runInAction(() => { + CollectionDockingView.Instances.splice(CollectionDockingView.Instances.indexOf(this), 1); + this._goldenLayout = null; + }); window.removeEventListener('resize', this.onResize); - if (this.reactionDisposer) { - this.reactionDisposer(); - } + this.reactionDisposer && this.reactionDisposer(); } @action onResize = (event: any) => { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0dfd1d9cf..57722b9b7 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -197,7 +197,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { if (!(d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(d[WidthSym](), wid); return wid * aspect; } - return d.fitWidth ? Math.min(wid * NumCast(d.scrollHeight, NumCast(d.nativeHeight)) / NumCast(d.nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : d[HeightSym](); + return d.fitWidth ? !d.nativeHeight ? this.props.PanelHeight() - 2 * this.yMargin : Math.min(wid * NumCast(d.scrollHeight, NumCast(d.nativeHeight)) / NumCast(d.nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : d[HeightSym](); } columnDividerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 882a0f144..37eb151b1 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -28,6 +28,7 @@ import { CollectionSchemaPreview } from './CollectionSchemaView'; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import React = require("react"); +import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; export interface TreeViewProps { @@ -198,6 +199,7 @@ class TreeView extends React.Component { } else { ContextMenu.Instance.addItem({ description: "Open as Workspace", event: () => MainView.Instance.openWorkspace(this.dataDoc), icon: "caret-square-right" }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" }); + ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" }); } ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.Create.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" }); ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" }); @@ -217,7 +219,7 @@ class TreeView extends React.Component { if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.document; - DocUtils.MakeLink({doc:sourceDoc}, {doc:destDoc}); + DocUtils.MakeLink({ doc: sourceDoc }, { doc: destDoc }); e.stopPropagation(); } if (de.data instanceof DragManager.DocumentDragData) { @@ -538,7 +540,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout - if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { + if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.workspaces) { ContextMenu.Instance.addItem({ description: "Create Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.remove(this.props.Document), icon: "minus" }); e.stopPropagation(); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 0fbfbf2f3..f3d5555ed 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -99,7 +99,7 @@ export class CurrentUserUtils { } if (doc.sidebar === undefined) { - const sidebar = Docs.Create.StackingDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" }); + const sidebar = Docs.Create.TreeDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" }); sidebar.forceActive = true; sidebar.lockedPosition = true; sidebar.gridGap = 5; -- cgit v1.2.3-70-g09d2 From a73a72586c72cd620c16dd7bc0baad88c8e49a34 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 11 Oct 2019 01:38:48 -0400 Subject: switching search around to left-hand side. --- src/client/documents/DocumentTypes.ts | 3 +- src/client/documents/Documents.ts | 10 +++++ src/client/views/GlobalKeyHandler.ts | 4 ++ src/client/views/MainView.tsx | 10 +++-- .../views/collections/CollectionTreeView.tsx | 5 ++- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/QueryBox.scss | 0 src/client/views/nodes/QueryBox.tsx | 50 ++++++++++++++++++++++ src/client/views/search/FilterBox.tsx | 4 +- src/client/views/search/IconBar.tsx | 14 ------ src/client/views/search/SearchBox.scss | 17 ++++++-- src/client/views/search/SearchBox.tsx | 2 - src/client/views/search/SearchItem.scss | 39 +++++++---------- src/client/views/search/SearchItem.tsx | 19 +++----- .../authentication/models/current_user_utils.ts | 6 +++ 15 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 src/client/views/nodes/QueryBox.scss create mode 100644 src/client/views/nodes/QueryBox.tsx (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index e5d5885cd..7abaa4043 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -20,5 +20,6 @@ export enum DocumentType { DRAGBOX = "dragbox", PRES = "presentation", LINKFOLLOW = "linkfollow", - PRESELEMENT = "preselement" + PRESELEMENT = "preselement", + QUERY = "search", } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0114f82d8..7f6ab50d8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -45,6 +45,7 @@ import { ProxyField } from "../../new_fields/Proxy"; import { DocumentType } from "./DocumentTypes"; import { LinkFollowBox } from "../views/linking/LinkFollowBox"; import { PresElementBox } from "../views/presentationview/PresElementBox"; +import { QueryBox } from "../views/nodes/QueryBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -62,6 +63,7 @@ export interface DocumentOptions { panY?: number; page?: number; scale?: number; + fitWidth?: boolean; layout?: string | Doc; isTemplate?: boolean; templates?: List; @@ -119,6 +121,10 @@ export namespace Docs { layout: { view: HistogramBox, collectionView: [CollectionView, data] as CollectionViewType }, options: { height: 300, backgroundColor: "black" } }], + [DocumentType.QUERY, { + layout: { view: QueryBox }, + options: { width: 400, fitWidth: true } + }], [DocumentType.IMG, { layout: { view: ImageBox, ext: anno }, options: {} @@ -374,6 +380,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.HIST), new HistogramField(histoOp), options); } + export function QueryDocument(options: DocumentOptions = {}) { + return InstanceFromProto(Prototypes.get(DocumentType.QUERY), "", options); + } + export function TextDocument(options: DocumentOptions = {}) { return InstanceFromProto(Prototypes.get(DocumentType.TEXT), "", options); } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c519991a5..6815ff926 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -7,6 +7,8 @@ import { action, runInAction } from "mobx"; import { Doc } from "../../new_fields/Doc"; import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { Cast, PromiseValue } from "../../new_fields/Types"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -162,6 +164,8 @@ export default class KeyManager { break; case "f": MainView.Instance.isSearchVisible = !MainView.Instance.isSearchVisible; + MainView.Instance.flyoutWidth = MainView.Instance.isSearchVisible ? 400 : 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.searchBox, Doc)).then(pv => pv && (pv.treeViewOpen = (MainView.Instance.flyoutWidth > 0))); break; case "o": let target = SelectionManager.SelectedDocuments()[0]; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ba4224875..1ec21f638 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -12,7 +12,7 @@ import { Id } from '../../new_fields/FieldSymbols'; import { InkTool } from '../../new_fields/InkField'; import { List } from '../../new_fields/List'; import { listSpec } from '../../new_fields/Schema'; -import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { BoolCast, Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; @@ -463,7 +463,7 @@ export class MainView extends React.Component { return (null); } return

: null, + //this.isSearchVisible ?
: null, ]; } @@ -648,7 +648,9 @@ export class MainView extends React.Component { @observable isSearchVisible = false; @action.bound toggleSearch = () => { - this.isSearchVisible = !this.isSearchVisible; + this.isSearchVisible = !MainView.Instance.isSearchVisible; + MainView.Instance.flyoutWidth = MainView.Instance.isSearchVisible ? 400 : 0; + PromiseValue(Cast(CurrentUserUtils.UserDocument.searchBox, Doc)).then(pv => pv && (pv.treeViewOpen = (MainView.Instance.flyoutWidth > 0))); } @computed private get dictationOverlay() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 37eb151b1..6f5587b5a 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -260,7 +260,10 @@ class TreeView extends React.Component { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); if (aspect) return this.docWidth() * aspect; if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x); - return NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50; + return this.props.document.fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection.height) : + Math.min(this.docWidth() * NumCast(this.props.document.scrollHeight, NumCast(this.props.document.nativeHeight)) / NumCast(this.props.document.nativeWidth, + NumCast(this.props.containingCollection.height)))) : + NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50; })()); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index e4b2ecffd..d4e7c6d4e 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,6 +24,7 @@ import { ImageBox } from "./ImageBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { PresBox } from "./PresBox"; +import { QueryBox } from "./QueryBox"; import { PresElementBox } from "../presentationview/PresElementBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; @@ -99,7 +100,7 @@ export class DocumentContentsView extends React.Component { + public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(QueryBox, fieldKey); } + _docListChangedReaction: IReactionDisposer | undefined; + componentDidMount() { + } + + componentWillUnmount() { + this._docListChangedReaction && this._docListChangedReaction(); + } + + render() { + return
+ +
+ } +} \ No newline at end of file diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index da733d64b..b841190d4 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -33,7 +33,7 @@ export enum Keys { export class FilterBox extends React.Component { static Instance: FilterBox; - public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.HIST, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB]; + public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB]; //if true, any keywords can be used. if false, all keywords are required. //this also serves as an indicator if the word status filter is applied @@ -393,7 +393,7 @@ export class FilterBox extends React.Component {
- {this.getActiveFilters()} + {/* {this.getActiveFilters()} */}
{this._filterOpen ? (
diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx index c9924222f..bdeb57d5c 100644 --- a/src/client/views/search/IconBar.tsx +++ b/src/client/views/search/IconBar.tsx @@ -59,23 +59,9 @@ export class IconBar extends React.Component { render() { return (
-
-
- -
-
Select All
-
{FilterBox.Instance._allIcons.map((type: string) => )} -
-
- -
-
Clear
-
); } diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss index 0dd4d3dc5..bc11604a5 100644 --- a/src/client/views/search/SearchBox.scss +++ b/src/client/views/search/SearchBox.scss @@ -1,6 +1,15 @@ @import "../globalCssVariables"; @import "./NaviconButton.scss"; +.searchBox-container { + display: flex; + flex-direction: column; + width:100%; + height:100%; + position: absolute; + font-size: 10px; + line-height: 1; +} .searchBox-bar { height: 32px; display: flex; @@ -49,17 +58,17 @@ } .searchBox-quickFilter { - width: 500px; - margin-left: 25px; + width: 100%; + height: 40px; margin-top: 10px; } .searchBox-results { - margin-right: 136px; + display:flex; + flex-direction: column; top: 300px; display: flex; flex-direction: column; - margin-right: 72px; // height: 560px; height: 100%; // overflow: hidden; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index be75a29e0..62c8c255e 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -346,8 +346,6 @@ export class SearchBox extends React.Component { className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter} onFocus={this.openSearch} style={{ width: this._searchbarOpen ? "500px" : "100px" }} /> - -
{(this._numTotalResults > 0 || !this._searchbarOpen) ? (null) : (
diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss index 62715c5eb..9f12994c3 100644 --- a/src/client/views/search/SearchItem.scss +++ b/src/client/views/search/SearchItem.scss @@ -2,19 +2,27 @@ .search-overview { display: flex; - flex-direction: row-reverse; + flex-direction: reverse; justify-content: flex-end; z-index: 0; } +.link-count { + background: black; + border-radius: 20px; + color: white; + width: 15px; + text-align: center; + margin-top: 5px; +} .searchBox-placeholder, .search-overview .search-item { - width: 500px; + width: 100%; background: $light-color-secondary; border-color: $intermediate-color; border-bottom-style: solid; padding: 10px; - min-height: 70px; + min-height: 50px; max-height: 150px; height: auto; z-index: 0; @@ -61,16 +69,6 @@ overflow: hidden; position: relative; - .link-count { - opacity: 1; - position: absolute; - z-index: 1000; - text-align: center; - -webkit-transition: opacity 0.2s ease-in-out; - -moz-transition: opacity 0.2s ease-in-out; - -o-transition: opacity 0.2s ease-in-out; - transition: opacity 0.2s ease-in-out; - } .link-extended { // display: none; @@ -112,7 +110,7 @@ .icon-icons, .icon-live { - height: 50px; + height: auto; margin: auto; overflow: hidden; @@ -174,9 +172,7 @@ .searchBox-instances:active { opacity: 1; background: $lighter-alt-accent; - -webkit-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); + width:150px } .search-item:hover { @@ -193,13 +189,10 @@ .searchBox-instances { float: left; opacity: 1; - width: 150px; + width: 0px; transition: all 0.2s ease; color: black; - transform-origin: top right; - -webkit-transform: scale(0); - -ms-transform: scale(0); - transform: scale(0); + overflow: hidden; } @@ -208,7 +201,7 @@ } .searchBox-placeholder { - min-height: 70px; + min-height: 50px; margin-left: 150px; text-transform: uppercase; text-align: left; diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index a7822ed46..b8cff16f2 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -213,15 +213,6 @@ export class SearchItem extends React.Component { @computed get linkCount() { return LinkManager.Instance.getAllRelatedLinks(this.props.doc).length; } - @computed - get linkString(): string { - let num = this.linkCount; - if (num === 1) { - return num.toString() + " link"; - } - return num.toString() + " links"; - } - @action pointerDown = (e: React.PointerEvent) => { e.preventDefault(); e.button === 0 && SearchBox.Instance.openSearch(e); } @@ -290,7 +281,11 @@ export class SearchItem extends React.Component {
-
+
+
+
{this.linkCount}
+
+
{StrCast(this.props.doc.title)}
{this.props.highlighting.length ? "Matched fields:" + this.props.highlighting.join(", ") : this.props.lines.length ? this.props.lines[0] : ""}
@@ -301,10 +296,6 @@ export class SearchItem extends React.Component {
{this.DocumentIcon()}
{this.props.doc.type ? this.props.doc.type : "Other"}
-
-
{this.linkCount}
-
{this.linkString}
-
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index f3d5555ed..32da29932 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -97,6 +97,12 @@ export class CurrentUserUtils { curPresentation.boxShadow = "0 0"; doc.curPresentation = curPresentation; } + if (doc.searchBox === undefined) { + const searchBox = Docs.Create.QueryDocument({ title: "Searching" }); + searchBox.boxShadow = "0 0"; + searchBox.ignoreClick = true; + doc.searchBox = searchBox; + } if (doc.sidebar === undefined) { const sidebar = Docs.Create.TreeDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" }); -- cgit v1.2.3-70-g09d2 From c03012fe8c9b77ddf3b7e6c589339eb9a0d967e6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 12 Oct 2019 01:33:20 -0400 Subject: working version of new docked sidebar + configurable bottom buttons by drag/drop --- src/client/views/GlobalKeyHandler.ts | 18 ++- src/client/views/Main.scss | 13 +- src/client/views/MainView.tsx | 157 ++++++++++----------- .../views/collections/CollectionTreeView.tsx | 2 +- .../nodes/CollectionFreeFormDocumentView.scss | 2 + src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/DragBox.tsx | 12 +- src/client/views/nodes/PDFBox.tsx | 2 +- .../authentication/models/current_user_utils.ts | 45 +++--- 9 files changed, 126 insertions(+), 126 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 9d239d0bf..82f5a573c 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -164,29 +164,27 @@ export default class KeyManager { } break; case "c": - if (MainView.Instance.flyoutWidth > 0) { + PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + if (MainView.Instance.flyoutWidth === 75) { MainView.Instance.flyoutWidth = 0; - PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); } else { - MainView.Instance.flyoutWidth = 400; - PromiseValue(Cast(CurrentUserUtils.UserDocument.Create, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + MainView.Instance.flyoutWidth = 75; } break; case "l": - if (MainView.Instance.flyoutWidth > 0) { + PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + if (MainView.Instance.flyoutWidth === 250) { MainView.Instance.flyoutWidth = 0; } else { - MainView.Instance.flyoutWidth = 400; - PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + MainView.Instance.flyoutWidth = 250; } break; case "f": - if (MainView.Instance.flyoutWidth > 0) { + PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); + if (MainView.Instance.flyoutWidth === 400) { MainView.Instance.flyoutWidth = 0; - PromiseValue(Cast(CurrentUserUtils.UserDocument.Library, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); } else { MainView.Instance.flyoutWidth = 400; - PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); } break; case "o": diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 4cd860da2..705da7b35 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -211,14 +211,21 @@ button:hover { } #add-options-content { - display: table; + display: flex; opacity: 1; margin: 0; padding: 0; position: relative; float: right; - bottom: 0.3em; - margin-bottom: -1.68em; + .mainView-docBtn { + position:relative; + margin-right: 10px; + width: 35px; + height: 35px; + } + .collectionFreeFormDocumentView-container { + position: relative; + } } ul#add-options-list { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 6f60de1c4..1fa231659 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,5 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faUndoAlt, faTv, faChevronRight, faEllipsisV } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -12,15 +12,16 @@ import { Id } from '../../new_fields/FieldSymbols'; import { InkTool } from '../../new_fields/InkField'; import { List } from '../../new_fields/List'; import { listSpec } from '../../new_fields/Schema'; -import { BoolCast, Cast, FieldValue, StrCast, PromiseValue } from '../../new_fields/Types'; +import { ScriptField } from '../../new_fields/ScriptField'; +import { BoolCast, Cast, FieldValue, PromiseValue, StrCast, NumCast } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnEmptyString, returnOne, returnTrue, returnFalse, Utils } from '../../Utils'; +import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; +import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; -import { ClientUtils } from '../util/ClientUtils'; import { DictationManager } from '../util/DictationManager'; -import { SetupDrag } from '../util/DragManager'; +import { SetupDrag, DragManager } from '../util/DragManager'; import { HistoryUtil } from '../util/History'; import SharingManager from '../util/SharingManager'; import { Transform } from '../util/Transform'; @@ -35,13 +36,10 @@ import { InkingControl } from './InkingControl'; import "./Main.scss"; import MainViewModal from './MainViewModal'; import { DocumentView } from './nodes/DocumentView'; +import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; -import { FilterBox } from './search/FilterBox'; -import { OverlayView } from './OverlayView'; -import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; -import { CollectionStackingView } from './collections/CollectionStackingView'; -import { ScriptField } from '../../new_fields/ScriptField'; +import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; @observer export class MainView extends React.Component { @@ -49,6 +47,7 @@ export class MainView extends React.Component { @observable addMenuToggle = React.createRef(); @observable public pwidth: number = 0; @observable public pheight: number = 0; + private dropDisposer?: DragManager.DragDropDisposer; @observable private dictationState = DictationManager.placeholder; @observable private dictationSuccessState: boolean | undefined = undefined; @@ -164,6 +163,7 @@ export class MainView extends React.Component { //close presentation window.removeEventListener("pointerdown", this.globalPointerDown); window.removeEventListener("pointerup", this.globalPointerUp); + this.dropDisposer && this.dropDisposer(); } constructor(props: Readonly<{}>) { @@ -287,18 +287,15 @@ export class MainView extends React.Component { let workspaces: FieldResult; let freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc, freeformDoc, 600)] }] }; - let mainDoc = Docs.Create.DockDocument([this.userDoc, freeformDoc], JSON.stringify(dockingLayout), {}, id); + let mainDoc = Docs.Create.DockDocument([freeformDoc], JSON.stringify(dockingLayout), {}, id); if (this.userDoc && ((workspaces = Cast(this.userDoc.workspaces, Doc)) instanceof Doc)) { - const list = Cast((workspaces).data, listSpec(Doc)); - if (list) { - if (!this.userDoc.linkManagerDoc) { - let linkManagerDoc = new Doc(); - linkManagerDoc.allLinks = new List([]); - this.userDoc.linkManagerDoc = linkManagerDoc; - } - list.push(mainDoc); - mainDoc.title = `Workspace ${list.length}`; + if (!this.userDoc.linkManagerDoc) { + let linkManagerDoc = new Doc(); + linkManagerDoc.allLinks = new List([]); + this.userDoc.linkManagerDoc = linkManagerDoc; } + Doc.AddDocToList(workspaces, "data", mainDoc); + mainDoc.title = `Workspace ${DocListCast(workspaces.data).length}`; } // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => { @@ -350,6 +347,10 @@ export class MainView extends React.Component { return true; } + drop = action((e: Event, de: DragManager.DropEvent) => { + (de.data as DragManager.DocumentDragData).draggedDocuments.map(doc => Doc.AddDocToList(CurrentUserUtils.UserDocument, "docButtons", doc)); + }) + onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -460,13 +461,14 @@ export class MainView extends React.Component { } @computed get flyout() { - let sidebar: FieldResult; - if (!this.userDoc || !((sidebar = this.userDoc.sidebarContainer) instanceof Doc)) { + let sidebarContent = this.userDoc && this.userDoc.sidebarContainer; + if (!(sidebarContent instanceof Doc)) { return (null); } (Cast(CurrentUserUtils.UserDocument.libraryButtons, Doc) as Doc).columnWidth = this.flyoutWidthFunc() / 3 - 30; + let buttonBarHeight = 85; return
-
+
-
+
{ //used for stacking and masonry view + this.dropDisposer && this.dropDisposer(); + if (ele) { + this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); + } + } @observable private _colorPickerDisplay = false; /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */ nodesMenu() { - let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; - - let addColNode = action(() => Docs.Create.FreeformDocument([], { width: this.pwidth * .7, height: this.pheight, title: "a freeform collection" })); - let addPresNode = action(() => Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { width: 200, height: 500, title: "a presentation trail" })); - let addWebNode = action(() => Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", { width: 300, height: 300, title: "New Webpage" })); - let addDragboxNode = action(() => Docs.Create.DragboxDocument({ width: 40, height: 40, title: "drag collection" })); - let addImageNode = action(() => Docs.Create.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addButtonDocument = action(() => Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })); - let addImportCollectionNode = action(() => Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })); // let youtubeurl = "https://www.youtube.com/embed/TqcApsGRzWw"; // let addYoutubeSearcher = action(() => Docs.Create.YoutubeDocument(youtubeurl, { width: 600, height: 600, title: "youtube search" })); // let googlePhotosSearch = () => GooglePhotosClientUtils.CollectionFromSearch(Docs.Create.MasonryDocument, { included: [GooglePhotosClientUtils.ContentCategories.LANDSCAPES] }); - let btns: [React.RefObject, IconName, string, () => Doc | Promise][] = [ - //[React.createRef(), "object-group", "Add Collection", addColNode], - //[React.createRef(), "tv", "Add Presentation Trail", addPresNode], - //[React.createRef(), "globe-asia", "Add Website", addWebNode], - //[React.createRef(), "bolt", "Add Button", addButtonDocument], - //[React.createRef(), "file", "Add Document Dragger", addDragboxNode], - // [React.createRef(), "object-group", "Test Google Photos Search", googlePhotosSearch], - //[React.createRef(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], //remove at some point in favor of addImportCollectionNode - //[React.createRef(), "play", "Add Youtube Searcher", addYoutubeSearcher], - ]; - //if (!ClientUtils.RELEASE) btns.unshift([React.createRef(), "cat", "Add Cat Image", addImageNode]); - return < div id="add-nodes-menu" style={{ left: (this.flyoutTranslate ? this.flyoutWidth : 0) + 20, bottom: 20 }} > - +
-
    - {/*
  • */} -
  • -
  • - {btns.map(btn => -
  • - -
  • )} - {/*
  • */} -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
+ {/*
  • */} + + + + {DocListCast(CurrentUserUtils.UserDocument.docButtons).map(doc =>
    + 35 / NumCast(doc.nativeWidth, 35)} + PanelWidth={() => 35} + PanelHeight={() => 35} + renderDepth={0} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + zoomToScale={emptyFunction} + getScale={returnOne}> + +
    )} + {/*
  • */} + + + + + + +
    ; } @@ -668,16 +674,6 @@ export class MainView extends React.Component { this._colorPickerDisplay = close ? false : !this._colorPickerDisplay; } - /* @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() { - return [ - //this.isSearchVisible ?
    : null, - ]; - - } - - @observable isSearchVisible = false; @action.bound toggleSearch = () => { PromiseValue(Cast(CurrentUserUtils.UserDocument.Search, Doc)).then(pv => pv && (pv.onClick as ScriptField).script.run({ this: pv })); @@ -716,7 +712,6 @@ export class MainView extends React.Component { {this.nodesMenu()} - {this.miscButtons}
    diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 6f5587b5a..a325e86c6 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -188,7 +188,7 @@ class TreeView extends React.Component { onWorkspaceContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) { + if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking && this.props.document !== CurrentUserUtils.UserDocument.workspaces) { ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" }); ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" }); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss index c0d9e1267..af9232c2f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss @@ -2,4 +2,6 @@ transform-origin: left top; position: absolute; background-color: transparent; + top:0; + left:0; } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 758222e52..20920a9b8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -614,6 +614,7 @@ export class DocumentView extends DocComponent(Docu DataDoc={this.props.DataDoc} />); } render() { + if (!this.props.Document) return (null); let animDims = this.props.Document.animateToDimensions ? Array.from(Cast(this.props.Document.animateToDimensions, listSpec("number"))!) : undefined; 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; diff --git a/src/client/views/nodes/DragBox.tsx b/src/client/views/nodes/DragBox.tsx index 8429382e3..ab3368b94 100644 --- a/src/client/views/nodes/DragBox.tsx +++ b/src/client/views/nodes/DragBox.tsx @@ -51,9 +51,15 @@ 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 }).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); + DragManager.StartDocumentDrag([this._mainCont.current!], new DragManager.DocumentDragData([this.props.Document]), e.clientX, e.clientY, { + finishDrag: (dropData) => { + 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" }); + dropData.droppedDocuments = [doc]; + }, + handlers: { dragComplete: emptyFunction }, + hideSource: false + }); } e.stopPropagation(); e.preventDefault(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 02a82e0ed..63b412a23 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -93,7 +93,7 @@ export class PDFBox extends DocAnnotatableComponent if (e.key === "PageUp" || e.key === "ArrowUp" || e.key === "ArrowLeft") { this.backPage(); } - }) + }); @undoBatch @action diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index e1bb91838..7408fd92b 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -127,46 +127,38 @@ export class CurrentUserUtils { Search.targetContainer = doc.sidebarContainer; Search.onClick = ScriptField.MakeScript("this.targetContainer.proto = this.searchBox"); - let createCollection = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Collection", icon: "folder" }); - let createWebPage = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Web Page", icon: "globe-asia" }); + let createCollection = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Collection", icon: "folder" }); + let createWebPage = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Web Page", icon: "globe-asia" }); createWebPage.onDragStart = ScriptField.MakeFunction('Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", { width: 300, height: 300, title: "New Webpage" })'); - let createCatImage = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Image", icon: "cat" }); + let createCatImage = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Image", icon: "cat" }); createCatImage.onDragStart = ScriptField.MakeFunction('Docs.Create.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })'); - let createButton = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Button", icon: "bolt" }); + let createButton = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Button", icon: "bolt" }); createButton.onDragStart = ScriptField.MakeFunction('Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })'); - let createPresentation = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Presentation", icon: "tv" }); + let createPresentation = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Presentation", icon: "tv" }); createPresentation.onDragStart = ScriptField.MakeFunction('Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { width: 200, height: 500, title: "a presentation trail" })'); - let createFolderImport = Docs.Create.DragboxDocument({ width: 35, height: 35, title: "Import Folder", icon: "cloud-upload-alt" }); + let createFolderImport = Docs.Create.DragboxDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Import Folder", icon: "cloud-upload-alt" }); createFolderImport.onDragStart = ScriptField.MakeFunction('Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })'); const creators = Docs.Create.MasonryDocument([createCollection, createWebPage, createCatImage, createButton, createPresentation, createFolderImport], { width: 500, height: 50, columnWidth: 35, chromeStatus: "disabled", title: "buttons" }); Create.targetContainer = doc.sidebarContainer; Create.creators = creators; Create.onClick = ScriptField.MakeScript("this.targetContainer.proto = this.creators"); - const buttons = Docs.Create.StackingDocument([Search, Library, Create], { width: 500, height: 80, chromeStatus: "disabled", title: "buttons" }); - buttons.sectionFilter = "title"; - buttons.boxShadow = "0 0"; - buttons.ignoreClick = true; - buttons.hideHeadings = true; - doc.libraryButtons = buttons; + const libraryButtons = Docs.Create.StackingDocument([Search, Library, Create], { width: 500, height: 80, chromeStatus: "disabled", title: "buttons" }); + libraryButtons.sectionFilter = "title"; + libraryButtons.boxShadow = "0 0"; + libraryButtons.ignoreClick = true; + libraryButtons.hideHeadings = true; + libraryButtons.backgroundColor = "lightgrey"; + doc.libraryButtons = libraryButtons; doc.Library = Library; doc.Create = Create; doc.Search = Search; - (Library.onClick as ScriptField).script.run({ this: Library }); - //(doc.sidebarContainer as Doc).proto = library; } - PromiseValue(Cast(doc.libraryButtons, Doc)).then(libraryButtons => { - if (libraryButtons) { - libraryButtons.backgroundColor = "lightgrey"; - } - }); - - PromiseValue(Cast(doc.sidebar, Doc)).then(sidebar => { - if (sidebar) { - sidebar.backgroundColor = "lightgrey"; - } - }); + PromiseValue(Cast(doc.libraryButtons, Doc)).then(libraryButtons => { }); + PromiseValue(Cast(doc.Library, Doc)).then(library => library && library.library && library.targetContainer && (library.onClick as ScriptField).script.run({ this: library })); + PromiseValue(Cast(doc.Create, Doc)).then(async create => create && create.creators && create.targetContainer); + PromiseValue(Cast(doc.Search, Doc)).then(async search => search && search.searchBox && search.targetContainer); if (doc.overlays === undefined) { const overlays = Docs.Create.FreeformDocument([], { title: "Overlays" }); @@ -178,8 +170,7 @@ export class CurrentUserUtils { PromiseValue(Cast(doc.overlays, Doc)).then(overlays => overlays && Doc.AddDocToList(overlays, "data", doc.linkFollowBox = Docs.Create.LinkFollowBoxDocument({ x: 250, y: 20, width: 500, height: 370, title: "Link Follower" }))); } - StrCast(doc.title).indexOf("@") !== -1 && (doc.title = (StrCast(doc.title).split("@")[0] + "'s Library").toUpperCase()); - StrCast(doc.title).indexOf("'s Library") !== -1 && (doc.title = StrCast(doc.title).toUpperCase()); + doc.title = "DOCUMENTS"; doc.backgroundColor = "#eeeeee"; doc.width = 100; doc.preventTreeViewOpen = true; -- cgit v1.2.3-70-g09d2 From 34a8b9dd402a247e7ad0a57115935b1e3a04a8d3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 12 Oct 2019 12:25:02 -0400 Subject: cleaned up notifs and bottom menu icons --- src/client/views/Main.scss | 21 +++----- src/client/views/MainView.tsx | 57 +++++++++------------- src/client/views/MainViewNotifs.scss | 18 +++++++ src/client/views/MainViewNotifs.tsx | 32 ++++++++++++ .../views/collections/CollectionTreeView.tsx | 26 +--------- .../authentication/models/current_user_utils.ts | 1 - 6 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 src/client/views/MainViewNotifs.scss create mode 100644 src/client/views/MainViewNotifs.tsx (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 705da7b35..debb941c8 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -93,21 +93,6 @@ button:hover { right: 0px; } -.main-notifs-badge { - position: absolute; - top: -10px; - right: -10px; - color: white; - background: #f44b42; - font-weight: 300; - border-radius: 100%; - width: 25px; - height: 25px; - text-align: center; - padding-top: 4px; - font-size: 12px; -} - //toolbar stuff #toolbar { position: absolute; @@ -237,6 +222,12 @@ ul#add-options-list { padding: 0; } } +.mainView-logout { + position: absolute; + right: 0; + bottom: 0; + font-size: 8px; +} .mainView-libraryFlyout { height: 100%; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1fa231659..e8ffa5987 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -16,7 +16,7 @@ import { ScriptField } from '../../new_fields/ScriptField'; import { BoolCast, Cast, FieldValue, PromiseValue, StrCast, NumCast } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; +import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; @@ -40,6 +40,7 @@ import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView'; +import { MainViewNotifs } from './MainViewNotifs'; @observer export class MainView extends React.Component { @@ -47,6 +48,7 @@ export class MainView extends React.Component { @observable addMenuToggle = React.createRef(); @observable public pwidth: number = 0; @observable public pheight: number = 0; + private _buttonBarHeight = 85; private dropDisposer?: DragManager.DragDropDisposer; @observable private dictationState = DictationManager.placeholder; @@ -138,24 +140,6 @@ export class MainView extends React.Component { firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); window.removeEventListener("keydown", KeyManager.Instance.handle); window.addEventListener("keydown", KeyManager.Instance.handle); - - if (this.userDoc) { - reaction(() => { - let workspaces = this.userDoc.workspaces; - let recent = this.userDoc.recentlyClosed; - if (!(recent instanceof Doc)) return 0; - if (!(workspaces instanceof Doc)) return 0; - let workspacesDoc = workspaces; - let recentDoc = recent; - let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 20 + this.userDoc[HeightSym]() * 0.00001; - return libraryHeight; - }, (libraryHeight: number) => { - if (libraryHeight && Math.abs(this.userDoc[HeightSym]() - libraryHeight) > 5) { - this.userDoc.height = libraryHeight; - } - (Cast(this.userDoc.recentlyClosed, Doc) as Doc).allowClear = true; - }, { fireImmediately: true }); - } } componentWillUnMount() { @@ -340,7 +324,7 @@ export class MainView extends React.Component { if (this.userDoc && (col = await Cast(this.userDoc.optionalRightCollection, Doc))) { const l = Cast(col.data, listSpec(Doc)); if (l) { - runInAction(() => CollectionTreeView.NotifsCol = col); + runInAction(() => MainViewNotifs.NotifsCol = col); } } }, 100); @@ -349,7 +333,7 @@ export class MainView extends React.Component { drop = action((e: Event, de: DragManager.DropEvent) => { (de.data as DragManager.DocumentDragData).draggedDocuments.map(doc => Doc.AddDocToList(CurrentUserUtils.UserDocument, "docButtons", doc)); - }) + }); onDrop = (e: React.DragEvent) => { e.preventDefault(); @@ -368,6 +352,9 @@ export class MainView extends React.Component { getPHeight = () => { return this.pheight; } + getContentsHeight = () => { + return this.pheight - this._buttonBarHeight; + } @observable flyoutWidth: number = 250; @observable flyoutTranslate: boolean = true; @@ -465,12 +452,12 @@ export class MainView extends React.Component { if (!(sidebarContent instanceof Doc)) { return (null); } - (Cast(CurrentUserUtils.UserDocument.libraryButtons, Doc) as Doc).columnWidth = this.flyoutWidthFunc() / 3 - 30; - let buttonBarHeight = 85; + let libraryButtonDoc = Cast(CurrentUserUtils.UserDocument.libraryButtons, Doc) as Doc; + libraryButtonDoc.columnWidth = this.flyoutWidthFunc() / 3 - 30; return
    -
    +
    -
    +
    +
    ; } @computed get mainContent() { - if (!this.userDoc) { - return (
    {this.dockingContent}
    ); - } - let sidebar = this.userDoc.sidebarContainer; - if (!(sidebar instanceof Doc)) { + let sidebar = this.userDoc && this.userDoc.sidebarContainer; + if (!this.userDoc || !(sidebar instanceof Doc)) { return (null); } return ( @@ -617,6 +604,7 @@ export class MainView extends React.Component { return < div id="add-nodes-menu" style={{ left: (this.flyoutTranslate ? this.flyoutWidth : 0) + 20, bottom: 20 }} > + @@ -632,7 +620,7 @@ export class MainView extends React.Component { addDocument={undefined} addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} - removeDocument={undefined} + removeDocument={(doc: Doc) => Doc.RemoveDocFromList(CurrentUserUtils.UserDocument, "docButtons", doc)} ruleProvider={undefined} onClick={undefined} ScreenToLocalTransform={Transform.Identity} @@ -662,7 +650,6 @@ export class MainView extends React.Component { -
    ; } diff --git a/src/client/views/MainViewNotifs.scss b/src/client/views/MainViewNotifs.scss new file mode 100644 index 000000000..25ec95643 --- /dev/null +++ b/src/client/views/MainViewNotifs.scss @@ -0,0 +1,18 @@ +.mainNotifs-container { + position:absolute; + + .mainNotifs-badge { + position: absolute; + top: -10px; + right: -10px; + color: white; + background: #f44b42; + font-weight: 300; + border-radius: 100%; + width: 25px; + height: 25px; + text-align: center; + padding-top: 4px; + font-size: 12px; + } +} \ No newline at end of file diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx new file mode 100644 index 000000000..09fa1cb0c --- /dev/null +++ b/src/client/views/MainViewNotifs.tsx @@ -0,0 +1,32 @@ +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import "normalize.css"; +import * as React from 'react'; +import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; +import { emptyFunction } from '../../Utils'; +import { SetupDrag } from '../util/DragManager'; +import "./MainViewNotifs.scss"; +import { CollectionDockingView } from './collections/CollectionDockingView'; + + +@observer +export class MainViewNotifs extends React.Component { + + @observable static NotifsCol: Opt; + openNotifsCol = () => { + if (MainViewNotifs.NotifsCol) { + CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol, undefined); + } + } + render() { + const length = MainViewNotifs.NotifsCol ? DocListCast(MainViewNotifs.NotifsCol.data).length : 0; + const notifsRef = React.createRef(); + const dragNotifs = action(() => MainViewNotifs.NotifsCol!); + return
    + +
    ; + } +} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a325e86c6..abaa9662c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -517,8 +517,6 @@ export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; - @observable static NotifsCol: Opt; - @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } protected createTreeDropTarget = (ele: HTMLDivElement) => { @@ -557,31 +555,10 @@ export class CollectionTreeView extends CollectionSubView(Document) { } outerXf = () => Utils.GetScreenTransform(this._mainEle!); onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {}); - openNotifsCol = () => { - if (CollectionTreeView.NotifsCol) { - this.props.addDocTab(CollectionTreeView.NotifsCol, undefined, "onRight"); - } - } - @computed get renderNotifsButton() { - const length = CollectionTreeView.NotifsCol ? DocListCast(CollectionTreeView.NotifsCol.data).length : 0; - const notifsRef = React.createRef(); - const dragNotifs = action(() => CollectionTreeView.NotifsCol!); - return
    -
    - -
    0 ? { "display": "initial" } : { "display": "none" }}> - {length} -
    -
    -
    ; - } @computed get renderClearButton() { return
    - @@ -614,7 +591,6 @@ export class CollectionTreeView extends CollectionSubView(Document) { TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false); })} /> - {this.props.Document.workspaceLibrary ? this.renderNotifsButton : (null)} {this.props.Document.allowClear ? this.renderClearButton : (null)}
      { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 7408fd92b..874f49f10 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -115,7 +115,6 @@ export class CurrentUserUtils { library.xMargin = 5; library.yMargin = 5; library.boxShadow = "1 1 3"; - library.workspaceLibrary = true; // flag that this is the document that shows the Notifications button when documents are shared Library.targetContainer = doc.sidebarContainer; Library.library = library; Library.onClick = ScriptField.MakeScript("this.targetContainer.proto = this.library"); -- cgit v1.2.3-70-g09d2 From 8a3cfa8d6e72c9bfea4b38760e0b138b6525574c Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 16 Oct 2019 16:42:37 -0400 Subject: a bunch of fixes to layouts to support templates in paticular. --- src/client/util/DocumentManager.ts | 2 + src/client/util/DragManager.ts | 4 +- src/client/views/CollectionLinearView.tsx | 7 +- src/client/views/DocumentButtonBar.tsx | 3 +- src/client/views/DocumentDecorations.tsx | 47 +++++----- src/client/views/InkingControl.tsx | 9 +- .../views/collections/CollectionStackingView.tsx | 11 ++- .../views/collections/CollectionTreeView.scss | 1 + .../views/collections/CollectionTreeView.tsx | 17 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 63 ++++++------- .../collections/collectionFreeForm/MarqueeView.tsx | 31 ++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 6 +- src/client/views/nodes/FontIconBox.tsx | 5 +- src/client/views/nodes/FormattedTextBox.tsx | 101 +++++++++++---------- src/new_fields/Doc.ts | 11 ++- 16 files changed, 178 insertions(+), 144 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 00de39671..e23ac55c2 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -72,6 +72,8 @@ export class DocumentManager { toReturn = view; } }); + } else { + break; } } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 12e0b11ba..06dab024e 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -211,7 +211,7 @@ export namespace DragManager { offset: number[]; dropAction: dropActionType; userDropAction: dropActionType; - forceUserDropAction: dropActionType; + embedDoc?: boolean; moveDocument?: MoveFunction; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts applyAsTemplate?: boolean; @@ -414,7 +414,7 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { - dragData.userDropAction = dragData.forceUserDropAction ? dragData.forceUserDropAction : e.ctrlKey || e.altKey ? "alias" : undefined; + dragData.userDropAction = e.ctrlKey ? "alias" : undefined; } if (((options && !options.withoutShiftDrag) || !options) && e.shiftKey && CollectionDockingView.Instance) { AbortDrag(); diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index af3b194ea..44d9b042e 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -15,6 +15,7 @@ import { CollectionViewType } from './collections/CollectionBaseView'; import { CollectionSubView } from './collections/CollectionSubView'; import { documentSchema, DocumentView } from './nodes/DocumentView'; import { translate } from 'googleapis/build/src/apis/translate'; +import { DocumentType } from '../documents/DocumentTypes'; type LinearDocument = makeInterface<[typeof documentSchema,]>; @@ -50,8 +51,10 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { (de.data as DragManager.DocumentDragData).draggedDocuments.map((doc, i) => { let dbox = doc; if (!doc.onDragStart && !doc.onClick && this.props.Document.convertToButtons && doc.viewType !== CollectionViewType.Linear) { - dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: "bolt" }); - dbox.dragFactory = doc; + let template = doc.layout instanceof Doc && doc.layout.isTemplate ? doc.layout : doc; + template.isTemplate = (template.type === DocumentType.TEXT || template.layout instanceof Doc) && de.data instanceof DragManager.DocumentDragData && !de.data.userDropAction; + dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: template.isTemplate ? "font" : "bolt" }); + dbox.dragFactory = template; dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); } else if (doc.viewType === CollectionViewType.Linear) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a00a4298f..959b120ed 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -165,7 +165,8 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], let dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0); dragData.offset = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.clientX - left, e.clientY - top); - dragData.forceUserDropAction = "alias"; + dragData.embedDoc = true; + dragData.dropAction = "alias"; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, e.x, e.y, { offsetX: dragData.offset[0], offsetY: dragData.offset[1], diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 755739a11..2f40ea746 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -471,47 +471,48 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.SelectedDocuments().forEach(element => { if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { let doc = PositionDocument(element.props.Document); + let layoutDoc = PositionDocument(element.props.Document.layout instanceof Doc ? element.props.Document.layout : element.props.Document); let nwidth = doc.nativeWidth || 0; let nheight = doc.nativeHeight || 0; - let width = (doc.width || 0); - let height = (doc.height || (nheight / nwidth * width)); + let width = (layoutDoc.width || 0); + let height = (layoutDoc.height || (nheight / nwidth * width)); let scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling(); let actualdW = Math.max(width + (dW * scale), 20); let actualdH = Math.max(height + (dH * scale), 20); - doc.x = (doc.x || 0) + dX * (actualdW - width); - doc.y = (doc.y || 0) + dY * (actualdH - height); + layoutDoc.x = (layoutDoc.x || 0) + dX * (actualdW - width); + layoutDoc.y = (layoutDoc.y || 0) + dY * (actualdH - height); let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... - let fixedAspect = e.ctrlKey || (!doc.ignoreAspect && nwidth && nheight); - if (fixedAspect && e.ctrlKey && doc.ignoreAspect) { - doc.ignoreAspect = false; - proto.nativeWidth = nwidth = doc.width || 0; - proto.nativeHeight = nheight = doc.height || 0; + let fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); + if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { + layoutDoc.ignoreAspect = false; + proto.nativeWidth = nwidth = layoutDoc.width || 0; + proto.nativeHeight = nheight = layoutDoc.height || 0; } if (fixedAspect && (!nwidth || !nheight)) { - proto.nativeWidth = nwidth = doc.width || 0; - proto.nativeHeight = nheight = doc.height || 0; + proto.nativeWidth = nwidth = layoutDoc.width || 0; + proto.nativeHeight = nheight = layoutDoc.height || 0; } - if (nwidth > 0 && nheight > 0 && !BoolCast(doc.ignoreAspect)) { + if (nwidth > 0 && nheight > 0 && !layoutDoc.ignoreAspect) { if (Math.abs(dW) > Math.abs(dH)) { if (!fixedAspect) { - Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true); + Doc.SetInPlace(doc, "nativeWidth", actualdW / (layoutDoc.width || 1) * (layoutDoc.nativeWidth || 0), true); } - doc.width = actualdW; - if (fixedAspect && !doc.fitWidth) doc.height = nheight / nwidth * doc.width; - else doc.height = actualdH; + layoutDoc.width = actualdW; + if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.height = nheight / nwidth * layoutDoc.width; + else layoutDoc.height = actualdH; } else { if (!fixedAspect) { - Doc.SetInPlace(element.props.Document, "nativeHeight", actualdH / (doc.height || 1) * (doc.nativeHeight || 0), true); + Doc.SetInPlace(doc, "nativeHeight", actualdH / (layoutDoc.height || 1) * (doc.nativeHeight || 0), true); } - doc.height = actualdH; - if (fixedAspect && !doc.fitWidth) doc.width = nwidth / nheight * doc.height; - else doc.width = actualdW; + layoutDoc.height = actualdH; + if (fixedAspect && !layoutDoc.fitWidth) layoutDoc.width = nwidth / nheight * layoutDoc.height; + else layoutDoc.width = actualdW; } } else { - dW && (doc.width = actualdW); - dH && (doc.height = actualdH); - dH && element.props.Document.autoHeight && Doc.SetInPlace(element.props.Document, "autoHeight", false, true); + dW && (layoutDoc.width = actualdW); + dH && (layoutDoc.height = actualdH); + dH && layoutDoc.autoHeight && Doc.SetInPlace(layoutDoc, "autoHeight", false, true); } } }); diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 51fc7ca8f..46c6fae1c 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -41,7 +41,9 @@ export class InkingControl { if (InkingControl.Instance.selectedTool === InkTool.None) { let selected = SelectionManager.SelectedDocuments(); let oldColors = selected.map(view => { - let targetDoc = view.props.Document.layout instanceof Doc ? view.props.Document.layout : view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); + let targetDoc = view.props.Document.dragFactory instanceof Doc ? view.props.Document.dragFactory : + view.props.Document.layout instanceof Doc ? view.props.Document.layout : + view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); let sel = window.getSelection(); if (StrCast(targetDoc.layout).indexOf("FormattedTextBox") !== -1 && (!sel || sel.toString() !== "")) { targetDoc.color = this._selectedColor; @@ -79,7 +81,10 @@ export class InkingControl { ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined; ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb))); } - !ruleProvider && (targetDoc.backgroundColor = matchedColor); + if (!ruleProvider) { + if (targetDoc) + targetDoc.backgroundColor = matchedColor; + } return { target: targetDoc, diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 90fc9c3e0..cde1a5036 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -110,9 +110,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } componentDidMount() { - // is there any reason this needs to exist? -syip. yes, it handles autoHeight for stacking views (masonry isn't yet supported). this._heightDisposer = reaction(() => { - if (BoolCast(this.props.Document.autoHeight)) { + if (this.props.Document.autoHeight) { let sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]); if (this.isStackingView) { return this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => Math.max(maxHght, @@ -188,15 +187,17 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } getDocHeight(d?: Doc) { if (!d) return 0; + let layoutDoc = d.layout instanceof Doc ? d.layout : d; let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); - if (!d.ignoreAspect && !d.fitWidth && nw && nh) { + if (!layoutDoc.ignoreAspect && !layoutDoc.fitWidth && nw && nh) { let aspect = nw && nh ? nh / nw : 1; - if (!(d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(d[WidthSym](), wid); + if (!(d.nativeWidth && !layoutDoc.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid); return wid * aspect; } - return d.fitWidth ? !d.nativeHeight ? this.props.PanelHeight() - 2 * this.yMargin : Math.min(wid * NumCast(d.scrollHeight, NumCast(d.nativeHeight)) / NumCast(d.nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : d[HeightSym](); + return layoutDoc.fitWidth ? !d.nativeHeight ? this.props.PanelHeight() - 2 * this.yMargin : + Math.min(wid * NumCast(layoutDoc.scrollHeight, NumCast(d.nativeHeight)) / NumCast(d.nativeWidth, 1), this.props.PanelHeight() - 2 * this.yMargin) : layoutDoc[HeightSym](); } columnDividerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index ca0c321b7..bff8ce5c1 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -16,6 +16,7 @@ background: $light-color-secondary; font-size: 13px; overflow: auto; + cursor: default; ul { list-style: none; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index abaa9662c..403da0e54 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -251,19 +251,21 @@ class TreeView extends React.Component { } docWidth = () => { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); - if (aspect) return Math.min(this.props.document[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20)); - return NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20; + let layoutDoc = this.props.document.layout instanceof Doc ? this.props.document.layout : this.props.document; + if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20)); + return NumCast(this.props.document.nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20; } docHeight = () => { let bounds = this.boundsOfCollectionDocument; return Math.min(this.MAX_EMBED_HEIGHT, (() => { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); + let layoutDoc = this.props.document.layout instanceof Doc ? this.props.document.layout : this.props.document; if (aspect) return this.docWidth() * aspect; if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x); - return this.props.document.fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection.height) : - Math.min(this.docWidth() * NumCast(this.props.document.scrollHeight, NumCast(this.props.document.nativeHeight)) / NumCast(this.props.document.nativeWidth, + return layoutDoc.fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection.height) : + Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(this.props.document.nativeHeight)) / NumCast(this.props.document.nativeWidth, NumCast(this.props.containingCollection.height)))) : - NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50; + NumCast(layoutDoc.height) ? NumCast(layoutDoc.height) : 50; })()); } @@ -461,10 +463,11 @@ class TreeView extends React.Component { let rowWidth = () => panelWidth() - 20; return docs.map((child, i) => { - let pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, key, child); + const pair = Doc.GetLayoutDataDocPair(containingCollection, dataDoc, key, child); if (!pair.layout || pair.data instanceof Promise) { return (null); } + const childLayout = pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout; let indent = i === 0 ? undefined : () => { if (StrCast(docs[i - 1].layout).indexOf("fieldKey") !== -1) { @@ -482,7 +485,7 @@ class TreeView extends React.Component { }; let rowHeight = () => { let aspect = NumCast(child.nativeWidth, 0) / NumCast(child.nativeHeight, 0); - return aspect ? Math.min(child[WidthSym](), rowWidth()) / aspect : child[HeightSym](); + return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym](); }; return { - d.x = x + NumCast(d.x) - dropX; - d.y = y + NumCast(d.y) - dropY; - if (!NumCast(d.width)) { - d.width = 300; + let layoutDoc = d.layout instanceof Doc ? d.layout : d; + layoutDoc.x = x + NumCast(layoutDoc.x) - dropX; + layoutDoc.y = y + NumCast(layoutDoc.y) - dropY; + if (!NumCast(layoutDoc.width)) { + layoutDoc.width = 300; } if (!NumCast(d.height)) { let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); - d.height = nw && nh ? nh / nw * NumCast(d.width) : 300; + layoutDoc.height = nw && nh ? nh / nw * NumCast(layoutDoc.width) : 300; } this.bringToFront(d); })); @@ -156,14 +157,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { else if (de.data instanceof DragManager.AnnotationDragData) { if (de.data.dropDocument) { let dragDoc = de.data.dropDocument; + let layoutDoc = dragDoc.layout instanceof Doc ? dragDoc.layout : dragDoc; let x = xp - de.data.offset[0]; let y = yp - de.data.offset[1]; - let dropX = NumCast(de.data.dropDocument.x); - let dropY = NumCast(de.data.dropDocument.y); - dragDoc.x = x + NumCast(dragDoc.x) - dropX; - dragDoc.y = y + NumCast(dragDoc.y) - dropY; - de.data.targetContext = this.props.Document; - dragDoc.targetContext = this.props.Document; + let dropX = NumCast(layoutDoc.x); + let dropY = NumCast(layoutDoc.y); + layoutDoc.x = x + NumCast(layoutDoc.x) - dropX; + layoutDoc.y = y + NumCast(layoutDoc.y) - dropY; + de.data.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation this.bringToFront(dragDoc); } } @@ -173,11 +174,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { pickCluster(probe: number[]) { return this.childLayoutPairs.map(pair => pair.layout).reduce((cluster, cd) => { - let cx = NumCast(cd.x) - this._clusterDistance; - let cy = NumCast(cd.y) - this._clusterDistance; - let cw = NumCast(cd.width) + 2 * this._clusterDistance; - let ch = NumCast(cd.height) + 2 * this._clusterDistance; - return !cd.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? + let layoutDoc = cd.layout instanceof Doc ? cd.layout : cd; + let cx = NumCast(layoutDoc.x) - this._clusterDistance; + let cy = NumCast(layoutDoc.y) - this._clusterDistance; + let cw = NumCast(layoutDoc.width) + 2 * this._clusterDistance; + let ch = NumCast(layoutDoc.height) + 2 * this._clusterDistance; + return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? NumCast(cd.cluster) : cluster; }, -1); } @@ -185,14 +187,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let cluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY)); if (cluster !== -1) { let eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => NumCast(cd.cluster) === cluster); - - // hacky way to get a list of DocumentViews in the current view given a list of Documents in the current view - let prevSelected = SelectionManager.SelectedDocuments(); - this.selectDocuments(eles); - let clusterDocs = SelectionManager.SelectedDocuments(); - SelectionManager.DeselectAll(); - prevSelected.map(dv => SelectionManager.SelectDoc(dv, true)); - + let clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!); let de = new DragManager.DocumentDragData(eles); de.moveDocument = this.props.moveDocument; const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); @@ -223,8 +218,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); let preferredInd = NumCast(doc.cluster); doc.cluster = -1; + let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; this._clusterSets.map((set, i) => set.map(member => { - if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { + let memberLayout = member.layout instanceof Doc ? member.layout : member; + if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(layoutDoc, memberLayout, this._clusterDistance)) { doc.cluster = i; } })); @@ -296,10 +293,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } let x = this.Document.panX || 0; let y = this.Document.panY || 0; - let docs = this.childLayoutPairs.map(pair => pair.layout); + let docs = this.childLayoutPairs.map(pair => pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout); let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); if (!this.isAnnotationOverlay) { - PDFMenu.Instance.fadeOut(true); let minx = docs.length ? NumCast(docs[0].x) : 0; let maxx = docs.length ? NumCast(docs[0].width) + minx : minx; let miny = docs.length ? NumCast(docs[0].y) : 0; @@ -549,7 +545,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { - const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state }); + let finalLayout = pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout; + const pos = this.getCalculatedPositions({ doc: finalLayout, index: i, collection: this.Document, docs: layoutDocs, state }); state = pos.state === undefined ? state : pos.state; layoutPoolData.set(pair, pos); }); @@ -592,7 +589,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let i = 0; const width = Math.max(...docs.map(doc => NumCast(doc.width))); const height = Math.max(...docs.map(doc => NumCast(doc.height))); - for (const doc of docs) { + for (const doc of docs.map(d => d.layout instanceof Doc ? d.layout : d)) { doc.x = x; doc.y = y; x += width + 20; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index ecdd02b0f..1362736cf 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -281,7 +281,7 @@ export class MarqueeView extends React.Component let bounds = this.Bounds; let selected = this.marqueeSelect(false); if (e.key === "c") { - selected.map(d => { + selected.map(d => d.layout instanceof Doc ? d.layout : d).map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; @@ -325,7 +325,7 @@ export class MarqueeView extends React.Component this.marqueeInkDelete(inkData); if (e.key === "s" || e.key === "S") { - selected.map(d => { + selected.map(d => d.layout instanceof Doc ? d.layout : d).map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; @@ -394,20 +394,22 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Doc[] = []; this.props.activeDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => { - var x = NumCast(doc.x); - var y = NumCast(doc.y); - var w = NumCast(doc.width); - var h = NumCast(doc.height); + let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; + var x = NumCast(layoutDoc.x); + var y = NumCast(layoutDoc.y); + var w = NumCast(layoutDoc.width); + var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } }); if (!selection.length && selectBackgrounds) { this.props.activeDocuments().filter(doc => doc.z === undefined).map(doc => { - var x = NumCast(doc.x); - var y = NumCast(doc.y); - var w = NumCast(doc.width); - var h = NumCast(doc.height); + let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; + var x = NumCast(layoutDoc.x); + var y = NumCast(layoutDoc.y); + var w = NumCast(layoutDoc.width); + var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } @@ -420,10 +422,11 @@ export class MarqueeView extends React.Component let size = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); let otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; this.props.activeDocuments().filter(doc => doc.z !== undefined).map(doc => { - var x = NumCast(doc.x); - var y = NumCast(doc.y); - var w = NumCast(doc.width); - var h = NumCast(doc.height); + let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; + var x = NumCast(layoutDoc.x); + var y = NumCast(layoutDoc.y); + var w = NumCast(layoutDoc.width); + var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, otherBounds)) { selection.push(doc); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 93f6dc468..5e8ac3ecd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -36,8 +36,8 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu maxLocation = this.Document.maximizeLocation = (!ctrlKey ? !altKey ? maxLocation : (maxLocation !== "inPlace" ? "inPlace" : "onRight") : (maxLocation !== "inPlace" ? "inPlace" : "inTab")); if (maxLocation === "inPlace") { expandedDocs.forEach(maxDoc => this.props.addDocument && this.props.addDocument(maxDoc)); - let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.Document.width) / 2, NumCast(this.Document.height) / 2); + let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(NumCast(this.layoutDoc.width) / 2, NumCast(this.layoutDoc.height) / 2); DocumentManager.Instance.animateBetweenPoint(scrpt, expandedDocs); } else { expandedDocs.forEach(maxDoc => (!this.props.addDocTab(maxDoc, undefined, "close") && this.props.addDocTab(maxDoc, undefined, maxLocation))); @@ -392,7 +392,7 @@ export class DocumentView extends DocComponent(Docu if (!anchors.find(anchor2 => anchor2 && anchor2.title === this.Document.title + ".portal" ? true : false)) { 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.Document.width || 0) + 10, height: this.Document.height || 0, title: portalID }); + let portal = existingPortal instanceof Doc ? existingPortal : Docs.Create.FreeformDocument([], { width: (this.layoutDoc.width || 0) + 10, height: this.layoutDoc.height || 0, title: portalID }); DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: portal }, portalID, "portal link"); this.Document.isButton = true; }); @@ -491,7 +491,7 @@ export class DocumentView extends DocComponent(Docu layoutItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc!), icon: "concierge-bell" }); } layoutItems.push({ description: `${this.Document.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document.chromeStatus = (this.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); - layoutItems.push({ description: `${this.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.Document.autoHeight = !this.Document.autoHeight, icon: "plus" }); + layoutItems.push({ description: `${this.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" }); layoutItems.push({ description: this.Document.ignoreAspect || !this.Document.nativeWidth || !this.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 848afccf3..c5bf28d5b 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -8,6 +8,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { StrCast } from '../../../new_fields/Types'; import { Utils } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer } from 'mobx'; +import { Doc } from '../../../new_fields/Doc'; const FontIconSchema = createSchema({ icon: "string" }); @@ -35,8 +36,10 @@ export class FontIconBox extends DocComponent( this._backgroundReaction && this._backgroundReaction(); } render() { + let referenceDoc = (this.props.Document.dragFactory instanceof Doc ? this.props.Document.dragFactory : this.props.Document); + let referenceLayout = referenceDoc.layout instanceof Doc ? referenceDoc.layout : referenceDoc; return ; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ae67e94cc..f157a953e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -127,7 +127,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let view = this._editorView!; if (view.state.selection.from === view.state.selection.to) return false; if (view.state.selection.to - view.state.selection.from > view.state.doc.nodeSize - 3) { - this.props.Document.color = color; + this.layoutDoc.color = color; } let colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color: color }); view.dispatch(view.state.tr.addMark(view.state.selection.from, view.state.selection.to, colorMark)); @@ -143,7 +143,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @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); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplate ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); } + + // 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 + @computed get layoutDoc(): Doc { + return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; + } linkOnDeselect: Map = new Map(); @@ -249,39 +255,41 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { - if (de.data instanceof DragManager.DocumentDragData && de.data.userDropAction) { - let target = de.data.droppedDocuments[0]; - const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "Embedded Doc:" + target.title); - target.fitToBox = true; - let node = schema.nodes.dashDoc.create({ - width: target[WidthSym](), height: target[HeightSym](), - title: "dashDoc", docid: target[Id], - float: "right" - }); - let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y }); - link && this._editorView!.dispatch(this._editorView!.state.tr.insert(pos!.pos, node)); - this.tryUpdateHeight(); - e.stopPropagation(); - } else if (de.data instanceof DragManager.DocumentDragData) { + if (de.data instanceof DragManager.DocumentDragData) { const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0]; - if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) { - if (de.mods === "AltKey") { - if (draggedDoc.data instanceof RichTextField) { - Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data); - e.stopPropagation(); - } - } else if (de.mods === "CtrlKey") { - draggedDoc.isTemplate = true; - if (typeof (draggedDoc.layout) === "string") { - let layoutDelegateToOverrideFieldKey = Doc.MakeDelegate(draggedDoc); - layoutDelegateToOverrideFieldKey.layout = StrCast(layoutDelegateToOverrideFieldKey.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${this.props.fieldKey}"}`); - this.props.Document.layout = layoutDelegateToOverrideFieldKey; - } else { - this.props.Document.layout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; - } + // replace text contents whend dragging with Alt + if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "AltKey") { + if (draggedDoc.data instanceof RichTextField) { + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data); + e.stopPropagation(); + } + // apply as template when dragging with Meta + } else if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "MetaKey") { + draggedDoc.isTemplate = true; + let newLayout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; + if (typeof (draggedDoc.layout) === "string") { + newLayout = Doc.MakeDelegate(draggedDoc); + newLayout.layout = StrCast(newLayout.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${this.props.fieldKey}"}`); } + this.props.Document.layout = newLayout; e.stopPropagation(); - } + // embed document when dragging with a userDropAction or an embedDoc flag set + } else if (de.data.userDropAction || de.data.embedDoc) { + let target = de.data.droppedDocuments[0]; + const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "Embedded Doc:" + target.title); + if (link) { + target.fitToBox = true; + let node = schema.nodes.dashDoc.create({ + width: target[WidthSym](), height: target[HeightSym](), + title: "dashDoc", docid: target[Id], + float: "right" + }); + let view = this._editorView!; + view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node)); + this.tryUpdateHeight(); + e.stopPropagation(); + } + } // otherwise, fall through to outer collection to handle drop } } @@ -486,7 +494,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ); this._heightReactionDisposer = reaction( - () => [this.props.Document[WidthSym](), this.props.Document.autoHeight], + () => [this.layoutDoc[WidthSym](), this.layoutDoc.autoHeight], () => this.tryUpdateHeight() ); @@ -505,7 +513,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this.setupEditor(this.config, this.dataDoc, this.props.fieldKey); this._searchReactionDisposer = reaction(() => { - return StrCast(this.props.Document.search_string); + return StrCast(this.layoutDoc.search_string); }, searchString => { if (searchString) { this.highlightSearchTerms([searchString]); @@ -518,7 +526,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._rulesReactionDisposer = reaction(() => { let ruleProvider = this.props.ruleProvider; - let heading = NumCast(this.props.Document.heading); + let heading = NumCast(this.layoutDoc.heading); if (ruleProvider instanceof Doc) { return { align: StrCast(ruleProvider["ruleAlign_" + heading], ""), @@ -530,7 +538,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }, action((rules: any) => { this._fontFamily = rules ? rules.font : "Arial"; - this._fontSize = rules ? rules.size : NumCast(this.props.Document.fontSize, 13); + this._fontSize = rules ? rules.size : NumCast(this.layoutDoc.fontSize, 13); rules && setTimeout(() => { const view = this._editorView!; if (this._proseRef) { @@ -547,7 +555,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }), { fireImmediately: true } ); this._scrollToRegionReactionDisposer = reaction( - () => StrCast(this.props.Document.scrollToLinkID), + () => StrCast(this.layoutDoc.scrollToLinkID), async (scrollToLinkID) => { let findLinkFrag = (frag: Fragment, editor: EditorView) => { const nodes: Node[] = []; @@ -585,7 +593,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0); setTimeout(() => this.unhighlightSearchTerms(), 2000); } - this.props.Document.scrollToLinkID = undefined; + this.layoutDoc.scrollToLinkID = undefined; } }, @@ -885,7 +893,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }); } } else { - let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.props.Document.x, 0) + NumCast(this.props.Document.width, 0), y: NumCast(this.props.Document.y) }); + let webDoc = Docs.Create.WebDocument(href, { x: NumCast(this.layoutDoc.x, 0) + NumCast(this.layoutDoc.width, 0), y: NumCast(this.layoutDoc.y) }); this.props.addDocument && this.props.addDocument(webDoc); } e.stopPropagation(); @@ -983,19 +991,19 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @action tryUpdateHeight() { let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0; - if (!this.props.Document.isAnimating && this.props.Document.autoHeight && scrollHeight !== 0 && + if (!this.layoutDoc.isAnimating && this.layoutDoc.autoHeight && scrollHeight !== 0 && getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0); - let dh = NumCast(this.props.Document.height, 0); - this.props.Document.height = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); + let dh = NumCast(this.layoutDoc.height, 0); + this.layoutDoc.height = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); this.dataDoc.nativeHeight = nh ? scrollHeight : undefined; } } render() { let style = "hidden"; - let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : ""; - let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.props.Document.isBackground + let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; + let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground ? "none" : "all"; Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey); if (this.props.isSelected()) { @@ -1004,8 +1012,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return (
      (field.map((d: any) => Doc.MakeAlias(d))); }); Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); -- cgit v1.2.3-70-g09d2 From 7763a08eb5ed931dbf854e2b72d07b7613791e2b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 16 Oct 2019 21:27:25 -0400 Subject: some fixes to linearView for handling templates. fixed DOCUMENTS on library view. renaming a bunch of template stuff... still in progress. --- src/client/documents/Documents.ts | 1 + src/client/views/CollectionLinearView.tsx | 18 ++++++++++++++---- src/client/views/DocComponent.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 4 ++-- src/client/views/InkingControl.tsx | 7 ++----- src/client/views/TemplateMenu.tsx | 2 +- src/client/views/collections/CollectionBaseView.tsx | 10 +++++----- .../views/collections/CollectionStackingView.tsx | 4 +++- src/client/views/collections/CollectionSubView.tsx | 11 ++++++++--- src/client/views/collections/CollectionTreeView.tsx | 3 ++- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/ButtonBox.tsx | 6 +++++- src/client/views/nodes/DocumentView.tsx | 6 +++--- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/new_fields/Doc.ts | 6 +++--- src/server/authentication/models/current_user_utils.ts | 16 ++++++++-------- 17 files changed, 61 insertions(+), 41 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ccb08f4cd..2ffbc8394 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -70,6 +70,7 @@ export interface DocumentOptions { layout?: string | Doc; hideHeadings?: boolean; // whether stacking view column headings should be hidden isTemplate?: boolean; + isTemplateDoc?: boolean; templates?: List; viewType?: number; backgroundColor?: string; diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 44d9b042e..3e2ab1459 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -1,7 +1,7 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, HeightSym, WidthSym } from '../../new_fields/Doc'; +import { Doc, HeightSym, WidthSym, DocListCast } from '../../new_fields/Doc'; import { ObjectField } from '../../new_fields/ObjectField'; import { makeInterface } from '../../new_fields/Schema'; import { ScriptField } from '../../new_fields/ScriptField'; @@ -51,9 +51,19 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { (de.data as DragManager.DocumentDragData).draggedDocuments.map((doc, i) => { let dbox = doc; if (!doc.onDragStart && !doc.onClick && this.props.Document.convertToButtons && doc.viewType !== CollectionViewType.Linear) { - let template = doc.layout instanceof Doc && doc.layout.isTemplate ? doc.layout : doc; - template.isTemplate = (template.type === DocumentType.TEXT || template.layout instanceof Doc) && de.data instanceof DragManager.DocumentDragData && !de.data.userDropAction; - dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: template.isTemplate ? "font" : "bolt" }); + let template = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; + if (template.type === DocumentType.COL) { + let layout = StrCast(template.layout).match(/fieldKey={"[^"]*"}/)![0]; + let fieldKey = layout.replace('fieldKey={"', "").replace(/"}$/, ""); + let docs = DocListCast(template[fieldKey]); + docs.map(d => { + Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(template)); + }); + template.isTemplateDoc = true; + } else { + template.isTemplateDoc = (template.type === DocumentType.TEXT || template.layout instanceof Doc) && de.data instanceof DragManager.DocumentDragData && !de.data.userDropAction; + } + dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: template.isTemplateDoc ? "font" : "bolt" }); dbox.dragFactory = template; dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index fbc27192c..b6b717be0 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -68,7 +68,7 @@ export function DocAnnotatableComponent

      (schema return index !== -1 && value.splice(index, 1) ? true : false; } - @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplate ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } + @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2f40ea746..6e8ba2d3d 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -380,7 +380,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> 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)). + !usingRule && SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplateField ? dv.props.Document : Doc.GetProto(dv.props.Document)). map(d => d.borderRounding = `${Math.min(100, dist)}%`); e.stopPropagation(); e.preventDefault(); @@ -481,7 +481,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let actualdH = Math.max(height + (dH * scale), 20); layoutDoc.x = (layoutDoc.x || 0) + dX * (actualdW - width); layoutDoc.y = (layoutDoc.y || 0) + dY * (actualdH - height); - let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... + let proto = doc.isTemplateField ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... let fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { layoutDoc.ignoreAspect = false; diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 46c6fae1c..bc5249acd 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -43,7 +43,7 @@ export class InkingControl { let oldColors = selected.map(view => { let targetDoc = view.props.Document.dragFactory instanceof Doc ? view.props.Document.dragFactory : view.props.Document.layout instanceof Doc ? view.props.Document.layout : - view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document); + view.props.Document.isTemplateField ? view.props.Document : Doc.GetProto(view.props.Document); let sel = window.getSelection(); if (StrCast(targetDoc.layout).indexOf("FormattedTextBox") !== -1 && (!sel || sel.toString() !== "")) { targetDoc.color = this._selectedColor; @@ -81,10 +81,7 @@ export class InkingControl { ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined; ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb))); } - if (!ruleProvider) { - if (targetDoc) - targetDoc.backgroundColor = matchedColor; - } + (!ruleProvider && targetDoc) && (targetDoc.backgroundColor = matchedColor); return { target: targetDoc, diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 9e5e62e03..da776f887 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -100,7 +100,7 @@ export class TemplateMenu extends React.Component { clearTemplates = (event: React.MouseEvent) => { 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) { + if (d.Document.isTemplateDoc && 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; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 7798964ea..15853fcae 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -84,7 +84,7 @@ export class CollectionBaseView extends React.Component { } } - @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 dataDoc() { return Doc.fieldExtensionDoc(this.props.Document.isTemplateField && 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 => { @@ -106,8 +106,8 @@ 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; } - 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 targetDataDoc = this.props.fieldExt || this.props.Document.isTemplateField ? this.extensionDoc : this.props.Document; + let targetField = (this.props.fieldExt || this.props.Document.isTemplateField) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey; Doc.AddDocToList(targetDataDoc, targetField, doc); Doc.GetProto(doc).lastOpened = new DateField; return true; @@ -118,8 +118,8 @@ export class CollectionBaseView extends React.Component { let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); //TODO This won't create the field if it doesn't already exist - 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 targetDataDoc = this.props.fieldExt || this.props.Document.isTemplateField ? this.extensionDoc : this.props.Document; + let targetField = (this.props.fieldExt || this.props.Document.isTemplateField) && 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 === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cde1a5036..e54374ad7 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -110,6 +110,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } componentDidMount() { + super.componentDidMount(); this._heightDisposer = reaction(() => { if (this.props.Document.autoHeight) { let sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]); @@ -137,6 +138,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { ); } componentWillUnmount() { + super.componentWillUnmount(); this._heightDisposer && this._heightDisposer(); this._sectionFilterDisposer && this._sectionFilterDisposer(); } @@ -167,7 +169,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} fitToBox={this.props.fitToBox} - onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler} + onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler} PanelWidth={width} PanelHeight={height} getTransform={finalDxf} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 9919a9dc3..46fbb5910 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -57,8 +57,13 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { componentDidMount() { this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], - async (args) => args[1] instanceof Doc && - this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc)))); + async (args) => { + if (args[1] instanceof Doc) { + this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc))); + } else { + this.childDocs.map(async doc => doc.layout = undefined); + } + }); } componentWillUnmount() { @@ -70,7 +75,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { // 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]; + return Doc.fieldExtensionDoc(this.props.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt)[this.props.fieldExt || this.props.fieldKey]; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 403da0e54..0e9c38fb4 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -520,7 +520,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { private treedropDisposer?: DragManager.DragDropDisposer; private _mainEle?: HTMLDivElement; - @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } + @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplateField) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } protected createTreeDropTarget = (ele: HTMLDivElement) => { this.treedropDisposer && this.treedropDisposer(); @@ -530,6 +530,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } componentWillUnmount() { + super.componentWillUnmount(); this.treedropDisposer && this.treedropDisposer(); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 229e7fffc..2b0ef8ada 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -627,7 +627,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onContextMenu = (e: React.MouseEvent) => { let layoutItems: ContextMenuProps[] = []; - if (this.childDocs.some(d => BoolCast(d.isTemplate))) { + if (this.childDocs.some(d => BoolCast(d.isTemplateDoc))) { 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" }); diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx index 3cf8c3eb3..b4d33fb0f 100644 --- a/src/client/views/nodes/ButtonBox.tsx +++ b/src/client/views/nodes/ButtonBox.tsx @@ -32,7 +32,11 @@ export class ButtonBox extends DocComponent(Butt public static LayoutString() { return FieldView.LayoutString(ButtonBox); } private dropDisposer?: DragManager.DragDropDisposer; - @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 && + (BoolCast(this.props.Document.isTemplateField) || BoolCast(this.props.DataDoc.isTemplateField) || + this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); + } protected createDropTarget = (ele: HTMLDivElement) => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a071f782a..a7e78a7e8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -110,7 +110,7 @@ export const documentSchema = createSchema({ dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. ignoreAspect: "boolean", // whether aspect ratio should be ignored when laying out or manipulating the document autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents - isTemplate: "boolean", // whether this document acts as a template layout for describing how other documents should be displayed + isTemplateField: "boolean", // whether this document acts as a template layout for describing how other documents should be displayed isBackground: "boolean", // whether document is a background element and ignores input events (can only selet with marquee) type: "string", // enumerated type of document maximizeLocation: "string", // flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab) @@ -196,7 +196,7 @@ export class DocumentView 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 }, console.log); + this.onClickHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log); } else if (this.props.Document.type === DocumentType.BUTTON) { ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY); } else if (this.Document.isButton) { @@ -376,7 +376,7 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action freezeNativeDimensions = (): void => { - let proto = this.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document); + let proto = this.Document.isTemplateDoc ? this.props.Document : Doc.GetProto(this.props.Document); proto.autoHeight = this.Document.autoHeight = false; proto.ignoreAspect = !proto.ignoreAspect; if (!proto.ignoreAspect && !proto.nativeWidth) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f157a953e..ea82b1161 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -993,7 +993,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0; if (!this.layoutDoc.isAnimating && this.layoutDoc.autoHeight && scrollHeight !== 0 && getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation - let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0); + let nh = this.props.Document.isTemplateField ? 0 : NumCast(this.dataDoc.nativeHeight, 0); let dh = NumCast(this.layoutDoc.height, 0); this.layoutDoc.height = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); this.dataDoc.nativeHeight = nh ? scrollHeight : undefined; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index aa9b28118..19968e6e1 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -323,7 +323,7 @@ export class VideoBox extends DocAnnotatableComponent(field.map((d: any) => Doc.MakeAlias(d))); }); Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index ef977c89a..5ce707011 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -36,11 +36,11 @@ export class CurrentUserUtils { // a default set of note types .. not being used yet... static setupNoteTypes(doc: Doc) { return [ - Docs.Create.TextDocument({ title: "Note", backgroundColor: "yellow", isTemplate: true }), - Docs.Create.TextDocument({ title: "Idea", backgroundColor: "pink", isTemplate: true }), - Docs.Create.TextDocument({ title: "Topic", backgroundColor: "lightBlue", isTemplate: true }), - Docs.Create.TextDocument({ title: "Person", backgroundColor: "lightGreen", isTemplate: true }), - Docs.Create.TextDocument({ title: "Todo", backgroundColor: "orange", isTemplate: true }) + Docs.Create.TextDocument({ title: "Note", backgroundColor: "yellow", isTemplateDoc: true }), + Docs.Create.TextDocument({ title: "Idea", backgroundColor: "pink", isTemplateDoc: true }), + Docs.Create.TextDocument({ title: "Topic", backgroundColor: "lightBlue", isTemplateDoc: true }), + Docs.Create.TextDocument({ title: "Person", backgroundColor: "lightGreen", isTemplateDoc: true }), + Docs.Create.TextDocument({ title: "Todo", backgroundColor: "orange", isTemplateDoc: true }) ]; } @@ -98,17 +98,17 @@ export class CurrentUserUtils { }); doc.documents = Docs.Create.TreeDocument([], { - title: "DOCUMENTS", gridGap: 5, xMargin: 5, yMargin: 5, height: 42, width: 100, boxShadow: "0 0", backgroundColor: "#eeeeee", preventTreeViewOpen: true, forceActive: true, lockedPosition: true + title: "DOCUMENTS", height: 42, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" }); // setup Recently Closed library item doc.recentlyClosed = Docs.Create.TreeDocument([], { - title: "Recently Closed".toUpperCase(), height: 75, boxShadow: "0 0", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, backgroundColor: "#eeeeee" + title: "RECENTLY CLOSED", height: 75, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee" }); return Docs.Create.ButtonDocument({ width: 50, height: 35, borderRounding: "50%", boxShadow: "2px 2px 1px", title: "Library", - panel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { + panel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, doc.recentlyClosed as Doc], { title: "Library", xMargin: 5, yMargin: 5, gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true }), targetContainer: sidebarContainer, -- cgit v1.2.3-70-g09d2 From 96960f20bb3a4f68dfd540425c778d9ad8ca067a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 14:45:02 -0400 Subject: fixed treeview to show dropdown options again. --- src/client/views/collections/CollectionTreeView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 0e9c38fb4..2c77c4b5b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -82,7 +82,7 @@ class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); - get defaultExpandedView() { return this.childDocs ? this.fieldKey : this.props.document.defaultExpandedView ? StrCast(this.props.document.defaultExpandedView) : ""; } + get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); } @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state @computed get treeViewOpen() { return (BoolCast(this.props.document.treeViewOpen) && !this.props.preventTreeViewOpen) || this._overrideTreeViewOpen; } set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = c; } @@ -600,7 +600,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { { TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, - this.outerXf, this.props.active, this.props.PanelWidth, this.props.renderDepth, () => this.props.Document.chromeStatus !== "disabled", + this.outerXf, this.props.active, this.props.PanelWidth, this.props.renderDepth, () => !this.props.Document.hideHeaderFields, BoolCast(this.props.Document.preventTreeViewOpen), []) }

    -- cgit v1.2.3-70-g09d2 From 1f3576a69a6a0396d07e965c700bb7d69d77a0a3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 17:06:41 -0400 Subject: fixed up creator buttons - factored out convert to buttons code into a dropConverter script. fixed issues with template loading for images. --- src/client/documents/Documents.ts | 2 +- src/client/util/DragManager.ts | 3 ++ src/client/util/DropConverter.ts | 46 ++++++++++++++++++++++ src/client/views/CollectionLinearView.tsx | 40 ------------------- .../views/collections/CollectionStackingView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 6 ++- .../views/collections/CollectionTreeView.scss | 1 - .../views/collections/CollectionTreeView.tsx | 2 +- .../CollectionFreeFormLinkView.tsx | 2 +- .../authentication/models/current_user_utils.ts | 11 ++++-- 10 files changed, 65 insertions(+), 50 deletions(-) create mode 100644 src/client/util/DropConverter.ts (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 651662ded..32fda1954 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -105,7 +105,7 @@ export interface DocumentOptions { yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts panel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script - convertToButtons?: boolean; // whether documents dropped onto a collection should be converted to buttons that will construct the dropped document + dropConverter?: ScriptField; // script to run when documents are dropped on this Document. // [key: string]: Opt; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 576b16bc8..bbc29585c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -14,6 +14,8 @@ import { ScriptField } from "../../new_fields/ScriptField"; import { List } from "../../new_fields/List"; import { PrefetchProxy } from "../../new_fields/Proxy"; import { listSpec } from "../../new_fields/Schema"; +import { Scripting } from "./Scripting"; +import { convertDropDataToButtons } from "./DropConverter"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( @@ -497,3 +499,4 @@ export namespace DragManager { } } } +Scripting.addGlobal(function convertToButtons(dragData: any) { convertDropDataToButtons(dragData as DragManager.DocumentDragData); }); diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts new file mode 100644 index 000000000..eea3da1bc --- /dev/null +++ b/src/client/util/DropConverter.ts @@ -0,0 +1,46 @@ +import { DragManager } from "./DragManager"; +import { CollectionViewType } from "../views/collections/CollectionBaseView"; +import { Doc, DocListCast } from "../../new_fields/Doc"; +import { DocumentType } from "../documents/DocumentTypes"; +import { ObjectField } from "../../new_fields/ObjectField"; +import { StrCast } from "../../new_fields/Types"; +import { Docs } from "../documents/Documents"; +import { ScriptField } from "../../new_fields/ScriptField"; + + +function makeTemplate(doc: Doc): boolean { + let layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; + let layout = StrCast(layoutDoc.layout).match(/fieldKey={"[^"]*"}/)![0]; + let fieldKey = layout.replace('fieldKey={"', "").replace(/"}$/, ""); + let docs = DocListCast(layoutDoc[fieldKey]); + let any = false; + docs.map(d => { + if (!StrCast(d.title).startsWith("-")) { + any = true; + return Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)); + } + if (d.type === DocumentType.COL) return makeTemplate(d); + return false; + }); + return any; +} +export function convertDropDataToButtons(data: DragManager.DocumentDragData) { + data && data.draggedDocuments.map((doc, i) => { + let dbox = doc; + if (!doc.onDragStart && !doc.onClick && doc.viewType !== CollectionViewType.Linear) { + let layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; + if (layoutDoc.type === DocumentType.COL) { + layoutDoc.isTemplateDoc = makeTemplate(layoutDoc); + } else { + layoutDoc.isTemplateDoc = (layoutDoc.type === DocumentType.TEXT || layoutDoc.layout instanceof Doc) && !data.userDropAction; + } + dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: layoutDoc.isTemplateDoc ? "font" : "bolt" }); + dbox.dragFactory = layoutDoc; + dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; + dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); + } else if (doc.viewType === CollectionViewType.Linear) { + dbox.ignoreClick = true; + } + data.droppedDocuments[i] = dbox; + }); +} diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 04e131135..e8ef20899 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -47,46 +47,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { } } - makeTemplate = (doc: Doc): boolean => { - let layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; - let layout = StrCast(layoutDoc.layout).match(/fieldKey={"[^"]*"}/)![0]; - let fieldKey = layout.replace('fieldKey={"', "").replace(/"}$/, ""); - let docs = DocListCast(layoutDoc[fieldKey]); - let any = false; - docs.map(d => { - if (!StrCast(d.title).startsWith("-")) { - any = true; - return Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)); - } - if (d.type === DocumentType.COL) return this.makeTemplate(d); - return false; - }); - return any; - } - - drop = action((e: Event, de: DragManager.DropEvent) => { - (de.data as DragManager.DocumentDragData).draggedDocuments.map((doc, i) => { - let dbox = doc; - if (!doc.onDragStart && !doc.onClick && this.props.Document.convertToButtons && doc.viewType !== CollectionViewType.Linear) { - let layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; - if (layoutDoc.type === DocumentType.COL) { - layoutDoc.isTemplateDoc = this.makeTemplate(layoutDoc); - } else { - layoutDoc.isTemplateDoc = (layoutDoc.type === DocumentType.TEXT || layoutDoc.layout instanceof Doc) && de.data instanceof DragManager.DocumentDragData && !de.data.userDropAction; - } - dbox = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: layoutDoc.isTemplateDoc ? "font" : "bolt" }); - dbox.dragFactory = layoutDoc; - dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; - dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); - } else if (doc.viewType === CollectionViewType.Linear) { - dbox.ignoreClick = true; - } - (de.data as DragManager.DocumentDragData).droppedDocuments[i] = dbox; - }); - e.stopPropagation(); - return super.drop(e, de); - }); - public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } dimension = () => NumCast(this.props.Document.height); // 2 * the padding diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index e54374ad7..f9f040c6b 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -65,7 +65,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap); let style = this.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` }; return
    - {this.getDisplayDoc(pair.layout as Doc, pair.data, dxf, width)} + {pair.layout instanceof Doc && this.getDisplayDoc(pair.layout, pair.data, dxf, width)}
    ; }); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1f8c0b18f..bc61492d0 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -6,7 +6,7 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { RouteStore } from "../../../server/RouteStore"; import { Utils } from "../../../Utils"; @@ -23,6 +23,8 @@ import React = require("react"); var path = require('path'); import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; +import { CollectionViewType } from "./CollectionBaseView"; +import { ObjectField } from "../../../new_fields/ObjectField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc) => boolean; @@ -126,6 +128,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch @action protected drop(e: Event, de: DragManager.DropEvent): boolean { + (this.props.Document.dropConverter instanceof ScriptField) && + this.props.Document.dropConverter.script.run({ dragData: de.data }); if (de.data instanceof DragManager.DocumentDragData && !de.data.applyAsTemplate) { if (de.mods === "AltKey" && de.data.draggedDocuments.length) { this.childDocs.map(doc => diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index bff8ce5c1..7d0c900a6 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -10,7 +10,6 @@ width:100%; position: relative; top:0; - padding-top: 20px; padding-left: 10px; padding-right: 10px; background: $light-color-secondary; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2c77c4b5b..5d88e6290 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -576,7 +576,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); return !this.childDocs ? (null) : (
    this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()} onDrop={this.onTreeDrop} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index c5bc2e7fb..962fe2a1c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -31,7 +31,7 @@ export class CollectionFreeFormLinkView extends React.Component(["dropAction"]), dragFactory: data.dragFactory + backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory: data.dragFactory, })); } @@ -69,7 +70,8 @@ export class CurrentUserUtils { static setupCreatePanel(sidebarContainer: Doc, doc: Doc) { // setup a masonry view of all he creators const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), { - width: 500, autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons" + width: 500, autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), yMargin: 0 }); // setup a color picker const color = Docs.Create.ColorDocument({ @@ -81,7 +83,7 @@ export class CurrentUserUtils { panel: Docs.Create.StackingDocument([dragCreators, color], { width: 500, height: 800, chromeStatus: "disabled", title: "creator stack" }), - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.panel") + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.panel"), }); } @@ -148,7 +150,8 @@ export class CurrentUserUtils { doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc], { title: "expanding buttons", gridGap: 5, xMargin: 5, yMargin: 5, height: 42, width: 100, boxShadow: "0 0", - backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, convertToButtons: true, + backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) }); } -- cgit v1.2.3-70-g09d2 From 3d910bae8771e67cabc1500c49b77d425fdf62e9 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 19 Oct 2019 13:49:20 -0400 Subject: cleaned up a bunch layout vs doc issues related to templates --- src/client/views/DocumentDecorations.tsx | 6 +- src/client/views/InkingControl.tsx | 2 +- src/client/views/TemplateMenu.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 8 +-- .../views/collections/CollectionTreeView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 66 +++++++++++----------- .../collections/collectionFreeForm/MarqueeView.tsx | 24 ++++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 14 ++--- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 11 ++-- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 6 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/new_fields/Doc.ts | 24 +++++--- 14 files changed, 86 insertions(+), 95 deletions(-) (limited to 'src/client/views/collections/CollectionTreeView.tsx') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8409a34da..07af4799b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -470,7 +470,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> SelectionManager.SelectedDocuments().forEach(element => { if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { let doc = PositionDocument(element.props.Document); - let layoutDoc = PositionDocument(element.props.Document.layout instanceof Doc ? element.props.Document.layout : element.props.Document); + let layoutDoc = PositionDocument(Doc.Layout(element.props.Document)); let nwidth = doc.nativeWidth || 0; let nheight = doc.nativeHeight || 0; let width = (layoutDoc.width || 0); @@ -478,8 +478,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling(); let actualdW = Math.max(width + (dW * scale), 20); let actualdH = Math.max(height + (dH * scale), 20); - layoutDoc.x = (layoutDoc.x || 0) + dX * (actualdW - width); - layoutDoc.y = (layoutDoc.y || 0) + dY * (actualdH - height); + doc.x = (doc.x || 0) + dX * (actualdW - width); + doc.y = (doc.y || 0) + dY * (actualdH - height); let proto = doc.isTemplateField ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here... let fixedAspect = e.ctrlKey || (!layoutDoc.ignoreAspect && nwidth && nheight); if (fixedAspect && e.ctrlKey && layoutDoc.ignoreAspect) { diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index c3a617ffe..105adc03d 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -81,7 +81,7 @@ export class InkingControl { ruleProvider = (view.props.Document.heading && ruleProvider) ? ruleProvider : undefined; ruleProvider && ((Doc.GetProto(ruleProvider)["ruleColor_" + NumCast(view.props.Document.heading)] = Utils.toRGBAstr(color.rgb))); } - (!ruleProvider && targetDoc) && (view.props.Document.backgroundColor = matchedColor); + (!ruleProvider && targetDoc) && (Doc.Layout(view.props.Document).backgroundColor = matchedColor); return { target: targetDoc, diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index da776f887..d76b033f0 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -117,13 +117,13 @@ export class TemplateMenu extends React.Component { @action toggleChrome = (): void => { this.props.docs.map(dv => { - let layout = dv.Document.layout instanceof Doc ? dv.Document.layout : dv.Document; + let layout = Doc.Layout(dv.Document); layout.chromeStatus = (layout.chromeStatus !== "disabled" ? "disabled" : "enabled"); }); } render() { - let layout = this.props.docs[0].Document.layout instanceof Doc ? this.props.docs[0].Document.layout : this.props.docs[0].Document; + let layout = Doc.Layout(this.props.docs[0].Document); let templateMenu: Array = []; this.props.templates.forEach((checked, template) => templateMenu.push()); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index f9f040c6b..1a578f4fc 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -74,11 +74,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { this._heightMap.set(key, sectionHeight); } - 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; - } + get layoutDoc() { return Doc.Layout(this.props.Document); } get Sections() { if (!this.sectionFilter || this.sectionHeaders instanceof Promise) return new Map(); @@ -189,7 +185,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } getDocHeight(d?: Doc) { if (!d) return 0; - let layoutDoc = d.layout instanceof Doc ? d.layout : d; + let layoutDoc = Doc.Layout(d); let nw = NumCast(d.nativeWidth); let nh = NumCast(d.nativeHeight); let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 5d88e6290..2fbe8527e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -251,7 +251,7 @@ class TreeView extends React.Component { } docWidth = () => { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); - let layoutDoc = this.props.document.layout instanceof Doc ? this.props.document.layout : this.props.document; + let layoutDoc = Doc.Layout(this.props.document); if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20)); return NumCast(this.props.document.nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20; } @@ -259,7 +259,7 @@ class TreeView extends React.Component { let bounds = this.boundsOfCollectionDocument; return Math.min(this.MAX_EMBED_HEIGHT, (() => { let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth); - let layoutDoc = this.props.document.layout instanceof Doc ? this.props.document.layout : this.props.document; + let layoutDoc = Doc.Layout(this.props.document); if (aspect) return this.docWidth() * aspect; if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x); return layoutDoc.fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection.height) : @@ -467,7 +467,6 @@ class TreeView extends React.Component { if (!pair.layout || pair.data instanceof Promise) { return (null); } - const childLayout = pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout; let indent = i === 0 ? undefined : () => { if (StrCast(docs[i - 1].layout).indexOf("fieldKey") !== -1) { @@ -483,6 +482,7 @@ class TreeView extends React.Component { let addDocument = (doc: Doc, relativeTo?: Doc, before?: boolean) => { return add(doc, relativeTo ? relativeTo : docs[i], before !== undefined ? before : false); }; + const childLayout = Doc.Layout(pair.layout); let rowHeight = () => { let aspect = NumCast(child.nativeWidth, 0) / NumCast(child.nativeHeight, 0); return aspect ? Math.min(childLayout[WidthSym](), rowWidth()) / aspect : childLayout[HeightSym](); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 932b6722b..eff73b14e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -130,22 +130,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (super.drop(e, de)) { if (de.data instanceof DragManager.DocumentDragData) { if (de.data.droppedDocuments.length) { - let firstLayoutDoc = de.data.droppedDocuments[0].layout instanceof Doc ? de.data.droppedDocuments[0].layout : de.data.droppedDocuments[0]; - let z = NumCast(firstLayoutDoc.z); + let firstDoc = de.data.droppedDocuments[0]; + let z = NumCast(firstDoc.z); let x = (z ? xpo : xp) - de.data.offset[0]; let y = (z ? ypo : yp) - de.data.offset[1]; - let dropX = NumCast(firstLayoutDoc.x); - let dropY = NumCast(firstLayoutDoc.y); + let dropX = NumCast(firstDoc.x); + let dropY = NumCast(firstDoc.y); de.data.droppedDocuments.forEach(action((d: Doc) => { - let layoutDoc = d.layout instanceof Doc ? d.layout : d; - layoutDoc.x = x + NumCast(layoutDoc.x) - dropX; - layoutDoc.y = y + NumCast(layoutDoc.y) - dropY; + let layoutDoc = Doc.Layout(d); + d.x = x + NumCast(d.x) - dropX; + d.y = y + NumCast(d.y) - dropY; if (!NumCast(layoutDoc.width)) { layoutDoc.width = 300; } - if (!NumCast(d.height)) { - let nw = NumCast(d.nativeWidth); - let nh = NumCast(d.nativeHeight); + if (!NumCast(layoutDoc.height)) { + let nw = NumCast(layoutDoc.nativeWidth); + let nh = NumCast(layoutDoc.nativeHeight); layoutDoc.height = nw && nh ? nh / nw * NumCast(layoutDoc.width) : 300; } this.bringToFront(d); @@ -157,13 +157,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { else if (de.data instanceof DragManager.AnnotationDragData) { if (de.data.dropDocument) { let dragDoc = de.data.dropDocument; - let layoutDoc = dragDoc.layout instanceof Doc ? dragDoc.layout : dragDoc; let x = xp - de.data.offset[0]; let y = yp - de.data.offset[1]; - let dropX = NumCast(layoutDoc.x); - let dropY = NumCast(layoutDoc.y); - layoutDoc.x = x + NumCast(layoutDoc.x) - dropX; - layoutDoc.y = y + NumCast(layoutDoc.y) - dropY; + let dropX = NumCast(dragDoc.x); + let dropY = NumCast(dragDoc.y); + dragDoc.x = x + NumCast(dragDoc.x) - dropX; + dragDoc.y = y + NumCast(dragDoc.y) - dropY; de.data.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation this.bringToFront(dragDoc); } @@ -174,9 +173,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { pickCluster(probe: number[]) { return this.childLayoutPairs.map(pair => pair.layout).reduce((cluster, cd) => { - let layoutDoc = cd.layout instanceof Doc ? cd.layout : cd; - let cx = NumCast(layoutDoc.x) - this._clusterDistance; - let cy = NumCast(layoutDoc.y) - this._clusterDistance; + let layoutDoc = Doc.Layout(cd); + let cx = NumCast(cd.x) - this._clusterDistance; + let cy = NumCast(cd.y) - this._clusterDistance; let cw = NumCast(layoutDoc.width) + 2 * this._clusterDistance; let ch = NumCast(layoutDoc.height) + 2 * this._clusterDistance; return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? @@ -218,10 +217,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); let preferredInd = NumCast(doc.cluster); doc.cluster = -1; - let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; this._clusterSets.map((set, i) => set.map(member => { - let memberLayout = member.layout instanceof Doc ? member.layout : member; - if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(layoutDoc, memberLayout, this._clusterDistance)) { + if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { doc.cluster = i; } })); @@ -293,18 +290,19 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } let x = this.Document.panX || 0; let y = this.Document.panY || 0; - let docs = this.childLayoutPairs.map(pair => pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout); + let docs = this.childLayoutPairs.map(pair => pair.layout); let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); if (!this.isAnnotationOverlay) { let minx = docs.length ? NumCast(docs[0].x) : 0; - let maxx = docs.length ? NumCast(docs[0].width) + minx : minx; + let maxx = docs.length ? NumCast(Doc.Layout(docs[0]).width) + minx : minx; let miny = docs.length ? NumCast(docs[0].y) : 0; - let maxy = docs.length ? NumCast(docs[0].height) + miny : miny; + let maxy = docs.length ? NumCast(Doc.Layout(docs[0]).height) + miny : miny; let ranges = docs.filter(doc => doc).reduce((range, doc) => { + let layoutDoc = Doc.Layout(doc); let x = NumCast(doc.x); - let xe = x + NumCast(doc.width); + let xe = x + NumCast(layoutDoc.width); let y = NumCast(doc.y); - let ye = y + NumCast(doc.height); + let ye = y + NumCast(layoutDoc.height); return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]], [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]]; }, [[minx, maxx], [miny, maxy]]); @@ -408,9 +406,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.props.Document.scrollY = NumCast(doc.y) - offset; } } else { - let layoutdoc = doc.layout instanceof Doc ? doc.layout : doc; - const newPanX = NumCast(layoutdoc.x) + NumCast(layoutdoc.width) / 2; - const newPanY = NumCast(layoutdoc.y) + NumCast(layoutdoc.height) / 2; + let layoutdoc = Doc.Layout(doc); + const newPanX = NumCast(doc.x) + NumCast(layoutdoc.width) / 2; + const newPanY = NumCast(doc.y) + NumCast(layoutdoc.height) / 2; const newState = HistoryUtil.getState(); newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; HistoryUtil.pushState(newState); @@ -471,10 +469,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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); + const layoutDoc = Doc.Layout(params.doc); 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") }; + return { x: Cast(params.doc.x, "number"), y: Cast(params.doc.y, "number"), z: Cast(params.doc.z, "number"), width: Cast(layoutDoc.width, "number"), height: Cast(layoutDoc.height, "number") }; } viewDefsToJSX = (views: any[]) => { @@ -530,8 +529,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { - let finalLayout = pair.layout.layout instanceof Doc ? pair.layout.layout : pair.layout; - const pos = this.getCalculatedPositions({ doc: finalLayout, index: i, collection: this.Document, docs: layoutDocs, state }); + const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state }); state = pos.state === undefined ? state : pos.state; layoutPoolData.set(pair, pos); }); @@ -574,7 +572,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let i = 0; const width = Math.max(...docs.map(doc => NumCast(doc.width))); const height = Math.max(...docs.map(doc => NumCast(doc.height))); - for (const doc of docs.map(d => d.layout instanceof Doc ? d.layout : d)) { + for (const doc of docs) { doc.x = x; doc.y = y; x += width + 20; @@ -592,7 +590,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // find rule colorations when rule providing is turned on by looking at each document to see if it has a coloring -- if so, use it's color as the rule for its associated heading. this.Document.isRuleProvider && this.childLayoutPairs.map(pair => // iterate over the children of a displayed document (or if the displayed document is a template, iterate over the children of that template) - DocListCast(pair.layout.layout instanceof Doc ? pair.layout.layout.data : pair.layout.data).map(heading => { + DocListCast(Doc.Layout(pair.layout).data).map(heading => { let headingPair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, heading); let headingLayout = headingPair.layout && (pair.layout.data_ext instanceof Doc) && (pair.layout.data_ext[`Layout[${headingPair.layout[Id]}]`] as Doc) || headingPair.layout; if (headingLayout && NumCast(headingLayout.heading) > 0 && headingLayout.backgroundColor !== headingLayout.defaultBackgroundColor) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1362736cf..637168f1b 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -281,7 +281,7 @@ export class MarqueeView extends React.Component let bounds = this.Bounds; let selected = this.marqueeSelect(false); if (e.key === "c") { - selected.map(d => d.layout instanceof Doc ? d.layout : d).map(d => { + selected.map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; @@ -296,7 +296,7 @@ export class MarqueeView extends React.Component let palette = Array.from(Cast(this.props.container.props.Document.colorPalette, listSpec("string")) as string[]); let usedPaletted = new Map(); [...this.props.activeDocuments(), this.props.container.props.Document].map(child => { - let bg = StrCast(child.layout instanceof Doc ? child.layout.backgroundColor : child.backgroundColor); + let bg = StrCast(Doc.Layout(child).backgroundColor); if (palette.indexOf(bg) !== -1) { palette.splice(palette.indexOf(bg), 1); if (usedPaletted.get(bg)) usedPaletted.set(bg, usedPaletted.get(bg)! + 1); @@ -325,7 +325,7 @@ export class MarqueeView extends React.Component this.marqueeInkDelete(inkData); if (e.key === "s" || e.key === "S") { - selected.map(d => d.layout instanceof Doc ? d.layout : d).map(d => { + selected.map(d => { this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; @@ -394,9 +394,9 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Doc[] = []; this.props.activeDocuments().filter(doc => !doc.isBackground && doc.z === undefined).map(doc => { - let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; - var x = NumCast(layoutDoc.x); - var y = NumCast(layoutDoc.y); + let layoutDoc = Doc.Layout(doc); + var x = NumCast(doc.x); + var y = NumCast(doc.y); var w = NumCast(layoutDoc.width); var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { @@ -405,9 +405,9 @@ export class MarqueeView extends React.Component }); if (!selection.length && selectBackgrounds) { this.props.activeDocuments().filter(doc => doc.z === undefined).map(doc => { - let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; - var x = NumCast(layoutDoc.x); - var y = NumCast(layoutDoc.y); + let layoutDoc = Doc.Layout(doc); + var x = NumCast(doc.x); + var y = NumCast(doc.y); var w = NumCast(layoutDoc.width); var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { @@ -422,9 +422,9 @@ export class MarqueeView extends React.Component let size = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); let otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; this.props.activeDocuments().filter(doc => doc.z !== undefined).map(doc => { - let layoutDoc = doc.layout instanceof Doc ? doc.layout : doc; - var x = NumCast(layoutDoc.x); - var y = NumCast(layoutDoc.y); + let layoutDoc = Doc.Layout(doc); + var x = NumCast(doc.x); + var y = NumCast(doc.y); var w = NumCast(layoutDoc.width); var h = NumCast(layoutDoc.height); if (this.intersectRect({ left: x, top: y, width: w, height: h }, otherBounds)) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 8153923de..2243a44d5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -34,13 +34,13 @@ export const PositionDocument = makeInterface(documentSchema, positionSchema); export class CollectionFreeFormDocumentView extends DocComponent(PositionDocument) { _disposer: IReactionDisposer | undefined = undefined; get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg)`; } - get X() { return this._animPos !== undefined ? this._animPos[0] : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : NumCast(this.layoutDoc.x); } - get Y() { return this._animPos !== undefined ? this._animPos[1] : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : NumCast(this.layoutDoc.y); } + get X() { return this._animPos !== undefined ? this._animPos[0] : this.renderScriptDim ? this.renderScriptDim.x : this.props.x !== undefined ? this.props.x : this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); } + get Y() { return this._animPos !== undefined ? this._animPos[1] : this.renderScriptDim ? this.renderScriptDim.y : this.props.y !== undefined ? this.props.y : this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); } get width() { return this.renderScriptDim ? this.renderScriptDim.width : this.props.width !== undefined ? this.props.width : this.props.dataProvider && this.dataProvider ? this.dataProvider.width : this.layoutDoc[WidthSym](); } get height() { return this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym](); } @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document, this.props.DataDoc) ? this.props.dataProvider(this.props.Document, this.props.DataDoc) : undefined; } - @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); } - @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); } + @computed get nativeWidth() { return NumCast(this.layoutDoc.nativeWidth); } + @computed get nativeHeight() { return NumCast(this.layoutDoc.nativeHeight); } @computed get renderScriptDim() { if (this.Document.renderScript) { @@ -92,11 +92,7 @@ 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; - } + get layoutDoc() { return Doc.Layout(this.props.Document); } @observable _animPos: number[] | undefined = undefined; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index d375405b9..bb9315ca3 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -77,11 +77,7 @@ export class DocumentContentsView extends React.Component(Docu public get ContentDiv() { return this._mainCont.current; } @computed get active() { return SelectionManager.IsSelected(this) || this.props.parentActive(); } @computed get topMost() { return this.props.renderDepth === 0; } - @computed get nativeWidth() { return this.Document.nativeWidth || 0; } - @computed get nativeHeight() { return this.Document.nativeHeight || 0; } + @computed get nativeWidth() { return this.layoutDoc.nativeWidth || 0; } + @computed get nativeHeight() { return this.layoutDoc.nativeHeight || 0; } @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } @action @@ -287,8 +287,9 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } - @undoBatch - static makeNativeViewClicked = async (doc: Doc): Promise => swapViews(doc, "layoutNative", "layoutCustom") + static makeNativeViewClicked = async (doc: Doc): Promise => { + undoBatch(() => swapViews(doc, "layoutNative", "layoutCustom"))(); + } static makeCustomViewClicked = async (doc: Doc, dataDoc: Opt) => { const batch = UndoManager.StartBatch("CustomViewClicked"); @@ -580,7 +581,7 @@ 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); + return Document(Doc.Layout(this.props.Document)); } // does Document set a layout prop diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index c5bf28d5b..fd6a475fb 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -37,7 +37,7 @@ export class FontIconBox extends DocComponent( } render() { let referenceDoc = (this.props.Document.dragFactory instanceof Doc ? this.props.Document.dragFactory : this.props.Document); - let referenceLayout = referenceDoc.layout instanceof Doc ? referenceDoc.layout : referenceDoc; + let referenceLayout = Doc.Layout(referenceDoc); return