From 988822bdeeed82b0c1ef611f2f7a3111d029d564 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 12 Oct 2019 19:37:06 -0400 Subject: a bunch of fixes to clean up drag box stuff. --- src/client/views/nodes/FontIconBox.tsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/client/views/nodes/FontIconBox.tsx (limited to 'src/client/views/nodes/FontIconBox.tsx') diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx new file mode 100644 index 000000000..3b580d851 --- /dev/null +++ b/src/client/views/nodes/FontIconBox.tsx @@ -0,0 +1,21 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { DocComponent } from '../DocComponent'; +import './FontIconBox.scss'; +import { FieldView, FieldViewProps } from './FieldView'; +const FontIconSchema = createSchema({ + icon: "string" +}); + +type FontIconDocument = makeInterface<[typeof FontIconSchema]>; +const FontIconDocument = makeInterface(FontIconSchema); +@observer +export class FontIconBox extends DocComponent(FontIconDocument) { + public static LayoutString() { return FieldView.LayoutString(FontIconBox); } + + render() { + return
; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a01d6183eeb6b895c50b3d09ea2113068bc11669 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 13 Oct 2019 19:17:45 -0400 Subject: minor cleanups --- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/util/UndoManager.ts | 4 +- src/client/views/CollectionLinearView.scss | 118 ++++++++++----------- src/client/views/CollectionLinearView.tsx | 103 ++++++++++-------- src/client/views/DocumentDecorations.tsx | 8 +- src/client/views/MainView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FontIconBox.tsx | 2 +- src/new_fields/Doc.ts | 5 +- .../authentication/models/current_user_utils.ts | 21 +++- 10 files changed, 150 insertions(+), 118 deletions(-) (limited to 'src/client/views/nodes/FontIconBox.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index c82d3bc63..31d98887f 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -850,7 +850,7 @@ export class TooltipTextMenu { } this.view = view; let state = view.state; - DocumentDecorations.Instance.TextBar && DocumentDecorations.Instance.setTextBar(DocumentDecorations.Instance.TextBar); + DocumentDecorations.Instance.showTextBar(); props && (this.editorProps = props); // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 7abb9d1ee..472afac1d 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -73,8 +73,8 @@ export namespace UndoManager { } type UndoBatch = UndoEvent[]; - let undoStack: UndoBatch[] = observable([]); - let redoStack: UndoBatch[] = observable([]); + export let undoStack: UndoBatch[] = observable([]); + export let redoStack: UndoBatch[] = observable([]); let currentBatch: UndoBatch | undefined; let batchCounter = 0; let undoing = false; diff --git a/src/client/views/CollectionLinearView.scss b/src/client/views/CollectionLinearView.scss index 46a226eef..1e6bb5922 100644 --- a/src/client/views/CollectionLinearView.scss +++ b/src/client/views/CollectionLinearView.scss @@ -5,73 +5,69 @@ overflow: hidden; height:100%; padding:5px; -} -.collectionLinearView { - display:flex; - >label { - background: $dark-color; - color: $light-color; - display: inline-block; - border-radius: 18px; - font-size: 25px; - width: 36px; - height: 36px; - margin-right: 10px; - cursor: pointer; - transition: transform 0.2s; - } + .collectionLinearView { + display:flex; + >label { + background: $dark-color; + color: $light-color; + display: inline-block; + border-radius: 18px; + font-size: 25px; + width: 36px; + height: 36px; + margin-right: 10px; + cursor: pointer; + transition: transform 0.2s; + } - label p { - padding-left: 10.5px; - width: 500px; - height: 500px; - } + label p { + padding-left: 10.5px; + width: 500px; + height: 500px; + } - label:hover { - background: $main-accent; - transform: scale(1.15); - } + label:hover { + background: $main-accent; + transform: scale(1.15); + } - >input { - display: none; - } - >input:not(:checked)~.collectionLinearView-content { - display: none; - } + >input { + display: none; + } + >input:not(:checked)~.collectionLinearView-content { + display: none; + } - >input:checked~label { - transform: rotate(45deg); - transition: transform 0.5s; - cursor: pointer; - } + >input:checked~label { + transform: rotate(45deg); + transition: transform 0.5s; + cursor: pointer; + } - .collectionLinearView-content { - display: flex; - opacity: 1; - padding: 0; - position: relative; - .collectionFreeFormDocumentView-container { + .collectionLinearView-content { + display: flex; + opacity: 1; + padding: 0; position: relative; - } - .collectionLinearView-docBtn { - position:relative; - margin-right: 10px; - } - .collectionLinearView-round-button { - width: 36px; - height: 36px; - border-radius: 18px; - font-size: 15px; - } - - .collectionLinearView-round-button:hover { - transform: scale(1.15); + + .collectionLinearView-docBtn { + position:relative; + margin-right: 10px; + } + .collectionLinearView-docBtn:hover { + transform: scale(1.15); + } + + .collectionLinearView-round-button { + width: 36px; + height: 36px; + border-radius: 18px; + font-size: 15px; + } + + .collectionLinearView-round-button:hover { + transform: scale(1.15); + } } - - } - - .collectionLinearView-add-button { - position: relative; - margin-right: 10px; } } diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 692f940f8..49c67a448 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -1,8 +1,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, computed } from 'mobx'; +import { action, observable, computed, IReactionDisposer, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; +import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc'; import { InkTool } from '../../new_fields/InkField'; import { ObjectField } from '../../new_fields/ObjectField'; import { ScriptField } from '../../new_fields/ScriptField'; @@ -25,12 +25,26 @@ const LinearDocument = makeInterface(documentSchema); @observer export class CollectionLinearView extends CollectionSubView(LinearDocument) { @observable public addMenuToggle = React.createRef(); + @observable private _checked = false; private _dropDisposer?: DragManager.DragDropDisposer; + private _heightDisposer?: IReactionDisposer; componentWillUnmount() { this._dropDisposer && this._dropDisposer(); + this._heightDisposer && this._heightDisposer(); } + 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(() => NumCast(this.props.Document.height, 0) + this.childDocs.length + (this._checked ? 1 : 0), + () => { + if (true || this.props.Document.fitWidth) { + this.props.Document.width = 36 + (this._checked ? this.childDocs.length * (this.props.Document[HeightSym]() + 10) : 10); + } + }, + { fireImmediately: true } + ); + } protected createDropTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this._dropDisposer && this._dropDisposer(); if (ele) { @@ -66,50 +80,49 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { dimension = () => NumCast(this.props.Document.height) - 5; render() { let guid = Utils.GenerateGuid(); - return
- - - -
- {this.props.showHiddenControls ? : (null)} - {this.props.showHiddenControls ? : (null)} + return
+
+ this._checked = this.addMenuToggle.current!.checked)} /> + - {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => -
- this.dimension() / (10 + NumCast(pair.layout.nativeWidth, this.dimension()))} // ugh - need to get rid of this inline function to avoid recomputing - PanelWidth={this.dimension} - PanelHeight={this.dimension} - renderDepth={this.props.renderDepth + 1} - focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - bringToFront={emptyFunction} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - zoomToScale={emptyFunction} - getScale={returnOne}> - -
)} - {/*
  • */} - {this.props.showHiddenControls ? <> - - - - - - : (null)} +
    + {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => +
    + this.dimension() / (10 + NumCast(pair.layout.nativeWidth, this.dimension()))} // ugh - need to get rid of this inline function to avoid recomputing + PanelWidth={this.dimension} + PanelHeight={this.dimension} + renderDepth={this.props.renderDepth + 1} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + zoomToScale={emptyFunction} + getScale={returnOne}> + +
    )} + {/*
  • */} + {this.props.showHiddenControls ? <> + + + + + + : (null)} +
    -
    ; +
    ; } } \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1d9f0c74b..3d73f048d 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -547,10 +547,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } TextBar: HTMLDivElement | undefined; - setTextBar = (ele: HTMLDivElement) => { + private setTextBar = (ele: HTMLDivElement) => { if (ele) { this.TextBar = ele; - TooltipTextMenu.Toolbar && Array.from(ele.childNodes).indexOf(TooltipTextMenu.Toolbar) === -1 && ele.appendChild(TooltipTextMenu.Toolbar); + } + } + public showTextBar = () => { + if (this.TextBar) { + TooltipTextMenu.Toolbar && Array.from(this.TextBar.childNodes).indexOf(TooltipTextMenu.Toolbar) === -1 && this.TextBar.appendChild(TooltipTextMenu.Toolbar); } } render() { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5756c1510..39585113b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -334,6 +334,7 @@ export class MainView extends React.Component { return CollectionDockingView.AddRightSplit(doc, undefined); } } + mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1); @computed get flyout() { let sidebarContent = this.userDoc && this.userDoc.sidebarContainer; @@ -379,7 +380,7 @@ export class MainView extends React.Component { removeDocument={returnFalse} ruleProvider={undefined} onClick={undefined} - ScreenToLocalTransform={Transform.Identity} + ScreenToLocalTransform={this.mainContainerXf} ContentScaling={returnOne} PanelWidth={this.flyoutWidthFunc} PanelHeight={this.getContentsHeight} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7334de92c..188c18ba7 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -185,7 +185,7 @@ export class DocumentView extends DocComponent(Docu (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { e.stopPropagation(); let preventDefault = true; - if (this._doubleTap && this.props.renderDepth) { + if (this._doubleTap && this.props.renderDepth && (!this.onClickHandler || !this.onClickHandler.script)) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click let fullScreenAlias = Doc.MakeAlias(this.props.Document); let layoutNative = await PromiseValue(Cast(this.props.Document.layoutNative, Doc)); if (layoutNative && fullScreenAlias.layout === layoutNative.layout) { diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 3b580d851..3f5afb6d1 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -16,6 +16,6 @@ export class FontIconBox extends DocComponent( public static LayoutString() { return FieldView.LayoutString(FontIconBox); } render() { - return
    ; + return ; } } \ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 66036f673..4bed113e3 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -14,6 +14,7 @@ import { ComputedField } from "./ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, PromiseValue, StrCast, ToConstructor } from "./Types"; import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; import { intersectRect } from "../Utils"; +import { UndoManager } from "../client/util/UndoManager"; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -733,4 +734,6 @@ Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return Doc.MakeCopy(doc, copyProto); }); 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); }); \ No newline at end of file +Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); +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 3858907ba..73cac879e 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,4 +1,4 @@ -import { action, computed, observable, runInAction } from "mobx"; +import { action, computed, observable, runInAction, reaction } from "mobx"; import * as rp from 'request-promise'; import { DocServer } from "../../../client/DocServer"; import { Docs } from "../../../client/documents/Documents"; @@ -13,6 +13,8 @@ import { Cast, StrCast, PromiseValue } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; import { RouteStore } from "../../RouteStore"; import { ScriptField } from "../../../new_fields/ScriptField"; +import { ButtonBox } from "../../../client/views/nodes/ButtonBox"; +import { UndoManager } from "../../../client/util/UndoManager"; export class CurrentUserUtils { private static curr_id: string; @@ -32,7 +34,6 @@ export class CurrentUserUtils { doc.viewType = CollectionViewType.Tree; doc.layout = CollectionView.LayoutString(); doc.title = Doc.CurrentUserEmail; - this.updateUserDocument(doc); doc.data = new List(); doc.gridGap = 5; doc.xMargin = 5; @@ -41,11 +42,21 @@ export class CurrentUserUtils { doc.boxShadow = "0 0"; doc.convertToButtons = true; // for CollectionLinearView used as the docButton layout doc.optionalRightCollection = Docs.Create.StackingDocument([], { title: "New mobile uploads" }); - return doc; + return this.updateUserDocument(doc);// this should be the last } static updateUserDocument(doc: Doc) { + if (doc.undoBtn === undefined) { + doc.undoBtn = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Collection", icon: "undo-alt" }); + (doc.undoBtn as Doc).onClick = ScriptField.MakeScript('undo()'); + Doc.AddDocToList(doc, "docButtons", doc.undoBtn as Doc); + } + if (doc.redoBtn === undefined) { + doc.redoBtn = Docs.Create.FontIconDocument({ nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, title: "Collection", icon: "redo-alt" }); + (doc.redoBtn as Doc).onClick = ScriptField.MakeScript('redo()'); + Doc.AddDocToList(doc, "docButtons", doc.redoBtn as Doc); + } // setup workspaces library item if (doc.workspaces === undefined) { const workspaces = Docs.Create.TreeDocument([], { title: "WORKSPACES", height: 100 }); @@ -181,6 +192,10 @@ export class CurrentUserUtils { doc.preventTreeViewOpen = true; doc.forceActive = true; doc.lockedPosition = true; + doc.undoBtn && reaction(() => UndoManager.undoStack.slice(), () => (doc.undoBtn as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + doc.redoBtn && reaction(() => UndoManager.redoStack.slice(), () => (doc.redoBtn as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); + + return doc; } public static loadCurrentUser() { -- cgit v1.2.3-70-g09d2 From 03f86e3b7b450699073c47aa43af23d31e0765d4 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 15 Oct 2019 13:42:13 -0400 Subject: extensions for linearViews or nesting. --- src/client/documents/Documents.ts | 2 +- src/client/views/CollectionLinearView.scss | 24 +++--- src/client/views/CollectionLinearView.tsx | 88 +++++++++++----------- src/client/views/DocComponent.tsx | 2 +- src/client/views/InkingControl.tsx | 58 +++++--------- src/client/views/MainView.tsx | 80 ++++++++++++-------- src/client/views/collections/CollectionSubView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 15 ++-- src/client/views/nodes/FontIconBox.tsx | 5 +- .../authentication/models/current_user_utils.ts | 26 ++++--- 10 files changed, 154 insertions(+), 147 deletions(-) (limited to 'src/client/views/nodes/FontIconBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5794a6bee..6df172f46 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -471,7 +471,7 @@ export namespace Docs { } export function LinearDocument(documents: Array, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Linear }, id); + return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, viewType: CollectionViewType.Linear }, id); } export function SchemaDocument(schemaColumns: SchemaHeaderField[], documents: Array, options: DocumentOptions) { diff --git a/src/client/views/CollectionLinearView.scss b/src/client/views/CollectionLinearView.scss index 4bfd88b69..4423a7020 100644 --- a/src/client/views/CollectionLinearView.scss +++ b/src/client/views/CollectionLinearView.scss @@ -4,26 +4,25 @@ .collectionLinearView-outer{ overflow: hidden; height:100%; - padding:5px; .collectionLinearView { display:flex; + height: 100%; >label { background: $dark-color; color: $light-color; display: inline-block; border-radius: 18px; - font-size: 25px; - width: 36px; - height: 36px; - margin-right: 10px; + font-size: 12.5px; + width: 18px; + height: 18px; + margin-top:auto; + margin-bottom:auto; cursor: pointer; transition: transform 0.2s; } label p { - padding-left: 10.5px; - width: 500px; - height: 500px; + padding-left:5px; } label:hover { @@ -47,20 +46,21 @@ .collectionLinearView-content { display: flex; opacity: 1; - padding: 0; position: relative; + margin-top: auto; .collectionLinearView-docBtn, .collectionLinearView-docBtn-scalable { position:relative; - margin-right: 10px; + margin-top: auto; + margin-bottom: auto; } .collectionLinearView-docBtn-scalable:hover { transform: scale(1.15); } .collectionLinearView-round-button { - width: 36px; - height: 36px; + width: 18px; + height: 18px; border-radius: 18px; font-size: 15px; } diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index 5c793f784..9d1dd7749 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -1,23 +1,20 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, computed, IReactionDisposer, reaction } from 'mobx'; +import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc'; -import { InkTool } from '../../new_fields/InkField'; +import { Doc, HeightSym, WidthSym } from '../../new_fields/Doc'; import { ObjectField } from '../../new_fields/ObjectField'; +import { makeInterface } from '../../new_fields/Schema'; import { ScriptField } from '../../new_fields/ScriptField'; -import { NumCast, StrCast } from '../../new_fields/Types'; -import { emptyFunction, returnEmptyString, returnOne, returnTrue, returnFalse, Utils } from '../../Utils'; +import { BoolCast, NumCast, StrCast } from '../../new_fields/Types'; +import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; -import { UndoManager } from '../util/UndoManager'; -import { InkingControl } from './InkingControl'; -import { DocumentView, documentSchema } from './nodes/DocumentView'; import "./CollectionLinearView.scss"; -import { makeInterface } from '../../new_fields/Schema'; +import { CollectionViewType } from './collections/CollectionBaseView'; import { CollectionSubView } from './collections/CollectionSubView'; -import { DocumentType } from '../documents/DocumentTypes'; +import { documentSchema, DocumentView } from './nodes/DocumentView'; +import { translate } from 'googleapis/build/src/apis/translate'; type LinearDocument = makeInterface<[typeof documentSchema,]>; @@ -26,7 +23,6 @@ const LinearDocument = makeInterface(documentSchema); @observer export class CollectionLinearView extends CollectionSubView(LinearDocument) { @observable public addMenuToggle = React.createRef(); - @observable private _checked = false; private _dropDisposer?: DragManager.DragDropDisposer; private _heightDisposer?: IReactionDisposer; @@ -37,12 +33,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { 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(() => NumCast(this.props.Document.height, 0) + this.childDocs.length + (this._checked ? 1 : 0), - () => { - if (true || this.props.Document.fitWidth) { - this.props.Document.width = 36 + (this._checked ? this.childDocs.length * (this.props.Document[HeightSym]() + 10) : 10); - } - }, + this._heightDisposer = reaction(() => NumCast(this.props.Document.height, 0) + this.childDocs.length + (this.props.Document.isExpanded ? 1 : 0), + () => this.props.Document.width = 18 + (this.props.Document.isExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10), { fireImmediately: true } ); } @@ -56,11 +48,13 @@ 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) { + if (!doc.onDragStart && 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; dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); + } else if (doc.viewType === CollectionViewType.Linear) { + dbox.ignoreClick = true; } (de.data as DragManager.DocumentDragData).droppedDocuments[i] = dbox; }); @@ -68,40 +62,51 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { return super.drop(e, de); }); - selected = (tool: InkTool) => { - if (!InkingControl.Instance || InkingControl.Instance.selectedTool === InkTool.None) return { display: "none" }; - if (InkingControl.Instance.selectedTool === tool) { - return { color: "#61aaa3", fontSize: "50%" }; - } - return { fontSize: "50%" }; - } - public isCurrent(doc: Doc) { return !doc.isMinimized && (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); } - dimension = () => NumCast(this.props.Document.height) - 5; + dimension = () => NumCast(this.props.Document.height); // 2 * the padding + getTransform = (ele: React.RefObject) => () => { + if (!ele.current) return Transform.Identity(); + let { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); + return new Transform(-translateX, -translateY, 1 / scale); + }; + _spacing = 20; render() { let guid = Utils.GenerateGuid(); return
    - this._checked = this.addMenuToggle.current!.checked)} /> - + this.props.Document.isExpanded = this.addMenuToggle.current!.checked)} /> +
    - {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => -
    + {this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => { + let nested = pair.layout.viewType === CollectionViewType.Linear; + let dref = React.createRef(); + let nativeWidth = NumCast(pair.layout.nativeWidth, this.dimension()); + let scalingContent = nested ? 1 : this.dimension() / (this._spacing + nativeWidth); + let scalingBox = nested ? 1 : this.dimension() / nativeWidth; + let deltaSize = nativeWidth * scalingBox - nativeWidth * scalingContent; + return
    this.dimension() / (10 + NumCast(pair.layout.nativeWidth, this.dimension()))} // ugh - need to get rid of this inline function to avoid recomputing - PanelWidth={this.dimension} - PanelHeight={this.dimension} + ScreenToLocalTransform={this.getTransform(dref)} + ContentScaling={() => scalingContent} // ugh - need to get rid of this inline function to avoid recomputing + PanelWidth={() => nested ? pair.layout[WidthSym]() : this.dimension()} + PanelHeight={() => nested ? pair.layout[HeightSym]() : this.dimension()} renderDepth={this.props.renderDepth + 1} focus={emptyFunction} backgroundColor={returnEmptyString} @@ -113,15 +118,10 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { zoomToScale={emptyFunction} getScale={returnOne}> -
    )} +
    + })} {/*
  • */} - {this.props.showHiddenControls ? <> - - - - - - : (null)} +
    ; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b05966bb5..fbc27192c 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -36,7 +36,7 @@ export function DocStaticComponent

    (schemaCtor: (doc get Document(): T { return schemaCtor(this.props.Document); } - active = () => (this.props.Document.forceActive || this.props.isSelected() || this.props.renderDepth === 0) && !InkingControl.Instance.selectedTool; + active = () => (this.props.Document.forceActive || this.props.isSelected() || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools } return Component; } diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index d42d8d2d9..41dec9f83 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,38 +1,30 @@ -import { observable, action, computed, runInAction } from "mobx"; +import { action, computed, observable } from "mobx"; import { ColorResult } from 'react-color'; -import React = require("react"); -import { observer } from "mobx-react"; -import "./InkingControl.scss"; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons'; -import { SelectionManager } from "../util/SelectionManager"; -import { InkTool } from "../../new_fields/InkField"; import { Doc } from "../../new_fields/Doc"; -import { undoBatch, UndoManager } from "../util/UndoManager"; -import { StrCast, NumCast, Cast } from "../../new_fields/Types"; -import { listSpec } from "../../new_fields/Schema"; +import { InkTool } from "../../new_fields/InkField"; import { List } from "../../new_fields/List"; +import { listSpec } from "../../new_fields/Schema"; +import { Cast, NumCast, StrCast } from "../../new_fields/Types"; import { Utils } from "../../Utils"; +import { Scripting } from "../util/Scripting"; +import { SelectionManager } from "../util/SelectionManager"; +import { undoBatch, UndoManager } from "../util/UndoManager"; -library.add(faPen, faHighlighter, faEraser, faBan); -@observer -export class InkingControl extends React.Component { +export class InkingControl { @observable static Instance: InkingControl; @observable private _selectedTool: InkTool = InkTool.None; @observable private _selectedColor: string = "rgb(244, 67, 54)"; @observable private _selectedWidth: string = "5"; @observable public _open: boolean = false; - constructor(props: Readonly<{}>) { - super(props); - runInAction(() => InkingControl.Instance = this); + constructor() { + InkingControl.Instance = this; } - @action - switchTool = (tool: InkTool): void => { + switchTool = action((tool: InkTool): void => { this._selectedTool = tool; - } + }) decimalToHexString(number: number) { if (number < 0) { number = 0xFFFFFFFF + number + 1; @@ -124,22 +116,10 @@ export class InkingControl extends React.Component { return this._selectedWidth; } - @action - toggleDisplay = () => { - this._open = !this._open; - this.switchTool(this._open ? InkTool.Pen : InkTool.None); - } - render() { - return ( -

      -
    • - - ) => this.switchWidth(e.target.value)} /> - ) => this.switchWidth(e.target.value)} /> -
    • -
    - ); - } -} \ No newline at end of file +} +Scripting.addGlobal(function activatePen() { return InkingControl.Instance.switchTool(InkTool.Pen); }); +Scripting.addGlobal(function activateBrush() { return InkingControl.Instance.switchTool(InkTool.Highlighter); }); +Scripting.addGlobal(function activateEraser() { return InkingControl.Instance.switchTool(InkTool.Eraser); }); +Scripting.addGlobal(function deactivateInk() { return InkingControl.Instance.switchTool(InkTool.None); }); +Scripting.addGlobal(function setInkWidth(width: any) { return InkingControl.Instance.switchWidth(width); }); +Scripting.addGlobal(function setInkColor(color: any) { return InkingControl.Instance.updateSelectedColor(color); }); \ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 701f094e2..4e06763a4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,5 +1,8 @@ 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, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; +import { + faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, + faMusic, faObjectGroup, faPause, faPenNib, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt +} from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -99,6 +102,8 @@ export class MainView extends React.Component { library.add(faGlobeAsia); library.add(faUndoAlt); library.add(faRedoAlt); + library.add(faPen); + library.add(faEraser); library.add(faPenNib); library.add(faFilm); library.add(faMusic); @@ -450,37 +455,50 @@ export class MainView extends React.Component { Doc.RemoveDocFromList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", doc); return true; } + @action + moveButtonDoc = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { + return this.remButtonDoc(doc) && addDocument(doc); + } + buttonBarXf = () => { + if (!this._docBtnRef.current) return Transform.Identity(); + let { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current); + return new Transform(-translateX, -translateY, 1 / scale); + } + _docBtnRef = React.createRef(); @computed get docButtons() { - return
    - - -
    ; + console.log("stuff = " + this.flyoutWidthFunc() + " " + this.getContentsHeight()); + if (CurrentUserUtils.UserDocument.expandingButtons instanceof Doc) { + return
    + + +
    ; + } + return (null); } render() { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 6e8e4fa12..fdbe5339d 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -33,7 +33,6 @@ export interface CollectionViewProps extends FieldViewProps { VisibleHeight?: () => number; chromeCollapsed: boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; - showHiddenControls?: boolean; // hack for showing the undo/redo/ink controls in a linear view -- needs to be redone } export interface SubCollectionViewProps extends CollectionViewProps { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 62264ea38..c0e5185c1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -39,6 +39,7 @@ import { ImageField } from '../../../new_fields/URLField'; import SharingManager from '../../util/SharingManager'; import { Scripting } from '../../util/Scripting'; import { DictationOverlay } from '../DictationOverlay'; +import { CollectionViewType } from '../collections/CollectionBaseView'; library.add(fa.faEdit); library.add(fa.faTrash); @@ -105,7 +106,7 @@ export const documentSchema = createSchema({ dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") 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 an Doc to drag. + 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 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 @@ -167,7 +168,7 @@ export class DocumentView extends DocComponent(Docu if (this._mainCont.current) { let dragData = new DragManager.DocumentDragData([this.props.Document]); const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); - dragData.offset = this.Document.onDragStart ? [0, 0] : this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); + dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.moveDocument = this.Document.onDragStart ? undefined : this.props.moveDocument; dragData.applyAsTemplate = applyAsTemplate; @@ -175,7 +176,7 @@ export class DocumentView extends DocComponent(Docu handlers: { dragComplete: action((emptyFunction)) }, - hideSource: !dropAction && !this.Document.onDragStart + hideSource: !dropAction && !this.Document.onDragStart && !this.Document.onClick }); } } @@ -249,7 +250,7 @@ export class DocumentView extends DocComponent(Docu this._hitTemplateDrag = true; } } - if ((this.active || this.Document.onDragStart) && e.button === 0 && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); + if ((this.active || this.Document.onDragStart || this.Document.onClick) && e.button === 0 && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); @@ -261,9 +262,9 @@ export class DocumentView extends DocComponent(Docu if (e.cancelBubble && this.active) { document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) } - else if (!e.cancelBubble && (SelectionManager.IsSelected(this) || this.props.parentActive() || this.Document.onDragStart) && !this.Document.lockedPosition && !this.Document.inOverlay) { + else if (!e.cancelBubble && (SelectionManager.IsSelected(this) || this.props.parentActive() || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { - if (!e.altKey && (!this.topMost || this.Document.onDragStart) && e.buttons === 1) { + if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && e.buttons === 1) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); @@ -684,7 +685,7 @@ export class DocumentView extends DocComponent(Docu 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, - background: backgroundColor, + background: this.props.Document.type === DocumentType.FONTICON || this.props.Document.viewType === CollectionViewType.Linear ? undefined : backgroundColor, width: animwidth, height: animheight, transform: `scale(${this.props.Document.fitWidth ? 1 : this.props.ContentScaling()})`, diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 3f5afb6d1..aa442cd92 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -5,6 +5,7 @@ import { createSchema, makeInterface } from '../../../new_fields/Schema'; import { DocComponent } from '../DocComponent'; import './FontIconBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; +import { StrCast } from '../../../new_fields/Types'; const FontIconSchema = createSchema({ icon: "string" }); @@ -16,6 +17,8 @@ export class FontIconBox extends DocComponent( public static LayoutString() { return FieldView.LayoutString(FontIconBox); } render() { - return ; + return ; } } \ 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 8af6bbfd5..c4b91dadd 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -12,6 +12,7 @@ import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { Utils } from "../../../Utils"; import { RouteStore } from "../../RouteStore"; +import { InkingControl } from "../../../client/views/InkingControl"; export class CurrentUserUtils { private static curr_id: string; @@ -45,17 +46,21 @@ export class CurrentUserUtils { // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools static setupCreatorButtons() { - let docProtoData = [ - { title: "collection", icon: "folder", script: 'Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" })' }, - { title: "web page", icon: "globe-asia", script: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", { width: 300, height: 300, title: "New Webpage" })' }, - { title: "image", icon: "cat", script: '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", script: 'Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", script: 'Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { width: 200, height: 500, title: "a presentation trail" })' }, - { title: "import folder", icon: "cloud-upload-alt", script: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })' }, + let docProtoData: { title: string, icon: string, drag?: string, click?: 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();' }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ - nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, - title: data.title, icon: data.icon, onDragStart: ScriptField.MakeFunction(data.script) + 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 })); } @@ -144,7 +149,7 @@ export class CurrentUserUtils { doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc], { title: "expanding buttons", gridGap: 5, xMargin: 5, yMargin: 5, height: 42, width: 100, boxShadow: "0 0", - backgroundColor: "#eeeeee", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, convertToButtons: true + backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, convertToButtons: true }); } @@ -165,6 +170,7 @@ export class CurrentUserUtils { } static updateUserDocument(doc: Doc) { + new InkingControl(); (doc.optionalRightCollection === undefined) && CurrentUserUtils.setupMobileUploads(doc); (doc.noteTypes === undefined) && CurrentUserUtils.setupNoteTypes(doc); (doc.overlays === undefined) && CurrentUserUtils.setupOverlays(doc); -- 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/FontIconBox.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 e4e6026dfb819dd141597e7a2dfab6c566f61fac Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 15 Oct 2019 23:37:36 -0400 Subject: fixes to feedback of color buttons --- src/Utils.ts | 10 +++++----- src/client/views/CollectionLinearView.tsx | 6 +++--- src/client/views/GlobalKeyHandler.ts | 3 +++ src/client/views/InkingControl.tsx | 2 +- src/client/views/nodes/ColorBox.tsx | 8 ++++++++ src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FontIconBox.tsx | 25 ++++++++++++++++++++++--- src/new_fields/Doc.ts | 2 +- 8 files changed, 44 insertions(+), 14 deletions(-) (limited to 'src/client/views/nodes/FontIconBox.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index 9a2f01f80..6889936b8 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -62,14 +62,14 @@ export namespace Utils { } export function fromRGBAstr(rgba: string) { - let rm = rgba.match(/rgb[a]?\(([0-9]+)/); + let rm = rgba.match(/rgb[a]?\(([ 0-9]+)/); let r = rm ? Number(rm[1]) : 0; - let gm = rgba.match(/rgb[a]?\([0-9]+,([0-9]+)/); + let gm = rgba.match(/rgb[a]?\([ 0-9]+,([ 0-9]+)/); let g = gm ? Number(gm[1]) : 0; - let bm = rgba.match(/rgb[a]?\([0-9]+,[0-9]+,([0-9]+)/); + let bm = rgba.match(/rgb[a]?\([ 0-9]+,[ 0-9]+,([ 0-9]+)/); let b = bm ? Number(bm[1]) : 0; - let am = rgba.match(/rgba?\([0-9]+,[0-9]+,[0-9]+,([0-9]+)/); - let a = am ? Number(am[1]) : 0; + let am = rgba.match(/rgba?\([ 0-9]+,[ 0-9]+,[ 0-9]+,([ .0-9]+)/); + let a = am ? Number(am[1]) : 1; return { r: r, g: g, b: b, a: a }; } diff --git a/src/client/views/CollectionLinearView.tsx b/src/client/views/CollectionLinearView.tsx index eb3c768d0..af3b194ea 100644 --- a/src/client/views/CollectionLinearView.tsx +++ b/src/client/views/CollectionLinearView.tsx @@ -25,6 +25,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { @observable public addMenuToggle = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; private _heightDisposer?: IReactionDisposer; + private _spacing = 20; componentWillUnmount() { this._dropDisposer && this._dropDisposer(); @@ -69,8 +70,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { if (!ele.current) return Transform.Identity(); let { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current); return new Transform(-translateX, -translateY, 1 / scale); - }; - _spacing = 20; + } render() { let guid = Utils.GenerateGuid(); return
    @@ -118,7 +118,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { zoomToScale={emptyFunction} getScale={returnOne}> -
    +
    ; })} {/*
  • */} diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index f31a29bdc..9ca9fc163 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -10,6 +10,8 @@ import SharingManager from "../util/SharingManager"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import { Cast, PromiseValue } from "../../new_fields/Types"; import { ScriptField } from "../../new_fields/ScriptField"; +import { InkingControl } from "./InkingControl"; +import { InkTool } from "../../new_fields/InkField"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -64,6 +66,7 @@ export default class KeyManager { switch (keyname) { case "escape": let main = MainView.Instance; + InkingControl.Instance.switchTool(InkTool.None); if (main.isPointerDown) { DragManager.AbortDrag(); } else { diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index b51264932..51fc7ca8f 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -25,7 +25,7 @@ export class InkingControl { switchTool = action((tool: InkTool): void => { this._selectedTool = tool; - }) + }); decimalToHexString(number: number) { if (number < 0) { number = 0xFFFFFFFF + number + 1; diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 87c91c121..e4fef0922 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -10,6 +10,8 @@ import { makeInterface } from "../../../new_fields/Schema"; import { trace, reaction, observable, action, IReactionDisposer } from "mobx"; import { SelectionManager } from "../../util/SelectionManager"; import { StrCast } from "../../../new_fields/Types"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { Doc } from "../../../new_fields/Doc"; type ColorDocument = makeInterface<[typeof documentSchema]>; const ColorDocument = makeInterface(documentSchema); @@ -18,10 +20,15 @@ const ColorDocument = makeInterface(documentSchema); export class ColorBox extends DocStaticComponent(ColorDocument) { public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(ColorBox, fieldKey); } _selectedDisposer: IReactionDisposer | undefined; + _penDisposer: IReactionDisposer | undefined; componentDidMount() { 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"), + { fireImmediately: true }); // compare to this reaction that used to be in Selection Manager // reaction(() => manager.SelectedDocuments, sel => { @@ -37,6 +44,7 @@ export class ColorBox extends DocStaticComponent( // }, { fireImmediately: true }); } componentWillUnmount() { + this._penDisposer && this._penDisposer(); this._selectedDisposer && this._selectedDisposer(); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6f99c541f..8a320d39b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -676,7 +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 + let highlighting = fullDegree && this.props.Document.type !== DocumentType.FONTICON && this.props.Document.viewType !== CollectionViewType.Linear; return (
    (FontIconDocument) { public static LayoutString() { return FieldView.LayoutString(FontIconBox); } - + @observable _foregroundColor = "white"; + _ref: React.RefObject = React.createRef(); + _backgroundReaction: IReactionDisposer | undefined; + componentDidMount() { + this._backgroundReaction = reaction(() => this.props.Document.backgroundColor, + () => { + if (this._ref && this._ref.current) { + let col = Utils.fromRGBAstr(getComputedStyle(this._ref.current).backgroundColor!); + let colsum = (col.r + col.g + col.b); + if (colsum / col.a > 600 || col.a < 0.25) runInAction(() => this._foregroundColor = "black"); + else if (colsum / col.a <= 600 || col.a >= .25) runInAction(() => this._foregroundColor = "white"); + } + }, { fireImmediately: true }); + } + componentWillUnmount() { + this._backgroundReaction && this._backgroundReaction(); + } render() { - return ; } } \ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 276596fb8..9e0944c69 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -738,6 +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 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 -- cgit v1.2.3-70-g09d2 From 6d9cad19047b9970a8429771e7c0e03554e63f39 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 16 Oct 2019 12:13:30 -0400 Subject: more small fixes. dragging dragIcons, pdfmenu highlighting, fonticonbox hover text --- src/client/util/DragManager.ts | 3 +- src/client/views/DocumentDecorations.tsx | 1 + src/client/views/MainView.tsx | 4 ++- src/client/views/collections/CollectionSubView.tsx | 7 ++--- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/PDFBox.scss | 1 + src/client/views/pdf/PDFMenu.scss | 2 +- .../authentication/models/current_user_utils.ts | 32 +++++++++++----------- 8 files changed, 28 insertions(+), 24 deletions(-) (limited to 'src/client/views/nodes/FontIconBox.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 92666c03c..dcd19e50b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -212,6 +212,7 @@ export namespace DragManager { dropAction: dropActionType; userDropAction: dropActionType; moveDocument?: MoveFunction; + isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged. this will suppress onDragStart scripts applyAsTemplate?: boolean; [id: string]: any; } @@ -240,7 +241,7 @@ export namespace DragManager { StartDrag(eles, dragData, downX, downY, options, options && options.finishDrag ? options.finishDrag : (dropData: { [id: string]: any }) => { (dropData.droppedDocuments = - dragData.draggedDocuments.map(d => ScriptCast(d.onDragStart) ? ScriptCast(d.onDragStart).script.run({ this: d }).result : + dragData.draggedDocuments.map(d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? ScriptCast(d.onDragStart).script.run({ this: d }).result : dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) : dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d) ); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 3d73f048d..755739a11 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -202,6 +202,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> 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.x - left, e.y - top); dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument; + dragData.isSelectionMove = true; this.Interacting = true; this._hidden = true; document.removeEventListener("pointermove", this.onBackgroundMove); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8035916a2..0e15784f7 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, faPenNib, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt + faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, 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'; @@ -102,7 +102,9 @@ export class MainView extends React.Component { library.add(faGlobeAsia); library.add(faUndoAlt); library.add(faRedoAlt); + library.add(faMousePointer); library.add(faPen); + library.add(faHighlighter); library.add(faEraser); library.add(faPenNib); library.add(faFilm); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index fdbe5339d..9919a9dc3 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -133,11 +133,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { if (de.data.dropAction || de.data.userDropAction) { added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); } else if (de.data.moveDocument) { - let movedDocs = de.data.draggedDocuments;// de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments; - // note that it's possible the drag function might create a drop document that's not the same as the - // original dragged document. So we explicitly call addDocument() with a droppedDocument and + let movedDocs = de.data.draggedDocuments; added = movedDocs.reduce((added: boolean, d, i) => - de.data.moveDocument(d, this.props.Document, (doc: Doc) => this.props.addDocument(de.data.droppedDocuments[i])) || added, false); + de.data.droppedDocuments[i] !== d ? this.props.addDocument(de.data.droppedDocuments[i]) : + de.data.moveDocument(d, this.props.Document, this.props.addDocument) || added, false); } else { added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); } diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 1c2ed33eb..848afccf3 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -35,7 +35,7 @@ export class FontIconBox extends DocComponent( this._backgroundReaction && this._backgroundReaction(); } render() { - return ; diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index dd909e09f..deb98dc8d 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -7,6 +7,7 @@ overflow: hidden; position:absolute; z-index: -1; + cursor:auto; } .pdfBox-title-outer { diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss index b06d19c53..44e075153 100644 --- a/src/client/views/pdf/PDFMenu.scss +++ b/src/client/views/pdf/PDFMenu.scss @@ -15,7 +15,7 @@ } .pdfMenu-button:hover { - background-color: #121212; + background-color: #d4d4d4; } .pdfMenu-dragger { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 4abf85381..0fe8d996f 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -47,20 +47,20 @@ export class CurrentUserUtils { // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools 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(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)`, backgroundColor: "pink", activePen: doc }, - { title: "none", icon: "pause", click: 'deactivateInk();this.activePen.pen = this;', unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, + let docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, unchecked?: string, activePen?: Doc, backgroundColor?: string }[] = [ + { title: "collection", icon: "folder", ignoreClick: true, drag: 'Docs.Create.FreeformDocument([], { nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: "freeform" })' }, + { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", { width: 300, height: 300, title: "New Webpage" })' }, + { title: "cat image", icon: "cat", ignoreClick: true, 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: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ width: 150, height: 50, title: "Button" })' }, + { title: "presentation", icon: "tv", ignoreClick: true, drag: 'Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { width: 200, height: 500, title: "a presentation trail" })' }, + { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 })' }, + { title: "use 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: "use highlighter", icon: "highlighter", 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: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, + { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', unchecked: `!sameDocs(this.activePen.pen, this) && this.activePen.pen !== undefined`, backgroundColor: "white", activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ - nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, + nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, 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, removeDropProperties: new List(["dropAction"]) @@ -144,9 +144,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, dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); doc.redoBtn = Docs.Create.FontIconDocument( - { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); + { nativeWidth: 100, nativeHeight: 100, width: 100, height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), removeDropProperties: new List(["dropAction"]), 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", @@ -192,8 +192,8 @@ export class CurrentUserUtils { }); // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet - doc.undoBtn && reaction(() => UndoManager.undoStack.slice(), () => (doc.undoBtn as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); - doc.redoBtn && reaction(() => UndoManager.redoStack.slice(), () => (doc.redoBtn as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); + doc.undoBtn && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc.undoBtn as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + doc.redoBtn && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc.redoBtn as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); return doc; } -- 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/FontIconBox.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 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/FontIconBox.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