From 26e215b0cddbb4c14cfd8eb7a720a373e797c615 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 15 Oct 2019 00:23:00 -0400 Subject: cleaned up current_user_utils. cleaned up some interactions with colorBox, textbox height --- src/client/views/nodes/FormattedTextBox.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index b05d0046c..181f37d36 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -43,7 +43,6 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format import React = require("react"); import { ContextMenuProps } from '../ContextMenuItem'; import { ContextMenu } from '../ContextMenu'; -import { TextShadowProperty } from 'csstype'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -490,7 +489,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ); this._heightReactionDisposer = reaction( - () => this.props.Document[WidthSym](), + () => [this.props.Document[WidthSym](), this.props.Document.autoHeight], () => this.tryUpdateHeight() ); @@ -984,13 +983,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @action tryUpdateHeight() { - const ChromeHeight = this.props.ChromeHeight; - let sh = this._ref.current ? this._ref.current.scrollHeight : 0; - if (!this.props.Document.isAnimating && this.props.Document.autoHeight && sh !== 0 && getComputedStyle(this._ref.current!.parentElement!).top === "0px") { + let scrollHeight = this._ref.current ? this._ref.current.scrollHeight : 0; + if (!this.props.Document.isAnimating && this.props.Document.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 * sh : sh) + (ChromeHeight ? ChromeHeight() : 0)); - this.dataDoc.nativeHeight = nh ? sh : undefined; + this.props.Document.height = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0)); + this.dataDoc.nativeHeight = nh ? scrollHeight : undefined; } } -- cgit v1.2.3-70-g09d2 From 33811c112c7e479813908ba10f72813954a3e289 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 15 Oct 2019 16:25:10 -0400 Subject: working version of inking buttons --- src/client/documents/Documents.ts | 2 ++ src/client/util/DragManager.ts | 4 +-- src/client/util/SelectionManager.ts | 11 -------- src/client/views/CollectionLinearView.tsx | 4 +-- src/client/views/InkingControl.tsx | 6 ++-- src/client/views/MainView.tsx | 6 ++-- src/client/views/nodes/ColorBox.tsx | 33 ++++++++++++++++++++-- src/client/views/nodes/DocumentView.tsx | 7 +++-- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 16 ++++++----- src/new_fields/Doc.ts | 4 +++ .../authentication/models/current_user_utils.ts | 31 +++++++++++--------- 12 files changed, 78 insertions(+), 48 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6df172f46..f4fce34ac 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -93,6 +93,8 @@ export interface DocumentOptions { autoHeight?: boolean; removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document dbDoc?: Doc; + unchecked?: ScriptField; // returns whether a check box is unchecked + activePen?: Doc; // which pen document is currently active (used as the radio button state for the 'unhecked' pen tool scripts) onClick?: ScriptField; onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop icon?: string; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 169f2edec..92666c03c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -234,9 +234,9 @@ export namespace DragManager { export let StartDragFunctions: (() => void)[] = []; - export async function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { runInAction(() => StartDragFunctions.map(func => func())); - await dragData.draggedDocuments.map(d => d.dragFactory); + dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : (dropData: { [id: string]: any }) => { (dropData.droppedDocuments = diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index df1b46b33..2d717ca57 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -45,17 +45,6 @@ export namespace SelectionManager { } const manager = new Manager(); - reaction(() => manager.SelectedDocuments, sel => { - let targetColor = "#FFFFFF"; - if (sel.length > 0) { - let firstView = sel[0]; - let doc = firstView.props.Document; - let targetDoc = doc.isTemplate ? doc : Doc.GetProto(doc); - let stored = StrCast(targetDoc.backgroundColor); - stored.length > 0 && (targetColor = stored); - } - InkingControl.Instance.updateSelectedColor(targetColor); - }, { fireImmediately: true }); export function DeselectDoc(docView: DocumentView): void { manager.DeselectDoc(docView); diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 9d1dd7749..eb3c768d0 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -48,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { drop = action((e: Event, de: DragManager.DropEvent) => { (de.data as DragManager.DocumentDragData).draggedDocuments.map((doc, i) => { let dbox = doc; - if (!doc.onDragStart && this.props.Document.convertToButtons && doc.viewType !== CollectionViewType.Linear) { + 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; dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined; @@ -90,7 +90,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { return
(); @computed get docButtons() { - console.log("stuff = " + this.flyoutWidthFunc() + " " + this.getContentsHeight()); if (CurrentUserUtils.UserDocument.expandingButtons instanceof Doc) { - return
+ return
; const ColorDocument = makeInterface(documentSchema); @@ -14,9 +17,35 @@ const ColorDocument = makeInterface(documentSchema); @observer export class ColorBox extends DocStaticComponent(ColorDocument) { public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(ColorBox, fieldKey); } + _selectedDisposer: IReactionDisposer | undefined; + componentDidMount() { + this._selectedDisposer = reaction(() => SelectionManager.SelectedDocuments(), + action(() => this._startupColor = SelectionManager.SelectedDocuments().length ? StrCast(SelectionManager.SelectedDocuments()[0].Document.backgroundColor, "black") : "black"), + { fireImmediately: true }); + + // compare to this reaction that used to be in Selection Manager + // reaction(() => manager.SelectedDocuments, sel => { + // let targetColor = "#FFFFFF"; + // if (sel.length > 0) { + // let firstView = sel[0]; + // let doc = firstView.props.Document; + // let targetDoc = doc.isTemplate ? doc : Doc.GetProto(doc); + // let stored = StrCast(targetDoc.backgroundColor); + // stored.length > 0 && (targetColor = stored); + // } + // InkingControl.Instance.updateSelectedColor(targetColor); + // }, { fireImmediately: true }); + } + componentWillUnmount() { + this._selectedDisposer && this._selectedDisposer(); + } + + @observable _startupColor = "black"; + render() { - return
e.button === 0 && !e.ctrlKey && e.stopPropagation()}> - + return
e.button === 0 && !e.ctrlKey && e.stopPropagation()}> +
; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c0e5185c1..6f99c541f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -107,7 +107,7 @@ export const documentSchema = createSchema({ removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. - dragFactory: Doc, // the document that serves as the "template" for the onDragStart script + 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 @@ -676,6 +676,7 @@ export class DocumentView extends DocComponent(Docu const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid", "solid"]; + let highlighting = fullDegree && this.props.Document.type !== DocumentType.FONTICON && this.props.Document.viewType !== CollectionViewType.Linear return (
(Docu transition: this.props.Document.isAnimating !== undefined ? ".5s linear" : StrCast(this.Document.transition), pointerEvents: this.Document.isBackground && !this.isSelected() ? "none" : "all", color: StrCast(this.Document.color), - outline: fullDegree && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", - border: fullDegree && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, + outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", + border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, background: this.props.Document.type === DocumentType.FONTICON || this.props.Document.viewType === CollectionViewType.Linear ? undefined : backgroundColor, width: animwidth, height: animheight, diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index aa442cd92..efe47d8a8 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -18,7 +18,7 @@ export class FontIconBox extends DocComponent( render() { return ; } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 181f37d36..1bdff3ec7 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -927,16 +927,18 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onMouseUp = (e: React.MouseEvent): void => { e.stopPropagation(); - // this interposes on prosemirror's upHandler to prevent prosemirror's up from invoked multiple times when there are nested prosemirrors. We only want the lowest level prosemirror to be invoked. - if ((this._editorView as any).mouseDown) { - let originalUpHandler = (this._editorView as any).mouseDown.up; - (this._editorView as any).root.removeEventListener("mouseup", originalUpHandler); - (this._editorView as any).mouseDown.up = (e: MouseEvent) => { + let view = this._editorView as any; + // this interposes on prosemirror's upHandler to prevent prosemirror's up from invoked multiple times when there + // are nested prosemirrors. We only want the lowest level prosemirror to be invoked. + if (view.mouseDown) { + let originalUpHandler = view.mouseDown.up; + view.root.removeEventListener("mouseup", originalUpHandler); + view.mouseDown.up = (e: MouseEvent) => { !(e as any).formattedHandled && originalUpHandler(e); - e.stopPropagation(); + // e.stopPropagation(); (e as any).formattedHandled = true; }; - (this._editorView as any).root.addEventListener("mouseup", (this._editorView as any).mouseDown.up); + view.root.addEventListener("mouseup", view.mouseDown.up); } } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 4bed113e3..276596fb8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -525,6 +525,7 @@ export namespace Doc { export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc { const copy = new Doc(copyProtoId, true); Object.keys(doc).forEach(key => { + let cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); const field = ProxyField.WithoutProxy(() => doc[key]); if (key === "proto" && copyProto) { if (doc[key] instanceof Doc) { @@ -533,6 +534,8 @@ export namespace Doc { } else { if (field instanceof RefField) { copy[key] = field; + } else if (cfield instanceof ComputedField) { + copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); } else if (field instanceof ObjectField) { copy[key] = ObjectField.MakeCopy(field); } else if (field instanceof Promise) { @@ -735,5 +738,6 @@ Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return Doc.Make Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); Scripting.addGlobal(function aliasDocs(field: any) { return new List(field.map((d: any) => Doc.MakeAlias(d))); }); Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); +Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2) }); Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index c4b91dadd..3c4a46ed8 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -8,7 +8,7 @@ import { UndoManager } from "../../../client/util/UndoManager"; import { Doc, DocListCast } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; +import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; import { RouteStore } from "../../RouteStore"; @@ -45,29 +45,32 @@ export class CurrentUserUtils { } // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools - static setupCreatorButtons() { - let docProtoData: { title: string, icon: string, drag?: string, click?: string }[] = [ + static setupCreatorButtons(doc: Doc) { + doc.activePen = doc; + let docProtoData: { title: string, icon: string, drag?: string, click?: string, unchecked?: string, activePen?: Doc, backgroundColor?: string }[] = [ { title: "collection", icon: "folder", drag: 'Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" })' }, { title: "web page", icon: "globe-asia", drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", { width: 300, height: 300, title: "New Webpage" })' }, { title: "image", icon: "cat", drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { width: 200, title: "an image of a cat" })' }, { title: "button", icon: "bolt", drag: 'Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })' }, { title: "presentation", icon: "tv", drag: 'Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { width: 200, height: 500, title: "a presentation trail" })' }, { title: "import folder", icon: "cloud-upload-alt", drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })' }, - { title: "pen", icon: "pen-nib", click: 'activatePen(); setInkWidth(2);' }, - { title: "highlighter", icon: "pen", click: 'activateBrush(); setInkWidth(20);' }, - { title: "eraser", icon: "eraser", click: 'activateEraser();' }, - { title: "none", icon: "pause", click: 'deactivateInk();' }, + { title: "pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "highlighter", icon: "pen", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, + { title: "none", icon: "pause", click: 'deactivateInk();this.activePen.pen = this;', unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ - nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.click ? "alias" : undefined, - title: data.title, icon: data.icon, onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined + nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, + onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, + unchecked: data.unchecked ? ComputedField.MakeFunction(data.unchecked) : undefined, activePen: data.activePen, + backgroundColor: data.backgroundColor })); } // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. when clicked, this panel will be displayed in the target container (ie, sidebarContainer) - static setupCreatePanel(sidebarContainer: Doc) { + static setupCreatePanel(sidebarContainer: Doc, doc: Doc) { // setup a masonry view of all he creators - const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(), { + const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), { width: 500, autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons" }); // setup a color picker @@ -129,7 +132,7 @@ export class CurrentUserUtils { doc.sidebarContainer = new Doc(); (doc.sidebarContainer as Doc).chromeStatus = "disabled"; - doc.CreateBtn = this.setupCreatePanel(doc.sidebarContainer as Doc); + doc.CreateBtn = this.setupCreatePanel(doc.sidebarContainer as Doc, doc); doc.LibraryBtn = this.setupLibraryPanel(doc.sidebarContainer as Doc, doc); doc.SearchBtn = this.setupSearchPanel(doc.sidebarContainer as Doc); @@ -143,9 +146,9 @@ export class CurrentUserUtils { /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupExpandingButtons(doc: Doc) { doc.undoBtn = Docs.Create.FontIconDocument( - { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); doc.redoBtn = Docs.Create.FontIconDocument( - { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); + { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); 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", -- cgit v1.2.3-70-g09d2 From 57ccb3e236a7dad71848a06dad757c5a5a081ce8 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 16 Oct 2019 12:34:47 -0400 Subject: starting to switch document embedding to alias dragging. --- src/client/util/DragManager.ts | 1 + src/client/views/DocumentButtonBar.tsx | 21 ++++++++++----------- src/client/views/collections/CollectionSubView.tsx | 3 +++ .../collectionFreeForm/CollectionFreeFormView.tsx | 15 +++++++++++++++ src/client/views/nodes/FormattedTextBox.tsx | 13 +++++-------- 5 files changed, 34 insertions(+), 19 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index dcd19e50b..29a75b9ae 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -311,6 +311,7 @@ export namespace DragManager { this.urlField = embeddableSourceDoc.data instanceof URLField ? embeddableSourceDoc.data : undefined; } embeddableSourceDoc: Doc; + embeddedDoc?: Doc; urlField?: URLField; [id: string]: any; } diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 9e2d41621..5561d699c 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -164,8 +164,12 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], let dragDocView = this.props.views[0]; let dragData = new DragManager.EmbedDragData(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); DragManager.StartEmbedDrag(dragDocView.ContentDiv!, dragData, e.x, e.y, { + offsetX: dragData.offset[0], + offsetY: dragData.offset[1], handlers: { dragComplete: action(emptyFunction), }, @@ -199,17 +203,12 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], e.stopPropagation(); } - considerEmbed = () => { - let thisDoc = this.props.views[0].props.Document; - let canEmbed = thisDoc.data && thisDoc.data instanceof URLField; - // if (!canEmbed) return (null); - return ( -
-
- -
+ embedDragger = () => { + return (
+
+
- ); +
); } private get targetDoc() { @@ -353,7 +352,7 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[],
{this.metadataMenu} - {this.considerEmbed()} + {this.embedDragger()} {this.considerGoogleDocsPush()} {this.considerGoogleDocsPull()} { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 9919a9dc3..077142e88 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -143,6 +143,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { e.stopPropagation(); return added; } + else if (de.data instanceof DragManager.EmbedDragData) { + return this.props.addDocument(de.data.embeddedDoc = Doc.MakeAlias(de.data.embeddableSourceDoc)); + } else if (de.data instanceof DragManager.AnnotationDragData) { e.stopPropagation(); return this.props.addDocument(de.data.dropDocument); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index adbad5da5..46aaed509 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -153,6 +153,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { de.data.droppedDocuments.length === 1 && this.updateCluster(de.data.droppedDocuments[0]); } } + else if (de.data instanceof DragManager.EmbedDragData && de.data.embeddedDoc) { + const d = de.data.embeddedDoc; + d.x = xp; + d.y = yp; + if (!NumCast(d.width)) { + d.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; + } + this.bringToFront(d); + this.updateCluster(d); + } else if (de.data instanceof DragManager.AnnotationDragData) { if (de.data.dropDocument) { let dragDoc = de.data.dropDocument; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 1bdff3ec7..8153cf61c 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -249,16 +249,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { - // We're dealing with a link to a document - if (de.data instanceof DragManager.EmbedDragData) { - let target = de.data.embeddableSourceDoc; - // We're dealing with an internal document drop - const link = DocUtils.MakeLink({ doc: this.dataDoc, ctx: this.props.ContainingCollectionDoc }, { doc: target }, "ImgRef:" + target.title); - let alias = Doc.MakeAlias(target); - alias.fitToBox = true; + if (de.data instanceof DragManager.EmbedDragData || (de.data instanceof DragManager.DocumentDragData && de.data.userDropAction)) { + let target = de.data instanceof DragManager.DocumentDragData ? de.data.droppedDocuments[0] : Doc.MakeAlias(de.data.embeddableSourceDoc); + 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: alias[Id], + title: "dashDoc", docid: target[Id], float: "right" }); let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y }); -- cgit v1.2.3-70-g09d2 From fb817995eb94727b11324f298d0a30eebda8dcb7 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 16 Oct 2019 12:47:09 -0400 Subject: removed DragEmbed -- subsumed by dragging aliases. --- src/client/util/DragManager.ts | 18 ++-------- src/client/views/DocumentButtonBar.tsx | 39 +++++++++++----------- src/client/views/collections/CollectionSubView.tsx | 3 -- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 --------- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- 5 files changed, 23 insertions(+), 56 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 29a75b9ae..12e0b11ba 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -211,6 +211,7 @@ export namespace DragManager { offset: number[]; dropAction: dropActionType; userDropAction: dropActionType; + forceUserDropAction: dropActionType; moveDocument?: MoveFunction; isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts applyAsTemplate?: boolean; @@ -305,17 +306,6 @@ export namespace DragManager { [id: string]: any; } - export class EmbedDragData { - constructor(embeddableSourceDoc: Doc) { - this.embeddableSourceDoc = embeddableSourceDoc; - this.urlField = embeddableSourceDoc.data instanceof URLField ? embeddableSourceDoc.data : undefined; - } - embeddableSourceDoc: Doc; - embeddedDoc?: Doc; - urlField?: URLField; - [id: string]: any; - } - // for column dragging in schema view export class ColumnDragData { constructor(colKey: SchemaHeaderField) { @@ -329,10 +319,6 @@ export namespace DragManager { StartDrag([ele], dragData, downX, downY, options); } - export function StartEmbedDrag(ele: HTMLElement, dragData: EmbedDragData, downX: number, downY: number, options?: DragOptions) { - StartDrag([ele], dragData, downX, downY, options); - } - export function StartColumnDrag(ele: HTMLElement, dragData: ColumnDragData, downX: number, downY: number, options?: DragOptions) { StartDrag([ele], dragData, downX, downY, options); } @@ -428,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 = e.ctrlKey || e.altKey ? "alias" : undefined; + dragData.userDropAction = dragData.forceUserDropAction ? dragData.forceUserDropAction : e.ctrlKey || e.altKey ? "alias" : undefined; } if (((options && !options.withoutShiftDrag) || !options) && e.shiftKey && CollectionDockingView.Instance) { AbortDrag(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 5561d699c..a00a4298f 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -6,7 +6,6 @@ import { observer } from "mobx-react"; import { Doc } from "../../new_fields/Doc"; import { RichTextField } from '../../new_fields/RichTextField'; import { NumCast } from "../../new_fields/Types"; -import { URLField } from '../../new_fields/URLField'; import { emptyFunction } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; @@ -45,7 +44,7 @@ const fetch: IconProp = "sync-alt"; export class DocumentButtonBar extends React.Component<{ views: DocumentView[], stack?: any }, {}> { private _linkButton = React.createRef(); private _linkerButton = React.createRef(); - private _embedButton = React.createRef(); + private _aliasButton = React.createRef(); private _tooltipoff = React.createRef(); private _textDoc?: Doc; private _linkDrag?: UndoManager.Batch; @@ -111,13 +110,13 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], document.addEventListener("pointerup", this.onLinkerButtonUp); } - onEmbedButtonDown = (e: React.PointerEvent): void => { + onAliasButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - document.removeEventListener("pointermove", this.onEmbedButtonMoved); - document.addEventListener("pointermove", this.onEmbedButtonMoved); - document.removeEventListener("pointerup", this.onEmbedButtonUp); - document.addEventListener("pointerup", this.onEmbedButtonUp); + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.addEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); + document.addEventListener("pointerup", this.onAliasButtonUp); } onLinkerButtonUp = (e: PointerEvent): void => { @@ -126,9 +125,9 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], e.stopPropagation(); } - onEmbedButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onEmbedButtonMoved); - document.removeEventListener("pointerup", this.onEmbedButtonUp); + onAliasButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); e.stopPropagation(); } @@ -157,17 +156,17 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], } @action - onEmbedButtonMoved = (e: PointerEvent): void => { - if (this._embedButton.current !== null) { - document.removeEventListener("pointermove", this.onEmbedButtonMoved); - document.removeEventListener("pointerup", this.onEmbedButtonUp); + onAliasButtonMoved = (e: PointerEvent): void => { + if (this._aliasButton.current !== null) { + document.removeEventListener("pointermove", this.onAliasButtonMoved); + document.removeEventListener("pointerup", this.onAliasButtonUp); let dragDocView = this.props.views[0]; - let dragData = new DragManager.EmbedDragData(dragDocView.props.Document); + 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); - - DragManager.StartEmbedDrag(dragDocView.ContentDiv!, dragData, e.x, e.y, { + dragData.forceUserDropAction = "alias"; + DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, e.x, e.y, { offsetX: dragData.offset[0], offsetY: dragData.offset[1], handlers: { @@ -203,9 +202,9 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], e.stopPropagation(); } - embedDragger = () => { + aliasDragger = () => { return (
-
+
); @@ -352,7 +351,7 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[],
{this.metadataMenu} - {this.embedDragger()} + {this.aliasDragger()} {this.considerGoogleDocsPush()} {this.considerGoogleDocsPull()} { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 077142e88..9919a9dc3 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -143,9 +143,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { e.stopPropagation(); return added; } - else if (de.data instanceof DragManager.EmbedDragData) { - return this.props.addDocument(de.data.embeddedDoc = Doc.MakeAlias(de.data.embeddableSourceDoc)); - } else if (de.data instanceof DragManager.AnnotationDragData) { e.stopPropagation(); return this.props.addDocument(de.data.dropDocument); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 46aaed509..adbad5da5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -153,21 +153,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { de.data.droppedDocuments.length === 1 && this.updateCluster(de.data.droppedDocuments[0]); } } - else if (de.data instanceof DragManager.EmbedDragData && de.data.embeddedDoc) { - const d = de.data.embeddedDoc; - d.x = xp; - d.y = yp; - if (!NumCast(d.width)) { - d.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; - } - this.bringToFront(d); - this.updateCluster(d); - } else if (de.data instanceof DragManager.AnnotationDragData) { if (de.data.dropDocument) { let dragDoc = de.data.dropDocument; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 8153cf61c..ae67e94cc 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -249,8 +249,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { - if (de.data instanceof DragManager.EmbedDragData || (de.data instanceof DragManager.DocumentDragData && de.data.userDropAction)) { - let target = de.data instanceof DragManager.DocumentDragData ? de.data.droppedDocuments[0] : Doc.MakeAlias(de.data.embeddableSourceDoc); + 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({ -- 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/nodes/FormattedTextBox.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/nodes/FormattedTextBox.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 caebaeca6993ff48609ab16dcc390d4d0458b03a Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 16 Oct 2019 23:50:27 -0400 Subject: fixed applying templates to collections. fixed templates containing collections --- src/client/documents/Documents.ts | 2 +- src/client/views/CollectionLinearView.tsx | 35 ++++++++++++++-------- src/client/views/InkingCanvas.tsx | 3 +- src/client/views/InkingControl.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionViewChromes.tsx | 4 +-- src/client/views/nodes/ColorBox.tsx | 7 ++--- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- src/new_fields/Doc.ts | 14 +++++++-- .../authentication/models/current_user_utils.ts | 14 +++------ 10 files changed, 51 insertions(+), 36 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2ffbc8394..62175cbe3 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -69,7 +69,7 @@ export interface DocumentOptions { preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view layout?: string | Doc; hideHeadings?: boolean; // whether stacking view column headings should be hidden - isTemplate?: boolean; + isTemplateField?: boolean; isTemplateDoc?: boolean; templates?: List; viewType?: number; diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 3e2ab1459..04e131135 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -47,24 +47,35 @@ 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 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; + let layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateField ? doc.layout : doc; + if (layoutDoc.type === DocumentType.COL) { + layoutDoc.isTemplateDoc = this.makeTemplate(layoutDoc); } else { - template.isTemplateDoc = (template.type === DocumentType.TEXT || template.layout instanceof Doc) && de.data instanceof DragManager.DocumentDragData && !de.data.userDropAction; + 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: template.isTemplateDoc ? "font" : "bolt" }); - dbox.dragFactory = template; + 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) { diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 9ab320eab..920ebaedd 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -181,9 +181,10 @@ export class InkingCanvas extends React.Component { render() { let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None && !this.props.Document.isBackground ? "canSelect" : "noSelect"; + let cursor = svgCanvasStyle === "canSelect" ? (InkingControl.Instance.selectedTool === InkTool.Eraser ? "pointer" : "default") : undefined; return (

-
+
{this.props.children()} {this.drawnPaths}
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index bc5249acd..b8f3c2875 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -94,7 +94,7 @@ export class InkingControl { redo: () => oldColors.forEach(pair => pair.target.backgroundColor = captured) }); } else { - CurrentUserUtils.UserDocument.activePen instanceof Doc && CurrentUserUtils.UserDocument.activePen.pen instanceof Doc && (CurrentUserUtils.UserDocument.activePen.pen.backgroundColor = this._selectedColor); + CurrentUserUtils.ActivePen && (CurrentUserUtils.ActivePen.backgroundColor = this._selectedColor); } }); @action diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 46fbb5910..1f8c0b18f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -61,7 +61,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { 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); + this.childDocs.filter(d => !d.isTemplateField).map(async doc => doc.layout = undefined); } }); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 3a66c05f4..a5b7f0181 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -40,9 +40,9 @@ export class CollectionViewBaseChrome extends React.Component this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined + immediate: (draggedDocs: Doc[]) => Doc.setChildLayout(this.props.CollectionView.props.Document, draggedDocs.length ? draggedDocs[0] : undefined) }; _contentCommand = { // title: "set content", script: "getProto(this.target).data = aliasDocs(this.source.map(async p => await p));", params: ["target", "source"], // bcz: doesn't look like we can do async stuff in scripting... diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index e4fef0922..30554ea36 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -25,9 +25,8 @@ export class ColorBox extends DocStaticComponent( this._selectedDisposer = reaction(() => SelectionManager.SelectedDocuments(), action(() => this._startupColor = SelectionManager.SelectedDocuments().length ? StrCast(SelectionManager.SelectedDocuments()[0].Document.backgroundColor, "black") : "black"), { fireImmediately: true }); - this._penDisposer = reaction(() => CurrentUserUtils.UserDocument.activePen instanceof Doc && CurrentUserUtils.UserDocument.activePen.pen, - action(() => this._startupColor = CurrentUserUtils.UserDocument.activePen instanceof Doc && CurrentUserUtils.UserDocument.activePen.pen instanceof Doc ? - StrCast(CurrentUserUtils.UserDocument.activePen.pen.backgroundColor, "black") : "black"), + this._penDisposer = reaction(() => CurrentUserUtils.ActivePen, + action(() => this._startupColor = CurrentUserUtils.ActivePen ? StrCast(CurrentUserUtils.ActivePen.backgroundColor, "black") : "black"), { fireImmediately: true }); // compare to this reaction that used to be in Selection Manager @@ -36,7 +35,7 @@ export class ColorBox extends DocStaticComponent( // if (sel.length > 0) { // let firstView = sel[0]; // let doc = firstView.props.Document; - // let targetDoc = doc.isTemplate ? doc : Doc.GetProto(doc); + // let targetDoc = doc.isTemplateField ? doc : Doc.GetProto(doc); // let stored = StrCast(targetDoc.backgroundColor); // stored.length > 0 && (targetColor = stored); // } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index ea82b1161..045eee3f7 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -143,7 +143,7 @@ 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 ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); } + @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateField ? 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 @@ -265,7 +265,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } // 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; + draggedDoc.isTemplateDoc = true; let newLayout = draggedDoc.layout instanceof Doc ? draggedDoc.layout : draggedDoc; if (typeof (draggedDoc.layout) === "string") { newLayout = Doc.MakeDelegate(draggedDoc); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 51fcb818a..04f310785 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -599,7 +599,7 @@ export namespace Doc { return target; } - export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc, suppressTitle: boolean = false) { + export function MakeMetadataFieldTemplate(fieldTemplate: Doc, templateDataDoc: Doc, suppressTitle: boolean = false): boolean { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let metadataFieldName = StrCast(fieldTemplate.title).replace(/^-/, ""); let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); @@ -613,7 +613,7 @@ export namespace Doc { fieldTemplate.templateField = metadataFieldName; fieldTemplate.title = metadataFieldName; - fieldTemplate.isTemplate = true; + fieldTemplate.isTemplateField = true; fieldTemplate.backgroundLayout = backgroundLayout; /* move certain layout properties from the original data doc to the template layout to avoid inheriting them from the template's data doc which may also define these fields for its own use. @@ -636,6 +636,7 @@ export namespace Doc { if (fieldTemplate.backgroundColor !== templateDataDoc.defaultBackgroundColor) fieldTemplate.defaultBackgroundColor = fieldTemplate.backgroundColor; fieldTemplate.proto = templateDataDoc; }), 0); + return true; } export function overlapping(doc: Doc, doc2: Doc, clusterDistance: number) { @@ -735,9 +736,18 @@ export namespace Doc { export function UnBrushAllDocs() { manager.BrushedDoc.clear(); } + + export function setChildLayout(target: Doc, source?: Doc) { + target.childLayout = source && source.isTemplateDoc ? source : source && + source.dragFactory instanceof Doc && source.dragFactory.isTemplateDoc ? source.dragFactory : + source && source.layout instanceof Doc && source.layout.isTemplateDoc ? source.layout : undefined; + } } + + Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); +Scripting.addGlobal(function setChildLayout(target: any, source: any) { Doc.setChildLayout(target, source); }); Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 5ce707011..e6f202685 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -23,16 +23,11 @@ export class CurrentUserUtils { public static get MainDocId() { return this.mainDocId; } public static set MainDocId(id: string | undefined) { this.mainDocId = id; } @computed public static get UserDocument() { return Doc.UserDoc(); } + @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).pen as Doc; } @observable public static GuestTarget: Doc | undefined; @observable public static GuestWorkspace: Doc | undefined; - private static createUserDocument(id: string): Doc { - let doc = new Doc(id, true); - doc.title = Doc.CurrentUserEmail; - return this.updateUserDocument(doc);// this should be the last - } - // a default set of note types .. not being used yet... static setupNoteTypes(doc: Doc) { return [ @@ -174,6 +169,7 @@ export class CurrentUserUtils { } static updateUserDocument(doc: Doc) { + doc.title = Doc.CurrentUserEmail; new InkingControl(); (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); @@ -216,10 +212,8 @@ export class CurrentUserUtils { Doc.CurrentUserEmail = email; await rp.get(Utils.prepend(RouteStore.getUserDocumentId)).then(id => { if (id && id !== "guest") { - return DocServer.GetRefField(id).then(async field => { - let userDoc = field instanceof Doc ? await this.updateUserDocument(field) : this.createUserDocument(id); - runInAction(() => Doc.SetUserDoc(userDoc)); - }); + return DocServer.GetRefField(id).then(async field => + Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(id, true)))); } else { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } -- cgit v1.2.3-70-g09d2 From e21810a4097e724a378416135c7cc6def7ff022c Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 18 Oct 2019 11:35:22 -0400 Subject: cleaned up dictation into text notes --- src/client/util/DictationManager.ts | 3 +- src/client/views/MainView.tsx | 3 +- src/client/views/nodes/FormattedTextBox.scss | 16 ++++++---- src/client/views/nodes/FormattedTextBox.tsx | 46 +++++++++++++++++++++++----- 4 files changed, 53 insertions(+), 15 deletions(-) (limited to 'src/client/views/nodes/FormattedTextBox.tsx') diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 182cfb70a..ae991635f 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -64,7 +64,7 @@ export namespace DictationManager { const intraSession = ". "; const interSession = " ... "; - let isListening = false; + export let isListening = false; let isManuallyStopped = false; let current: string | undefined = undefined; @@ -200,6 +200,7 @@ export namespace DictationManager { if (!isListening || !recognizer) { return; } + isListening = false; isManuallyStopped = true; salvageSession ? recognizer.stop() : recognizer.abort(); // let main = MainView.Instance; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0e15784f7..9304f4bef 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, - faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter + faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; @@ -106,6 +106,7 @@ export class MainView extends React.Component { library.add(faPen); library.add(faHighlighter); library.add(faEraser); + library.add(faFileAudio); library.add(faPenNib); library.add(faFilm); library.add(faMusic); diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 0550f9708..a4acd3b82 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -10,8 +10,7 @@ outline: none !important; } -.formattedTextBox-cont-scroll, -.formattedTextBox-cont-hidden { +.formattedTextBox-cont { cursor: text; background: inherit; padding: 0; @@ -26,10 +25,15 @@ color: initial; height: 100%; pointer-events: all; -} - -.formattedTextBox-cont-hidden { - // pointer-events: none; + overflow-y: auto; + max-height: 100%; + .formattedTextBox-dictation { + height: 20px; + width: 20px; + top: 0px; + left: 0px; + position: absolute; + } } .formattedTextBox-inner-rounded { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 045eee3f7..6f4ced7f3 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,7 +1,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { faEdit, faSmile, faTextHeight, faUpload } from '@fortawesome/free-solid-svg-icons'; import _ from "lodash"; -import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; import { history } from "prosemirror-history"; @@ -43,6 +43,8 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './Format import React = require("react"); import { ContextMenuProps } from '../ContextMenuItem'; import { ContextMenu } from '../ContextMenu'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { siteVerification } from 'googleapis/build/src/apis/siteVerification'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -369,7 +371,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe specificContextMenu = (e: React.MouseEvent): void => { let funcs: ContextMenuProps[] = []; - funcs.push({ description: "Dictate", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); + funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ description: (FormattedTextBox._highlights.indexOf(option) === -1 ? "Highlight " : "Unhighlight ") + option, event: () => { @@ -386,6 +388,27 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: funcs, icon: "asterisk" }); } + @observable _recording = false; + + recordDictation = () => { + //this._editorView!.focus(); + if (this._recording) return; + runInAction(() => this._recording = true); + DictationManager.Controls.listen({ + interimHandler: this.setCurrentBulletContent, + continuous: { indefinite: false }, + }).then(results => { + if (results && [DictationManager.Controls.Infringed].includes(results)) { + DictationManager.Controls.stop(); + } + this._editorView!.focus(); + }); + } + stopDictation = (abort: boolean) => { + runInAction(() => this._recording = false); + DictationManager.Controls.stop(!abort); + } + recordBullet = async () => { let completedCue = "end session"; let results = await DictationManager.Controls.listen({ @@ -902,6 +925,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } this.hitBulletTargets(e.clientX, e.clientY, e.nativeEvent.offsetX, e.shiftKey); + if (this._recording) setTimeout(() => { this.stopDictation(true); setTimeout(() => this.recordDictation(), 500); }, 500); } // this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them. @@ -965,7 +989,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }); } onBlur = (e: any) => { - DictationManager.Controls.stop(false); + //DictationManager.Controls.stop(false); if (this._undoTyping) { this._undoTyping.end(); this._undoTyping = undefined; @@ -986,6 +1010,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (!this._undoTyping) { this._undoTyping = UndoManager.StartBatch("undoTyping"); } + if (this._recording) { this.stopDictation(true); setTimeout(() => this.recordDictation(), 250); } } @action @@ -1001,7 +1026,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } render() { - let style = "hidden"; let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; let interactive: "all" | "none" = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground ? "none" : "all"; @@ -1010,10 +1034,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props); } return ( -
this._entered = false)} >
+ +
{ + this._recording ? this.stopDictation(true) : this.recordDictation(); + setTimeout(() => this._editorView!.focus(), 500); + e.stopPropagation(); + }} > + +
); } -- 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/nodes/FormattedTextBox.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