From 175d3fca55bd1838203d67884bb5206597e68b60 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 20 Nov 2020 19:23:02 -0500 Subject: added a preliminary Layer mechanism. changed documentDecrations to not go out of the mainDocument area. changed parentActive to work "recursively" through stacks of background documents. --- src/client/documents/Documents.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2d8a897a5..ae0cd8b92 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -138,7 +138,7 @@ export interface DocumentOptions { isAnnotating?: boolean; // whether we web document is annotation mode where links can't be clicked to allow annotations to be created opacity?: number; defaultBackgroundColor?: string; - _isBackground?: boolean; + _layers?: List; _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged. isLinkButton?: boolean; _columnWidth?: number; @@ -712,7 +712,7 @@ export namespace Docs { const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { dontRegisterChildViews: true, isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightBlue", // lightBlue is default color for linking dot and link documents text comment area - treeViewExpandedView: "fields", removeDropProperties: new List(["_isBackground", "isLinkButton"]), ...options + treeViewExpandedView: "fields", removeDropProperties: new List(["_layers", "isLinkButton"]), ...options }, id); const linkDocProto = Doc.GetProto(doc); linkDocProto.treeViewOpen = true;// setting this in the instance creator would set it on the view document. -- cgit v1.2.3-70-g09d2 From 81ee0bf99da264b76f26a21d57259d478cac07f3 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Dec 2020 11:58:25 -0500 Subject: fixed filterBox/TreeView to support checkboxes again. Simplified {DocumentView/CollectionView/FieldView}props --- src/client/documents/Documents.ts | 2 +- src/client/views/PreviewCursor.tsx | 5 +- .../views/collections/CollectionCarousel3DView.tsx | 4 +- .../views/collections/CollectionCarouselView.tsx | 4 +- .../collections/CollectionMasonryViewFieldRow.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 6 +- .../views/collections/CollectionSchemaCells.tsx | 2 +- .../views/collections/CollectionSchemaHeaders.tsx | 3 - .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 12 ++-- .../CollectionStackingViewFieldColumn.tsx | 14 ++-- src/client/views/collections/CollectionSubView.tsx | 42 ++---------- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 20 +++--- src/client/views/collections/CollectionView.tsx | 75 ++++++++++------------ src/client/views/collections/SchemaTable.tsx | 8 +-- src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/collections/TreeView.scss | 4 ++ src/client/views/collections/TreeView.tsx | 24 +++---- .../CollectionFreeFormRemoteCursors.tsx | 8 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 24 +++---- .../collections/collectionFreeForm/MarqueeView.tsx | 28 ++++---- .../CollectionMulticolumnView.tsx | 6 +- .../CollectionMultirowView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 71 ++++++++++---------- src/client/views/nodes/FieldView.tsx | 61 +++--------------- src/client/views/nodes/FilterBox.tsx | 8 +-- src/client/views/nodes/LinkBox.tsx | 4 +- src/client/views/nodes/PresBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 1 - 30 files changed, 189 insertions(+), 265 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ae0cd8b92..8a5f0fb5e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1136,7 +1136,7 @@ export namespace DocUtils { newDoc.x = x; newDoc.y = y; if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id]; - docAdder(newDoc); + docAdder?.(newDoc); } }), icon: "eye" diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index d756227f6..ac61dd1d8 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -11,6 +11,7 @@ import { Transform } from "../util/Transform"; import { undoBatch, UndoManager } from '../util/UndoManager'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import "./PreviewCursor.scss"; +import { returnFalse } from '../../Utils'; @observer export class PreviewCursor extends React.Component<{}> { @@ -145,13 +146,13 @@ export class PreviewCursor extends React.Component<{}> { onKeyPress: (e: KeyboardEvent) => void, addLiveText: (doc: Doc) => void, getTransform: () => Transform, - addDocument: (doc: Doc | Doc[]) => boolean, + addDocument: undefined | ((doc: Doc | Doc[]) => boolean), nudge: undefined | ((nudgeX: number, nudgeY: number) => boolean)) { this._clickPoint = [x, y]; this._onKeyPress = onKeyPress; this._addLiveTextDoc = addLiveText; this._getTransform = getTransform; - this._addDocument = addDocument; + this._addDocument = addDocument || returnFalse; this._nudge = nudge; this.Visible = true; } diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index 4e30709a6..67f73d44a 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -46,8 +46,8 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume onDoubleClick={this.onChildDoubleClick} onClick={onChildClick} renderDepth={this.props.renderDepth + 1} - LayoutTemplate={this.props.ChildLayoutTemplate} - LayoutTemplateString={this.props.ChildLayoutString} + LayoutTemplate={this.props.childLayoutTemplate} + LayoutTemplateString={this.props.childLayoutString} Document={childPair.layout} DataDoc={childPair.data} PanelWidth={this.panelWidth} diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 16ccdc6f4..8b7a46e2f 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -53,8 +53,8 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) onDoubleClick={this.onContentDoubleClick} onClick={this.onContentClick} renderDepth={this.props.renderDepth + 1} - LayoutTemplate={this.props.ChildLayoutTemplate} - LayoutTemplateString={this.props.ChildLayoutString} + LayoutTemplate={this.props.childLayoutTemplate} + LayoutTemplateString={this.props.childLayoutString} Document={curDoc.layout} DataDoc={curDoc.data} PanelHeight={this.panelHeight} diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index b35644c6b..ff69c7d05 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -146,7 +146,7 @@ export class CollectionMasonryViewFieldRow extends React.Component { diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 2636b98e5..f054e7b7f 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -36,11 +36,11 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { { (doc instanceof Doc ? [doc] : doc).map((d) => DocUtils.iconify(d)); - return this.props.addDocument(doc); + return this.props.addDocument?.(doc) || false; })} moveDocument={undoBatch((doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { (doc instanceof Doc ? [doc] : doc).map(undoBatch((d) => Doc.deiconifyView(d))); - return this.props.moveDocument(doc, targetCollection, addDoc); + return this.props.moveDocument?.(doc, targetCollection, addDoc) || false; })} /> ; } @@ -91,7 +91,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { const doc = this.childDocs[0]; doc.x = e.clientX; doc.y = e.clientY; - this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc); + this.props.addDocTab(doc, "inParent") && (this.props.removeDocument?.(doc) || false); dist = 0; } } diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 0b3dfe1e4..904b4c761 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -44,7 +44,7 @@ export interface CellProps { renderDepth: number; addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; - moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, + moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index b408fd680..f50da0134 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -461,9 +461,6 @@ export class KeysDropdown extends React.Component { } } - - get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } - @computed get scriptField() { const scriptText = "setDocFilter(containingTreeView, heading, this.title, checked)"; const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name }); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 8ae70ce20..e22b8effe 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -484,7 +484,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { const cm = ContextMenu.Instance; const options = cm.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; - optionItems.push({ description: "remove", event: () => this._previewDoc && this.props.removeDocument(this._previewDoc), icon: "trash" }); + optionItems.push({ description: "remove", event: () => this._previewDoc && this.props.removeDocument?.(this._previewDoc), icon: "trash" }); !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" }); cm.displayMenu(e.clientX, e.clientY); (e.nativeEvent as any).SchemaHandled = true; // not sure why this is needed, but if you right-click quickly on a cell, the Document/Collection contextMenu handlers still fire without this. diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0e4029764..83ac138f5 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -152,7 +152,7 @@ export class CollectionStackingView extends CollectionSubView boolean): boolean => { - return this.props.removeDocument(doc) && addDocument(doc); + return this.props.removeDocument?.(doc) && addDocument?.(doc) ? true : false; } createRef = (ele: HTMLDivElement | null) => { this._masonryGridRef = ele; @@ -193,9 +193,9 @@ export class CollectionStackingView extends CollectionSubView { FormattedTextBox.SelectOnLoad = doc[Id]; - return this.props.parent.props.addDocument(doc); - }, this.props.parent.props.addDocument, x, y, true); + return this.props.parent.props.addDocument?.(doc) || false; + }, this.props.parent.props.addDocument || returnFalse, x, y, true); Array.from(Object.keys(Doc.GetProto(dataDoc))).filter(fieldKey => dataDoc[fieldKey] instanceof RichTextField || dataDoc[fieldKey] instanceof ImageField || typeof (dataDoc[fieldKey]) === "string").map(fieldKey => docItems.push({ @@ -249,7 +249,7 @@ export class CollectionStackingViewFieldColumn extends React.Component boolean; - removeDocument: (document: Doc | Doc[]) => boolean; - moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - PanelWidth: () => number; - PanelHeight: () => number; - VisibleHeight?: () => number; - setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; - rootSelected: (outsideReaction?: boolean) => boolean; - fieldKey: string; - NativeWidth?: () => number; - NativeHeight?: () => number; -} export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; - children?: never | (() => JSX.Element[]) | React.ReactNode; - ChildLayoutTemplate?: () => Doc; - childOpacity?: () => number; - childIgnoreNativeSize?: boolean; - ChildLayoutString?: string; - childClickScript?: ScriptField; - childDoubleClickScript?: ScriptField; - freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height - overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) - ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox) - parentActive: (outsideReaction: boolean) => boolean; - isAnnotationOverlay?: boolean; - annotationsKey: string; - layoutEngine?: () => string; } export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: X) { @@ -112,11 +84,11 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: return Cast(this.dataField, listSpec(Doc)); } docFilters = () => { - return this.props.ignoreFields?.includes("_docFilters") ? [] : + return this.props.ignoreFilters ? [] : [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; } docRangeFilters = () => { - return this.props.ignoreFields?.includes("_docRangeFilters") ? [] : + return this.props.ignoreFilters ? [] : [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])]; } searchFilterDocs = () => { @@ -220,7 +192,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } } - addDocument = (doc: Doc | Doc[]) => this.props.addDocument(doc); + addDocument = (doc: Doc | Doc[]) => this.props.addDocument?.(doc) || false; @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { @@ -329,7 +301,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: DocServer.GetRefField(docid).then(f => { if (f instanceof Doc) { if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView - (f instanceof Doc) && this.props.addDocument(f); + (f instanceof Doc) && this.addDocument(f); } }); } else { @@ -343,7 +315,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 }); Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text; - this.props.addDocument(htmlDoc); + this.addDocument(htmlDoc); if (srcWeb) { const iframe = SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0]; const focusNode = (iframe?.contentDocument?.getSelection()?.focusNode as any); @@ -503,7 +475,7 @@ import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { DocumentType } from "../../documents/DocumentTypes"; import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox"; -import { CollectionView, CollectionViewType } from "./CollectionView"; +import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView"; import { SelectionManager } from "../../util/SelectionManager"; import { OverlayView } from "../OverlayView"; import { setTimeout } from "timers"; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index c2d682361..e4a3c384c 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -85,7 +85,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @computed get contents() { return
- +
; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 681584cc5..265f5a323 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -6,10 +6,11 @@ import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { Document } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../fields/Types'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, Utils } from '../../../Utils'; +import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, Utils } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; +import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from "../../util/DragManager"; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -17,20 +18,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from "../EditableView"; -import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; +import { DocumentView } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { TreeView } from "./TreeView"; import React = require("react"); -import { DocumentManager } from '../../util/DocumentManager'; -import { FormattedTextBoxComment } from '../nodes/formattedText/FormattedTextBoxComment'; -import { DocumentView } from '../nodes/DocumentView'; export type collectionTreeViewProps = { treeViewHideTitle?: boolean; treeViewHideHeaderFields?: boolean; + treeViewSkipFields?: string[]; // prevents specific fields from being displayed (see LinkBox) onCheckedClick?: () => ScriptField; onChildClick?: () => ScriptField; }; @@ -92,7 +90,7 @@ export class CollectionTreeView extends CollectionSubView doAddDoc(doc)); } else if (relativeTo === undefined) { - this.props.addDocument(doc); + this.props.addDocument?.(doc); } else { doAddDoc(doc); (doc instanceof Doc ? [doc] : doc).forEach(d => d.context = this.props.Document); @@ -195,18 +193,18 @@ export class CollectionTreeView extends CollectionSubView this.props.active(outsideReaction) || this._isChildActive; @computed get treeChildren() { TraceMobx(); - return this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs; + return this.props.childDocuments || this.childDocs; } @computed get treeViewElements() { TraceMobx(); const dropAction = StrCast(this.doc.childDropAction) as dropActionType; const addDoc = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before); - const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument(d, target, addDoc); + const moveDoc = (d: Doc | Doc[], target: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => this.props.moveDocument?.(d, target, addDoc) || false; return TreeView.GetChildElements(this.treeChildren, this, this.doc, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove, moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.styleProvider, this.props.ScreenToLocalTransform, this.outerXf, this.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => this.props.treeViewHideHeaderFields || BoolCast(this.doc.treeViewHideHeaderFields), BoolCast(this.doc.treeViewPreventOpen), [], this.props.onCheckedClick, - this.onChildClick, this.props.ignoreFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null)); + this.onChildClick, this.props.treeViewSkipFields, true, this.whenActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.dontRegisterChildViews, "boolean", null)); } @computed get titleBar() { const hideTitle = this.props.treeViewHideTitle || this.doc.treeViewHideTitle; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8f402c427..af03e4ceb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -10,7 +10,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx, normalizeEmail, denormalizeEmail } from '../../../fields/util'; +import { denormalizeEmail, distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { returnFalse, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -38,10 +38,7 @@ import { SubCollectionViewProps } from './CollectionSubView'; import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; -import { listSpec } from '../../../fields/Schema'; -const higflyout = require("@hig/flyout"); -export const { anchorPoints } = higflyout; -export const Flyout = higflyout.default; +import { ScriptField } from '../../../fields/ScriptField'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); @@ -64,28 +61,29 @@ export enum CollectionViewType { Grid = "grid", Pile = "pileup" } -export interface CollectionViewCustomProps { +export interface CollectionViewProps extends FieldViewProps { + isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) + annotationsKey: string; // which data field on the collection stores the collection of annotation documents + ignoreFilters?: boolean; + layoutEngine?: () => string; + parentActive: (outsideReaction: boolean) => boolean; filterAddDocument?: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + VisibleHeight?: () => number; + setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; + + // property overrides for child documents + childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) childOpacity?: () => number; - hideFilter?: true; + childLayoutTemplate?: () => (Doc | undefined);// specify a layout Doc template to use for children of the collection + childLayoutString?: string; + children?: never | (() => JSX.Element[]) | React.ReactNode; + childFreezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height childIgnoreNativeSize?: boolean; + childClickScript?: ScriptField; + childDoubleClickScript?: ScriptField; } - -export interface CollectionRenderProps { - addDocument: (document: Doc | Doc[]) => boolean; - removeDocument: (document: Doc | Doc[]) => boolean; - moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - active: () => boolean; - parentActive: (outsideReaction: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; - PanelWidth: () => number; - PanelHeight: () => number; - ChildLayoutTemplate?: () => Doc;// specify a layout Doc template to use for children of the collection - ChildLayoutString?: string;// specify a layout string to use for children of the collection -} - @observer -export class CollectionView extends Touchable { +export class CollectionView extends Touchable { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } _isChildActive = false; //TODO should this be observable? @@ -97,22 +95,13 @@ export class CollectionView extends Touchable([ - [AclPrivate, SharingPermissions.None], - [AclReadonly, SharingPermissions.View], - [AclAddonly, SharingPermissions.Add], - [AclEdit, SharingPermissions.Edit], - [AclAdmin, SharingPermissions.Admin] - ]); - get collectionViewType(): CollectionViewType | undefined { const viewField = StrCast(this.props.Document._viewType); if (CollectionView._safeMode) { - if (viewField === CollectionViewType.Freeform || viewField === CollectionViewType.Schema) { - return CollectionViewType.Tree; - } - if (viewField === CollectionViewType.Invalid) { - return CollectionViewType.Freeform; + switch (viewField) { + case CollectionViewType.Freeform: + case CollectionViewType.Schema: return CollectionViewType.Tree; + case CollectionViewType.Invalid: return CollectionViewType.Freeform; } } return viewField as any as CollectionViewType; @@ -136,7 +125,6 @@ export class CollectionView extends Touchable Doc.AreProtosEqual(doc, this.props.Document))) return false; const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[this.props.fieldKey]); @@ -253,9 +241,8 @@ export class CollectionView extends Touchable this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()); - private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { + private SubView = (type: CollectionViewType, props: SubCollectionViewProps) => { TraceMobx(); - const props: SubCollectionViewProps = { ...this.props, ...renderProps, ScreenToLocalTransform: this.screenToLocalTransform, CollectionView: this, annotationsKey: "" }; switch (type) { case CollectionViewType.Schema: return (); case CollectionViewType.Docking: return (); @@ -273,7 +260,7 @@ export class CollectionView extends Touchable); case CollectionViewType.Grid: return (); case CollectionViewType.Freeform: - default: { this.props.Document._freeformLayoutEngine = undefined; return (); } + default: { this.props.Document._freeformLayoutEngine = undefined; return (); } } } @@ -386,7 +373,8 @@ export class CollectionView extends Touchable; fieldKey: string; renderDepth: number; - deleteDocument: (document: Doc | Doc[]) => boolean; - addDocument: (document: Doc | Doc[]) => boolean; - moveDocument: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; + deleteDocument?: (document: Doc | Doc[]) => boolean; + addDocument?: (document: Doc | Doc[]) => boolean; + moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean | undefined) => boolean; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; @@ -376,7 +376,7 @@ export class SchemaTable extends React.Component { @undoBatch createRow = action(() => { - this.props.addDocument(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 })); + this.props.addDocument?.(Docs.Create.TextDocument("", { title: "", _width: 100, _height: 30 })); this._focusedCell = { row: this.childDocs.length, col: this._focusedCell.col }; }); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index e1fd47592..3c1aaae47 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -339,7 +339,7 @@ export class TabDocView extends React.Component { ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} parentActive={returnFalse} - ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. + childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this. noOverlay={true} // don't render overlay Docs since they won't scale active={returnTrue} select={emptyFunction} diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 84b5af7be..0a97166f0 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -17,6 +17,10 @@ left: -10px; position: absolute; } + .treeView-checkIcon { + left: -10px; + position: absolute; + } &:hover { .treeView-expandIcon { display: unset; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 675ba60c0..be8a27ab0 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -49,7 +49,7 @@ export interface TreeViewProps { outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; dontRegisterView?: boolean; - backgroundColor?: (doc: Opt, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined; + backgroundColor?: (doc: Opt, props: DocumentViewProps, property: string) => string | undefined; outerXf: () => { translateX: number, translateY: number }; treeView: CollectionTreeView; parentKey: string; @@ -59,7 +59,7 @@ export interface TreeViewProps { renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: () => ScriptField; onChildClick?: () => ScriptField; - ignoreFields?: string[]; + skipFields?: string[]; firstLevel: boolean; whenActiveChanged: (isActive: boolean) => void; } @@ -311,7 +311,7 @@ export class TreeView extends React.Component { doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key)); for (const key of Object.keys(ids).slice().sort()) { - if (this.props.ignoreFields?.includes(key) || key === "title" || key === "treeViewOpen") continue; + if (this.props.skipFields?.includes(key) || key === "title" || key === "treeViewOpen") continue; const contents = doc[key]; let contentElement: (JSX.Element | null)[] | JSX.Element = []; @@ -327,7 +327,7 @@ export class TreeView extends React.Component { this.props.treeView, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, - [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields, false, this.props.whenActiveChanged, this.props.dontRegisterView); + [...this.props.renderedIds, doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView); } else { contentElement = { this.dataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move, StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen, - [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.ignoreFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)} + [...this.props.renderedIds, this.doc[Id]], this.props.onCheckedClick, this.props.onChildClick, this.props.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)} ; } else if (this.treeViewExpandedView === "fields") { return
    @@ -449,14 +449,14 @@ export class TreeView extends React.Component { !(this.doc.text as RichTextField)?.Text ? (null) : :
    -
    - +
    - + {this.onCheckedClick ? (null) : }
    }
    ; @@ -710,7 +710,7 @@ export class TreeView extends React.Component { dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => boolean, pinToPres: (document: Doc) => void, - backgroundColor: undefined | ((document: Opt, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => string | undefined), + styleProvider: undefined | ((document: Opt, props: DocumentViewProps, property: string) => string | undefined), screenToLocalXf: () => Transform, outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, @@ -722,7 +722,7 @@ export class TreeView extends React.Component { renderedIds: string[], onCheckedClick: undefined | (() => ScriptField), onChildClick: undefined | (() => ScriptField), - ignoreFields: string[] | undefined, + skipFields: string[] | undefined, firstLevel: boolean, whenActiveChanged: (isActive: boolean) => void, dontRegisterView: boolean | undefined) { @@ -783,7 +783,7 @@ export class TreeView extends React.Component { renderDepth={renderDepth} removeDoc={StrCast(containingCollection.freezeChildren).includes("remove") ? undefined : remove} addDocument={addDocument} - backgroundColor={backgroundColor} + backgroundColor={styleProvider} panelWidth={rowWidth} panelHeight={rowHeight} ChromeHeight={ChromeHeight} @@ -799,7 +799,7 @@ export class TreeView extends React.Component { treeViewHideHeaderFields={treeViewHideHeaderFields} treeViewPreventOpen={treeViewPreventOpen} renderedIds={renderedIds} - ignoreFields={ignoreFields} + skipFields={skipFields} firstLevel={firstLevel} whenActiveChanged={whenActiveChanged} />; }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 548ad78a5..9f6938e67 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,16 +1,16 @@ +import { computed } from "mobx"; import { observer } from "mobx-react"; import * as mobxUtils from 'mobx-utils'; import CursorField from "../../../../fields/CursorField"; +import { FieldResult } from "../../../../fields/Doc"; +import { List } from "../../../../fields/List"; import { listSpec } from "../../../../fields/Schema"; import { Cast } from "../../../../fields/Types"; import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; -import { CollectionViewProps } from "../CollectionSubView"; +import { CollectionViewProps } from "../CollectionView"; import "./CollectionFreeFormView.scss"; import React = require("react"); import v5 = require("uuid/v5"); -import { computed } from "mobx"; -import { FieldResult } from "../../../../fields/Doc"; -import { List } from "../../../../fields/List"; @observer export class CollectionFreeFormRemoteCursors extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 136600164..0f466fc16 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -158,11 +158,11 @@ export class CollectionFreeFormView extends CollectionSubView { let retVal = false; if (newBox instanceof Doc) { - retVal = this.props.addDocument(newBox); + retVal = this.props.addDocument?.(newBox) || false; retVal && this.bringToFront(newBox); retVal && this.updateCluster(newBox); } else { - retVal = this.props.addDocument(newBox); + retVal = this.props.addDocument?.(newBox) || false; // bcz: deal with clusters } if (retVal) { @@ -270,7 +270,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { + getClusterColor = (doc: Opt, props: DocumentViewProps, property: string) => { let clusterColor = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (property !== "backgroundColor") return clusterColor; const cluster = NumCast(doc?.cluster); @@ -510,7 +510,7 @@ export class CollectionFreeFormView extends CollectionSubView this.props.removeDocument(d)); + sel.forEach(d => this.props.removeDocument?.(d)); e.stopPropagation(); break; case GestureUtils.Gestures.StartBracket: @@ -999,9 +999,9 @@ export class CollectionFreeFormView extends CollectionSubView { const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; doc.y = pt[1]; }); - return this.props.addDocument(doc); + return this.props.addDocument?.(doc) || false; } } if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { @@ -1172,8 +1172,8 @@ export class CollectionFreeFormView extends CollectionSubView, bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index a963b9158..39df606f7 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -8,7 +8,7 @@ import { RichTextField } from "../../../../fields/RichTextField"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; import { GetEffectiveAcl } from "../../../../fields/util"; -import { Utils, intersectRect } from "../../../../Utils"; +import { Utils, intersectRect, returnFalse } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents"; import { DocumentType } from "../../../documents/DocumentTypes"; @@ -93,7 +93,7 @@ export class MarqueeView extends React.Component { const indent = line.search(/\S|$/); const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line }); - this.props.addDocument(newBox); + this.props.addDocument?.(newBox); ypos += 40 * this.Transform.Scale; }); })(); @@ -143,11 +143,11 @@ export class MarqueeView extends React.Component SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false)); e.stopPropagation(); } else if (!e.ctrlKey && !e.metaKey && SelectionManager.SelectedDocuments().length < 2) { - FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.ChildLayoutString ? e.key : ""; + FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.childLayoutString ? e.key : ""; FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch"); this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0)); e.stopPropagation(); @@ -191,7 +191,7 @@ export class MarqueeView extends React.Component c).map(c => new SchemaHeaderField(c, "#f1efeb"))], docList, { x: x, y: y, title: "droppedTable", _width: 300, _height: 100 }); - this.props.addDocument(newCol); + this.props.addDocument?.(newCol); } } @@ -333,7 +333,7 @@ export class MarqueeView extends React.Component { const selected = this.marqueeSelect(false); SelectionManager.DeselectAll(); - selected.forEach(doc => this.props.removeDocument(doc)); + selected.forEach(doc => this.props.removeDocument?.(doc)); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -363,9 +363,9 @@ export class MarqueeView extends React.Component { const selected = this.marqueeSelect(false); SelectionManager.DeselectAll(); - selected.forEach(d => this.props.removeDocument(d)); + selected.forEach(d => this.props.removeDocument?.(d)); const newCollection = DocUtils.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2); - this.props.addDocument(newCollection!); + this.props.addDocument?.(newCollection!); this.props.selectDocuments([newCollection!]); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); @@ -424,10 +424,10 @@ export class MarqueeView extends React.Component r.category === "line"); const text = lines.map((l: any) => l.recognizedText).join("\r\n"); - this.props.addDocument(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text })); + this.props.addDocument?.(Docs.Create.TextDocument(text, { _width: this.Bounds.width, _height: this.Bounds.height, x: this.Bounds.left + this.Bounds.width, y: this.Bounds.top, title: text })); }); } } @@ -503,7 +503,7 @@ export class MarqueeView extends React.Component { const selected = this.marqueeSelect(false).map(d => { - this.props.removeDocument(d); + this.props.removeDocument?.(d); d.x = NumCast(d.x) - this.Bounds.left; d.y = NumCast(d.y) - this.Bounds.top; return d; @@ -524,7 +524,7 @@ export class MarqueeView extends React.Component { const newCollection = this.getCollection([], undefined, ["background"]); - this.props.addDocument(newCollection); + this.props.addDocument?.(newCollection); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); setTimeout(() => this.props.selectDocuments([newCollection])); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 7ce269c92..586c5d1df 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -217,9 +217,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu Document={layout} DataDoc={layout.resolvedDataDoc as Doc} styleProvider={this.props.styleProvider} - LayoutTemplate={this.props.ChildLayoutTemplate} - LayoutTemplateString={this.props.ChildLayoutString} - FreezeDimensions={this.props.freezeChildDimensions} + LayoutTemplate={this.props.childLayoutTemplate} + LayoutTemplateString={this.props.childLayoutString} + FreezeDimensions={this.props.childFreezeDimensions} renderDepth={this.props.renderDepth + 1} PanelWidth={width} PanelHeight={height} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7700ea128..87c56de6f 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -217,9 +217,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) Document={layout} DataDoc={layout.resolvedDataDoc as Doc} styleProvider={this.props.styleProvider} - LayoutTemplate={this.props.ChildLayoutTemplate} - LayoutTemplateString={this.props.ChildLayoutString} - FreezeDimensions={this.props.freezeChildDimensions} + LayoutTemplate={this.props.childLayoutTemplate} + LayoutTemplateString={this.props.childLayoutString} + FreezeDimensions={this.props.childFreezeDimensions} renderDepth={this.props.renderDepth + 1} PanelWidth={width} PanelHeight={height} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5ed49185b..dc048843f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -45,57 +45,60 @@ import React = require("react"); export type DocAfterFocusFunc = (notFocused: boolean) => boolean; export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void; -export interface DocumentViewProps { +export interface DocumentViewSharedProps { ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; - docFilters: () => string[]; + Document: Doc; + DataDoc?: Doc; contentsActive?: (setActive: () => boolean) => void; + onClick?: () => ScriptField; + dropAction?: dropActionType; + backgroundHalo?: (doc: Doc) => boolean; + docFilters: () => string[]; docRangeFilters: () => string[]; searchFilterDocs: () => Doc[]; - FreezeDimensions?: boolean; + rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected + renderDepth: number; + addDocTab: (doc: Doc, where: string) => boolean; + addDocument?: (doc: Doc | Doc[]) => boolean; + removeDocument?: (doc: Doc | Doc[]) => boolean; + moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; + pinToPres: (document: Doc) => void; + layerProvider?: (doc: Doc, assign?: boolean) => boolean; + styleProvider?: (doc: Opt, props: DocumentViewProps, property: string) => any; + ScreenToLocalTransform: () => Transform; + bringToFront: (doc: Doc, sendToBack?: boolean) => void; + parentActive: (outsideReaction: boolean) => boolean; + whenActiveChanged: (isActive: boolean) => void; + LayoutTemplateString?: string; + dontRegisterView?: boolean; + focus: DocFocusFunc; + ignoreAutoHeight?: boolean; + PanelWidth: () => number; + PanelHeight: () => number; NativeWidth?: () => number; NativeHeight?: () => number; - Document: Doc; - DataDoc?: Doc; - layerProvider?: (doc: Doc, assign?: boolean) => boolean; + ContentScaling: () => number; + ChromeHeight?: () => number; + pointerEvents?: string; +} +export interface DocumentViewProps extends DocumentViewSharedProps { + // properties specific to DocumentViews but not to FieldView + FreezeDimensions?: boolean; + fitToBox?: boolean; + treeViewDoc?: Doc; + dragDivName?: string; + contentsPointerEvents?: string; getView?: (view: DocumentView) => any; - LayoutTemplateString?: string; LayoutTemplate?: () => Opt; - fitToBox?: boolean; - ignoreAutoHeight?: boolean; contextMenuItems?: () => { script: ScriptField, label: string }[]; - rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected - onClick?: () => ScriptField; onDoubleClick?: () => ScriptField; onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; - treeViewDoc?: Doc; - dropAction?: dropActionType; - dragDivName?: string; nudge?: (x: number, y: number) => void; - addDocument?: (doc: Doc | Doc[]) => boolean; - removeDocument?: (doc: Doc | Doc[]) => boolean; - moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - ScreenToLocalTransform: () => Transform; setupDragLines?: (snapToDraggedDoc: boolean) => void; - renderDepth: number; - ContentScaling: () => number; - PanelWidth: () => number; - PanelHeight: () => number; - pointerEvents?: string; - contentsPointerEvents?: string; - focus: DocFocusFunc; - parentActive: (outsideReaction: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; - bringToFront: (doc: Doc, sendToBack?: boolean) => void; - addDocTab: (doc: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - backgroundHalo?: (doc: Doc) => boolean; - styleProvider?: (doc: Opt, props: DocumentViewProps, property: string) => any; forceHideLinkButton?: () => boolean; opacity?: () => number | undefined; - ChromeHeight?: () => number; - dontRegisterView?: boolean; layoutKey?: string; radialMenu?: String[]; display?: string; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 5cd752fdb..1d58893ae 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -2,70 +2,29 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; import { DateField } from "../../../fields/DateField"; -import { Doc, FieldResult, Opt, Field } from "../../../fields/Doc"; +import { Doc, Field, FieldResult, Opt } from "../../../fields/Doc"; import { List } from "../../../fields/List"; -import { ScriptField } from "../../../fields/ScriptField"; -import { AudioField, VideoField, WebField } from "../../../fields/URLField"; -import { Transform } from "../../util/Transform"; -import { CollectionView } from "../collections/CollectionView"; -import { AudioBox } from "./AudioBox"; +import { VideoField, WebField } from "../../../fields/URLField"; +import { DocumentViewSharedProps } from "./DocumentView"; import { VideoBox } from "./VideoBox"; -import { dropActionType } from "../../util/DragManager"; -import { DocAfterFocusFunc, DocFocusFunc, DocumentViewProps } from "./DocumentView"; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // -export interface FieldViewProps { +export interface FieldViewProps extends DocumentViewSharedProps { + // FieldView specific props that are not part of DocumentView props fieldKey: string; fitToBox?: boolean; - ContainingCollectionView: Opt; - ContainingCollectionDoc: Opt; - Document: Doc; - DataDoc?: Doc; - layerProvider?: (doc: Doc, assign?: boolean) => boolean; - contentsActive?: (setActive: () => boolean) => void; - onClick?: () => ScriptField; - dropAction: dropActionType; - backgroundHalo?: () => boolean; - docFilters: () => string[]; - docRangeFilters: () => string[]; - searchFilterDocs: () => Doc[]; - isSelected: (outsideReaction?: boolean) => boolean; - select: (isCtrlPressed: boolean) => void; - rootSelected: (outsideReaction?: boolean) => boolean; - renderDepth: number; - addDocument?: (document: Doc | Doc[]) => boolean; - addDocTab: (document: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - removeDocument?: (document: Doc | Doc[]) => boolean; - moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; - styleProvider?: (document: Opt, props: Opt, property: string) => any; - ScreenToLocalTransform: () => Transform; - bringToFront: (doc: Doc, sendToBack?: boolean) => void; - parentActive: (outsideReaction: boolean) => boolean; + overflow?: boolean; // bcz: would like to think this can be avoided -- need to look at further active: (outsideReaction?: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; - LayoutTemplateString?: string; - dontRegisterView?: boolean; - focus: DocFocusFunc; - presMultiSelect?: (doc: Doc) => void; //added for selecting multiple documents in a presentation - ignoreAutoHeight?: boolean; - PanelWidth: () => number; - PanelHeight: () => number; - PanelPosition?: string; - overflow?: boolean; - NativeHeight?: () => number; - NativeWidth?: () => number; - setVideoBox?: (player: VideoBox) => void; - ContentScaling: () => number; - ChromeHeight?: () => number; - childLayoutTemplate?: () => Opt; + select: (isCtrlPressed: boolean) => void; + isSelected: (outsideReaction?: boolean) => boolean; + // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) - fontSize?: number; pointerEvents?: string; + fontSize?: number; height?: number; width?: number; background?: string; diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 0161f51fd..b90bf9eb1 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -9,7 +9,7 @@ import { RichTextField } from "../../../fields/RichTextField"; import { listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; import { Cast } from "../../../fields/Types"; -import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../../Utils"; +import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero, returnTrue } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -153,7 +153,6 @@ export class FilterBox extends ViewBoxBaseComponent "rgba(105, 105, 105, 0.432)"; - get ignoreFields() { return ["_docFilters", "_docRangeFilters"]; } // this makes the tree view collection ignore these filters (otherwise, the filters would filter themselves) @computed get scriptField() { const scriptText = "setDocFilter(this?.target, heading, this.title, checked)"; const script = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name }); @@ -181,7 +180,6 @@ export class FilterBox extends ViewBoxBaseComponent
    (
    {mode !== CollectionViewType.Invalid ? removeDocument={returnFalse} dontRegisterView={true} focus={this.selectElement} - ScreenToLocalTransform={this.getTransform} /> + ScreenToLocalTransform={this.getTransform} + /> : (null) }
    diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 998ca839d..f64d80731 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -183,7 +183,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.Document._videoStart, (videoStart) => { -- cgit v1.2.3-70-g09d2 From 7a9d8f1e87f6f05433bbe4eab9fad85c3a07fa5a Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Dec 2020 02:48:36 -0500 Subject: fixed pointerevents set through styleProvider. fixed crash when color strings use uppercase. fixed empty text boxes to set default font size/family --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/collections/TabDocView.tsx | 27 ++++++++++------------ src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 6 ++--- 5 files changed, 18 insertions(+), 21 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8a5f0fb5e..2f190fbfd 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -711,7 +711,7 @@ export namespace Docs { export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) { const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, { dontRegisterChildViews: true, - isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightBlue", // lightBlue is default color for linking dot and link documents text comment area + isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area treeViewExpandedView: "fields", removeDropProperties: new List(["_layers", "isLinkButton"]), ...options }, id); const linkDocProto = Doc.GetProto(doc); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 676e7ce3e..2a7e95666 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -252,7 +252,7 @@ export class CurrentUserUtils { doc["template-note-Idea"] = new PrefetchProxy(noteView); } if (doc["template-note-Topic"] === undefined) { - const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue", system: true }); + const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightblue", system: true }); noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic"); doc["template-note-Topic"] = new PrefetchProxy(noteView); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 0fac68582..ba8b5e418 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -433,7 +433,7 @@ export class TabDocView extends React.Component { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // public static styleProvider = (doc: Opt, props: Opt, property: string): any => { - switch (property) { + switch (property.split(":")[0]) { case "docContents": return undefined; case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey"; case "opacity": return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null)); @@ -459,7 +459,7 @@ export class TabDocView extends React.Component { default: docColor = TabDocView.darkScheme ? "black" : "white"; break; } } - if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString(); + if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor.toLowerCase()).fade(0.5).toString(); return docColor; } case "boxShadow": { @@ -475,15 +475,14 @@ export class TabDocView extends React.Component { StrCast(doc.boxShadow, ""); } } - default: - if (property.startsWith("pointerEvents")) { - const layer = doc && props?.layerProvider?.(doc); - if (props?.styleProvider?.(doc, props, "opacity") === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none"; - if (layer === false && !property.includes(":selected") && !SnappingManager.GetIsDragging()) return "none"; - if (doc?.type !== DocumentType.INK && layer === true) return "all"; - return undefined; - } - if (property.startsWith("decorations") && props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) { + case "pointerEvents": + const layer = doc && props?.layerProvider?.(doc); + if (props?.styleProvider?.(doc, props, "opacity") === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none"; + if (layer === false && !property.includes(":selected") && !SnappingManager.GetIsDragging()) return "none"; + if (doc?.type !== DocumentType.INK && layer === true) return "all"; + return undefined; + case "decorations": + if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) { const isBackground = StrListCast(doc?.layers).includes("background"); return doc && (isBackground || property.includes(":selected")) && (props?.renderDepth || 0) > 0 && ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ? @@ -498,13 +497,11 @@ export class TabDocView extends React.Component { if (doc) { switch (property) { case "docContents": - if (doc.type === DocumentType.COL) return null; const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" : doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : "gray"; - return
    ; + return doc.type === DocumentType.COL ? undefined :
    ; default: - if (property.startsWith("pointerEvents")) return "none"; - return TabDocView.styleProvider(doc, props, property); + return (property.startsWith("pointerEvents")) ? "none" : TabDocView.styleProvider(doc, props, property); } } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9449f92ab..cbbb27450 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1093,7 +1093,6 @@ export class DocumentView extends DocComponent(Docu transformOrigin: this._animateScalingTo ? "center center" : undefined, transform: this._animateScalingTo ? `scale(${this._animateScalingTo})` : undefined, transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform 0.5s ease-${this._animateScalingTo < 1 ? "in" : "out"}`, - pointerEvents: this.pointerEvents, }}> {this.innards} {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
    : (null)} @@ -1124,6 +1123,7 @@ export class DocumentView extends DocComponent(Docu !entered && Doc.UnBrushDoc(this.props.Document); })} style={{ + pointerEvents: this.pointerEvents, outline: highlighting && !borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px", border: highlighting && borderRounding && highlightStyle === "dashed" ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined, boxShadow: highlighting && borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` : diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bfbd7805d..415c8c184 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -270,8 +270,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._pause = false; this.insertTime(); } - !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize)); - !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily)); + !curText && tx.storedMarks?.filter(m => m.type.name === "pFontSize").map(m => Doc.UserDoc().fontSize = this.layoutDoc._fontSize = (m.attrs.fontSize + "px")); + !curText && tx.storedMarks?.filter(m => m.type.name === "pFontFamily").map(m => Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily); this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = true;//(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText }); @@ -1599,7 +1599,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const annotated = DocListCast(this.dataDoc[this.annotationKey]).filter(d => d?.author).length; return !this.props.isSelected() && !(annotated && !this.sidebarWidth()) ? (null) :
    ; } -- cgit v1.2.3-70-g09d2 From 00d859f5c334fa105e3f6d572b74cb04fa9dd026 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Dec 2020 21:08:01 -0500 Subject: more documentViewProps cleanup. fixed embedding documents into treeView / slide bullet items. --- src/client/documents/Documents.ts | 2 +- src/client/views/DocumentDecorations.tsx | 1 - src/client/views/GlobalKeyHandler.ts | 2 ++ src/client/views/MainView.tsx | 2 -- src/client/views/collections/TreeView.scss | 11 ++++++++++- src/client/views/collections/TreeView.tsx | 1 - .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- src/client/views/nodes/DocumentView.tsx | 4 +--- 8 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2f190fbfd..95daecc64 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -113,7 +113,7 @@ export interface DocumentOptions { _viewScale?: number; forceActive?: boolean; layout?: string | Doc; // default layout string for a document - contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" sidebar views that are intended to document "menus" + contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents childLimitHeight?: number; // whether to limit the height of colleciton children. 0 - means height can be no bigger than width childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view) childLayoutString?: string; // template string for collection to use to render its children diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d4d91659f..5c7f5d9e4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -339,7 +339,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b this._offY = this._resizeHdlId.toLowerCase().includes("top") ? bounds.bottom - e.clientY : bounds.top - e.clientY; this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them this._resizeUndo = UndoManager.StartBatch("DocDecs resize"); - SelectionManager.SelectedDocuments()[0].props.setupDragLines?.(e.ctrlKey || e.shiftKey); } this._snapX = e.pageX; this._snapY = e.pageY; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index aa901911f..283419b82 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -86,6 +86,8 @@ export class KeyManager { private unmodified = action((keyname: string, e: KeyboardEvent) => { switch (keyname) { + case "a": SnappingManager.GetIsDragging() && (DragManager.CanEmbed = true); + break; case "u": if (document.activeElement?.tagName === "INPUT" || document.activeElement?.tagName === "TEXTAREA") { return { stopPropagation: false, preventDefault: false }; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5d26404ff..d55d43623 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -327,7 +327,6 @@ export class MainView extends React.Component { searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} - relative={true} />
    {this.docButtons} @@ -360,7 +359,6 @@ export class MainView extends React.Component { searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} - relative={true} scriptContext={this} />
    ; diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 796b2438e..cc6267f45 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -65,7 +65,16 @@ cursor: pointer; } -.treeView-border-outline, +.treeView-borderoutline { + ul { + .contentFittingDocumentView { + width: unset; + height: unset; + } + } +} + +.treeView-borderoutline, .treeView-border { display: flex; overflow: hidden; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a69e44515..5982934ff 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -505,7 +505,6 @@ export class TreeView extends React.Component { case StyleProp.DocContents: return !props?.treeViewDoc ? (null) :
    {StrCast(doc?.title)} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7ab297504..b8576681d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -48,6 +48,7 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; import { StyleProp, StyleLayers } from "../../StyleProvider"; +import { DocumentDecorations } from "../../DocumentDecorations"; export const panZoomSchema = createSchema({ _panX: "number", @@ -1003,7 +1004,6 @@ export class CollectionFreeFormView extends CollectionSubView { - SnappingManager.GetIsDragging() && this.setupDragLines(e.ctrlKey || e.shiftKey); + (DocumentDecorations.Instance.Interacting || SnappingManager.GetIsDragging()) && this.setupDragLines(e.ctrlKey || e.shiftKey); e.stopPropagation(); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 65779088f..1b1870f81 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -87,19 +87,17 @@ export interface DocumentViewSharedProps { export interface DocumentViewProps extends DocumentViewSharedProps { // properties specific to DocumentViews but not to FieldView freezeDimensions?: boolean; - hideTitle?: boolean; + hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings fitToBox?: boolean; treeViewDoc?: Doc; dragDivName?: string; contentPointerEvents?: string; radialMenu?: String[]; - relative?: boolean; LayoutTemplate?: () => Opt; contextMenuItems?: () => { script: ScriptField, label: string }[]; onDoubleClick?: () => ScriptField; onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; - setupDragLines?: (snapToDraggedDoc: boolean) => void; } @observer -- cgit v1.2.3-70-g09d2 From 7b82359d68bf2fbc91d8851e2eb80c8b22930fd2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 15 Dec 2020 13:01:18 -0500 Subject: simplifying dragging to make links by moving linkDocument to event, instead of dragData. moved link anchor and caption styling to default style provider. CURRENTLY, typing text, brushing doc highlights along with a bunch of other things ARE BROKEN .. --- src/client/documents/Documents.ts | 34 +- src/client/util/DragManager.ts | 7 +- src/client/views/StyleProvider.tsx | 9 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 9 +- src/client/views/nodes/DocumentView.tsx | 386 ++++++++------------- src/client/views/nodes/WebBox.tsx | 4 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 9 +- src/client/views/pdf/PDFViewer.tsx | 6 +- 9 files changed, 197 insertions(+), 269 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 95daecc64..8fd906dc7 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,4 +1,4 @@ -import { runInAction } from "mobx"; +import { runInAction, action } from "mobx"; import { basename, extname } from "path"; import { DateField } from "../../fields/DateField"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; @@ -53,6 +53,8 @@ import { PresElementBox } from "../views/presentationview/PresElementBox"; import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; +import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; +import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup"; const path = require('path'); const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -1011,11 +1013,37 @@ export namespace DocUtils { DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d }, "audio link", "audio timeline")); } - export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean) { + export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) { const sv = DocumentManager.Instance.getDocumentView(source.doc); if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return; if (target.doc === Doc.UserDoc()) return undefined; + + const makeLink = action((linkDoc: Doc, showPopup: number[]) => { + LinkManager.currentLink = linkDoc; + + TaskCompletionBox.textDisplayed = "Link Created"; + TaskCompletionBox.popupX = showPopup[0]; + TaskCompletionBox.popupY = showPopup[1] - 33; + TaskCompletionBox.taskCompleted = true; + + LinkDescriptionPopup.popupX = showPopup[0]; + LinkDescriptionPopup.popupY = showPopup[1]; + LinkDescriptionPopup.descriptionPopup = true; + + const rect = document.body.getBoundingClientRect(); + if (LinkDescriptionPopup.popupX + 200 > rect.width) { + LinkDescriptionPopup.popupX -= 190; + TaskCompletionBox.popupX -= 40; + } + if (LinkDescriptionPopup.popupY + 100 > rect.height) { + LinkDescriptionPopup.popupY -= 40; + TaskCompletionBox.popupY -= 40; + } + + setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); + }); + const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id); Doc.GetProto(linkDoc)["anchor1-useLinkSmallAnchor"] = source.doc.useLinkSmallAnchor; Doc.GetProto(linkDoc)["anchor2-useLinkSmallAnchor"] = target.doc.useLinkSmallAnchor; @@ -1024,7 +1052,7 @@ export namespace DocUtils { Doc.GetProto(linkDoc)["acl-Public"] = linkDoc["acl-Public"] = SharingPermissions.Add; linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null); Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title'); - + showPopup && makeLink(linkDoc, showPopup); return linkDoc; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4704d9e71..1a58b4bf1 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -109,6 +109,7 @@ export namespace DragManager { this.linkDragData = dragData instanceof LinkDragData ? dragData : undefined; this.columnDragData = dragData instanceof ColumnDragData ? dragData : undefined; } + linkDocument?: Doc; aborted: boolean; docDragData?: DocumentDragData; annoDragData?: PdfAnnoDragData; @@ -143,8 +144,7 @@ export namespace DragManager { droppedDocuments: Doc[] = []; linkSourceDocument: Doc; dontClearTextBox?: boolean; - linkDocument?: Doc; - linkDropCallback?: (data: { linkDocument?: Doc }) => void; + linkDropCallback?: (data: { linkDocument: Doc }) => void; } export class ColumnDragData { constructor(colKey: SchemaHeaderField) { @@ -161,7 +161,6 @@ export namespace DragManager { this.annotationDocument = annotationDoc; this.offset = [0, 0]; } - linkDocument?: Doc; targetContext: Doc | undefined; dragDocument: Doc; annotationDocument: Doc; @@ -169,7 +168,7 @@ export namespace DragManager { offset: number[]; dropAction: dropActionType; userDropAction: dropActionType; - linkDropCallback?: (data: { linkDocument?: Doc }) => void; + linkDropCallback?: (data: { linkDocument: Doc }) => void; } export function MakeDropTarget( diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index f2569edbd..912d718cf 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -70,20 +70,24 @@ export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentVie export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const docProps = testDocProps(props) ? props : undefined; const selected = property.includes(":selected"); + const isCaption = property.includes(":caption"); + const isAnchor = property.includes(":anchor"); const isBackground = () => StrListCast(doc?.layers).includes(StyleLayers.Background); const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor); const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity); switch (property.split(":")[0]) { case StyleProp.DocContents: return undefined; + case StyleProp.LinkSource: return isAnchor && docProps?.Document; // pass the LinkSource to the LinkAnchorBox case StyleProp.WidgetColor: return darkScheme() ? "lightgrey" : "dimgrey"; case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null)); - case StyleProp.HideLinkButton: return props?.dontRegisterView || (!selected && (doc?.isLinkButton || doc?.hideLinkButton)); + case StyleProp.HideLinkButton: return isAnchor || props?.dontRegisterView || (!selected && (doc?.isLinkButton || doc?.hideLinkButton)); case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle, !Doc.IsSystem(doc) && doc.type === DocumentType.RTF ? (doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : undefined); case StyleProp.Color: + if (isCaption) return "white"; const backColor = backgroundCol() || "black"; const col = Color(backColor).rgb(); const colsum = (col.red() + col.green() + col.blue()); @@ -93,6 +97,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor)); if (!docProps) { @@ -144,6 +150,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { - const linkDoc = dropEv.linkDragData?.linkDocument as Doc; // equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop - if (this.props.View && linkDoc) { - !linkDoc.linkRelationship && (Doc.GetProto(linkDoc).linkRelationship = "hyperlink"); + if (this.props.View && dropEv.linkDocument) {// dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop + !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = "hyperlink"); // we want to allow specific views to handle the link creation in their own way (e.g., rich text makes text hyperlinks) // the dragged view can regiser a linkDropCallback to be notified that the link was made and to update their data structures // however, the dropped document isn't so accessible. What we do is set the newly created link document on the documentView // The documentView passes a function prop returning this link doc to its descendants who can react to changes to it. - dropEv.linkDragData?.linkDropCallback?.(dropEv.linkDragData); - runInAction(() => this.props.View.LinkBeingCreated = linkDoc); + dropEv.linkDragData?.linkDropCallback?.(dropEv as { linkDocument: Doc }); // bcz: typescript can't figure out that this is valid even though we tested dropEv.linkDocument above + runInAction(() => this.props.View.LinkBeingCreated = dropEv.linkDocument); setTimeout(action(() => this.props.View.LinkBeingCreated = undefined), 0); } linkDrag?.end(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index a005a5db4..da10f2a69 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -153,6 +153,25 @@ export class DocumentViewInternal extends DocComponent): any => { this.removeMoveListeners(); this.removeEndListeners(); @@ -194,6 +213,113 @@ export class DocumentViewInternal extends DocComponent) => { + if (!e.nativeEvent.cancelBubble && !this.props.isSelected()) { + e.stopPropagation(); + e.preventDefault(); + + this.removeMoveListeners(); + this.addMoveListeners(); + this.removeEndListeners(); + this.addEndListeners(); + } + } + + handle1PointerDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent) => { + SelectionManager.DeselectAll(); + if (this.Document.onPointerDown) return; + const touch = me.touchEvent.changedTouches.item(0); + if (touch) { + this._downX = touch.clientX; + this._downY = touch.clientY; + if (!e.nativeEvent.cancelBubble) { + if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation(); + this.removeMoveListeners(); + this.addMoveListeners(); + this.removeEndListeners(); + this.addEndListeners(); + e.stopPropagation(); + } + } + } + + handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent) => { + if ((e as any).formattedHandled) { e.stopPropagation; return; } + if (e.cancelBubble && this.active) { + this.removeMoveListeners(); + } + else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { + const touch = me.touchEvent.changedTouches.item(0); + if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) { + if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { + this.cleanUpInteractions(); + this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); + } + } + e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers + e.preventDefault(); + } + } + + @action + handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent) => { + const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true); + const pt1 = myTouches[0]; + const pt2 = myTouches[1]; + const oldPoint1 = this.prevPoints.get(pt1.identifier); + const oldPoint2 = this.prevPoints.get(pt2.identifier); + const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!); + if (pinching !== 0 && oldPoint1 && oldPoint2) { + const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX)); + const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY)); + const dX = -1 * Math.sign(dW); + const dY = -1 * Math.sign(dH); + + if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { + const doc = Document(this.props.Document); + const layoutDoc = Document(Doc.Layout(this.props.Document)); + let nwidth = Doc.NativeWidth(layoutDoc); + let nheight = Doc.NativeHeight(layoutDoc); + const width = (layoutDoc._width || 0); + const height = (layoutDoc._height || (nheight / nwidth * width)); + const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale; + const actualdW = Math.max(width + (dW * scale), 20); + const actualdH = Math.max(height + (dH * scale), 20); + doc.x = (doc.x || 0) + dX * (actualdW - width); + doc.y = (doc.y || 0) + dY * (actualdH - height); + const fixedAspect = e.ctrlKey || (nwidth && nheight); + if (fixedAspect && (!nwidth || !nheight)) { + Doc.SetNativeWidth(layoutDoc, nwidth = layoutDoc._width || 0); + Doc.SetNativeHeight(layoutDoc, nheight = layoutDoc._height || 0); + } + if (nwidth > 0 && nheight > 0) { + if (Math.abs(dW) > Math.abs(dH)) { + if (!fixedAspect) { + Doc.SetNativeWidth(layoutDoc, actualdW / (layoutDoc._width || 1) * Doc.NativeWidth(layoutDoc)); + } + layoutDoc._width = actualdW; + if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width; + else layoutDoc._height = actualdH; + } + else { + if (!fixedAspect) { + Doc.SetNativeHeight(layoutDoc, actualdH / (layoutDoc._height || 1) * Doc.NativeHeight(doc)); + } + layoutDoc._height = actualdH; + if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height; + else layoutDoc._width = actualdW; + } + } else { + dW && (layoutDoc._width = actualdW); + dH && (layoutDoc._height = actualdH); + dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false); + } + } + e.stopPropagation(); + e.preventDefault(); + } + } + @action onRadialMenu = (e: Event, me: InteractionUtils.MultiTouchEvent): void => { const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1]; @@ -209,43 +335,15 @@ export class DocumentViewInternal extends DocComponent) => { - SelectionManager.DeselectAll(); - if (this.Document.onPointerDown) return; - const touch = me.touchEvent.changedTouches.item(0); - if (touch) { - this._downX = touch.clientX; - this._downY = touch.clientY; - if (!e.nativeEvent.cancelBubble) { - if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation(); - this.removeMoveListeners(); - this.addMoveListeners(); - this.removeEndListeners(); - this.addEndListeners(); - e.stopPropagation(); - } - } - } - - handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent) => { - if ((e as any).formattedHandled) { e.stopPropagation; return; } - if (e.cancelBubble && this.active) { - this.removeMoveListeners(); - } - else if (!e.cancelBubble && (this.props.isSelected(true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { - - const touch = me.touchEvent.changedTouches.item(0); - if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) { - if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler)) { - this.cleanUpInteractions(); - this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined); - } - } - e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers - e.preventDefault(); - } - } - - handle2PointersDown = (e: React.TouchEvent, me: InteractionUtils.MultiTouchEvent) => { - if (!e.nativeEvent.cancelBubble && !this.props.isSelected()) { - e.stopPropagation(); - e.preventDefault(); - - this.removeMoveListeners(); - this.addMoveListeners(); - this.removeEndListeners(); - this.addEndListeners(); - } - } - - - @action - handle2PointersMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent) => { - const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true); - const pt1 = myTouches[0]; - const pt2 = myTouches[1]; - const oldPoint1 = this.prevPoints.get(pt1.identifier); - const oldPoint2 = this.prevPoints.get(pt2.identifier); - const pinching = InteractionUtils.Pinning(pt1, pt2, oldPoint1!, oldPoint2!); - if (pinching !== 0 && oldPoint1 && oldPoint2) { - const dW = (Math.abs(pt1.clientX - pt2.clientX) - Math.abs(oldPoint1.clientX - oldPoint2.clientX)); - const dH = (Math.abs(pt1.clientY - pt2.clientY) - Math.abs(oldPoint1.clientY - oldPoint2.clientY)); - const dX = -1 * Math.sign(dW); - const dY = -1 * Math.sign(dH); - - if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) { - const doc = Document(this.props.Document); - const layoutDoc = Document(Doc.Layout(this.props.Document)); - let nwidth = Doc.NativeWidth(layoutDoc); - let nheight = Doc.NativeHeight(layoutDoc); - const width = (layoutDoc._width || 0); - const height = (layoutDoc._height || (nheight / nwidth * width)); - const scale = this.props.ScreenToLocalTransform().Scale * this.ContentScale; - const actualdW = Math.max(width + (dW * scale), 20); - const actualdH = Math.max(height + (dH * scale), 20); - doc.x = (doc.x || 0) + dX * (actualdW - width); - doc.y = (doc.y || 0) + dY * (actualdH - height); - const fixedAspect = e.ctrlKey || (nwidth && nheight); - if (fixedAspect && (!nwidth || !nheight)) { - Doc.SetNativeWidth(layoutDoc, nwidth = layoutDoc._width || 0); - Doc.SetNativeHeight(layoutDoc, nheight = layoutDoc._height || 0); - } - if (nwidth > 0 && nheight > 0) { - if (Math.abs(dW) > Math.abs(dH)) { - if (!fixedAspect) { - Doc.SetNativeWidth(layoutDoc, actualdW / (layoutDoc._width || 1) * Doc.NativeWidth(layoutDoc)); - } - layoutDoc._width = actualdW; - if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._height = nheight / nwidth * layoutDoc._width; - else layoutDoc._height = actualdH; - } - else { - if (!fixedAspect) { - Doc.SetNativeHeight(layoutDoc, actualdH / (layoutDoc._height || 1) * Doc.NativeHeight(doc)); - } - layoutDoc._height = actualdH; - if (fixedAspect && !layoutDoc._fitWidth) layoutDoc._width = nwidth / nheight * layoutDoc._height; - else layoutDoc._width = actualdW; - } - } else { - dW && (layoutDoc._width = actualdW); - dH && (layoutDoc._height = actualdH); - dH && layoutDoc._autoHeight && (layoutDoc._autoHeight = false); - } - } - e.stopPropagation(); - e.preventDefault(); - } - } + }) onPointerDown = (e: React.PointerEvent): void => { // continue if the event hasn't been canceled AND we are using a moues or this is has an onClick or onDragStart function (meaning it is a button document) @@ -526,11 +515,6 @@ export class DocumentViewInternal extends DocComponent { - this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined; - } - @undoBatch @action toggleFollowLink = (location: Opt, zoom: boolean, setPushpin: boolean): void => { this.Document.ignoreClick = false; @@ -564,7 +548,6 @@ export class DocumentViewInternal extends DocComponent { this.Document.ignoreClick = false; @@ -585,45 +568,10 @@ export class DocumentViewInternal extends DocComponent { - LinkManager.currentLink = linkDoc; - - TaskCompletionBox.textDisplayed = "Link Created"; - TaskCompletionBox.popupX = de.x; - TaskCompletionBox.popupY = de.y - 33; - TaskCompletionBox.taskCompleted = true; - - LinkDescriptionPopup.popupX = de.x; - LinkDescriptionPopup.popupY = de.y; - LinkDescriptionPopup.descriptionPopup = true; - - const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; - TaskCompletionBox.popupX -= 40; - } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; - TaskCompletionBox.popupY -= 40; - } - - setTimeout(action(() => TaskCompletionBox.taskCompleted = false), 2500); - }); - if (de.complete.annoDragData) { - /// this whole section for handling PDF annotations looks weird. Need to rethink this to make it cleaner - e.stopPropagation(); - de.complete.annoDragData.linkDocument = DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document }, "link"); - de.complete.annoDragData.linkDocument && makeLink(de.complete.annoDragData.linkDocument); - } - if (de.complete.linkDragData) { + const linkSource = de.complete.annoDragData ? de.complete.annoDragData.annotationDocument : de.complete.linkDragData ? de.complete.linkDragData.linkSourceDocument : undefined; + if (linkSource && linkSource !== this.props.Document) { e.stopPropagation(); - const linkSource = de.complete.linkDragData.linkSourceDocument; - if (linkSource !== this.props.Document) { - const linkDoc = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, `link`); - linkSource !== this.props.Document && (de.complete.linkDragData.linkDocument = linkDoc); // TODODO this is where in text links get passed - linkDoc && makeLink(linkDoc); - } - + de.complete.linkDocument = DocUtils.MakeLink({ doc: linkSource }, { doc: this.props.Document }, "link", undefined, undefined, undefined, [de.x, de.y]); } } @@ -707,7 +655,7 @@ export class DocumentViewInternal extends DocComponent SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" }); zorderItems.push({ description: "Send to Back", event: () => SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" }); - zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: this.toggleRaiseWhenDragged, icon: "expand-arrows-alt" }); + zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: undoBatch(action(() => this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined)), icon: "expand-arrows-alt" }); !zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" }); onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); @@ -784,17 +732,13 @@ export class DocumentViewInternal extends DocComponent { - return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; - } - + rootSelected = (outsideReaction?: boolean) => { return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; } panelHeight = () => this.props.PanelHeight() - this.headerMargin; parentActive = (outsideReaction: boolean) => this.props.layerProvider?.(this.layoutDoc) === false ? this.props.parentActive(outsideReaction) : false; screenToLocal = () => this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; - onDoubleClickFunc = () => this.onDoubleClickHandler; - + makeLink = () => this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. @observable contentsActive: () => boolean = returnFalse; @action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive; @@ -805,41 +749,14 @@ export class DocumentViewInternal extends DocComponent - {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} @@ -859,26 +776,11 @@ export class DocumentViewInternal extends DocComponent this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. - @undoBatch hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true) anchorPanelWidth = () => this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { - if (testDocProps(props)) { - switch (property.split(":")[0]) { - case StyleProp.BackgroundColor: return "transparent"; // background of linkanchor documentView is transparent since it covers the whole document - case StyleProp.HideLinkButton: return true; // don't want linkAnchor documentview to show its own link button - case StyleProp.PointerEvents: return "none"; // don't want linkAnchor documentView to handle events (since it covers the whole document). However, the linkAnchorBox itself is set to pointerEvent all - } - } else { - switch (property.split(":")[0]) { - case StyleProp.LinkSource: return this.props.Document; // pass the LinkSource to the LinkAnchorBox - } - } - return this.props.styleProvider?.(doc, props, property); - } + anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => this.props.styleProvider?.(doc, props, property + ":anchor"); @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } @@ -904,11 +806,7 @@ export class DocumentViewInternal extends DocComponent
    ); } - captionStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { - if (property === StyleProp.Color) return "white"; - if (property === StyleProp.BackgroundColor) return "rgba(0,0,0 ,0.4)"; - return this.props?.styleProvider?.(doc, props, property); - } + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this.props?.styleProvider?.(doc, props, property + ":caption"); @computed get innards() { TraceMobx(); const showTitle = this.ShowTitle; @@ -938,9 +836,7 @@ export class DocumentViewInternal extends DocComponent Field.toString((this.dataDoc || this.props.Document)[showTitle.split(";")[0]] as any as Field)} - SetValue={undoBatch((value: string) => { - showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true; - })} + SetValue={undoBatch((value) => showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true)} />
    ); return this.props.hideTitle || (!showTitle && !showCaption) ? @@ -988,7 +884,7 @@ export class DocumentViewInternal extends DocComponent !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} onPointerLeave={action(e => { let entered = false; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 125bf62f0..8e824a447 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -546,8 +546,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) { - e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation"); + if (!e.aborted && e.annoDragData && !e.linkDocument) { + e.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation"); annotationDoc.isLinkButton = true; annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f82e533ad..0bb483b41 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -478,11 +478,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp de.complete.annoDragData.linkDropCallback = this.linkDrop; } } - linkDrop = (data: { linkDocument?: Doc }) => { - const linkDoc = data.linkDocument!; - const anchor1Title = linkDoc.anchor1 instanceof Doc ? StrCast(linkDoc.anchor1.title) : "-untitled-"; - const anchor1Id = linkDoc.anchor1 instanceof Doc ? linkDoc.anchor1[Id] : ""; - this.makeLinkToSelection(linkDoc[Id], anchor1Title, "add:right", anchor1Id); + linkDrop = (data: { linkDocument: Doc }) => { + const anchor1Title = data.linkDocument.anchor1 instanceof Doc ? StrCast(data.linkDocument.anchor1.title) : "-untitled-"; + const anchor1Id = data.linkDocument.anchor1 instanceof Doc ? data.linkDocument.anchor1[Id] : ""; + this.makeLinkToSelection(data.linkDocument[Id], anchor1Title, "add:right", anchor1Id); } getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index be64754af..d6d500702 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -633,12 +633,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent { - if (!e.aborted && e.annoDragData && !e.annoDragData.linkDocument) { - e.annoDragData.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation"); + if (!e.aborted && e.annoDragData && !e.linkDocument) { + e.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation"); } annotationDoc.isLinkButton = true; // prevents link button fro showing up --- maybe not a good thing? annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document; - e.annoDragData && e.annoDragData.linkDocument && e.annoDragData?.linkDropCallback?.({ linkDocument: e.annoDragData.linkDocument }); + e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument above } }); } -- cgit v1.2.3-70-g09d2 From e59f88e1af2ca691bd48188e5bef9e6a4d4e2dab Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 31 Dec 2020 13:53:29 -0500 Subject: fixes for sliderBox to work in FilterBox. suppressed brush highlighting in filterBox. --- src/client/documents/Documents.ts | 4 ++-- src/client/views/StyleProvider.tsx | 4 +++- src/client/views/collections/TreeView.tsx | 13 +++++++++---- src/client/views/nodes/DocumentView.tsx | 3 ++- src/client/views/nodes/FilterBox.tsx | 9 +++++---- src/client/views/nodes/SliderBox.scss | 4 +++- src/client/views/nodes/SliderBox.tsx | 10 ++++++---- 7 files changed, 30 insertions(+), 17 deletions(-) (limited to 'src/client/documents') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 8fd906dc7..c457fb722 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -113,6 +113,7 @@ export interface DocumentOptions { page?: number; description?: string; // added for links _viewScale?: number; + _overflow?: string; forceActive?: boolean; layout?: string | Doc; // default layout string for a document contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents @@ -1250,14 +1251,13 @@ export namespace DocUtils { }); }); if (x !== undefined && y !== undefined) { - const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100 }); + const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _overflow: "visible" }); newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; newCollection._width = newCollection._height = 110; //newCollection.borderRounding = "40px"; newCollection._jitterRotation = 10; newCollection._backgroundColor = "gray"; - newCollection._overflow = "visible"; return newCollection; } } diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 056854ad3..e1600f748 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; import { runInAction } from 'mobx'; -import { Doc, Opt, StrListCast } from "../../fields/Doc"; +import { Doc, Opt, StrListCast, LayoutSym } from "../../fields/Doc"; import { List } from '../../fields/List'; import { listSpec } from '../../fields/Schema'; import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; @@ -107,9 +107,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { parentActive={returnTrue} whenActiveChanged={this.props.whenActiveChanged} bringToFront={emptyFunction} + cantBrush={this.props.treeView.props.cantBrush} dontRegisterView={BoolCast(this.props.treeView.props.Document.dontRegisterChildViews)} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} @@ -616,15 +618,17 @@ export class TreeView extends React.Component { } renderEmbeddedDocument = (asText: boolean) => { - const panelWidth = asText || StrCast(Doc.LayoutField(this.layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.expandPanelWidth; - const panelHeight = asText ? this.rtfOutlineHeight : StrCast(Doc.LayoutField(this.layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.expandPanelHeight; + const layout = StrCast(Doc.LayoutField(this.layoutDoc)); + const isExpandable = layout.includes(FormattedTextBox.name) || layout.includes(SliderBox.name); + const panelWidth = asText || isExpandable ? this.rtfWidth : this.expandPanelWidth; + const panelHeight = asText ? this.rtfOutlineHeight : isExpandable ? this.rtfHeight : this.expandPanelHeight; return this._dref = r)} Document={this.doc} DataDoc={undefined} PanelWidth={panelWidth} PanelHeight={panelHeight} - NativeWidth={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} - NativeHeight={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined} + NativeWidth={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfWidth : undefined} + NativeHeight={!asText && (this.layoutDoc.type === DocumentType.RTF || this.layoutDoc.type === DocumentType.SLIDER) ? this.rtfHeight : undefined} fitContentsToDoc={true} hideTitle={asText} LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined} @@ -646,6 +650,7 @@ export class TreeView extends React.Component { whenActiveChanged={this.props.whenActiveChanged} addDocTab={this.props.addDocTab} pinToPres={this.props.pinToPres} + cantBrush={this.props.treeView.props.cantBrush} bringToFront={returnFalse} />; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e99b0a155..d72e555a0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -74,6 +74,7 @@ export interface DocumentViewSharedProps { dropAction?: dropActionType; dontRegisterView?: boolean; ignoreAutoHeight?: boolean; + cantBrush?: boolean; // whether the document doesn't show brush highlighting pointerEvents?: string; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document } @@ -820,7 +821,7 @@ export class DocumentViewInternal extends DocComponent item.split(":")[0] === facetHeader)) !== -1) { - docRangeFilters.splice(index, 1); + docRangeFilters.splice(index, 3); } } } else { @@ -122,13 +122,13 @@ export class FilterBox extends ViewBoxBaseComponent; if (facetHeader === "text" || facetValues.rtFields / allCollectionDocs.length > 0.1) { - newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true }); + newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, system: true, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true }); Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox newFacet._textBoxPadding = 4; const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`; newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" }); } else if (facetHeader !== "tags" && nonNumbers / facetValues.strings.length < .1) { - newFacet = Docs.Create.SliderDocument({ title: facetHeader, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", treeViewOpen: true }); + newFacet = Docs.Create.SliderDocument({ title: facetHeader, _overflow: "visible", _height: 40, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", treeViewOpen: true }); const newFacetField = Doc.LayoutFieldKey(newFacet); const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader); Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox @@ -146,7 +146,7 @@ export class FilterBox extends ViewBoxBaseComponent e.stopPropagation()} style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}> -
    +