From b3d1b60ac867a472ba791f57c8eb2d7afbb95767 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 3 Dec 2020 10:55:05 -0500 Subject: changed parameters for style provider to use documentViewProps instead of renderDepth --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0ba13192d..ab0c3964b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -393,8 +393,8 @@ export class CollectionFreeFormView extends CollectionSubView, renderDepth: number, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => { - let clusterColor = this.props.styleProvider?.(doc, this.props.renderDepth + 1, property, layerProvider); + getClusterColor = (doc: Opt, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => { + let clusterColor = this.props.styleProvider?.(doc, props, property, layerProvider); // bcz: check 'props' used to be renderDepth + 1 if (property !== "backgroundColor") return clusterColor; const cluster = NumCast(doc?.cluster); if (this.Document._useClusters) { -- cgit v1.2.3-70-g09d2 From ff791402919478bf153179a6629752f2066edc29 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 7 Dec 2020 14:03:46 -0500 Subject: fixed lists to allow multiple null-value entries & be able to edit in KeyValuePane. cleaned up a lot of stuff with animation frames and got working again. fixed previews of links to text selections to preview properly. --- src/client/views/ScriptBox.tsx | 1 - src/client/views/collections/TabDocView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 144 +++++++-------------- src/client/views/nodes/LinkDocPreview.tsx | 8 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 140 ++++++++++++-------- src/fields/Doc.ts | 1 + src/fields/ScriptField.ts | 17 ++- src/server/websocket.ts | 4 +- 9 files changed, 159 insertions(+), 165 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 2c185be86..e2b5d8dc3 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -12,7 +12,6 @@ import { CompileScript } from "../util/Scripting"; import { ScriptField } from "../../fields/ScriptField"; import { DragManager } from "../util/DragManager"; import { EditableView } from "./EditableView"; -import { getEffectiveTypeRoots } from "typescript"; export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 61650da6c..a8a95bf08 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -431,7 +431,7 @@ export class TabDocView extends React.Component { // Doc.SetNativeWidth(this.props.Document[DataSym], wid); // Doc.SetNativeHeight(this.props.Document[DataSym], hgt); } - })) + })); // // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ab0c3964b..fa84e5539 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -222,14 +222,17 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); zsorted.forEach((doc, index) => doc.zIndex = doc.isInkMask ? 5000 : index + 1); const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000)); - const dropPos = this.Document._currentFrame !== undefined ? [dvals.x, dvals.y] : [NumCast(refDoc.x), NumCast(refDoc.y)]; + const dropPos = this.Document._currentFrame !== undefined ? [dvals.x || 0, dvals.y || 0] : [NumCast(refDoc.x), NumCast(refDoc.y)]; for (let i = 0; i < docDragData.droppedDocuments.length; i++) { const d = docDragData.droppedDocuments[i]; const layoutDoc = Doc.Layout(d); if (this.Document._currentFrame !== undefined) { CollectionFreeFormDocumentView.setupKeyframes([d], this.Document._currentFrame, false); const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000)); - CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, this.Document.editScrollProgressivize ? vals.scroll : undefined, vals.opacity); + vals.x = x + (vals.x || 0) - dropPos[0]; + vals.y = y + (vals.y || 0) - dropPos[1]; + vals._scrollTop = this.Document.editScrollProgressivize ? vals._scrollTop : undefined; + CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, vals); } else { d.x = x + NumCast(d.x) - dropPos[0]; d.y = y + NumCast(d.y) - dropPos[1]; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 94793ffff..942182191 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,25 +1,23 @@ -import { computed, IReactionDisposer, observable, reaction, trace, action } from "mobx"; +import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../fields/Doc"; +import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; +import { Doc, HeightSym, WidthSym, Opt } from "../../../fields/Doc"; +import { Document } from "../../../fields/documentSchemas"; +import { List } from "../../../fields/List"; +import { listSpec } from "../../../fields/Schema"; +import { ComputedField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { TraceMobx } from "../../../fields/util"; +import { numberRange, returnVal } from "../../../Utils"; +import { DocumentType } from "../../documents/DocumentTypes"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; +import { InkingStroke } from "../InkingStroke"; import "./CollectionFreeFormDocumentView.scss"; -import { DocumentView, DocumentViewProps } from "./DocumentView"; -import React = require("react"); -import { Document } from "../../../fields/documentSchemas"; -import { TraceMobx } from "../../../fields/util"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; -import { List } from "../../../fields/List"; -import { numberRange, smoothScroll, returnVal } from "../../../Utils"; -import { ComputedField } from "../../../fields/ScriptField"; -import { listSpec } from "../../../fields/Schema"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal'; +import { DocumentView, DocumentViewProps } from "./DocumentView"; import { PresBox, PresEffect } from "./PresBox"; -import { InkingStroke } from "../InkingStroke"; -import { SnappingManager } from "../../util/SnappingManager"; -import { InkTool } from "../../../fields/InkField"; +import React = require("react"); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; @@ -62,46 +60,24 @@ export class CollectionFreeFormDocumentView extends DocComponent (i <= timecode && h !== undefined) || p === undefined ? h : p, undefined as any as number), - w: Cast(doc["w-indexed"], listSpec("number"), [NumCast(doc._width)]).reduce((p, w, i) => (i <= timecode && w !== undefined) || p === undefined ? w : p, undefined as any as number), - x: Cast(doc["x-indexed"], listSpec("number"), [NumCast(doc.x)]).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number), - y: Cast(doc["y-indexed"], listSpec("number"), [NumCast(doc.y)]).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number), - scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollTop, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number), - opacity: Cast(doc["opacity-indexed"], listSpec("number"), [NumCast(doc.opacity, 1)]).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number), - }); + return CollectionFreeFormDocumentView.animFields.reduce((p, val) => { + p[val] = Cast(`${val}-indexed`, listSpec("number"), [NumCast(doc[val])]).reduce((p, v, i) => (i <= Math.round(time) && v !== undefined) || p === undefined ? v : p, undefined as any as number); + return p; + }, {} as { [val: string]: Opt }); } - public static setValues(time: number, d: Doc, x?: number, y?: number, h?: number, w?: number, scroll?: number, opacity?: number) { + public static setValues(time: number, d: Doc, vals: { [val: string]: Opt }) { const timecode = Math.round(time); - const hindexed = Cast(d["h-indexed"], listSpec("number"), []).slice(); - const windexed = Cast(d["w-indexed"], listSpec("number"), []).slice(); - const xindexed = Cast(d["x-indexed"], listSpec("number"), []).slice(); - const yindexed = Cast(d["y-indexed"], listSpec("number"), []).slice(); - const oindexed = Cast(d["opacity-indexed"], listSpec("number"), []).slice(); - const scrollIndexed = Cast(d["scroll-indexed"], listSpec("number"), []).slice(); - xindexed[timecode] = x as any as number; - yindexed[timecode] = y as any as number; - hindexed[timecode] = h as any as number; - windexed[timecode] = w as any as number; - oindexed[timecode] = opacity as any as number; - if (scroll) scrollIndexed[timecode] = scroll as any as number; - d["x-indexed"] = new List(xindexed); - d["y-indexed"] = new List(yindexed); - d["h-indexed"] = new List(hindexed); - d["w-indexed"] = new List(windexed); - d["opacity-indexed"] = new List(oindexed); - d["scroll-indexed"] = new List(scrollIndexed); - if (d.appearFrame) { - if (d.appearFrame === timecode + 1) { - d["text-color"] = "red"; - } else if (d.appearFrame < timecode + 1) { - d["text-color"] = "grey"; - } else { d["text-color"] = "black"; } - } else if (d.appearFrame === 0) { - } + Object.keys(vals).forEach(val => { + const findexed = Cast(d[`${val}-indexed`], listSpec("number"), []).slice(); + findexed[timecode] = vals[val] as any as number; + d[`${val}-indexed`] = new List(findexed); + }); + d.appearFrame && (d["text-color"] = + d.appearFrame === timecode + 1 ? "red" : + d.appearFrame < timecode + 1 ? "grey" : "black"); } // public static updateScrollframe(doc: Doc, time: number) { @@ -123,37 +99,26 @@ export class CollectionFreeFormDocumentView extends DocComponent { - const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); - const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); - const hindexed = Cast(doc['h-indexed'], listSpec("number"), null); - const windexed = Cast(doc['w-indexed'], listSpec("number"), null); - const opacityindexed = Cast(doc['opacity-indexed'], listSpec("number"), null); - hindexed?.length <= timecode + 1 && hindexed.push(undefined as any as number); - windexed?.length <= timecode + 1 && windexed.push(undefined as any as number); - xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number); - yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number); - opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number); - if (doc.appearFrame && targetDoc) { - if (doc.appearFrame === timecode + 1) { - doc["text-color"] = StrCast(targetDoc["pres-text-color"]); - } else if (doc.appearFrame < timecode + 1) { - doc["text-color"] = StrCast(targetDoc["pres-text-viewed-color"]); - } else { doc["text-color"] = "black"; } - } else if (doc.appearFrame === 0) { - doc["text-color"] = "black"; - } - doc.dataTransition = "all 1s"; - }); - setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010); + docs.forEach(action(doc => { + doc._viewTransition = doc.dataTransition = "all 1s"; + doc["text-color"] = + !doc.appearFrame || !targetDoc ? "black" : + doc.appearFrame === timecode + 1 ? StrCast(targetDoc["pres-text-color"]) : + doc.appearFrame < timecode + 1 ? StrCast(targetDoc["pres-text-viewed-color"]) : + "black"; + CollectionFreeFormDocumentView.animFields.forEach(val => { + const findexed = Cast(doc[`${val}-indexed`], listSpec("number"), null); + findexed?.length <= timecode + 1 && findexed.push(undefined as any as number); + }); + })); + setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit"; }), 1010); } public static gotoKeyframe(docs: Doc[]) { - docs.forEach(doc => doc.dataTransition = "all 1s"); - setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010); + docs.forEach(doc => doc._viewTransition = doc.dataTransition = "all 1s"); + setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit" }), 1010); } - public static setupZoom(doc: Doc, targDoc: Doc) { const width = new List(); const height = new List(); @@ -172,27 +137,12 @@ export class CollectionFreeFormDocumentView extends DocComponent { if (doc.appearFrame === undefined) doc.appearFrame = currTimecode; - const curTimecode = currTimecode; - const xlist = new List(numberRange(currTimecode + 1).map(i => undefined) as any as number[]); - const ylist = new List(numberRange(currTimecode + 1).map(i => undefined) as any as number[]); - const wlist = new List(numberRange(currTimecode + 1).map(i => undefined) as any as number[]); - const hlist = new List(numberRange(currTimecode + 1).map(i => undefined) as any as number[]); - const olist = new List(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1)); - wlist[curTimecode] = NumCast(doc._width); - hlist[curTimecode] = NumCast(doc._height); - xlist[curTimecode] = NumCast(doc.x); - ylist[curTimecode] = NumCast(doc.y); - doc["x-indexed"] = xlist; - doc["y-indexed"] = ylist; - doc["w-indexed"] = wlist; - doc["h-indexed"] = hlist; - doc["opacity-indexed"] = olist; + if (!doc["opacity-indexed"]) { // opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in + const olist = new List(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1)); + doc["opacity-indexed"] = olist; + } + CollectionFreeFormDocumentView.animFields.forEach(val => doc[val] = ComputedField.MakeInterpolated(val, "activeFrame", doc, currTimecode)); doc.activeFrame = ComputedField.MakeFunction("self.context?._currentFrame||0"); - doc._height = ComputedField.MakeInterpolated("h", "activeFrame"); - doc._width = ComputedField.MakeInterpolated("w", "activeFrame"); - doc.x = ComputedField.MakeInterpolated("x", "activeFrame"); - doc.y = ComputedField.MakeInterpolated("y", "activeFrame"); - doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame"); doc.dataTransition = "inherit"; }); } diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 0256d394e..c4bb2b8d8 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -12,6 +12,7 @@ import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import { DocumentLinksButton } from './DocumentLinksButton'; import React = require("react"); import { DocumentViewProps } from './DocumentView'; +import { Id } from '../../../fields/FieldSymbols'; interface Props { linkDoc?: Doc; @@ -64,8 +65,11 @@ export class LinkDocPreview extends React.Component { runInAction(() => { this._toolTipText = ""; LinkDocPreview.TargetDoc = this._targetDoc = target; - if (anchor !== this._targetDoc && anchor && this._targetDoc) { - this._targetDoc._scrollPreviewY = NumCast(anchor?.y); + if (this._targetDoc) { + this._targetDoc._scrollToPreviewLinkID = linkDoc?.[Id]; + if (anchor !== this._targetDoc && anchor) { + this._targetDoc._scrollPreviewY = NumCast(anchor?.y); + } } }); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 125447f28..6768acce4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -61,6 +61,7 @@ import { DocumentManager } from '../../../util/DocumentManager'; import { CollectionStackingView } from '../../collections/CollectionStackingView'; import { CollectionViewType } from '../../collections/CollectionView'; import { SnappingManager } from '../../../util/SnappingManager'; +import { LinkDocPreview } from '../LinkDocPreview'; export interface FormattedTextBoxProps { makeLink?: () => Opt; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text @@ -98,6 +99,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _currentTime: number = 0; private _linkTime: number | null = null; private _pause: boolean = false; + private _animatingScroll: numher = 0; // hack to prevent scroll values from being written to document when scroll is animating @computed get _recording() { return this.dataDoc?.audioState === "recording"; } set _recording(value) { @@ -815,6 +817,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return this.active();//this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0; } + scrollToLinkId = (linkId: string) => { + const findLinkFrag = (frag: Fragment, editor: EditorView) => { + const nodes: Node[] = []; + let hadStart = start !== 0; + frag.forEach((node, index) => { + const examinedNode = findLinkNode(node, editor); + if (examinedNode?.node.textContent) { + nodes.push(examinedNode.node); + !hadStart && (start = index + examinedNode.start); + hadStart = true; + } + }); + return { frag: Fragment.fromArray(nodes), start }; + }; + const findLinkNode = (node: Node, editor: EditorView) => { + if (!node.isText) { + const content = findLinkFrag(node.content, editor); + return { node: node.copy(content.frag), start: content.start }; + } + const marks = [...node.marks]; + const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor); + return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => linkId === item.href.replace(/.*\/doc\//, "")) ? { node, start: 0 } : undefined; + }; + + let start = 0; + if (this._editorView && linkId) { + const editor = this._editorView; + const ret = findLinkFrag(editor.state.doc.content, editor); + + if (ret.frag.size > 2 && ret.start >= 0) { + let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start + if (ret.frag.firstChild) { + selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected + } + editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView()); + const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight); + setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0); + setTimeout(() => this.unhighlightSearchTerms(), 2000); + } + Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false); + Doc.SetInPlace(this.layoutDoc, "_scrollToPreviewLinkID", undefined, false); + } + } + componentDidMount() { this.props.contentsActive?.(this.IsActive); this._cachedLinks = DocListCast(this.Document.links); @@ -910,7 +956,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp search => search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms(), { fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false }); - this._disposers.selected = reaction(() => this.props.isSelected(), action(() => this._recording = false)); + this._disposers.selected = reaction(() => this.props.isSelected(), + action((selected) => { + this._recording = false; + if (RichTextMenu.Instance?.view === this._editorView && !selected) { + RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined); + } + })); if (!this.props.dontRegisterView) { this._disposers.record = reaction(() => this._recording, @@ -924,65 +976,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } ); } - this._disposers.scrollToRegion = reaction( - () => StrCast(this.layoutDoc.scrollToLinkID), - async (scrollToLinkID) => { - const findLinkFrag = (frag: Fragment, editor: EditorView) => { - const nodes: Node[] = []; - let hadStart = start !== 0; - frag.forEach((node, index) => { - const examinedNode = findLinkNode(node, editor); - if (examinedNode?.node.textContent) { - nodes.push(examinedNode.node); - !hadStart && (start = index + examinedNode.start); - hadStart = true; - } - }); - return { frag: Fragment.fromArray(nodes), start }; - }; - const findLinkNode = (node: Node, editor: EditorView) => { - if (!node.isText) { - const content = findLinkFrag(node.content, editor); - return { node: node.copy(content.frag), start: content.start }; - } - const marks = [...node.marks]; - const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor); - return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? { node, start: 0 } : undefined; - }; - - let start = 0; - if (this._editorView && scrollToLinkID) { - const editor = this._editorView; - const ret = findLinkFrag(editor.state.doc.content, editor); - - if (ret.frag.size > 2 && ret.start >= 0) { - let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start - if (ret.frag.firstChild) { - selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected - } - editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView()); - const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight); - setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0); - setTimeout(() => this.unhighlightSearchTerms(), 2000); - } - Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false); - } - - }, - { fireImmediately: true } + this._disposers.previewScrollToRegion = reaction(() => StrCast(this.layoutDoc._scrollToPreviewLinkID), + scrollToLinkID => this.props.renderDepth === -1 && scrollToLinkID && this.scrollToLinkId(scrollToLinkID), { fireImmediately: true } + ); + this._disposers.scrollToRegion = reaction(() => StrCast(this.layoutDoc.scrollToLinkID), + scrollToLinkID => scrollToLinkID && this.scrollToLinkId(scrollToLinkID), { fireImmediately: true } ); this._disposers.scroll = reaction(() => NumCast(this.layoutDoc._scrollTop), - pos => this._scrollRef.current?.scrollTo({ top: pos }), { fireImmediately: true } + pos => { + const durationMiliStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/); + const durationSecStr = StrCast(this.Document._viewTransition).match(/([0-9.]*)s/); + const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0; + if (duration) { + this._animatingScroll++; + this._scrollRef.current && smoothScroll(duration, this._scrollRef.current, Math.abs(pos || 0)); + setTimeout(() => this._animatingScroll--, duration); + } else { + this._scrollRef.current?.scrollTo({ top: pos }); + } + }, { fireImmediately: true } ); this._disposers.scrollY = reaction(() => Cast(this.layoutDoc._scrollY, "number", null), - scrollY => { - if (scrollY !== undefined) { - const delay = this._scrollRef.current ? 0 : 250; // wait for mainCont and try again to scroll - const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/); - const duration = durationStr ? Number(durationStr[1]) : 1000; - setTimeout(() => this._scrollRef.current && smoothScroll(duration, this._scrollRef.current, Math.abs(scrollY || 0)), delay); - setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, duration + delay); - } + pos => { + this.Document._scrollY = undefined; + pos !== undefined && setTimeout(() => this.layoutDoc._scrollTop = pos, this._scrollRef.current ? 0 : 250); + }, { fireImmediately: true } + ); + this._disposers.scrollPreviewY = reaction(() => Cast(this.layoutDoc.scrollPreviewY, "number", null), + pos => { + this.Document.scrollPreviewY = undefined; + pos !== undefined && setTimeout(() => this.layoutDoc._scrollTop = pos, this._scrollRef.current ? 0 : 250); }, { fireImmediately: true } ); @@ -1233,6 +1256,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp componentWillUnmount() { this.endUndoTypingBatch(); + this.unhighlightSearchTerms(); Object.values(this._disposers).forEach(disposer => disposer?.()); this._editorView?.destroy(); FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none"); @@ -1529,7 +1553,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp eve.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash. } onscrolled = (ev: React.UIEvent) => { - this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop; + if (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && !this._animatingScroll) { + this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop; + } } @action tryUpdateHeight(limitHeight?: number) { diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index ffb1bbf83..fdea47c84 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -36,6 +36,7 @@ export namespace Field { export function toScriptString(field: Field): string { if (typeof field === "string") return `"${field}"`; if (typeof field === "number" || typeof field === "boolean") return String(field); + if (field === undefined || field === null) return "null"; return field[ToScriptString](); } export function toString(field: Field): string { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 024017302..c949e0791 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -7,7 +7,9 @@ import { Doc, Field, Opt } from "./Doc"; import { Plugins, setter } from "./util"; import { computedFn } from "mobx-utils"; import { ProxyField } from "./Proxy"; -import { Cast } from "./Types"; +import { Cast, NumCast } from "./Types"; +import { List } from "./List"; +import { numberRange } from "../Utils"; function optional(propSchema: PropSchema) { return custom(value => { @@ -188,12 +190,21 @@ export class ComputedField extends ScriptField { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { + public static MakeInterpolated(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) { + if (!doc[`${fieldKey}-indexed`]) { + const flist = new List(numberRange(curTimecode + 1).map(i => undefined) as any as number[]); + flist[curTimecode] = NumCast(doc[fieldKey]); + doc[`${fieldKey}-indexed`] = flist; + } const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); - const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); + const setField = ScriptField.CompileScript(`setIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey}, value)`, { value: "any" }, true, {}); return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; } } +Scripting.addGlobal(function setIndexVal(list: any[], index: number, value: any) { + while (list.length <= index) list.push(undefined); + list[index] = value; +}, "sets the value at a given index of a list", "(list: any[], index: number, value: any)"); Scripting.addGlobal(function getIndexVal(list: any[], index: number) { return list?.reduce((p, x, i) => (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any); diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 7d111f359..6850f0601 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -279,13 +279,13 @@ export namespace WebSocket { const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; const newListItems = diff.diff.$set[updatefield].fields; const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields.filter((item: any) => item !== undefined) || []; - diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => newItem && !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; + diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; delete diff.diff.length; Database.Instance.update(diff.id, diff.diff, () => { if (sendBack) { - console.log("RET BACK"); + console.log("Warning: list modified during update. Composite list is being returned."); const id = socket.id; socket.id = ""; socket.broadcast.emit(MessageStore.UpdateField.Message, diff); -- cgit v1.2.3-70-g09d2 From 8bbe55468f2ea222ed8c4dc513e65707c8835737 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 7 Dec 2020 17:15:09 -0500 Subject: got rid of LibraryPath. Fixed collectionFreeFormDocViews to use pres Effects whenever doc is selected --- src/client/views/GestureOverlay.tsx | 1 - src/client/views/MainView.tsx | 9 +-- src/client/views/OverlayView.tsx | 1 - src/client/views/Palette.tsx | 1 - src/client/views/PropertiesView.tsx | 1 - src/client/views/TemplateMenu.tsx | 1 - .../views/collections/CollectionDockingView.tsx | 2 +- .../views/collections/CollectionLinearView.tsx | 1 - .../views/collections/CollectionSchemaView.tsx | 1 - .../views/collections/CollectionStackingView.tsx | 1 - .../views/collections/CollectionTreeView.tsx | 1 - src/client/views/collections/SchemaTable.tsx | 1 - src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 1 - .../CollectionMultirowView.tsx | 1 - .../views/nodes/CollectionFreeFormDocumentView.tsx | 90 ++++++++++------------ .../views/nodes/ContentFittingDocumentView.tsx | 1 - src/client/views/nodes/DocHolderBox.tsx | 2 - src/client/views/nodes/DocumentView.tsx | 6 +- src/client/views/nodes/FieldView.tsx | 1 - src/client/views/nodes/FilterBox.tsx | 1 - src/client/views/nodes/KeyValuePair.tsx | 1 - src/client/views/nodes/LinkDocPreview.tsx | 1 - .../views/nodes/formattedText/DashDocView.tsx | 1 - .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- .../formattedText/FormattedTextBoxComment.tsx | 1 - .../views/nodes/formattedText/RichTextSchema.tsx | 1 - src/client/views/pdf/PDFViewer.tsx | 1 - .../views/presentationview/PresElementBox.tsx | 1 - src/mobile/AudioUpload.tsx | 1 - src/mobile/MobileInterface.tsx | 1 - 33 files changed, 51 insertions(+), 98 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 35dedf016..c60060095 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -889,7 +889,6 @@ export class GestureOverlay extends Touchable { this._flyoutWidth; sidebarScreenToLocal = () => new Transform(0, -this.topOffset, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftOffset, 0); - addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => { + addDocTabFunc = (doc: Doc, where: string): boolean => { return where === "close" ? CollectionDockingView.CloseSplit(doc) : doc.dockingConfig ? CurrentUserUtils.openDashboard(Doc.UserDoc(), doc) : CollectionDockingView.AddSplit(doc, "right"); } @@ -308,7 +307,6 @@ export class MainView extends React.Component { { { { rootSelected={returnFalse} onCheckedClick={this.scriptField} onChildClick={this.scriptField} - LibraryPath={emptyPath} dropAction={undefined} active={returnTrue} parentActive={returnFalse} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 57b038c73..eee939c07 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -90,7 +90,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) { } @undoBatch - public static OpenFullScreen(doc: Doc, libraryPath?: Doc[]) { + public static OpenFullScreen(doc: Doc) { const instance = CollectionDockingView.Instance; if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") { return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc); diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index b427e35c3..c7c510306 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -140,7 +140,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) { doc) { FreezeDimensions={true} dontCenter={"y"} focus={emptyFunction} - LibraryPath={this.props.LibraryPath} renderDepth={this.props.renderDepth} rootSelected={this.rootSelected} PanelWidth={this.previewWidth} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 4b3393e14..0e4029764 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -195,7 +195,6 @@ export class CollectionStackingView extends CollectionSubView { fitToBox={true} FreezeDimensions={true} focus={emptyFunction} - LibraryPath={emptyPath} renderDepth={this.props.renderDepth} rootSelected={() => false} PanelWidth={() => 150} diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index a8a95bf08..45658418c 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -288,7 +288,7 @@ export class TabDocView extends React.Component { // "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, // "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right // inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack - addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => { + addDocTab = (doc: Doc, location: string) => { SelectionManager.DeselectAll(); const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":"); const locationParams = locationFields.length > 1 ? locationFields[1] : ""; @@ -335,7 +335,6 @@ export class TabDocView extends React.Component {
{ TraceMobx(); return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) : <> boolean) | undefined; moveDocument: DragManager.MoveFunction; dropAction: dropActionType; - addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean; + addDocTab: (doc: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; panelWidth: () => number; panelHeight: () => number; @@ -521,7 +521,6 @@ export class TreeView extends React.Component { Document={this.doc} DataDoc={undefined} treeViewDoc={this.props.treeView.props.Document} - LibraryPath={emptyPath} addDocument={undefined} addDocTab={this.props.addDocTab} rootSelected={returnTrue} @@ -598,7 +597,6 @@ export class TreeView extends React.Component { focus={asText ? this.refocus : returnFalse} dontRegisterView={asText ? undefined : this.props.dontRegisterView} ScreenToLocalTransform={this.docTransform} - LibraryPath={emptyPath} renderDepth={this.props.renderDepth + 1} rootSelected={returnTrue} treeViewDoc={undefined} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index fa84e5539..652b926ce 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -12,7 +12,7 @@ import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnVal } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnVal, returnTrue } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -982,11 +982,10 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); - backgroundHalo = computedFn(function (doc: Doc) { return BoolCast(this.Document._useClusters) || (NumCast(doc.group, -1) !== -1); }).bind(this); + backgroundHalo = this.Document._useClusters ? returnTrue : computedFn(function (doc: Doc) { return NumCast(doc.group, -1) !== -1; }); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { @@ -999,7 +998,6 @@ export class CollectionFreeFormView extends CollectionSubView doc._viewTransition = doc.dataTransition = "all 1s"); - setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit" }), 1010); + setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit"; }), 1010); } public static setupZoom(doc: Doc, targDoc: Doc) { @@ -153,41 +153,41 @@ export class CollectionFreeFormDocumentView extends DocComponent; - if (PresBox.Instance && this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc) { - const effectProps = { - left: this.layoutDoc.presEffectDirection === PresEffect.Left, - right: this.layoutDoc.presEffectDirection === PresEffect.Right, - top: this.layoutDoc.presEffectDirection === PresEffect.Top, - bottom: this.layoutDoc.presEffectDirection === PresEffect.Bottom, - opposite: true, - delay: this.layoutDoc.presTransition, - // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, - }; - switch (this.layoutDoc.presEffect) { - case "Zoom": return ({node}); break; - case PresEffect.Fade: return ({node}); break; - case PresEffect.Flip: return ({node}); break; - case PresEffect.Rotate: return ({node}); break; - case PresEffect.Bounce: return ({node}); break; - case PresEffect.Roll: return ({node}); break; - case "LightSpeed": return ({node}); break; - case PresEffect.None: return node; break; - default: return node; break; - } - } else { - return node; + const divProps = { + ...this.props, + nudge: this.nudge, + dragDivName: "collectionFreeFormDocumentView-container", + opacity: this.opacity, + ScreenToLocalTransform: this.getTransform, + NativeHeight: this.NativeHeight, + NativeWidth: this.NativeWidth, + PanelWidth: this.panelWidth, + PanelHeight: this.panelHeight + }; + return this.props.fitToBox ? + this._contentView = r)} /> : + ; + } + @computed get effectsNodeDiv() { + const effectProps = { + left: this.layoutDoc.presEffectDirection === PresEffect.Left, + right: this.layoutDoc.presEffectDirection === PresEffect.Right, + top: this.layoutDoc.presEffectDirection === PresEffect.Top, + bottom: this.layoutDoc.presEffectDirection === PresEffect.Bottom, + opposite: true, + delay: this.layoutDoc.presTransition, + // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, + }; + switch (this.layoutDoc.presEffect) { + case "Zoom": return ({this.freeformNodeDiv}); + case PresEffect.Fade: return ({this.freeformNodeDiv}); + case PresEffect.Flip: return ({this.freeformNodeDiv}); + case PresEffect.Rotate: return ({this.freeformNodeDiv}); + case PresEffect.Bounce: return ({this.freeformNodeDiv}); + case PresEffect.Roll: return ({this.freeformNodeDiv}); + case "LightSpeed": return ({this.freeformNodeDiv}); + case PresEffect.None: + default: return this.freeformNodeDiv; } } @@ -207,6 +207,7 @@ export class CollectionFreeFormDocumentView extends DocComponent
} - {!this.props.fitToBox ? - <>{this.freeformNodeDiv} - : this._contentView = r)} - ContainingCollectionDoc={this.props.ContainingCollectionDoc} - DataDoc={this.props.DataDoc} - ScreenToLocalTransform={this.getTransform} - NativeHeight={this.NativeHeight} - NativeWidth={this.NativeWidth} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight} - />} + {PresBox.Instance && this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? + this.effectsNodeDiv + : + this.freeformNodeDiv + } ; } } diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index a54479f55..74d7cb24e 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -71,7 +71,6 @@ export class ContentFittingDocumentView extends React.Component any; LayoutTemplateString?: string; LayoutTemplate?: () => Opt; - LibraryPath: Doc[]; fitToBox?: boolean; ignoreAutoHeight?: boolean; contextMenuItems?: () => { script: ScriptField, label: string }[]; @@ -90,7 +89,7 @@ export interface DocumentViewProps { parentActive: (outsideReaction: boolean) => boolean; whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc, sendToBack?: boolean) => void; - addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean; + addDocTab: (doc: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; backgroundHalo?: (doc: Doc) => boolean; styleProvider?: (doc: Opt, props: DocumentViewProps, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any; @@ -386,7 +385,7 @@ export class DocumentView extends DocComponent(Docu // depending on the followLinkLocation property of the source (or the link itself as a fallback); public static followLinkClick = async (linkDoc: Opt, sourceDoc: Doc, docView: { focus: DocFocusFunc, - addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean, + addDocTab: (doc: Doc, where: string) => boolean, ContainingCollectionDoc?: Doc }, shiftKey: boolean, altKey: boolean) => { const batch = UndoManager.StartBatch("follow link click"); @@ -933,7 +932,6 @@ export class DocumentView extends DocComponent(Docu backgroundHalo={this.props.backgroundHalo} dontRegisterView={this.props.dontRegisterView} fitToBox={this.props.fitToBox} - LibraryPath={this.props.LibraryPath} addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} moveDocument={this.props.moveDocument} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index ed91cf47d..f2fdf7a6b 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -25,7 +25,6 @@ export interface FieldViewProps { ContainingCollectionDoc: Opt; Document: Doc; DataDoc?: Doc; - LibraryPath: Doc[]; layerProvider?: (doc: Doc, assign?: boolean) => boolean; contentsActive?: (setActive: () => boolean) => void; onClick?: () => ScriptField; diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 6f0828a7d..0161f51fd 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -193,7 +193,6 @@ export class FilterBox extends ViewBoxBaseComponent { const props: FieldViewProps = { Document: this.props.doc, DataDoc: this.props.doc, - LibraryPath: [], docFilters: returnEmptyFilter, docRangeFilters: returnEmptyFilter, searchFilterDocs: returnEmptyDoclist, diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index c4bb2b8d8..5017b3a71 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -94,7 +94,6 @@ export class LinkDocPreview extends React.Component { : { Date: Tue, 8 Dec 2020 12:55:54 -0500 Subject: simplified styleProvider arguments. fixed useClusters --- src/client/views/PropertiesView.tsx | 2 +- .../views/collections/CollectionCarouselView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 12 ++++++------ .../collectionFreeForm/CollectionFreeFormView.tsx | 7 ++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 6 +++--- src/client/views/nodes/DocHolderBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 21 +++++++++------------ src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FontIconBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- .../views/presentationview/PresElementBox.tsx | 2 +- 15 files changed, 33 insertions(+), 35 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 9f1b8dad3..08394cd97 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -37,7 +37,7 @@ const _global = (window /* browser */ || global /* node */) as any; interface PropertiesViewProps { width: number; height: number; - styleProvider?: (doc: Opt, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any; + styleProvider?: (doc: Opt, props: Opt, property: string) => any; } @observer diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 62c1bce3f..16ccdc6f4 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -65,7 +65,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index ac01536c9..681584cc5 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -215,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView {this.showIsTagged()} diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 45658418c..e1fd47592 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -434,7 +434,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: DocumentViewProps | undefined, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean): any => { + public static styleProvider = (doc: Opt, props: DocumentViewProps | undefined, property: string): any => { switch (property) { case "backgroundColor": { if (Doc.UserDoc().renderStyle === "comic") return undefined; @@ -456,11 +456,11 @@ export class TabDocView extends React.Component { default: docColor = TabDocView.darkScheme ? "black" : "white"; break; } } - if (docColor && (!doc || layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString(); + if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString(); return docColor; } case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey"; - case "hidden": return (BoolCast(doc?.hidden) /* || layerProvider?.(doc) === false*/); + case "hidden": return (BoolCast(doc?.hidden) /* || props?.layerProvider?.(doc) === false*/); case "boxShadow": { switch (doc?.type) { case DocumentType.COL: return StrListCast(doc.layers).includes("background") ? undefined : @@ -471,7 +471,7 @@ export class TabDocView extends React.Component { case "docContents": return undefined; default: if (property.startsWith("pointerEvents")) { - const layer = doc && layerProvider?.(doc); + const layer = doc && props?.layerProvider?.(doc); if (doc?.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"; @@ -488,7 +488,7 @@ export class TabDocView extends React.Component { } } } - public static miniStyleProvider = (doc: Opt, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean): any => { + public static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { switch (property) { case "docContents": @@ -498,7 +498,7 @@ export class TabDocView extends React.Component { return
; default: if (property.startsWith("pointerEvents")) return "none"; - return TabDocView.styleProvider(doc, props, property, layerProvider); + return TabDocView.styleProvider(doc, props, property); } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 652b926ce..136600164 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -396,8 +396,8 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => { - let clusterColor = this.props.styleProvider?.(doc, props, property, layerProvider); // bcz: check 'props' used to be renderDepth + 1 + getClusterColor = (doc: Opt, props: Opt, 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); if (this.Document._useClusters) { @@ -985,7 +985,8 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); - backgroundHalo = this.Document._useClusters ? returnTrue : computedFn(function (doc: Doc) { return NumCast(doc.group, -1) !== -1; }); + // @ts-ignore + backgroundHalo = computedFn(function (doc: Doc) { return this.Document._useClusters || NumCast(doc.group, -1) !== -1; }).bind(this); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 51ed49df3..b4b887617 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -142,11 +142,11 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeHeight; @computed get pointerEvents() { if (this.props.pointerEvents === "none") return "none"; - return this.props.styleProvider?.(this.Document, this.props, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider); + return this.props.styleProvider?.(this.Document, this.props, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents"); } render() { TraceMobx(); - const backgroundColor = this.props.styleProvider?.(this.Document, this.props, "backgroundColor", this.props.layerProvider); + const backgroundColor = this.props.styleProvider?.(this.Document, this.props, "backgroundColor"); const borderRounding = StrCast(Doc.Layout(this.layoutDoc).borderRounding) || StrCast(this.layoutDoc.borderRounding) || StrCast(this.Document.borderRounding) || undefined; const divProps = { @@ -165,7 +165,7 @@ export class CollectionFreeFormDocumentView extends DocComponent boolean; pinToPres: (document: Doc) => void; backgroundHalo?: (doc: Doc) => boolean; - styleProvider?: (doc: Opt, props: DocumentViewProps, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any; + styleProvider?: (doc: Opt, props: DocumentViewProps, property: string) => any; forceHideLinkButton?: () => boolean; opacity?: () => number | undefined; ChromeHeight?: () => number; @@ -1062,7 +1062,7 @@ export class DocumentView extends DocComponent(Docu } @computed get pointerEvents() { if (this.props.pointerEvents === "none") return "none"; - return this.props.styleProvider?.(this.Document, this.props, this.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider); + return this.props.styleProvider?.(this.Document, this.props, this.isSelected() ? "pointerEvents:selected" : "pointerEvents"); } @undoBatch @action @@ -1086,8 +1086,8 @@ export class DocumentView extends DocComponent(Docu TraceMobx(); if (!(this.props.Document instanceof Doc)) return (null); if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null); - if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden", this.props.layerProvider)) return null; - const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor", this.props.layerProvider); + if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden")) return null; + const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor"); const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; @@ -1101,14 +1101,14 @@ export class DocumentView extends DocComponent(Docu let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK; highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way const topmost = this.topMost ? "-topmost" : ""; - return this.props.styleProvider?.(this.rootDoc, this.props, "docContents", this.props.layerProvider) ??
!SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} onPointerLeave={action(e => { let entered = false; - for (let child = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); child; child = child.parentElement) { + for (let child = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); !entered && child; child = child.parentElement) { entered = entered || child === this.ContentDiv; } !entered && Doc.UnBrushDoc(this.props.Document); @@ -1131,12 +1131,9 @@ export class DocumentView extends DocComponent(Docu fontFamily: StrCast(this.Document._fontFamily, "inherit"), fontSize: !this.props.treeViewDoc ? Cast(this.Document._fontSize, "string", null) : undefined, }}> - {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <> - {this.innards} -
- : - this.innards} - {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations", this.props.layerProvider) || (null)} + {this.innards} + {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: (null)} + {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations") || (null)}
; } render() { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f2fdf7a6b..5cd752fdb 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -42,7 +42,7 @@ export interface FieldViewProps { 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, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any; + styleProvider?: (document: Opt, props: Opt, property: string) => any; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; parentActive: (outsideReaction: boolean) => boolean; diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index c9ee4126e..a1bb0604e 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -61,7 +61,7 @@ export class FontIconBox extends DocComponent( render() { const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); const color = StrCast(this.layoutDoc.color, this._foregroundColor); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, "backgroundColor", this.props.layerProvider); + const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, "backgroundColor"); const shape = StrCast(this.layoutDoc.iconShape, label ? "round" : "circle"); const icon = StrCast(this.dataDoc.icon, "user") as any; const presSize = shape === 'round' ? 25 : 30; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 1b181cef1..bf19457da 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -17,7 +17,7 @@ export class LinkBox extends ViewBoxBaseComponent( public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } render() { return
+ style={{ background: this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor") }} > , props: Opt, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any; + styleProvider?: (doc: Opt, props: Opt, property: string) => any; addDocTab: (document: Doc, where: string) => boolean; location: number[]; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 59909cea1..22e3ac1e9 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1598,7 +1598,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) :
; } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 9742faa2b..37752d6ee 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -322,7 +322,7 @@ export class PresElementBox extends ViewBoxBaseComponent} {miniView ? (null) :
-- cgit v1.2.3-70-g09d2 From 4473461d56720e8bdfd540fa67098ebccb29899c Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 8 Dec 2020 15:51:20 -0500 Subject: cleaned up MarqueeView code a bit. --- .../collections/collectionFreeForm/MarqueeView.tsx | 394 ++++++--------------- 1 file changed, 114 insertions(+), 280 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index eb781ed0a..ac82f60e1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,31 +1,32 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, DocListCast, Opt } from "../../../../fields/Doc"; +import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; 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 } from "../../../../Utils"; +import { Utils, intersectRect } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents"; +import { DocumentType } from "../../../documents/DocumentTypes"; +import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; import { DocumentManager } from "../../../util/DocumentManager"; import { SelectionManager } from "../../../util/SelectionManager"; import { Transform } from "../../../util/Transform"; import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { ContextMenu } from "../../ContextMenu"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; +import { PresBox, PresMovement } from "../../nodes/PresBox"; import { PreviewCursor } from "../../PreviewCursor"; import { CollectionDockingView } from "../CollectionDockingView"; import { SubCollectionViewProps } from "../CollectionSubView"; -import { CollectionView, CollectionViewType } from "../CollectionView"; +import { CollectionView } from "../CollectionView"; import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); -import { Id } from "../../../../fields/FieldSymbols"; -import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; -import { PresBox, PresMovement } from "../../nodes/PresBox"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -38,20 +39,28 @@ interface MarqueeViewProps { nudge?: (x: number, y: number) => boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } - @observer export class MarqueeView extends React.Component { + private _commandExecuted = false; @observable public static DragMarquee = false; @observable _lastX: number = 0; @observable _lastY: number = 0; @observable _downX: number = 0; @observable _downY: number = 0; @observable _visible: boolean = false; - _commandExecuted = false; - @observable _pointsX: number[] = []; - @observable _pointsY: number[] = []; - @observable _freeHand: boolean = false; + @observable _lassoPts: [number, number][] = []; + @observable _lassoFreehand: boolean = false; + + @computed get Transform() { return this.props.getTransform(); } + @computed get Bounds() { + const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); + const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY); + return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; + } + get inkDoc() { return this.props.Document; } + get ink() { return Cast(this.props.Document.ink, InkField); } + set ink(value: Opt) { this.props.Document.ink = value; } componentDidMount() { this.props.setPreviewCursor?.(this.setPreviewCursor); @@ -64,11 +73,9 @@ export class MarqueeView extends React.Component this.props.addDocTab( Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _fitWidth: true, _width: 400, x, y, _height: 512, _nativeWidth: 850, isAnnotating: false, title: "bing", useCors: true }), "add:right")); @@ -115,7 +122,7 @@ export class MarqueeView extends React.Component { this._downX = this._lastX = e.clientX; @@ -210,13 +218,12 @@ export class MarqueeView extends React.Component { this._lastX = e.pageX; this._lastY = e.pageY; - this._pointsX.push(e.clientX); - this._pointsY.push(e.clientY); + this._lassoPts.push([e.clientX, e.clientY]); if (!e.cancelBubble) { if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) { if (!this._commandExecuted) { - this._visible = true; + this.showMarquee(); } e.stopPropagation(); e.preventDefault(); @@ -267,6 +274,7 @@ export class MarqueeView extends React.Component r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); - } - - @computed - get Bounds() { - const left = this._downX < this._lastX ? this._downX : this._lastX; - const top = this._downY < this._lastY ? this._downY : this._lastY; - const topLeft = this.props.getTransform().transformPoint(left, top); - const size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; - } - - get inkDoc() { - return this.props.Document; - } - - get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored. - return Cast(this.props.Document.ink, InkField); - } - - set ink(value: InkField | undefined) { - this.props.Document.ink = value; - } - @action - showMarquee = () => { - this._visible = true; - } + showMarquee = () => { this._visible = true; } @action - hideMarquee = () => { - this._visible = false; - } + hideMarquee = () => { this._visible = false; } @undoBatch @action @@ -393,11 +371,10 @@ export class MarqueeView extends React.Component { const doc = this.props.Document; - const bounds = this.Bounds; - const selected = this.marqueeSelect(false); const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; if (curPres) { if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; } @@ -407,9 +384,9 @@ export class MarqueeView extends React.Component { - const bounds = this.Bounds; const selected = this.marqueeSelect(false); if (e instanceof KeyboardEvent ? e.key === "c" : true) { selected.map(action(d => { @@ -447,8 +420,8 @@ export class MarqueeView extends React.Component { const selected = this.marqueeSelect(false); if (e instanceof KeyboardEvent ? e.key === "i" : true) { - const inks = selected.filter(s => s.proto?.type === "ink"); - const setDocs = selected.filter(s => s.proto?.type === "text" && s.color); - const sets = setDocs.map((sd) => { - return Cast(sd.data, RichTextField)?.Text as string; - }); + const inks = selected.filter(s => s.proto?.type === DocumentType.INK); + const setDocs = selected.filter(s => s.proto?.type === DocumentType.RTF && s.color); + const sets = setDocs.map((sd) => Cast(sd.data, RichTextField)?.Text as string); const colors = setDocs.map(sd => FieldValue(sd.color) as string); const wordToColor = new Map(); - sets.forEach((st: string, i: number) => { - const words = st.split(","); - words.forEach(word => { - wordToColor.set(word, colors[i]); - }); - }); + sets.forEach((st: string, i: number) => st.split(",").forEach(word => wordToColor.set(word, colors[i]))); const strokes: InkData[] = []; - inks.forEach(i => { - const d = Cast(i.data, InkField); - const x = NumCast(i.x); - const y = NumCast(i.y); + inks.filter(i => Cast(i.data, InkField)).forEach(i => { + const d = Cast(i.data, InkField, null); const left = Math.min(...d?.inkData.map(pd => pd.X) ?? [0]); const top = Math.min(...d?.inkData.map(pd => pd.Y) ?? [0]); - if (d) { - strokes.push(d.inkData.map(pd => ({ X: pd.X + x - left, Y: pd.Y + y - top }))); - } + strokes.push(d.inkData.map(pd => ({ X: pd.X + NumCast(i.x) - left, Y: pd.Y + NumCast(i.y) - top }))); }); CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then((results) => { // const wordResults = results.filter((r: any) => r.category === "inkWord"); @@ -536,18 +499,16 @@ export class MarqueeView extends React.Component { - const bounds = this.Bounds; - const selected = this.marqueeSelect(false); - selected.map(d => { + const selected = this.marqueeSelect(false).map(d => { this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left; - d.y = NumCast(d.y) - bounds.top; - d.page = -1; + d.x = NumCast(d.x) - this.Bounds.left; + d.y = NumCast(d.y) - this.Bounds.top; return d; }); - const summary = Docs.Create.TextDocument("", { x: bounds.left, y: bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" }); + const summary = Docs.Create.TextDocument("", { x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" }); const portal = Doc.MakeAlias(summary); Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List(selected); Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations"); @@ -559,18 +520,18 @@ export class MarqueeView extends React.Component { const newCollection = this.getCollection([], undefined, ["background"]); this.props.addDocument(newCollection); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); - setTimeout(() => this.props.selectDocuments([newCollection]), 0); + setTimeout(() => this.props.selectDocuments([newCollection])); } @undoBatch - @action - marqueeCommand = async (e: KeyboardEvent) => { + marqueeCommand = action((e: KeyboardEvent) => { if (this._commandExecuted || (e as any).propagationIsStopped) { return; } @@ -581,83 +542,30 @@ export class MarqueeView extends React.Component { - this._freeHand = !this._freeHand; - } - // @action - // marqueeInkSelect(ink: Map) { - // let idata = new Map(); - // let centerShiftX = 0 - (this.Bounds.left + this.Bounds.width / 2); // moves each point by the offset that shifts the selection's center to the origin. - // let centerShiftY = 0 - (this.Bounds.top + this.Bounds.height / 2); - // ink.forEach((value: PointData, key: string, map: any) => { - // if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) { - // // let transform = this.props.container.props.ScreenToLocalTransform().scale(this.props.container.props.ContentScaling()); - // idata.set(key, - // { - // pathData: value.pathData.map(val => { - // let tVal = this.props.getTransform().inverse().transformPoint(val.x, val.y); - // return { x: tVal[0], y: tVal[1] }; - // // return { x: val.x + centerShiftX, y: val.y + centerShiftY } - // }), - // color: value.color, - // width: value.width, - // tool: value.tool, - // page: -1 - // }); - // } - // }); - // // InkSelectDecorations.Instance.SetSelected(idata); - // return idata; - // } - - // @action - // marqueeInkDelete(ink?: Map) { - // // bcz: this appears to work but when you restart all the deleted strokes come back -- InkField isn't observing its changes so they aren't written to the DB. - // // ink.forEach((value: StrokeData, key: string, map: any) => - // // InkingCanvas.IntersectStrokeRect(value, this.Bounds) && ink.delete(key)); - - // if (ink) { - // let idata = new Map(); - // ink.forEach((value: PointData, key: string, map: any) => - // !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value)); - // this.ink = new InkField(idata); - // } - // } touchesLine(r1: { left: number, top: number, width: number, height: number }) { - for (var i = 0; i < this._pointsX.length; i++) { - const topLeft = this.props.getTransform().transformPoint(this._pointsX[i], this._pointsY[i]); - if (topLeft[0] > r1.left && - topLeft[0] < r1.left + r1.width && - topLeft[1] > r1.top && - topLeft[1] < r1.top + r1.height) { + for (var i = 0; i < this._lassoPts.length; i++) { + const topLeft = this.Transform.transformPoint(this._lassoPts[i][0], this._lassoPts[i][1]); + if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width && + r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) { return true; } } @@ -665,30 +573,22 @@ export class MarqueeView extends React.Component trueLeft && r1.top > trueTop && r1.left + r1.width < trueRight && r1.top + r1.height < trueBottom) { - var hasTop = false; - var hasLeft = false; - var hasBottom = false; - var hasRight = false; - for (var i = 0; i < this._pointsX.length; i++) { - const truePoint = this.props.getTransform().transformPoint(this._pointsX[i], this._pointsY[i]); - if (!hasLeft && (truePoint[0] > trueLeft && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height)) { - hasLeft = true; - } - if (!hasTop && (truePoint[1] > trueTop && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width)) { - hasTop = true; - } - if (!hasRight && (truePoint[0] < trueRight && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height)) { - hasRight = true; - } - if (!hasBottom && (truePoint[1] < trueBottom && truePoint[1] > r1.top + r1.height) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width)) { - hasBottom = true; - } + const xs = this._lassoPts.map(pair => pair[0]); + const ys = this._lassoPts.map(pair => pair[1]); + const tl = this.Transform.transformPoint(Math.min(...xs), Math.min(...ys)); + const br = this.Transform.transformPoint(Math.max(...xs), Math.max(...ys)); + + if (r1.left > tl[0] && r1.top > tl[1] && r1.left + r1.width < br[0] && r1.top + r1.height < br[1]) { + let hasTop = false; + let hasLeft = false; + let hasBottom = false; + let hasRight = false; + for (let i = 0; i < this._lassoPts.length; i++) { + const truePoint = this.Transform.transformPoint(this._lassoPts[i][0], this._lassoPts[i][1]); + hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); + hasTop = hasTop || (truePoint[1] > tl[1] && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width); + hasRight = hasRight || (truePoint[0] < br[0] && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); + hasBottom = hasBottom || (truePoint[1] < br[1] && truePoint[1] > r1.top + r1.height) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width); if (hasTop && hasLeft && hasBottom && hasRight) { return true; } @@ -696,106 +596,40 @@ export class MarqueeView extends React.Component this.props.layerProvider?.(doc) !== false && !doc.z).map(doc => { + const selectFunc = (doc: Doc) => { const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this._freeHand === false) { - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { - selection.push(doc); - } + const bounds = { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(layoutDoc._width), height: NumCast(layoutDoc._height) }; + if (!this._lassoFreehand) { + intersectRect(bounds, this.Bounds) && selection.push(doc); } else { - if (this.touchesLine({ left: x, top: y, width: w, height: h }) || - this.boundingShape({ left: x, top: y, width: w, height: h })) { - selection.push(doc); - } + (this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc); } - }); - if (!selection.length && selectBackgrounds) { - this.props.activeDocuments().filter(doc => doc.z === undefined).map(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { - selection.push(doc); - } - }); - } - if (!selection.length) { - const left = this._downX < this._lastX ? this._downX : this._lastX; - const top = this._downY < this._lastY ? this._downY : this._lastY; - const topLeft = this.props.getContainerTransform().transformPoint(left, top); - const size = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - const otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; - this.props.activeDocuments().filter(doc => doc.z !== undefined).map(doc => { - const layoutDoc = Doc.Layout(doc); - const x = NumCast(doc.x); - const y = NumCast(doc.y); - const w = NumCast(layoutDoc._width); - const h = NumCast(layoutDoc._height); - if (this._freeHand === false) { - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { - selection.push(doc); - } - } else { - if (this.touchesLine({ left: x, top: y, width: w, height: h }) || - this.boundingShape({ left: x, top: y, width: w, height: h })) { - selection.push(doc); - } - } - }); - } + }; + this.props.activeDocuments().filter(doc => this.props.layerProvider?.(doc) !== false && !doc.z).map(selectFunc); + if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc); + if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc); return selection; } - @computed - get marqueeDiv() { - const p = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0]; - const v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - /** - * @RE - The commented out span below - * This contains the "C for collection, ..." text on marquees. - * Commented out by syip2 when the marquee menu was added. - */ - if (!this._freeHand) { - return
- -
; - - } else { - var str: string = ""; - for (var i = 0; i < this._pointsX.length; i++) { - const pt = this.props.getContainerTransform().transformPoint(this._pointsX[i], this._pointsY[i]); - str += pt[0].toString(); - str += ","; - str += pt[1].toString(); - str += (" "); - } - - //hardcoded height and width. - return
- - - -
; - } + @computed get marqueeDiv() { + const cpt = this._lassoFreehand || !this._visible ? [0, 0] : [this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY]; + const p = this.props.getContainerTransform().transformPoint(cpt[0], cpt[1]); + const v = this._lassoFreehand ? [0, 0] : this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); + return
{this._lassoFreehand ? + + s + pt[0] + "," + pt[1] + " ", "")} fill="none" stroke="black" strokeWidth="1" strokeDasharray="3" /> + + : + } +
; } render() { -- cgit v1.2.3-70-g09d2 From 7a09a2e77af9d236265cd975f24a38cda1735493 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 9 Dec 2020 13:59:31 -0500 Subject: final improvements to audio waveform rendering. --- .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- src/client/views/nodes/AudioBox.tsx | 83 +++++++++------------- 2 files changed, 38 insertions(+), 51 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index ac82f60e1..df3d3106e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -559,10 +559,11 @@ export class MarqueeView extends React.Component tl[0] && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 785bb5ce8..c89e21312 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,34 +1,34 @@ import React = require("react"); -import { FieldViewProps, FieldView } from './FieldView'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import axios from "axios"; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import "./AudioBox.scss"; -import { Cast, DateCast, NumCast, FieldValue, ScriptCast } from "../../../fields/Types"; -import { AudioField, nullAudio } from "../../../fields/URLField"; -import { ViewBoxAnnotatableComponent } from "../DocComponent"; -import { makeInterface, createSchema, listSpec } from "../../../fields/Schema"; -import { documentSchema } from "../../../fields/documentSchemas"; -import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime, setupMoveUpEvents } from "../../../Utils"; -import { runInAction, observable, reaction, IReactionDisposer, computed, action, trace, toJS } from "mobx"; +import Waveform from "react-audio-waveform"; import { DateField } from "../../../fields/DateField"; -import { SelectionManager } from "../../util/SelectionManager"; import { Doc, DocListCast, Opt } from "../../../fields/Doc"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { ContextMenu } from "../ContextMenu"; +import { documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { DocumentView, DocumentViewProps } from "./DocumentView"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { List } from "../../../fields/List"; +import { createSchema, listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; +import { Cast, DateCast, NumCast } from "../../../fields/Types"; +import { AudioField, nullAudio } from "../../../fields/URLField"; +import { emptyFunction, formatTime, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils, numberRange } from "../../../Utils"; +import { Docs, DocUtils } from "../../documents/Documents"; import { Networking } from "../../Network"; -import { LinkAnchorBox } from "./LinkAnchorBox"; -import { List } from "../../../fields/List"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { Scripting } from "../../util/Scripting"; -import Waveform from "react-audio-waveform"; -import axios from "axios"; +import { SelectionManager } from "../../util/SelectionManager"; import { SnappingManager } from "../../util/SnappingManager"; -import { CurrentUserUtils } from "../../util/CurrentUserUtils"; -import { LinkDocPreview } from "./LinkDocPreview"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { ViewBoxAnnotatableComponent } from "../DocComponent"; +import "./AudioBox.scss"; +import { DocumentView, DocumentViewProps } from "./DocumentView"; +import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; +import { LinkAnchorBox } from "./LinkAnchorBox"; +import { LinkDocPreview } from "./LinkDocPreview"; declare class MediaRecorder { // whatever MediaRecorder has @@ -43,6 +43,7 @@ const AudioDocument = makeInterface(documentSchema, audioSchema); export class AudioBox extends ViewBoxAnnotatableComponent(AudioDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); } public static Enabled = false; + public static NUMBER_OF_BUCKETS = 100; static Instance: AudioBox; static RangeScript: ScriptField; @@ -508,7 +509,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.buckets()); + !audioBuckets.length && setTimeout(() => this.createWaveformBuckets()); return ; } // decodes the audio file into peaks for generating the waveform - @action - buckets = async () => { - const audioCtx = new (window.AudioContext)(); - + createWaveformBuckets = async () => { axios({ url: this.path, responseType: "arraybuffer" }) - .then(response => { - const audioData = response.data; - - audioCtx.decodeAudioData(audioData, action(buffer => { + .then(response => (new (window.AudioContext)()).decodeAudioData(response.data, + action(buffer => { const decodedAudioData = buffer.getChannelData(0); - const NUMBER_OF_BUCKETS = 100; - const bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS); - let _buckets: number[] = []; - for (let i = 0; i < NUMBER_OF_BUCKETS; i++) { - const startingPoint = i * bucketDataSize; - const endingPoint = i * bucketDataSize + bucketDataSize; - let max = 0; - for (let j = startingPoint; j < endingPoint; j++) { - if (decodedAudioData[j] > max) { - max = decodedAudioData[j]; - } - } - const size = Math.abs(max); - _buckets.push(size / 2); - } - this.dataDoc.audioBuckets = new List(_buckets); - })); - }); + const bucketDataSize = Math.floor(decodedAudioData.length / AudioBox.NUMBER_OF_BUCKETS); + const brange = Array.from(Array(bucketDataSize)); + this.dataDoc.audioBuckets = new List( + numberRange(AudioBox.NUMBER_OF_BUCKETS).map(i => + brange.reduce((p, x, j) => Math.abs(Math.max(p, decodedAudioData[i * bucketDataSize + j])), 0) / 2)); + })) + ); } rangeScript = () => AudioBox.RangeScript; -- cgit v1.2.3-70-g09d2 From 3412313dcde569f1f23616fa5e8a92c3985e0449 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 9 Dec 2020 14:25:40 -0500 Subject: from last - fixed warnings. --- .../views/collections/collectionFreeForm/MarqueeView.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index df3d3106e..a963b9158 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -562,9 +562,8 @@ export class MarqueeView extends React.Component tl[0] && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); hasTop = hasTop || (truePoint[1] > tl[1] && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width); hasRight = hasRight || (truePoint[0] < br[0] && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height); -- 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/views/collections/collectionFreeForm') 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 30338491c7b3cbba852931c76774f6bfd44d4060 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Dec 2020 12:54:41 -0500 Subject: removed annotationsKey prop in favor of reusing fieldKey. Fixed web pages to allow dash annotations again. --- src/client/views/MainView.tsx | 1 - src/client/views/TemplateMenu.tsx | 1 - src/client/views/collections/CollectionStackingView.tsx | 4 ++-- src/client/views/collections/CollectionSubView.tsx | 14 ++++++-------- src/client/views/collections/CollectionView.tsx | 5 +---- src/client/views/collections/TabDocView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++------ .../views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- src/client/views/nodes/FilterBox.tsx | 2 -- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/LinkBox.tsx | 1 - src/client/views/nodes/PresBox.tsx | 1 - src/client/views/nodes/ScreenshotBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.scss | 4 +++- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 13 ++++++++----- src/client/views/pdf/PDFViewer.tsx | 4 ++-- src/client/views/search/SearchBox.tsx | 1 - 19 files changed, 31 insertions(+), 41 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9b3d5c6ae..2705d2c34 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -456,7 +456,6 @@ export class MainView extends React.Component { DataDoc={undefined} fieldKey={"data"} dropAction={"alias"} - annotationsKey={""} parentActive={returnFalse} styleProvider={TabDocView.styleProvider} rootSelected={returnTrue} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 9c5c70c60..203274681 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -152,7 +152,6 @@ export class TemplateMenu extends React.Component { PanelWidth={this.return100} PanelHeight={this.return100} treeViewHideHeaderFields={true} - annotationsKey={""} dontRegisterView={true} fieldKey={"data"} moveDocument={returnFalse} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 83ac138f5..058536f69 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -352,8 +352,8 @@ export class CollectionStackingView extends CollectionSubView { if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { const height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => NumCast(Doc.Layout(doc)._viewScale, 1) * Number(getComputedStyle(r).height.replace("px", ""))))); - if (this.props.annotationsKey) { - doc[this.props.annotationsKey + "-height"] = height; + if (this.props.isAnnotationOverlay) { + doc[this.props.fieldKey + "-height"] = height; } else { Doc.Layout(doc)._height = height * NumCast(Doc.Layout(doc)._viewScale, 1); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 592d6ab87..38e461e46 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -67,14 +67,14 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: // sets the dataDoc's data field to an empty list if the data field is undefined - prevents issues with addonly // setTimeout changes it outside of the @computed section setTimeout(() => { - if (!this.dataDoc[this.props.annotationsKey || this.props.fieldKey]) this.dataDoc[this.props.annotationsKey || this.props.fieldKey] = new List(); + if (!this.dataDoc[this.props.fieldKey]) this.dataDoc[this.props.fieldKey] = new List(); }, 1000); - return this.dataDoc[this.props.annotationsKey || this.props.fieldKey]; + return this.dataDoc[this.props.fieldKey]; } get childLayoutPairs(): { layout: Doc; data: Doc; }[] { const { Document, DataDoc } = this.props; - const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)). + const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.isAnnotationOverlay ? DataDoc : undefined, doc)). filter(pair => { // filter out any documents that have a proto that we don't have permissions to (which we determine by not having any keys return pair.layout && (!pair.layout.proto || (pair.layout.proto instanceof Doc && GetEffectiveAcl(pair.layout.proto) !== AclPrivate));// Object.keys(pair.layout.proto).length)); }); @@ -84,12 +84,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: return Cast(this.dataField, listSpec(Doc)); } docFilters = () => { - return this.props.ignoreFilters ? [] : - [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; + return [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])]; } docRangeFilters = () => { - return this.props.ignoreFilters ? [] : - [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])]; + return [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])]; } searchFilterDocs = () => { return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)]; @@ -104,7 +102,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection. // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image. const rootDoc = Cast(this.props.Document.rootDocument, Doc, null); - rawdocs = rootDoc && !this.props.annotationsKey ? [Doc.GetProto(rootDoc)] : []; + rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : []; } const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate).map(d => d as Doc); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index af03e4ceb..511fc723d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -63,8 +63,6 @@ export enum CollectionViewType { } 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) @@ -72,11 +70,11 @@ export interface CollectionViewProps extends FieldViewProps { setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; // property overrides for child documents + children?: never | (() => JSX.Element[]) | React.ReactNode; childDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox) childOpacity?: () => number; 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; @@ -387,7 +385,6 @@ export class CollectionView extends Touchable { childLayoutString: this.childLayoutString, ScreenToLocalTransform: this.screenToLocalTransform, CollectionView: this, - annotationsKey: "" }; const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || this.collectionViewType === CollectionViewType.Linear ? undefined : this.props.styleProvider?.(this.props.Document, this.props, "boxShadow"); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 3c1aaae47..fd50c6273 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -346,7 +346,6 @@ export class TabDocView extends React.Component { dropAction={undefined} isSelected={returnFalse} dontRegisterView={true} - annotationsKey={""} fieldKey={Doc.LayoutFieldKey(this._document!)} bringToFront={emptyFunction} rootSelected={returnTrue} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0f466fc16..e09abd017 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -47,7 +47,6 @@ import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; -import { isUndefined } from "lodash"; export const panZoomSchema = createSchema({ _panX: "number", @@ -950,7 +949,7 @@ export class CollectionFreeFormView extends CollectionSubView this.doLayoutComputation, (elements) => this._layoutElements = elements || [], { fireImmediately: true, name: "doLayout" }); - if (!this.props.annotationsKey) { + if (!this.props.isAnnotationOverlay) { this._boundsReaction = reaction(() => this.contentBounds, bounds => (!this.fitToContent && this._layoutElements?.length) && setTimeout(() => { const rbounds = Cast(this.Document._renderContentBounds, listSpec("number"), [0, 0, 0, 0]); @@ -1291,7 +1290,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.annotationsKey || this.props.Document.annotationOn || !ContextMenu.Instance) return; + if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; const appearance = ContextMenu.Instance.findByDescription("Appearance..."); const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : []; @@ -1527,7 +1526,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? + {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} {!this.props.noOverlay ? : (null)} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 39df606f7..52310d628 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -634,7 +634,7 @@ export class MarqueeView extends React.Component e.preventDefault()} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index b90bf9eb1..ffe1684d4 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -208,8 +208,6 @@ export class FilterBox extends ViewBoxBaseComponent( ChromeHeight={returnZero} childDocuments={[this.dataDoc]} treeViewSkipFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)} - annotationsKey={""} dontRegisterView={true} renderDepth={this.props.renderDepth + 1} CollectionView={undefined} diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index c2385cab8..da74edbe3 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2412,7 +2412,6 @@ export class PresBox extends ViewBoxBaseComponent
    {mode !== CollectionViewType.Invalid ? Opt; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text @@ -1606,7 +1607,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp sidebarContentScaling = () => this.props.ContentScaling() * NumCast(this.layoutDoc._viewScale, 1); @computed get sidebarCollection() { const fitToBox = this.props.Document._fitToBox; - const collectionProps = { + const collectionProps: SubCollectionViewProps & collectionFreeformViewProps = { ...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit, NativeWidth: returnZero, NativeHeight: returnZero, @@ -1616,8 +1617,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp yMargin: 0, chromeStatus: "enabled", scaleField: this.annotationKey + "-scale", - annotationsKey: this.annotationKey, isAnnotationOverlay: true, + fieldKey: this.annotationKey, fitToBox: fitToBox, focus: this.props.focus, isSelected: this.props.isSelected, @@ -1636,7 +1637,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp return !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
    - {this.layoutDoc.sidebarViewType === CollectionViewType.Freeform ? : } + {this.layoutDoc.sidebarViewType === CollectionViewType.Freeform ? + : + }
    ; } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9b689eb6b..633a34c5e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -736,7 +736,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent Date: Thu, 10 Dec 2020 14:18:53 -0500 Subject: more cleanup/organization of 'props' . removed VisibleHeight props and cleaned up PDF and other props --- src/client/util/CurrentUserUtils.ts | 1 - .../util/Import & Export/DirectoryImportBox.tsx | 1 - src/client/views/PropertiesView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 21 +++-- .../views/collections/CollectionTimeView.tsx | 7 +- src/client/views/collections/CollectionView.tsx | 36 ++++---- src/client/views/collections/SchemaTable.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 ++-- .../collectionGrid/CollectionGridView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- .../views/nodes/ContentFittingDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 4 +- src/client/views/nodes/KeyValueBox.tsx | 1 - src/client/views/nodes/PDFBox.tsx | 96 +++++----------------- src/client/views/nodes/VideoBox.tsx | 11 +-- src/client/views/nodes/WebBox.tsx | 19 +---- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 - src/client/views/pdf/PDFViewer.tsx | 50 +++-------- src/fields/documentSchemas.ts | 2 - 22 files changed, 84 insertions(+), 200 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 213bc3d88..676e7ce3e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -801,7 +801,6 @@ export class CurrentUserUtils { } } - static setupUserDoc(doc: Doc) { if (doc.myUserDoc === undefined) { doc.treeViewOpen = true; diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 7f01966b9..d9f010557 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -158,7 +158,6 @@ export class DirectoryImportBox extends React.Component { importContainer = Docs.Create.SchemaDocument(headers, docs, options); } runInAction(() => this.phase = 'External: uploading files to Google Photos...'); - importContainer._columnsStack = false; await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer }); Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer); !this.persistent && this.props.removeDocument && this.props.removeDocument(doc); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 08394cd97..233429f4d 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -272,7 +272,7 @@ export class PropertiesView extends React.Component { treeViewDoc={undefined} styleProvider={this.props.styleProvider} fitToBox={true} - FreezeDimensions={true} + freezeDimensions={true} dontCenter={"y"} NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index e22b8effe..c64048345 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -401,7 +401,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { Document={this.previewDocument} DataDoc={undefined} fitToBox={true} - FreezeDimensions={true} + freezeDimensions={true} dontCenter={"y"} focus={emptyFunction} renderDepth={this.props.renderDepth} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 058536f69..b1c5dec84 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,7 +3,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import Switch from 'rc-switch'; import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc"; import { collectionSchema, documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; @@ -12,23 +11,23 @@ import { listSpec, makeInterface } from "../../../fields/Schema"; import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll, returnVal } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, returnVal, returnZero, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils"; +import { DocUtils } from "../../documents/Documents"; import { DragManager, dropActionType } from "../../util/DragManager"; +import { SnappingManager } from "../../util/SnappingManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; +import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; +import { DocAfterFocusFunc } from "../nodes/DocumentView"; import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; -import { SnappingManager } from "../../util/SnappingManager"; -import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; -import { DocUtils } from "../../documents/Documents"; -import { DocAfterFocusFunc } from "../nodes/DocumentView"; const _global = (window /* browser */ || global /* node */) as any; type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -56,7 +55,7 @@ export class CollectionStackingView extends CollectionSubView doc) { @computed get contents() { return
    - +
    ; } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 511fc723d..dbbb3e991 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -66,7 +66,6 @@ export interface CollectionViewProps extends FieldViewProps { 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 @@ -242,28 +241,27 @@ export class CollectionView extends Touchable { private SubView = (type: CollectionViewType, props: SubCollectionViewProps) => { TraceMobx(); switch (type) { - case CollectionViewType.Schema: return (); - case CollectionViewType.Docking: return (); - case CollectionViewType.Tree: return (); - //case CollectionViewType.Staff: return (); - case CollectionViewType.Multicolumn: return (); - case CollectionViewType.Multirow: return (); - case CollectionViewType.Linear: { return (); } - case CollectionViewType.Pile: { return (); } - case CollectionViewType.Carousel: { return (); } - case CollectionViewType.Carousel3D: { return (); } - case CollectionViewType.Stacking: { this.props.Document._columnsStack = true; return (); } - case CollectionViewType.Masonry: { this.props.Document._columnsStack = false; return (); } - case CollectionViewType.Time: { return (); } - case CollectionViewType.Map: return (); - case CollectionViewType.Grid: return (); - case CollectionViewType.Freeform: - default: { this.props.Document._freeformLayoutEngine = undefined; return (); } + default: + case CollectionViewType.Freeform: return ; + case CollectionViewType.Schema: return ; + case CollectionViewType.Docking: return ; + case CollectionViewType.Tree: return ; + case CollectionViewType.Multicolumn: return ; + case CollectionViewType.Multirow: return ; + case CollectionViewType.Linear: return ; + case CollectionViewType.Pile: return ; + case CollectionViewType.Carousel: return ; + case CollectionViewType.Carousel3D: return ; + case CollectionViewType.Stacking: return ; + case CollectionViewType.Masonry: return ; + case CollectionViewType.Time: return ; + case CollectionViewType.Map: return ; + case CollectionViewType.Grid: return ; + //case CollectionViewType.Staff: return ; } } setupViewTypes(category: string, func: (viewType: CollectionViewType) => Doc, addExtras: boolean) { - const subItems: ContextMenuProps[] = []; subItems.push({ description: "Freeform", event: () => func(CollectionViewType.Freeform), icon: "signature" }); if (addExtras && CollectionView._safeMode) { diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx index b532d3302..24a67faaf 100644 --- a/src/client/views/collections/SchemaTable.tsx +++ b/src/client/views/collections/SchemaTable.tsx @@ -571,7 +571,7 @@ export class SchemaTable extends React.Component { Document={this._showDoc} DataDoc={this._showDataDoc} fitToBox={true} - FreezeDimensions={true} + freezeDimensions={true} focus={emptyFunction} renderDepth={this.props.renderDepth} rootSelected={() => false} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e09abd017..94de40bc8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -918,7 +918,7 @@ export class CollectionFreeFormView extends CollectionSubView, bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica) })); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index f3e385746..bef197bee 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -170,7 +170,7 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { PanelWidth={width} PanelHeight={height} ContentScaling={returnOne} - FreezeDimensions={true} + freezeDimensions={true} fitToBox={true} ScreenToLocalTransform={dxf} onClick={this.onChildClickHandler} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 586c5d1df..d4913a5ed 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -219,7 +219,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu styleProvider={this.props.styleProvider} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} - FreezeDimensions={this.props.childFreezeDimensions} + 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 87c56de6f..9039090d1 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -219,7 +219,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) styleProvider={this.props.styleProvider} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} - FreezeDimensions={this.props.childFreezeDimensions} + freezeDimensions={this.props.childFreezeDimensions} renderDepth={this.props.renderDepth + 1} PanelWidth={width} PanelHeight={height} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index b4b887617..d68184da6 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -52,7 +52,7 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu undefined); } @computed get topMost() { return this.props.renderDepth === 0; } - @computed get freezeDimensions() { return this.props.FreezeDimensions; } + @computed get freezeDimensions() { return this.props.freezeDimensions; } @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.dataDoc, this.freezeDimensions)); } @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.dataDoc, this.freezeDimensions)); } @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); } diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 4ac932c24..8acf4081c 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -169,7 +169,6 @@ export class KeyValueBox extends React.Component { getTemplate = async () => { const parent = Docs.Create.StackingDocument([], { _width: 800, _height: 800, title: "Template" }); - parent._columnsStack = false; parent._columnWidth = 100; for (const row of this.rows.filter(row => row.isChecked)) { await this.createTemplateField(parent, row); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 42b24f6f6..a2f3fb2d1 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,28 +1,27 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, runInAction, reaction, IReactionDisposer, trace, untracked, computed } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Opt, WidthSym, Doc, HeightSym } from "../../../fields/Doc"; +import { Doc, Opt, WidthSym } from "../../../fields/Doc"; +import { documentSchema } from '../../../fields/documentSchemas'; import { makeInterface } from "../../../fields/Schema"; -import { ScriptField } from '../../../fields/ScriptField'; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { PdfField, URLField } from "../../../fields/URLField"; +import { Cast, NumCast } from "../../../fields/Types"; +import { PdfField } from "../../../fields/URLField"; +import { TraceMobx } from '../../../fields/util'; import { Utils } from '../../../Utils'; +import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView'; +import { CollectionViewType } from '../collections/CollectionView'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { PDFViewer } from "../pdf/PDFViewer"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; -import { KeyCodes } from '../../util/KeyCodes'; import "./PDFBox.scss"; import React = require("react"); -import { documentSchema } from '../../../fields/documentSchemas'; -import { CollectionViewType } from '../collections/CollectionView'; -import { TraceMobx } from '../../../fields/util'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -30,17 +29,11 @@ const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @observer export class PDFBox extends ViewBoxAnnotatableComponent(PdfDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } - private _keyValue: string = ""; - private _valueValue: string = ""; - private _scriptValue: string = ""; private _searchString: string = ""; private _initialScale: number = 0; // the initial scale of the PDF when first rendered which determines whether the document will be live on startup or not. Getting bigger after startup won't make it automatically be live. private _displayPdfLive = false; // has this box ever had its contents activated -- if so, stop drawing the overlay title private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef(); - private _keyRef = React.createRef(); - private _valueRef = React.createRef(); - private _scriptRef = React.createRef(); private _selectReactionDisposer: IReactionDisposer | undefined; @observable private _searching: boolean = false; @@ -130,25 +123,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - const scriptText = this._scriptValue ? this._scriptValue : - this._keyValue && this._valueValue ? `this.${this._keyValue} === ${this._valueValue}` : "true"; - this.props.Document.filterScript = ScriptField.MakeFunction(scriptText); - } - - private resetFilters = () => { - this._keyValue = this._valueValue = this._scriptValue = ""; - this._keyRef.current && (this._keyRef.current.value = ""); - this._valueRef.current && (this._valueRef.current.value = ""); - this._scriptRef.current && (this._scriptRef.current.value = ""); - this.applyFilter(); - } - private newKeyChange = (e: React.ChangeEvent) => this._keyValue = e.currentTarget.value; - private newValueChange = (e: React.ChangeEvent) => this._valueValue = e.currentTarget.value; - private newScriptChange = (e: React.ChangeEvent) => this._scriptValue = e.currentTarget.value; - whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); setPdfViewer = (pdfViewer: PDFViewer) => { this._pdfViewer = pdfViewer; }; searchStringChanged = (e: React.ChangeEvent) => this._searchString = e.currentTarget.value; @@ -197,36 +171,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pageControls = !this._pageControls)} /> {this._pageControls ? pageBtns : (null)}
    - {/*
    e.stopPropagation()}> - -
    -
    - Annotation View Settings -
    -
    - - -
    -
    - -
    -
    - - -
    -
    -
    */}
    ); } @@ -253,19 +197,19 @@ export class PDFBox extends ViewBoxAnnotatableComponent 600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> -
    - 600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> +
    + + startupLive={true} + /> {this.settingsPanel()}
    ; } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 8d10768ff..90a5dee23 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -427,11 +427,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent + renderDepth={this.props.renderDepth + 1}> {this.contentFunc}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 197ff20d5..47464d794 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -646,14 +646,6 @@ export class WebBox extends ViewBoxAnnotatableComponent this._marqueeX; marqueeY = () => this._marqueeY; marqueeing = () => this._marqueeing; - visibleHeight = () => { - if (this._mainCont.current) { - const boundingRect = this._mainCont.current.getBoundingClientRect(); - const scaling = (Doc.NativeWidth(this.Document) || 0) / boundingRect.width; - return Math.min(boundingRect.height * scaling, this.props.PanelHeight() * scaling); - } - return this.props.PanelHeight(); - } scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop)); render() { const scaling = Number.isFinite(this.props.ContentScaling()) ? this.props.ContentScaling() || 1 : 1; @@ -697,13 +689,8 @@ export class WebBox extends ViewBoxAnnotatableComponent + renderDepth={this.props.renderDepth + 1}>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 33515e475..bfbd7805d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1620,8 +1620,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp isAnnotationOverlay: true, fieldKey: this.annotationKey, fitToBox: fitToBox, - focus: this.props.focus, - isSelected: this.props.isSelected, select: emptyFunction, active: this.annotationsActive, ContentScaling: this.sidebarContentScaling, @@ -1632,7 +1630,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp CollectionView: undefined, ScreenToLocalTransform: this.sidebarScreenToLocal, renderDepth: this.props.renderDepth + 1, - ContainingCollectionDoc: this.props.ContainingCollectionDoc, }; return !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
+ renderDepth={this.props.renderDepth + 1}>
; } @@ -778,7 +751,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent this._marqueeX; marqueeY = () => this._marqueeY; marqueeing = () => this._marqueeing; - visibleHeight = () => this.props.PanelHeight() / this.props.ContentScaling(); contentZoom = () => this._zoomed; render() { TraceMobx(); diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 979238767..67df56015 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -49,14 +49,12 @@ export const documentSchema = createSchema({ _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document _showTitleHover: "string", // the showTitle should be shown only on hover _showAudio: "boolean", // whether to show the audio record icon on documents - _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents _freeformLOD: "boolean", // whether to enable LOD switching for CollectionFreeFormViews _pivotField: "string", // specifies which field key should be used as the timeline/pivot axis _replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's. _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' _columnsFill: "boolean", // whether documents in a stacking view column should be sized to fill the column _columnsSort: "string", // how a document should be sorted "ascending", "descending", undefined (none) - _columnsStack: "boolean", // whether a stacking document stacks vertically (as opposed to masonry horizontal) _columnsHideIfEmpty: "boolean", // whether empty stacking view column headings should be hidden _columnHeaders: listSpec(SchemaHeaderField), // header descriptions for stacking/masonry _schemaHeaders: listSpec(SchemaHeaderField), // header descriptions for schema views -- cgit v1.2.3-70-g09d2 From 896db53261aca91de21eabfaa6fed0c1b27e3e51 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Dec 2020 21:41:54 -0500 Subject: moved opacity and borderRounding into styleProviders. fixed contextMenu clcik from button bar --- src/client/views/DocumentButtonBar.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 17 +++++++++--- src/client/views/collections/TabDocView.tsx | 24 +++++++++++------ src/client/views/collections/TreeView.tsx | 10 ++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 ++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 24 ++++++++--------- src/client/views/nodes/DocumentView.scss | 3 +++ src/client/views/nodes/DocumentView.tsx | 30 ++++++++++------------ src/client/views/nodes/LabelBox.tsx | 2 +- src/client/views/nodes/SliderBox.tsx | 2 +- .../views/presentationview/PresElementBox.tsx | 8 ++++-- 11 files changed, 76 insertions(+), 49 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index fa0b9a238..dc6311696 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -339,7 +339,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV let child = SelectionManager.SelectedDocuments()[0].ContentDiv!.children[0]; while (child.children.length) { const next = Array.from(child.children).find(c => typeof (c.className) === "string"); - if (next?.className.includes("documentView-node")) break; + if (next?.className.includes(DocumentView.ROOT_DIV)) break; if (next?.className.includes("dashFieldView")) break; if (next) child = next; else break; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b1c5dec84..408a8d969 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -22,7 +22,7 @@ import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView"; -import { DocAfterFocusFunc } from "../nodes/DocumentView"; +import { DocAfterFocusFunc, DocumentViewProps } from "../nodes/DocumentView"; import { CollectionMasonryViewFieldRow } from "./CollectionMasonryViewFieldRow"; import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; @@ -187,14 +187,24 @@ export class CollectionStackingView extends CollectionSubView Transform, width: () => number) { const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); - const opacity = () => this.Document._currentFrame === undefined ? this.props.childOpacity?.() : CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity; + const styleProvider = (doc: Doc | undefined, props: DocumentViewProps, property: string) => { + if (property === "opacity" && doc) { + if (this.props.childOpacity) { + return this.props.childOpacity(); + } + if (this.Document._currentFrame !== undefined) { + return CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity; + } + } + return this.props.styleProvider?.(doc, props, property); + }; return { // // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // - public static styleProvider = (doc: Opt, props: DocumentViewProps | undefined, property: string): any => { + public static styleProvider = (doc: Opt, props: DocumentViewProps, property: string): any => { switch (property) { + case "docContents": return undefined; + case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey"; + case "opacity": return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null)); + case "hidden": return BoolCast(doc?._hidden, BoolCast(doc?.hidden)); + case "borderRounding": return !doc ? undefined : StrCast(doc._borderRounding, StrCast(doc.borderRounding)); case "backgroundColor": { if (Doc.UserDoc().renderStyle === "comic") return undefined; - let docColor = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor)); + let docColor: Opt = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor)); if (!docColor) { switch (doc?.type) { case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "" : ""; break; @@ -457,20 +462,23 @@ export class TabDocView extends React.Component { if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString(); return docColor; } - case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey"; - case "hidden": return (BoolCast(doc?.hidden) /* || props?.layerProvider?.(doc) === false*/); case "boxShadow": { + if (!doc || props.styleProvider?.(doc, props, "opacity") === 0) return undefined; // if it's not visible, then no shadow) + const isBackground = StrListCast(doc.layers).includes("background"); switch (doc?.type) { - case DocumentType.COL: return StrListCast(doc.layers).includes("background") ? undefined : + case DocumentType.COL: return isBackground ? undefined : `${TabDocView.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`; - default: return undefined; + default: + return doc.z ? `#9c9396 ${StrCast(doc?.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow + props.backgroundHalo?.(doc) && doc.type !== DocumentType.INK ? (`${props.styleProvider?.(doc, props, "backgroundColor")} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground ? 100 : 50) / props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent + isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big + StrCast(doc.boxShadow, "") } } - case "docContents": return undefined; default: if (property.startsWith("pointerEvents")) { const layer = doc && props?.layerProvider?.(doc); - if (doc?.Opacity === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none"; + 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; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index be8a27ab0..24dd905a9 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -441,7 +441,7 @@ export class TreeView extends React.Component { return
@@ -496,6 +496,12 @@ export class TreeView extends React.Component { e.preventDefault(); } } + styleProvider = (doc: (Doc | undefined), props: DocumentViewProps, property: string): any => { + // override opacity and backgroundColor just for this treeView document: opacity = 1, and backgroundColor = undefined unless it is explicitly set on the document + if (property === "opacity" && doc === this.props.document) return this.outlineMode ? undefined : 1; + if (property === "backgroundColor" && doc === this.props.document) return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + return this.props.treeView.props.styleProvider?.(doc, props, property); + } onKeyDown = (e: React.KeyboardEvent) => { if (this.doc.treeViewHideHeader || this.outlineMode) { e.stopPropagation(); @@ -520,6 +526,7 @@ export class TreeView extends React.Component { ref={this._docRef} Document={this.doc} DataDoc={undefined} + styleProvider={this.styleProvider} treeViewDoc={this.props.treeView.props.Document} addDocument={undefined} addDocTab={this.props.addDocTab} @@ -535,7 +542,6 @@ export class TreeView extends React.Component { PanelWidth={this.truncateTitleWidth} PanelHeight={returnZero} contextMenuItems={this.contextMenuItems} - opacity={this.outlineMode ? undefined : returnOne} renderDepth={1} focus={returnTrue} parentActive={returnTrue} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 94de40bc8..a8e24ebbe 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1049,7 +1049,8 @@ export class CollectionFreeFormView extends CollectionSubView { + if (property === "opacity" && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children + return this.props.styleProvider?.(doc, props, property); + } + static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"]; public static getValues(doc: Doc, time: number) { return CollectionFreeFormDocumentView.animFields.reduce((p, val) => { @@ -137,7 +142,6 @@ export class CollectionFreeFormDocumentView extends DocComponent (this.sizeProvider?.height || this.props.PanelHeight?.()); getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y).scale(1 / this.contentScaling()); focusDoc = (doc: Doc) => this.props.focus(doc, false); - opacity = () => this.Opacity; NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; returnThis = () => this; @@ -148,13 +152,13 @@ export class CollectionFreeFormDocumentView extends DocComponent diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index ad72250b6..d25d7af05 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -1,5 +1,8 @@ @import "../globalCssVariables"; +.documentView-effectsWrapper { + border-radius: inherit; +} .documentView-node, .documentView-node-topmost { position: inherit; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 591859737..ed3fa6918 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -103,11 +103,11 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onPointerUp?: () => ScriptField; setupDragLines?: (snapToDraggedDoc: boolean) => void; forceHideLinkButton?: () => boolean; - opacity?: () => number | undefined; } @observer export class DocumentView extends DocComponent(Document) { + public static ROOT_DIV = "documentView-effectsWrapper"; @observable _animateScalingTo = 0; private _downX: number = 0; private _downY: number = 0; @@ -1090,24 +1090,22 @@ export class DocumentView extends DocComponent(Docu if (!(this.props.Document instanceof Doc)) return (null); if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null); if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden")) return null; - const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor"); - const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); - const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; - const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; - const fullDegree = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString - const borderRounding = this.layoutDoc.borderRounding; - const localScale = fullDegree; + const background = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor"); + const borderRounding = this.props.styleProvider?.(this.layoutDoc, this.props, "borderRounding"); + const opacity = this.props.styleProvider?.(this.layoutDoc, this.props, "opacity"); + const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString const highlightColors = CurrentUserUtils.ActiveDashboard?.darkScheme ? ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; - let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK; + let highlighting = highlightIndex && ![DocumentType.FONTICON, DocumentType.INK].includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way const topmost = this.topMost ? "-topmost" : ""; return this.props.styleProvider?.(this.rootDoc, this.props, "docContents") ??
!SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} onPointerLeave={action(e => { let entered = false; @@ -1122,15 +1120,15 @@ export class DocumentView extends DocComponent(Docu transition: !this._animateScalingTo ? StrCast(this.Document.dataTransition) : `transform 0.5s ease-${this._animateScalingTo < 1 ? "in" : "out"}`, pointerEvents: this.pointerEvents, color: StrCast(this.layoutDoc.color, "inherit"), - outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px", - border: highlighting && borderRounding && highlightStyles[fullDegree] === "dashed" ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, - boxShadow: highlighting && borderRounding && highlightStyles[fullDegree] !== "dashed" ? `0 0 0 ${localScale}px ${highlightColors[fullDegree]}` : + outline: highlighting && !borderRounding ? `${highlightColors[highlightIndex]} ${highlightStyles[highlightIndex]} ${highlightIndex}px` : "solid 0px", + border: highlighting && borderRounding && highlightStyles[highlightIndex] === "dashed" ? `${highlightStyles[highlightIndex]} ${highlightColors[highlightIndex]} ${highlightIndex}px` : undefined, + boxShadow: highlighting && borderRounding && highlightStyles[highlightIndex] !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColors[highlightIndex]}` : this.Document.isLinkButton && !this.props.dontRegisterView && !this.props.forceHideLinkButton?.() ? StrCast(this.layoutDoc._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, - background: finalColor, - opacity: finalOpacity, + background, + opacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), fontSize: !this.props.treeViewDoc ? Cast(this.Document._fontSize, "string", null) : undefined, }}> @@ -1140,7 +1138,7 @@ export class DocumentView extends DocComponent(Docu
; } render() { - return
+ return
{PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
; } diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 826ccd340..dd751b802 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -72,7 +72,7 @@ export class LabelBox extends ViewBoxBaseComponent this._mouseOver = false)} onMouseOver={action(() => this._mouseOver = true)} ref={this.createDropTarget} onContextMenu={this.specificContextMenu} - style={{ boxShadow: this.layoutDoc.opacity ? StrCast(this.layoutDoc.boxShadow) : "" }}> + style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, "boxShadow") }}>
e.stopPropagation()} - style={{ boxShadow: this.layoutDoc.opacity === 0 ? undefined : StrCast(this.layoutDoc.boxShadow, "") }}> + style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, "boxShadow") }}>
this.props.PanelWidth(); // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight); embedWidth = (): number => this.props.PanelWidth() - 35; + styleProvider = (doc: (Doc | undefined), props: DocumentViewProps, property: string): any => { + if (property === "opacity") return 1; + return this.props.styleProvider?.(doc, props, property); + } /** * The function that is responsible for rendering a preview or not for this * presentation element. @@ -87,7 +92,7 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Thu, 10 Dec 2020 22:25:37 -0500 Subject: fixed infinite loop in treeView. changed styleProvider signature back to have an optional 'props' --- src/client/views/PropertiesView.tsx | 4 ++-- .../views/collections/CollectionStackingView.tsx | 4 ++-- src/client/views/collections/TabDocView.tsx | 10 +++++----- src/client/views/collections/TreeView.tsx | 18 +++++++++--------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 ++++++-- src/client/views/nodes/LinkDocPreview.tsx | 4 ++-- src/client/views/presentationview/PresElementBox.tsx | 4 ++-- 9 files changed, 30 insertions(+), 26 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 233429f4d..352c70e94 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -28,7 +28,7 @@ import { PropertiesButtons } from "./PropertiesButtons"; import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector"; import "./PropertiesView.scss"; import { CollectionViewType } from "./collections/CollectionView"; -import { DocumentViewProps } from "./nodes/DocumentView"; +import { DocumentViewProps, StyleProviderFunc } from "./nodes/DocumentView"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -37,7 +37,7 @@ const _global = (window /* browser */ || global /* node */) as any; interface PropertiesViewProps { width: number; height: number; - styleProvider?: (doc: Opt, props: Opt, property: string) => any; + styleProvider?: StyleProviderFunc; } @observer diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 408a8d969..8dfb7cefe 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc"; +import { DataSym, Doc, HeightSym, WidthSym, Opt } from "../../../fields/Doc"; import { collectionSchema, documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; @@ -187,7 +187,7 @@ export class CollectionStackingView extends CollectionSubView Transform, width: () => number) { const dataDoc = (!doc.isTemplateDoc && !doc.isTemplateForField && !doc.PARAMS) ? undefined : this.props.DataDoc; const height = () => this.getDocHeight(doc); - const styleProvider = (doc: Doc | undefined, props: DocumentViewProps, property: string) => { + const styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === "opacity" && doc) { if (this.props.childOpacity) { return this.props.childOpacity(); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 5b5d8ee4a..045fee797 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -432,7 +432,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: DocumentViewProps, property: string): any => { + public static styleProvider = (doc: Opt, props: Opt, property: string): any => { switch (property) { case "docContents": return undefined; case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey"; @@ -463,22 +463,22 @@ export class TabDocView extends React.Component { return docColor; } case "boxShadow": { - if (!doc || props.styleProvider?.(doc, props, "opacity") === 0) return undefined; // if it's not visible, then no shadow) + if (!doc || props?.styleProvider?.(doc, props, "opacity") === 0) return undefined; // if it's not visible, then no shadow) const isBackground = StrListCast(doc.layers).includes("background"); switch (doc?.type) { case DocumentType.COL: return isBackground ? undefined : `${TabDocView.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`; default: return doc.z ? `#9c9396 ${StrCast(doc?.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow - props.backgroundHalo?.(doc) && doc.type !== DocumentType.INK ? (`${props.styleProvider?.(doc, props, "backgroundColor")} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground ? 100 : 50) / props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent + props?.backgroundHalo?.(doc) && doc.type !== DocumentType.INK ? (`${props?.styleProvider?.(doc, props, "backgroundColor")} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground ? 100 : 50) / props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big - StrCast(doc.boxShadow, "") + 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 (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; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 24dd905a9..d34cca852 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -21,7 +21,7 @@ import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { EditableView } from "../EditableView"; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; -import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { KeyValueBox } from '../nodes/KeyValueBox'; @@ -49,7 +49,7 @@ export interface TreeViewProps { outdentDocument?: () => void; ScreenToLocalTransform: () => Transform; dontRegisterView?: boolean; - backgroundColor?: (doc: Opt, props: DocumentViewProps, property: string) => string | undefined; + styleProvider?: StyleProviderFunc | undefined; outerXf: () => { translateX: number, translateY: number }; treeView: CollectionTreeView; parentKey: string; @@ -325,7 +325,7 @@ export class TreeView extends React.Component { const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), 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.dropAction, this.props.addDocTab, this.props.pinToPres, this.styleProvider, 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.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView); } else { @@ -404,7 +404,7 @@ export class TreeView extends React.Component { {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc, 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, + StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.styleProvider, 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.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)} ; @@ -496,11 +496,11 @@ export class TreeView extends React.Component { e.preventDefault(); } } - styleProvider = (doc: (Doc | undefined), props: DocumentViewProps, property: string): any => { + styleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { // override opacity and backgroundColor just for this treeView document: opacity = 1, and backgroundColor = undefined unless it is explicitly set on the document if (property === "opacity" && doc === this.props.document) return this.outlineMode ? undefined : 1; if (property === "backgroundColor" && doc === this.props.document) return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); - return this.props.treeView.props.styleProvider?.(doc, props, property); + return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView } onKeyDown = (e: React.KeyboardEvent) => { if (this.doc.treeViewHideHeader || this.outlineMode) { @@ -606,7 +606,7 @@ export class TreeView extends React.Component { renderDepth={this.props.renderDepth + 1} rootSelected={returnTrue} treeViewDoc={undefined} - styleProvider={this.props.backgroundColor} + styleProvider={this.styleProvider} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} @@ -716,7 +716,7 @@ export class TreeView extends React.Component { dropAction: dropActionType, addDocTab: (doc: Doc, where: string) => boolean, pinToPres: (document: Doc) => void, - styleProvider: undefined | ((document: Opt, props: DocumentViewProps, property: string) => string | undefined), + styleProvider: undefined | StyleProviderFunc, screenToLocalXf: () => Transform, outerXf: () => { translateX: number, translateY: number }, active: (outsideReaction?: boolean) => boolean, @@ -789,7 +789,7 @@ export class TreeView extends React.Component { renderDepth={renderDepth} removeDoc={StrCast(containingCollection.freezeChildren).includes("remove") ? undefined : remove} addDocument={addDocument} - backgroundColor={styleProvider} + styleProvider={styleProvider} panelWidth={rowWidth} panelHeight={rowHeight} ChromeHeight={ChromeHeight} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a8e24ebbe..1b6cfbd21 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -395,7 +395,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: DocumentViewProps, property: string) => { + getClusterColor = (doc: Opt, props: Opt, 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); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 60d33468a..46c311350 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -58,7 +58,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === "opacity" && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children return this.props.styleProvider?.(doc, props, property); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ed3fa6918..502f874e0 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -45,6 +45,7 @@ import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView export type DocAfterFocusFunc = (notFocused: boolean) => boolean; export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void; +export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocumentViewSharedProps { ContainingCollectionView: Opt; @@ -67,7 +68,7 @@ export interface DocumentViewSharedProps { 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; + styleProvider?: StyleProviderFunc; ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; parentActive: (outsideReaction: boolean) => boolean; @@ -982,6 +983,9 @@ export class DocumentView extends DocComponent(Docu @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } + anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + return property === "backgroundColor" ? "transparent" : undefined; + } @computed get allAnchors() { TraceMobx(); if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null; @@ -1003,7 +1007,7 @@ export class DocumentView extends DocComponent(Docu ContentScaling={returnOne} dontRegisterView={false} forceHideLinkButton={returnTrue} - styleProvider={(doc: Opt, props: DocumentViewProps, property: string) => property === "backgroundColor" ? "transparent" : undefined} + styleProvider={this.anchorStyleProvider} removeDocument={this.hideLinkAnchor} pointerEvents={"none"} LayoutTemplate={undefined} diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index f66811098..e0c8c032f 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -11,14 +11,14 @@ import { ContextMenu } from '../ContextMenu'; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import { DocumentLinksButton } from './DocumentLinksButton'; import React = require("react"); -import { DocumentViewProps } from './DocumentView'; +import { StyleProviderFunc } from './DocumentView'; import { Id } from '../../../fields/FieldSymbols'; interface Props { linkDoc?: Doc; linkSrc?: Doc; href?: string; - styleProvider?: (doc: Opt, props: Opt, property: string) => any; + styleProvider?: StyleProviderFunc; addDocTab: (document: Doc, where: string) => boolean; location: number[]; } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 7eda04930..45d943bff 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, reaction, runInAction, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym } from "../../../fields/Doc"; +import { Doc, DataSym, Opt } from "../../../fields/Doc"; import { documentSchema } from '../../../fields/documentSchemas'; import { Id } from "../../../fields/FieldSymbols"; import { createSchema, makeInterface } from '../../../fields/Schema'; @@ -77,7 +77,7 @@ export class PresElementBox extends ViewBoxBaseComponent this.props.PanelWidth(); // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight); embedWidth = (): number => this.props.PanelWidth() - 35; - styleProvider = (doc: (Doc | undefined), props: DocumentViewProps, property: string): any => { + styleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { if (property === "opacity") return 1; return this.props.styleProvider?.(doc, props, property); } -- cgit v1.2.3-70-g09d2 From f9f7e0aac784d3b32c5adab04d8ec5d7807b0390 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Dec 2020 23:11:46 -0500 Subject: a little refactoring in CollecftionFreeFormView --- .../collectionFreeForm/CollectionFreeFormView.tsx | 95 ++++++++-------------- 1 file changed, 35 insertions(+), 60 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1b6cfbd21..75411b3c5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym, StrListCast } from "../../../../fields/Doc"; import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas"; import { Id } from "../../../../fields/FieldSymbols"; import { InkData, InkField, InkTool } from "../../../../fields/InkField"; @@ -80,6 +80,8 @@ export type collectionFreeformViewProps = { @observer export class CollectionFreeFormView extends CollectionSubView>(PanZoomDocument) { + public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title?.toString() + ")"; } // this makes mobx trace() statements more descriptive + private _lastX: number = 0; private _lastY: number = 0; private _downX: number = 0; @@ -94,18 +96,22 @@ export class CollectionFreeFormView extends CollectionSubView(); private _layoutSizeData = new ObservableMap(); private _cachedPool: Map = new Map(); + private _lastTap = 0; + private _nudgeTime = 0; + private _thumbIdentifier?: number; + + @observable private _hLines: number[] | undefined; + @observable private _vLines: number[] | undefined; @observable private _pullCoords: number[] = [0, 0]; @observable private _pullDirection: string = ""; + @observable private _showAnimTimeline = false; - public get displayName() { return "CollectionFreeFormView(" + this.props.Document.title?.toString() + ")"; } // this makes mobx trace() statements more descriptive @observable.shallow _layoutElements: ViewDefResult[] = []; // shallow because some layout items (eg pivot labels) are just generated 'divs' and can't be frozen as observables @observable _clusterSets: (Doc[])[] = []; @observable _timelineRef = React.createRef(); - @observable _marqueeRef = React.createRef(); - @observable canPanX: boolean = true; - @observable canPanY: boolean = true; + @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); } @computed get fitToContentScaling() { return this.fitToContent ? NumCast(this.layoutDoc.fitToContentScaling, 1) : 1; } @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; } @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent ? this.props.ContentScaling() : 1; } @@ -154,6 +160,7 @@ export class CollectionFreeFormView extends CollectionSubView { let retVal = false; if (newBox instanceof Doc) { @@ -303,6 +310,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (e.nativeEvent.cancelBubble || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) || InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || (Doc.GetSelectedTool() === InkTool.Highlighter || Doc.GetSelectedTool() === InkTool.Pen)) { @@ -595,8 +602,6 @@ export class CollectionFreeFormView extends CollectionSubView { if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return; @@ -768,7 +773,6 @@ export class CollectionFreeFormView extends CollectionSubView { let deltaScale = deltaY > 0 ? (1 / 1.05) : 1.05; @@ -981,7 +984,6 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); // @ts-ignore @@ -1047,6 +1049,7 @@ export class CollectionFreeFormView extends CollectionSubView - @action onDragAutoScroll = (e: CustomEvent) => { if ((e as any).handlePan || this.props.isAnnotationOverlay) return; @@ -1254,7 +1255,6 @@ export class CollectionFreeFormView extends CollectionSubView { const docs = this.childLayoutPairs; @@ -1288,8 +1288,6 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.isAnnotationOverlay || this.props.Document.annotationOn || !ContextMenu.Instance) return; @@ -1304,7 +1302,6 @@ export class CollectionFreeFormView extends CollectionSubView Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null; !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" }); @@ -1312,7 +1309,7 @@ export class CollectionFreeFormView extends CollectionSubView this.showTimeline = !this.showTimeline), icon: "eye" }); + optionItems.push({ description: (this._showAnimTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this._showAnimTimeline = !this._showAnimTimeline), icon: "eye" }); this.props.ContainingCollectionView && optionItems.push({ description: "Move Items Out of Collection", event: this.promoteCollection, icon: "table" }); optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" }); @@ -1320,7 +1317,6 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" }); - } !options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" }); const mores = ContextMenu.Instance.findByDescription("More..."); @@ -1349,11 +1345,10 @@ export class CollectionFreeFormView extends CollectionSubView { + setTimeout(() => SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => { docs.docs.forEach(d => LinkManager.Instance.addLink(d)); - }); - }, 2000); // need to give solr some time to update so that this query will find any link docs we've added. + }), 2000); // need to give solr some time to update so that this query will find any link docs we've added. } } } @@ -1361,57 +1356,38 @@ export class CollectionFreeFormView extends CollectionSubView r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); - } - @action setupDragLines = (snapToDraggedDoc: boolean = false) => { const activeDocs = this.getActiveDocuments(); - if (activeDocs.length > 50) { - DragManager.SetSnapLines([], []); - return; - } const size = this.getTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); - const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => { - if (this.intersectRect(docDims(doc), rect)) { - snappableDocs.push(doc); - } - }; - const snappableDocs: Doc[] = []; // the set of documents in the visible viewport that we will try to snap to; + const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => intersectRect(docDims(doc), rect); + const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; - this.getActiveDocuments().filter(doc => !Cast(doc.layers, listSpec("string"), []).includes("background") && doc.z === undefined).map(doc => isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to - !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z === undefined).map(doc => isDocInView(doc, selRect)); // if not, see if there are background docs to snap to - !snappableDocs.length && this.getActiveDocuments().filter(doc => doc.z !== undefined).map(doc => isDocInView(doc, otherBounds)); // if not, then why not snap to floating docs + let snappableDocs = activeDocs.filter(doc => !StrListCast(doc.layers).includes("background") && doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to + !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect))); // if not, see if there are background docs to snap to + !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z !== undefined && isDocInView(doc, otherBounds))); // if not, then why not snap to floating docs const horizLines: number[] = []; const vertLines: number[] = []; + const invXf = this.getTransform().inverse(); snappableDocs.filter(doc => snapToDraggedDoc || !DragManager.docsBeingDragged.includes(Cast(doc.rootDocument, Doc, null) || doc)).forEach(doc => { const { left, top, width, height } = docDims(doc); - const topLeftInScreen = this.getTransform().inverse().transformPoint(left, top); - const docSize = this.getTransform().inverse().transformDirection(width, height); + const topLeftInScreen = invXf.transformPoint(left, top); + const docSize = invXf.transformDirection(width, height); horizLines.push(topLeftInScreen[1], topLeftInScreen[1] + docSize[1] / 2, topLeftInScreen[1] + docSize[1]); // horiz center line vertLines.push(topLeftInScreen[0], topLeftInScreen[0] + docSize[0] / 2, topLeftInScreen[0] + docSize[0]);// right line }); DragManager.SetSnapLines(horizLines, vertLines); } + onPointerOver = (e: React.PointerEvent) => { - if (SnappingManager.GetIsDragging()) { - this.setupDragLines(e.ctrlKey || e.shiftKey); - } + SnappingManager.GetIsDragging() && this.setupDragLines(e.ctrlKey || e.shiftKey); e.stopPropagation(); } - @observable private _hLines: number[] | undefined; - @observable private _vLines: number[] | undefined; - private childViews = () => { const children = typeof this.props.children === "function" ? (this.props.children as any)() as JSX.Element[] : []; return [ @@ -1426,13 +1402,13 @@ export class CollectionFreeFormView extends CollectionSubView); return eles; } + @computed get placeholder() { return
{this.props.Document.title?.toString()}
; } - _nudgeTime = 0; nudge = action((x: number, y: number) => { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { // bcz: this isn't ideal, but want to try it out... @@ -1450,7 +1426,7 @@ export class CollectionFreeFormView extends CollectionSubView; } + trySelectCluster = (addToSel: boolean) => { if (this._hitCluster !== -1) { - if (!addToSel) { - SelectionManager.DeselectAll(); - } + !addToSel && SelectionManager.DeselectAll(); const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster); this.selectDocuments(eles); return true; } return false; } + @computed get marqueeView() { return
- {this.layoutDoc["_backgroundGrid-show"] ? this.grid : (null)} + {this.layoutDoc["_backgroundGrid-show"] ? this.backgroundGrid : (null)}
- {this.showTimeline ? : (null)} + {this._showAnimTimeline ? : (null)}
; } - @computed get contentScaling() { if (this.props.isAnnotationOverlay && !this.props.forceScaling) return 0; const nw = returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.Document)); -- cgit v1.2.3-70-g09d2 From 495b60322b56d50f90398757c3a3c1f56da66cdc Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Dec 2020 02:07:40 -0500 Subject: cleaning up more doumentViewProps. reduced use of treeViewDoc prop. added hideTitle. fixed background shadow on isButton documents. --- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/PropertiesView.tsx | 1 - .../views/collections/CollectionTreeView.tsx | 2 - src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/collections/TreeView.scss | 8 ++ src/client/views/collections/TreeView.tsx | 43 ++++++---- .../CollectionFreeFormLinkView.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 94 ++++++++++------------ src/client/views/nodes/LinkAnchorBox.tsx | 4 +- 10 files changed, 87 insertions(+), 79 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8d905bcac..d4d91659f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -630,8 +630,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, }}> {closeIcon} - {Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : titleArea} - {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : + {titleArea} + {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : {`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top">
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 352c70e94..03e0a35ec 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -269,7 +269,6 @@ export class PropertiesView extends React.Component { DataDoc={this.dataDoc} renderDepth={1} rootSelected={returnFalse} - treeViewDoc={undefined} styleProvider={this.props.styleProvider} fitToBox={true} freezeDimensions={true} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 265f5a323..89ed3a147 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -104,7 +104,6 @@ export class CollectionTreeView extends CollectionSubView this.doc.treeViewPreventOpen = !this.doc.treeViewPreventOpen, icon: "paint-brush" }); layoutItems.push({ description: (this.doc.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.doc.treeViewHideHeaderFields = !this.doc.treeViewHideHeaderFields, icon: "paint-brush" }); layoutItems.push({ description: (this.doc.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.doc.treeViewHideTitle = !this.doc.treeViewHideTitle, icon: "paint-brush" }); - layoutItems.push({ description: (this.doc.treeViewHideLinkLines ? "Show" : "Hide") + " Link Lines", event: () => this.doc.treeViewHideLinkLines = !this.doc.treeViewHideLinkLines, icon: "paint-brush" }); ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); const existingOnClick = ContextMenu.Instance.findByDescription("OnClick..."); const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : []; @@ -163,7 +162,6 @@ export class CollectionTreeView extends CollectionSubView { (document.activeElement !== titleEle) && titleEle.focus(); } }; - tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => (v.topMost || v.props.treeViewDoc) && v.props.Document === doc), + tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc), action((selected) => { if (selected) this._activated = true; const toggle = tab.element[0].children[1].children[0] as HTMLInputElement; diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss index 0a97166f0..796b2438e 100644 --- a/src/client/views/collections/TreeView.scss +++ b/src/client/views/collections/TreeView.scss @@ -1,5 +1,13 @@ @import "../globalCssVariables"; +.treeView-label { + max-height: 1.5em; + text-overflow: ellipsis; + display: inline-block; + white-space: pre; + width: 100%; + overflow: hidden; +} .treeView-container, .treeView-container-active { .bullet-outline { diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index d34cca852..53cdca2af 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -325,7 +325,7 @@ export class TreeView extends React.Component { const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] : DocListCast(contents), 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.styleProvider, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, + this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, 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.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView); } else { @@ -404,7 +404,7 @@ export class TreeView extends React.Component { {!docs ? (null) : TreeView.GetChildElements(docs, this.props.treeView, this.layoutDoc, 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.styleProvider, this.props.ScreenToLocalTransform, + StrCast(this.doc.childDropAction, this.props.dropAction) as dropActionType, this.props.addDocTab, this.props.pinToPres, this.titleStyleProvider, 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.skipFields, false, this.props.whenActiveChanged, this.props.dontRegisterView)} ; @@ -413,7 +413,7 @@ export class TreeView extends React.Component { {this.expandedField}
; } else { - return this.renderDocument(false); + return this.renderEmbeddedDocument(false); } } @@ -441,7 +441,7 @@ export class TreeView extends React.Component { return
@@ -496,10 +496,25 @@ export class TreeView extends React.Component { e.preventDefault(); } } - styleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { - // override opacity and backgroundColor just for this treeView document: opacity = 1, and backgroundColor = undefined unless it is explicitly set on the document - if (property === "opacity" && doc === this.props.document) return this.outlineMode ? undefined : 1; - if (property === "backgroundColor" && doc === this.props.document) return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + titleStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { + if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView + + switch (property) { + case "opacity": return this.outlineMode ? undefined : 1; + case "backgroundColor": return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + case "docContents": return !props?.treeViewDoc ? (null) : +
+ {StrCast(doc?.title)} +
; + default: if (property.startsWith("decorations")) return (null); + } + } + embeddedStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { + if (property.startsWith("decorations")) return (null); return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView } onKeyDown = (e: React.KeyboardEvent) => { @@ -526,7 +541,7 @@ export class TreeView extends React.Component { ref={this._docRef} Document={this.doc} DataDoc={undefined} - styleProvider={this.styleProvider} + styleProvider={this.titleStyleProvider} treeViewDoc={this.props.treeView.props.Document} addDocument={undefined} addDocTab={this.props.addDocTab} @@ -552,7 +567,7 @@ export class TreeView extends React.Component { docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} - ContainingCollectionDoc={this.props.containingCollection} + ContainingCollectionDoc={this.props.treeView.props.Document} />; return <>
{ ; } - renderDocument = (asText: boolean) => { + 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; return this._dref = r)} @@ -599,14 +614,14 @@ export class TreeView extends React.Component { NativeWidth={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined} NativeHeight={!asText && this.layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined} fitToBox={!asText && this.isCollectionDoc !== undefined} + hideTitle={asText} LayoutTemplateString={asText ? FormattedTextBox.LayoutString("text") : undefined} focus={asText ? this.refocus : returnFalse} dontRegisterView={asText ? undefined : this.props.dontRegisterView} ScreenToLocalTransform={this.docTransform} renderDepth={this.props.renderDepth + 1} rootSelected={returnTrue} - treeViewDoc={undefined} - styleProvider={this.styleProvider} + styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} @@ -627,7 +642,7 @@ export class TreeView extends React.Component { @computed get renderDocumentAsHeader() { return <> {this.renderBullet} - {this.renderDocument(true)} + {this.renderEmbeddedDocument(true)} ; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index c81bd068c..473363292 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -103,7 +103,7 @@ export class CollectionFreeFormLinkView extends React.Component - c.a.props.Document.type === DocumentType.LINK - && !c.a.props.treeViewDoc?.treeViewHideLinkLines && !c.b.props.treeViewDoc?.treeViewHideLinkLines - ).map(c => ); + return connections.filter(c => c.a.props.Document.type === DocumentType.LINK) + .map(c => ); } render() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 502f874e0..9449f92ab 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -90,6 +90,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps { // properties specific to DocumentViews but not to FieldView layoutKey?: string; freezeDimensions?: boolean; + hideTitle?: boolean; fitToBox?: boolean; treeViewDoc?: Doc; dragDivName?: string; @@ -103,7 +104,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onPointerDown?: () => ScriptField; onPointerUp?: () => ScriptField; setupDragLines?: (snapToDraggedDoc: boolean) => void; - forceHideLinkButton?: () => boolean; } @observer @@ -129,7 +129,7 @@ export class DocumentView extends DocComponent(Docu public get LayoutFieldKey() { return this.props.layoutKey || Doc.LayoutFieldKey(this.layoutDoc); } @computed get ShowTitle() { return StrCast(this.layoutDoc._showTitle, - !Doc.IsSystem(this.layoutDoc) && this.rootDoc.type === DocumentType.RTF && !this.props.treeViewDoc && !this.rootDoc.presentationTargetDoc ? + !Doc.IsSystem(this.layoutDoc) && this.rootDoc.type === DocumentType.RTF && !this.rootDoc.presentationTargetDoc ? (this.dataDoc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : undefined); } @@ -813,7 +813,7 @@ export class DocumentView extends DocComponent(Docu if (!this.Document.annotationOn) { const options = cm.findByDescription("Options..."); const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : []; - !this.props.treeViewDoc && this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); + this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" }); onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" }); @@ -957,8 +957,7 @@ export class DocumentView extends DocComponent(Docu onClick={this.onClickFunc} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} - {/* {this.allAnchors} */} - {this.props.forceHideLinkButton?.() || (!this.isSelected() && (this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton)) || this.props.dontRegisterView ? (null) : + {this.props.styleProvider?.(this.layoutDoc, this.props, "hideLinkButton") || (!this.isSelected() && (this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton)) || this.props.dontRegisterView ? (null) : }
); @@ -980,17 +979,17 @@ export class DocumentView extends DocComponent(Docu hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, 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 (property === "backgroundColor") return props?.LayoutTemplateString ? "transparent" : this.props.styleProvider?.(doc, props, "backgroundColor"); + if (property === "hideLinkButton") return true; + } @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { - return property === "backgroundColor" ? "transparent" : undefined; - } @computed get allAnchors() { TraceMobx(); if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null; - if ((this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots - this.layoutDoc.presBox || // presentationbox nodes + if (this.layoutDoc.presBox || // presentationbox nodes this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) {// view that are not registered return (null); @@ -1006,7 +1005,6 @@ export class DocumentView extends DocComponent(Docu PanelHeight={this.anchorPanelHeight} ContentScaling={returnOne} dontRegisterView={false} - forceHideLinkButton={returnTrue} styleProvider={this.anchorStyleProvider} removeDocument={this.hideLinkAnchor} pointerEvents={"none"} @@ -1016,17 +1014,6 @@ export class DocumentView extends DocComponent(Docu } @computed get innards() { TraceMobx(); - const pos = this.props.relative ? "relative" : undefined; - if (this.props.treeViewDoc && !this.props.LayoutTemplateString?.includes("LinkAnchorBox")) { // this happens when the document is a tree view label (but not an anchor dot) - return
- {StrCast(this.props.Document.title)} - {this.allAnchors} -
; - } - const showTitleHover = StrCast(this.layoutDoc._showTitleHover); const showCaption = StrCast(this.layoutDoc._showCaption); const captionView = (!showCaption ? (null) : @@ -1060,7 +1047,7 @@ export class DocumentView extends DocComponent(Docu })} />
); - return !this.ShowTitle && !showCaption ? + return this.props.hideTitle || (!this.ShowTitle && !showCaption) ? this.contents :
{this.showOverlappingTitle ? <> {this.contents} {titleView} : <> {titleView} {this.contents} } @@ -1094,19 +1081,37 @@ export class DocumentView extends DocComponent(Docu if (!(this.props.Document instanceof Doc)) return (null); if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null); if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden")) return null; - const background = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor"); + return this.props.styleProvider?.(this.rootDoc, this.props, "docContents") ?? +
+ {this.innards} + {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: (null)} + {this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations") || (null)} +
; + } + render() { const borderRounding = this.props.styleProvider?.(this.layoutDoc, this.props, "borderRounding"); - const opacity = this.props.styleProvider?.(this.layoutDoc, this.props, "opacity"); const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString - const highlightColors = CurrentUserUtils.ActiveDashboard?.darkScheme ? + const highlightColor = (CurrentUserUtils.ActiveDashboard?.darkScheme ? ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : - ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"]; - const highlightStyles = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"]; + ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"])[highlightIndex]; + const highlightStyle = ["solid", "dashed", "solid", "solid", "solid", "solid", "solid"][highlightIndex]; let highlighting = highlightIndex && ![DocumentType.FONTICON, DocumentType.INK].includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way - const topmost = this.topMost ? "-topmost" : ""; - return this.props.styleProvider?.(this.rootDoc, this.props, "docContents") ??
(Docu !entered && Doc.UnBrushDoc(this.props.Document); })} style={{ - 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, - color: StrCast(this.layoutDoc.color, "inherit"), - outline: highlighting && !borderRounding ? `${highlightColors[highlightIndex]} ${highlightStyles[highlightIndex]} ${highlightIndex}px` : "solid 0px", - border: highlighting && borderRounding && highlightStyles[highlightIndex] === "dashed" ? `${highlightStyles[highlightIndex]} ${highlightColors[highlightIndex]} ${highlightIndex}px` : undefined, - boxShadow: highlighting && borderRounding && highlightStyles[highlightIndex] !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColors[highlightIndex]}` : - this.Document.isLinkButton && !this.props.dontRegisterView && !this.props.forceHideLinkButton?.() ? + 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}` : + this.Document.isLinkButton && !this.props.dontRegisterView && !this.props.styleProvider?.(this.layoutDoc, this.props, "hideLinkButton") ? StrCast(this.layoutDoc._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, - background, - opacity, - fontFamily: StrCast(this.Document._fontFamily, "inherit"), - fontSize: !this.props.treeViewDoc ? Cast(this.Document._fontSize, "string", null) : undefined, - }}> - {this.innards} - {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: (null)} - {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations") || (null)} -
; - } - render() { - return
+ }} + > {PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
; } diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 7ce9abf27..b5b53501d 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -4,7 +4,7 @@ import { Doc, DocListCast } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils'; +import { Utils, setupMoveUpEvents, emptyFunction, OmitKeys } from '../../../Utils'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; import { ViewBoxBaseComponent } from "../DocComponent"; @@ -117,7 +117,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent Date: Fri, 11 Dec 2020 12:25:06 -0500 Subject: converted all style sheet properties to enums. --- src/client/views/MainView.tsx | 13 +- src/client/views/OverlayView.tsx | 3 +- src/client/views/PropertiesView.tsx | 3 +- src/client/views/StyleProvider.scss | 19 +++ src/client/views/StyleProvider.tsx | 153 +++++++++++++++++++++ .../views/collections/CollectionCarouselView.tsx | 3 +- .../views/collections/CollectionStackingView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 3 +- src/client/views/collections/CollectionView.tsx | 3 +- src/client/views/collections/TabDocView.tsx | 127 ++--------------- src/client/views/collections/TreeView.tsx | 17 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- .../collectionGrid/CollectionGridView.tsx | 2 - src/client/views/nodes/AudioBox.tsx | 9 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 11 +- .../views/nodes/ContentFittingDocumentView.tsx | 19 --- src/client/views/nodes/DocHolderBox.tsx | 3 +- src/client/views/nodes/DocumentView.scss | 19 --- src/client/views/nodes/DocumentView.tsx | 39 +++--- src/client/views/nodes/FontIconBox.tsx | 3 +- src/client/views/nodes/LabelBox.tsx | 3 +- src/client/views/nodes/LinkAnchorBox.tsx | 10 +- src/client/views/nodes/LinkBox.tsx | 3 +- src/client/views/nodes/SliderBox.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 +- .../views/presentationview/PresElementBox.tsx | 5 +- 27 files changed, 280 insertions(+), 226 deletions(-) create mode 100644 src/client/views/StyleProvider.scss create mode 100644 src/client/views/StyleProvider.tsx (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2705d2c34..2cb529317 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -59,6 +59,7 @@ import { TraceMobx } from '../../fields/util'; import { SelectionManager } from '../util/SelectionManager'; import { UndoManager } from '../util/UndoManager'; import { TabDocView } from './collections/TabDocView'; +import { DefaultStyleProvider } from './StyleProvider'; const _global = (window /* browser */ || global /* node */) as any; @observer @@ -319,7 +320,7 @@ export class MainView extends React.Component { PanelHeight={this.getContentsHeight} renderDepth={0} focus={emptyFunction} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} @@ -352,7 +353,7 @@ export class MainView extends React.Component { PanelHeight={this.getContentsHeight} renderDepth={0} focus={emptyFunction} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} @@ -404,7 +405,7 @@ export class MainView extends React.Component {
- {this.propertiesWidth() < 10 ? (null) : } + {this.propertiesWidth() < 10 ? (null) : }
; } @@ -457,7 +458,7 @@ export class MainView extends React.Component { fieldKey={"data"} dropAction={"alias"} parentActive={returnFalse} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} rootSelected={returnTrue} bringToFront={emptyFunction} select={emptyFunction} @@ -532,7 +533,7 @@ export class MainView extends React.Component { pinToPres={emptyFunction} rootSelected={returnTrue} onClick={undefined} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} @@ -595,7 +596,7 @@ export class MainView extends React.Component { {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.EditLink ? : (null)} - {LinkDocPreview.LinkInfo ? : (null)} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index b7bd88344..124da6016 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -16,6 +16,7 @@ import { DragManager } from "../util/DragManager"; import { List } from "../../fields/List"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { TabDocView } from "./collections/TabDocView"; +import { DefaultStyleProvider } from "./StyleProvider"; export type OverlayDisposer = () => void; @@ -195,7 +196,7 @@ export class OverlayView extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} addDocTab={returnFalse} pinToPres={emptyFunction} docFilters={returnEmptyFilter} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 03e0a35ec..eb7df0248 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -29,6 +29,7 @@ import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector"; import "./PropertiesView.scss"; import { CollectionViewType } from "./collections/CollectionView"; import { DocumentViewProps, StyleProviderFunc } from "./nodes/DocumentView"; +import { DefaultStyleProvider } from "./StyleProvider"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -269,7 +270,7 @@ export class PropertiesView extends React.Component { DataDoc={this.dataDoc} renderDepth={1} rootSelected={returnFalse} - styleProvider={this.props.styleProvider} + styleProvider={DefaultStyleProvider} fitToBox={true} freezeDimensions={true} dontCenter={"y"} diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss new file mode 100644 index 000000000..df63288f1 --- /dev/null +++ b/src/client/views/StyleProvider.scss @@ -0,0 +1,19 @@ +.styleProvider-lock { + font-size: 12px; + width: 20; + height: 20; + position: absolute; + right: -5; + top: -5; + background: transparent; + pointer-events: all; + opacity: 0.3; + display: flex; + color: gold; + border-radius: 3px; + justify-content: center; + cursor: default; +} +.styleProvider-lock:hover { + opacity:1; +} \ No newline at end of file diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx new file mode 100644 index 000000000..0fe6df84c --- /dev/null +++ b/src/client/views/StyleProvider.tsx @@ -0,0 +1,153 @@ +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 { List } from '../../fields/List'; +import { BoolCast, Cast, StrCast } from "../../fields/Types"; +import { DocumentType } from '../documents/DocumentTypes'; +import { CurrentUserUtils } from '../util/CurrentUserUtils'; +import { SnappingManager } from '../util/SnappingManager'; +import { UndoManager } from '../util/UndoManager'; +import { CollectionViewType } from './collections/CollectionView'; +import { DocumentViewProps } from "./nodes/DocumentView"; +import "./StyleProvider.scss"; +import React = require("react"); +import Color = require('color'); +import { listSpec } from '../../fields/Schema'; + +export enum StyleLayers { + Background = "background" +} + +export enum StyleProp { + DocContents = "docContents", + Opacity = "opacity", + Hidden = "hidden", + BoxShadow = "boxShadow", + BorderRounding = "borderRounding", + BackgroundColor = "backgroundColor", + WidgetColor = "widgetColor", + LinkBackgroundColor = "linkBackgroundColor", + HideLinkButton = "hideLinkButton", + LinkSource = "linkSource", + PointerEvents = "pointerEvents", + Decorations = "decorations", +} + +function darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); } + +function toggleBackground(doc: Doc) { + UndoManager.RunInBatch(() => runInAction(() => { + const layers = StrListCast(doc.layers); + if (!layers.includes(StyleLayers.Background)) { + if (!layers.length) doc.layers = new List([StyleLayers.Background]); + else layers.push(StyleLayers.Background); + } + else layers.splice(layers.indexOf(StyleLayers.Background), 1); + doc._overflow = !layers.includes(StyleLayers.Background) ? "visible" : undefined; + if (!layers.includes(StyleLayers.Background)) { + //this.props.bringToFront(doc, true); + // const wid = this.Document[WidthSym](); // change the nativewidth and height if the background is to be a collection that aggregates stuff that is added to it. + // const hgt = this.Document[HeightSym](); + // Doc.SetNativeWidth(this.props.Document[DataSym], wid); + // Doc.SetNativeHeight(this.props.Document[DataSym], hgt); + } + }), "toggleBackground"); +} + +// +// a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab +// +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { + switch (property.split(":")[0]) { + case StyleProp.DocContents: return undefined; + case StyleProp.WidgetColor: return darkScheme() ? "lightgrey" : "dimgrey"; + case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null)); + case StyleProp.Hidden: return BoolCast(doc?._hidden, BoolCast(doc?.hidden)); + case StyleProp.BorderRounding: return !doc ? undefined : StrCast(doc._borderRounding, StrCast(doc.borderRounding)); + case StyleProp.BackgroundColor: { + if (Doc.UserDoc().renderStyle === "comic") return undefined; + let docColor: Opt = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor)); + if (!docColor) { + switch (doc?.type) { + case DocumentType.PRESELEMENT: docColor = darkScheme() ? "" : ""; break; + case DocumentType.PRES: docColor = darkScheme() ? "#3e3e3e" : "white"; break; + case DocumentType.FONTICON: docColor = "black"; break; + case DocumentType.RTF: docColor = darkScheme() ? "#2d2d2d" : "#f1efeb"; break; + case DocumentType.LABEL: + case DocumentType.BUTTON: docColor = darkScheme() ? "#2d2d2d" : "lightgray"; break; + case DocumentType.LINK: + case DocumentType.COL: + docColor = Doc.IsSystem(doc) ? (darkScheme() ? "rgb(62,62,62)" : "lightgrey") : + StrListCast(doc.layers).includes(StyleLayers.Background) ? "cyan" : + doc.annotationOn ? "#00000015" : + StrCast((props?.renderDepth || 0) > 0 ? + Doc.UserDoc().activeCollectionNestedBackground : + Doc.UserDoc().activeCollectionBackground); + break; + //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; + default: docColor = darkScheme() ? "black" : "white"; break; + } + } + if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor.toLowerCase()).fade(0.5).toString(); + return docColor; + } + case StyleProp.BoxShadow: { + if (!doc || props?.styleProvider?.(doc, props, StyleProp.Opacity) === 0) return undefined; // if it's not visible, then no shadow) + const isBackground = StrListCast(doc.layers).includes(StyleLayers.Background); + switch (doc?.type) { + case DocumentType.COL: return isBackground ? undefined : + `${darkScheme() ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`; + default: + return doc.z ? `#9c9396 ${StrCast(doc?.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow + props?.backgroundHalo?.(doc) && doc.type !== DocumentType.INK ? (`${props?.styleProvider?.(doc, props, StyleProp.BackgroundColor)} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground ? 100 : 50) / props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent + isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big + StrCast(doc.boxShadow, ""); + } + } + case StyleProp.PointerEvents: + const layer = doc && props?.layerProvider?.(doc); + if (props?.styleProvider?.(doc, props, StyleProp.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 StyleProp.Decorations: + if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) { + const isBackground = StrListCast(doc?.layers).includes(StyleLayers.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)) ? +
toggleBackground(doc)}> + +
+ : (null); + } + } +} + +// +// a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents +// currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab. +// if it matches, then the document gets pointer events, otherwise it does not. +// +export function DefaultLayerProvider(thisDoc: Doc) { + return (doc: Doc, assign?: boolean) => { + if (doc.z) return true; + if (assign) { + const activeLayer = StrCast(thisDoc?.activeLayer); + if (activeLayer) { + const layers = Cast(doc.layers, listSpec("string"), []); + if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer); + else if (!layers.length) doc.layers = new List([activeLayer]); + if (activeLayer === "red" || activeLayer === "green" || activeLayer === "blue") doc._backgroundColor = activeLayer; + } + return true; + } else { + if (Doc.AreProtosEqual(doc, thisDoc)) return true; + const layers = Cast(doc.layers, listSpec("string"), []); + if (!layers.length && !thisDoc?.activeLayer) return true; + if (layers.includes(StrCast(thisDoc?.activeLayer))) return true; + return false; + } + }; +} \ No newline at end of file diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 8b7a46e2f..26c36507a 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -15,6 +15,7 @@ import { ContextMenu } from '../ContextMenu'; import { ObjectField } from '../../../fields/ObjectField'; import { returnFalse, returnZero, OmitKeys } from '../../../Utils'; import { ScriptField } from '../../../fields/ScriptField'; +import { StyleProp } from '../StyleProvider'; type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>; const CarouselDocument = makeInterface(documentSchema, collectionSchema); @@ -65,7 +66,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 8dfb7cefe..2896d244e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -28,6 +28,7 @@ import "./CollectionStackingView.scss"; import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn"; import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; +import { StyleProp } from "../StyleProvider"; const _global = (window /* browser */ || global /* node */) as any; type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -188,7 +189,7 @@ export class CollectionStackingView extends CollectionSubView this.getDocHeight(doc); const styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { - if (property === "opacity" && doc) { + if (property === StyleProp.Opacity && doc) { if (this.props.childOpacity) { return this.props.childOpacity(); } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 89ed3a147..4e521956d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -24,6 +24,7 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { TreeView } from "./TreeView"; import React = require("react"); +import { StyleProp } from '../StyleProvider'; export type collectionTreeViewProps = { treeViewHideTitle?: boolean; @@ -211,7 +212,7 @@ export class CollectionTreeView extends CollectionSubView { CollectionView: this, }; const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || this.collectionViewType === CollectionViewType.Linear ? undefined : - this.props.styleProvider?.(this.props.Document, this.props, "boxShadow"); + this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BoxShadow); return (
{this.showIsTagged()} diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index ba8b5e418..8b5143013 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -32,6 +32,7 @@ import React = require("react"); import { List } from '../../../fields/List'; import { DocumentType } from '../../documents/DocumentTypes'; import Color = require('color'); +import { StyleProp, DefaultStyleProvider, DefaultLayerProvider, StyleLayers } from '../StyleProvider'; const _global = (window /* browser */ || global /* node */) as any; interface TabDocViewProps { @@ -84,7 +85,7 @@ export class TabDocView extends React.Component { toggle.style.borderLeft = "solid 1px black"; toggle.onclick = (e: MouseEvent) => { if (tab.contentItem === tab.header.parent.getActiveContentItem()) { - tab.DashDoc.activeLayer = tab.DashDoc.activeLayer ? undefined : "background"; + tab.DashDoc.activeLayer = tab.DashDoc.activeLayer ? undefined : StyleLayers.Background; } }; tab.element[0].style.borderTopRightRadius = "8px"; @@ -279,7 +280,6 @@ export class TabDocView extends React.Component { @computed get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.ContentScaling()) / 2 : 0; } @computed get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.ContentScaling()) / this._panelWidth * 100}% ` : undefined; } @computed get layoutDoc() { return this._document && Doc.Layout(this._document); } - @computed static get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); } // adds a tab to the layout based on the locaiton parameter which can be: // close[:{left,right,top,bottom}] - e.g., "close" will close the tab, "close:left" will close the left tab, @@ -303,7 +303,7 @@ export class TabDocView extends React.Component { } } - @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, TabDocView.styleProvider(this._document, undefined, "backgroundColor"))); } + @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); } @computed get renderBounds() { const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0]; const xbounds = bounds[2] - bounds[0]; @@ -374,7 +374,7 @@ export class TabDocView extends React.Component { {"toggle minimap"}
}>
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} - style={{ background: TabDocView.styleProvider(this._document, undefined, "backgroundColor") }} > + style={{ background: DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor) }} >
@@ -388,123 +388,22 @@ export class TabDocView extends React.Component { } active = () => this._isActive; - // - // a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents - // currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab. - // if it matches, then the document gets pointer events, otherwise it does not. - // - layerProvider = (doc: Doc, assign?: boolean) => { - if (doc.z) return true; - if (assign) { - const activeLayer = StrCast(this._document?.activeLayer); - if (activeLayer) { - const layers = Cast(doc.layers, listSpec("string"), []); - if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer); - else if (!layers.length) doc.layers = new List([activeLayer]); - if (activeLayer === "red" || activeLayer === "green" || activeLayer === "blue") doc._backgroundColor = activeLayer; - } - return true; - } else { - if (Doc.AreProtosEqual(doc, this._document)) return true; - const layers = Cast(doc.layers, listSpec("string"), []); - if (!layers.length && !this._document?.activeLayer) return true; - if (layers.includes(StrCast(this._document?.activeLayer))) return true; - return false; - } - } - static toggleBackground = undoBatch(action((doc: Doc) => { - const layers = StrListCast(doc.layers); - if (!layers.includes("background")) { - if (!layers.length) doc.layers = new List(["background"]); - else layers.push("background"); - } - else layers.splice(layers.indexOf("background"), 1); - doc._overflow = !layers.includes("background") ? "visible" : undefined; - if (!layers.includes("background")) { - //this.props.bringToFront(doc, true); - // const wid = this.Document[WidthSym](); // change the nativewidth and height if the background is to be a collection that aggregates stuff that is added to it. - // const hgt = this.Document[HeightSym](); - // Doc.SetNativeWidth(this.props.Document[DataSym], wid); - // Doc.SetNativeHeight(this.props.Document[DataSym], hgt); - } - })); - // - // 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.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)); - case "hidden": return BoolCast(doc?._hidden, BoolCast(doc?.hidden)); - case "borderRounding": return !doc ? undefined : StrCast(doc._borderRounding, StrCast(doc.borderRounding)); - case "backgroundColor": { - if (Doc.UserDoc().renderStyle === "comic") return undefined; - let docColor: Opt = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor)); - if (!docColor) { - switch (doc?.type) { - case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "" : ""; break; - case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "white"; break; - case DocumentType.FONTICON: docColor = "black"; break; - case DocumentType.RTF: docColor = TabDocView.darkScheme ? "#2d2d2d" : "#f1efeb"; break; - case DocumentType.LABEL: - case DocumentType.BUTTON: docColor = TabDocView.darkScheme ? "#2d2d2d" : "lightgray"; break; - case DocumentType.LINK: - case DocumentType.COL: - docColor = Doc.IsSystem(doc) ? (TabDocView.darkScheme ? "rgb(62,62,62)" : "lightgrey") : - StrCast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground); - break; - //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; - default: docColor = TabDocView.darkScheme ? "black" : "white"; break; - } - } - if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor.toLowerCase()).fade(0.5).toString(); - return docColor; - } - case "boxShadow": { - if (!doc || props?.styleProvider?.(doc, props, "opacity") === 0) return undefined; // if it's not visible, then no shadow) - const isBackground = StrListCast(doc.layers).includes("background"); - switch (doc?.type) { - case DocumentType.COL: return isBackground ? undefined : - `${TabDocView.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(doc.boxShadow, "0.2vw 0.2vw 0.8vw")}`; - default: - return doc.z ? `#9c9396 ${StrCast(doc?.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow - props?.backgroundHalo?.(doc) && doc.type !== DocumentType.INK ? (`${props?.styleProvider?.(doc, props, "backgroundColor")} ${StrCast(doc.boxShadow, `0vw 0vw ${(isBackground ? 100 : 50) / props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent - isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big - StrCast(doc.boxShadow, ""); - } - } - 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)) ? -
TabDocView.toggleBackground(doc)}> - -
- : (null); - } - } - } public static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { - switch (property) { - case "docContents": + switch (property.split(":")[0]) { + default: return DefaultStyleProvider(doc, props, property); + case StyleProp.PointerEvents: return "none"; + case StyleProp.DocContents: 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 doc.type === DocumentType.COL ? undefined :
; - default: - return (property.startsWith("pointerEvents")) ? "none" : TabDocView.styleProvider(doc, props, property); + return doc.type === DocumentType.COL ? + undefined : +
; } } } + @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); } @computed get docView() { TraceMobx(); return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) : @@ -526,7 +425,7 @@ export class TabDocView extends React.Component { parentActive={this.active} whenActiveChanged={emptyFunction} focus={this.focusFunc} - styleProvider={TabDocView.styleProvider} + styleProvider={DefaultStyleProvider} addDocTab={this.addDocTab} pinToPres={TabDocView.PinDoc} docFilters={CollectionDockingView.Instance.docFilters} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 53cdca2af..28503a23f 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -29,6 +29,7 @@ import { CollectionTreeView } from './CollectionTreeView'; import { CollectionView, CollectionViewType } from './CollectionView'; import "./TreeView.scss"; import React = require("react"); +import { StyleProp } from '../StyleProvider'; export interface TreeViewProps { document: Doc; @@ -441,7 +442,7 @@ export class TreeView extends React.Component { return
@@ -499,22 +500,22 @@ export class TreeView extends React.Component { titleStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { if (!doc || doc !== this.doc) return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView - switch (property) { - case "opacity": return this.outlineMode ? undefined : 1; - case "backgroundColor": return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); - case "docContents": return !props?.treeViewDoc ? (null) : + switch (property.split(":")[0]) { + case StyleProp.Opacity: return this.outlineMode ? undefined : 1; + case StyleProp.BackgroundColor: return StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); + case StyleProp.DocContents: return !props?.treeViewDoc ? (null) :
{StrCast(doc?.title)}
; - default: if (property.startsWith("decorations")) return (null); + case StyleProp.Decorations: return (null); } } embeddedStyleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { - if (property.startsWith("decorations")) return (null); + if (property.startsWith(StyleProp.Decorations)) return (null); return this.props?.treeView?.props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView } onKeyDown = (e: React.KeyboardEvent) => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 75411b3c5..cfc5e8b61 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -47,6 +47,7 @@ import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; +import { StyleProp, StyleLayers } from "../../StyleProvider"; export const panZoomSchema = createSchema({ _panX: "number", @@ -246,7 +247,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { - let clusterColor = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 - if (property !== "backgroundColor") return clusterColor; + let styleProp = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 + if (property !== StyleProp.BackgroundColor) return styleProp; const cluster = NumCast(doc?.cluster); if (this.Document._useClusters) { if (this._clusterSets.length <= cluster) { @@ -413,14 +414,14 @@ export class CollectionFreeFormView extends CollectionSubView s.backgroundColor); // override the cluster color with an explicitly set color on a non-background document. then override that with an explicitly set color on a background document - set && set.filter(s => !Cast(s.layers, listSpec("string"), []).includes("background")).map(s => clusterColor = StrCast(s.backgroundColor)); - set && set.filter(s => Cast(s.layers, listSpec("string"), []).includes("background")).map(s => clusterColor = StrCast(s.backgroundColor)); + set && set.filter(s => !StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); + set && set.filter(s => StrListCast(s.layers).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor)); } - } else if (doc && NumCast(doc.group, -1) !== -1) clusterColor = "gray"; - return clusterColor; + } else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray"; + return styleProp; } @action @@ -870,7 +871,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (sendToBack || Cast(doc.layers, listSpec("string"), []).includes("background")) { + if (sendToBack || StrListCast(doc.layers).includes(StyleLayers.Background)) { doc.zIndex = 0; } else if (doc.isInkMask) { doc.zIndex = 5000; @@ -1053,7 +1054,7 @@ export class CollectionFreeFormView extends CollectionSubView intersectRect(docDims(doc), rect); const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) }; - let snappableDocs = activeDocs.filter(doc => !StrListCast(doc.layers).includes("background") && doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to + let snappableDocs = activeDocs.filter(doc => !StrListCast(doc.layers).includes(StyleLayers.Background) && doc.z === undefined && isDocInView(doc, selRect)); // first see if there are any foreground docs to snap to !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect))); // if not, see if there are background docs to snap to !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z !== undefined && isDocInView(doc, otherBounds))); // if not, then why not snap to floating docs diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 52310d628..f1f190bff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -27,6 +27,7 @@ import { CollectionView } from "../CollectionView"; import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); +import { StyleLayers } from "../../StyleProvider"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -349,7 +350,6 @@ export class MarqueeView extends React.Component(layers); - newCollection.backgroundColor = this.props.isAnnotationOverlay ? "#00000015" : layers.includes("background") ? "cyan" : undefined; newCollection._width = this.Bounds.width; newCollection._height = this.Bounds.height; newCollection.x = this.Bounds.left; @@ -523,7 +523,7 @@ export class MarqueeView extends React.Component { - const newCollection = this.getCollection([], undefined, ["background"]); + const newCollection = this.getCollection([], undefined, [StyleLayers.Background]); this.props.addDocument?.(newCollection); MarqueeOptionsMenu.Instance.fadeOut(true); this.hideMarquee(); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index bef197bee..1a4eb8b7b 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -165,8 +165,6 @@ export class CollectionGridView extends CollectionSubView(GridSchema) { {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} Document={layout} DataDoc={layout.resolvedDataDoc as Doc} - styleProvider={this.props.styleProvider} - ContainingCollectionDoc={this.props.Document} PanelWidth={width} PanelHeight={height} ContentScaling={returnOne} diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index c89e21312..b495cdd1b 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -29,6 +29,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { LinkAnchorBox } from "./LinkAnchorBox"; import { LinkDocPreview } from "./LinkDocPreview"; +import { StyleProp } from "../StyleProvider"; declare class MediaRecorder { // whatever MediaRecorder has @@ -538,7 +539,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.RangeScript; labelScript = () => AudioBox.LabelScript; - + static audioStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + if (property === StyleProp.BackgroundColor) return "transparent"; + if (property === StyleProp.PointerEvents) return "none"; + } render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; this._first = true; // for indicating the first marker that is rendered @@ -637,8 +641,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent, props: Opt, property: string) => property === "backgroundColor" ? "transparent" : undefined} - pointerEvents={"none"} + styleProvider={AudioBox.audioStyleProvider} LayoutTemplate={undefined} LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)} /> diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 46c311350..1b47f4551 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -16,6 +16,7 @@ import "./CollectionFreeFormDocumentView.scss"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import React = require("react"); +import { StyleProp } from "../StyleProvider"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; @@ -59,7 +60,7 @@ export class CollectionFreeFormDocumentView extends DocComponent, property: string) => { - if (property === "opacity" && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children + if (property === StyleProp.Opacity && doc === this.layoutDoc) return this.Opacity; // only change the opacity for this specific document, not its children return this.props.styleProvider?.(doc, props, property); } @@ -147,13 +148,13 @@ export class CollectionFreeFormDocumentView extends DocComponent this; @computed get pointerEvents() { if (this.props.pointerEvents === "none") return "none"; - return this.props.styleProvider?.(this.Document, this.props, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents"); + return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (!this._contentView?.docView?.isSelected() ? ":selected" : "")); } render() { TraceMobx(); - const backgroundColor = this.props.styleProvider?.(this.Document, this.props, "backgroundColor"); - const borderRadius = this.props.styleProvider?.(this.Document, this.props, "borderRounding"); - const boxShadow = this.props.styleProvider?.(this.Document, this.props, "boxShadow"); + const backgroundColor = this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor); + const borderRadius = this.props.styleProvider?.(this.Document, this.props, StyleProp.BorderRounding); + const boxShadow = this.props.styleProvider?.(this.Document, this.props, StyleProp.BoxShadow); const divProps: DocumentViewProps = { ...this.props, CollectionFreeFormDocumentView: this.returnThis, diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 7b767a10a..ae0275c3d 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -67,32 +67,13 @@ export class ContentFittingDocumentView extends React.Component this.docView = r)} - Document={this.props.Document} - DataDoc={this.props.DataDoc} LayoutTemplate={this.props.LayoutTemplate} - LayoutTemplateString={this.props.LayoutTemplateString} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} ContentScaling={returnOne} - fitToBox={this.props.fitToBox} - layoutKey={this.props.layoutKey} - dropAction={this.props.dropAction} - onClick={this.props.onClick} - styleProvider={this.props.styleProvider} - addDocument={this.props.addDocument} - removeDocument={this.props.removeDocument} - moveDocument={this.props.moveDocument} - whenActiveChanged={this.props.whenActiveChanged} - ContainingCollectionView={this.props.ContainingCollectionView} - ContainingCollectionDoc={this.props.ContainingCollectionDoc} - addDocTab={this.props.addDocTab} - pinToPres={this.props.pinToPres} - parentActive={this.props.parentActive} ScreenToLocalTransform={this.getTransform} - renderDepth={this.props.renderDepth} focus={this.props.focus || emptyFunction} bringToFront={emptyFunction} - dontRegisterView={this.props.dontRegisterView} />
)}
); diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index e14093e70..1bc7bc8d7 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -19,6 +19,7 @@ import "./DocHolderBox.scss"; import { DocumentView } from "./DocumentView"; import { FieldView, FieldViewProps } from "./FieldView"; import React = require("react"); +import { StyleProp } from "../StyleProvider"; type DocHolderBoxSchema = makeInterface<[typeof documentSchema, typeof collectionSchema]>; const DocHolderBoxDocument = makeInterface(documentSchema, collectionSchema); @@ -182,7 +183,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent boolean; export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void; export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; - export interface DocumentViewSharedProps { ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; @@ -118,6 +118,7 @@ export class DocumentView extends DocComponent(Docu private _doubleTap = false; private _mainCont = React.createRef(); private _titleRef = React.createRef(); + private _timeout: NodeJS.Timeout | undefined; private _dropDisposer?: DragManager.DragDropDisposer; private _gestureEventDisposer?: GestureUtils.GestureEventDisposer; private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer; @@ -310,14 +311,12 @@ export class DocumentView extends DocComponent(Docu } } - _timeout: NodeJS.Timeout | undefined; - onClick = action((e: React.MouseEvent | React.PointerEvent) => { if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && this.props.renderDepth >= 0 && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { let stopPropagate = true; let preventDefault = true; - !Cast(this.props.Document.layers, listSpec("string"), []).includes("background") && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); + !StrListCast(this.props.Document.layers).includes(StyleLayers.Background) && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc); if (this._doubleTap && ((this.props.renderDepth && this.props.Document.type !== DocumentType.FONTICON) || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click if (this._timeout) { clearTimeout(this._timeout); @@ -957,7 +956,7 @@ export class DocumentView extends DocComponent(Docu onClick={this.onClickFunc} layoutKey={this.finalLayoutKey} /> {this.layoutDoc.hideAllLinks ? (null) : this.allAnchors} - {this.props.styleProvider?.(this.layoutDoc, this.props, "hideLinkButton") || (!this.isSelected() && (this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton)) || this.props.dontRegisterView ? (null) : + {this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton) || (!this.isSelected() && (this.layoutDoc.isLinkButton || this.layoutDoc.hideLinkButton)) || this.props.dontRegisterView ? (null) : }
); @@ -980,8 +979,13 @@ export class DocumentView extends DocComponent(Docu anchorPanelWidth = () => this.props.PanelWidth() || 1; anchorPanelHeight = () => this.props.PanelHeight() || 1; anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { - if (property === "backgroundColor") return props?.LayoutTemplateString ? "transparent" : this.props.styleProvider?.(doc, props, "backgroundColor"); - if (property === "hideLinkButton") return true; + switch (property.split(":")[0]) { + case StyleProp.BackgroundColor: return "transparent"; + case StyleProp.LinkBackgroundColor: return this.props.styleProvider?.(doc, props, StyleProp.BackgroundColor); + case StyleProp.HideLinkButton: return true; + case StyleProp.PointerEvents: return "none"; + case StyleProp.LinkSource: return this.props.Document; + } } @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } @@ -999,15 +1003,12 @@ export class DocumentView extends DocComponent(Docu
); @@ -1056,7 +1057,7 @@ export class DocumentView extends DocComponent(Docu } @computed get pointerEvents() { if (this.props.pointerEvents === "none") return "none"; - return this.props.styleProvider?.(this.Document, this.props, this.isSelected() ? "pointerEvents:selected" : "pointerEvents"); + return this.props.styleProvider?.(this.Document, this.props, StyleProp.PointerEvents + (this.isSelected() ? ":selected" : "")); } @undoBatch @action @@ -1080,13 +1081,13 @@ export class DocumentView extends DocComponent(Docu TraceMobx(); if (!(this.props.Document instanceof Doc)) return (null); if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null); - if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden")) return null; - return this.props.styleProvider?.(this.rootDoc, this.props, "docContents") ?? + if (this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Hidden)) return null; + return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.DocContents) ??
(Docu }}> {this.innards} {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ?
: (null)} - {this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations") || (null)} + {this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Decorations + (this.isSelected() ? ":selected" : "")) || (null)}
; } render() { - const borderRounding = this.props.styleProvider?.(this.layoutDoc, this.props, "borderRounding"); + const borderRounding = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow); const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString const highlightColor = (CurrentUserUtils.ActiveDashboard?.darkScheme ? ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] : @@ -1127,7 +1128,7 @@ export class DocumentView extends DocComponent(Docu 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}` : - this.Document.isLinkButton && !this.props.dontRegisterView && !this.props.styleProvider?.(this.layoutDoc, this.props, "hideLinkButton") ? + this.Document.isLinkButton && !this.props.dontRegisterView && !this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton) ? StrCast(this.layoutDoc._linkButtonShadow, "lightblue 0em 0em 1em") : this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index a1bb0604e..000c72e94 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -14,6 +14,7 @@ import { ScriptField } from '../../../fields/ScriptField'; import { Tooltip } from '@material-ui/core'; import { DragManager } from '../../util/DragManager'; import { GetEffectiveAcl } from '../../../fields/util'; +import { StyleProp } from '../StyleProvider'; const FontIconSchema = createSchema({ icon: "string", }); @@ -61,7 +62,7 @@ export class FontIconBox extends DocComponent( render() { const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); const color = StrCast(this.layoutDoc.color, this._foregroundColor); - const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, "backgroundColor"); + const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); const shape = StrCast(this.layoutDoc.iconShape, label ? "round" : "circle"); const icon = StrCast(this.dataDoc.icon, "user") as any; const presSize = shape === 'round' ? 25 : 30; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index dd751b802..bc2090a33 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -13,6 +13,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxBaseComponent } from '../DocComponent'; import { FieldView, FieldViewProps } from './FieldView'; import './LabelBox.scss'; +import { StyleProp } from '../StyleProvider'; const LabelSchema = createSchema({}); @@ -72,7 +73,7 @@ export class LabelBox extends ViewBoxBaseComponent this._mouseOver = false)} onMouseOver={action(() => this._mouseOver = true)} ref={this.createDropTarget} onContextMenu={this.specificContextMenu} - style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, "boxShadow") }}> + style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}>
LinkDocPreview.LinkInfo = undefined)} onPointerEnter={action(e => LinkDocPreview.LinkInfo = { addDocTab: this.props.addDocTab, - linkSrc: this.props.ContainingCollectionDoc!, + linkSrc: linkSource, linkDoc: this.rootDoc, Location: [e.clientX, e.clientY + 20] })} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu} ref={this._ref} style={{ - background: c, + background, left: `calc(${x}% - ${small ? 2.5 : 7.5}px)`, top: `calc(${y}% - ${small ? 2.5 : 7.5}px)`, transform: `scale(${anchorScale / this.props.ContentScaling()})` diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index b3fd13a77..a12a23dff 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -8,6 +8,7 @@ import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; import { Cast } from "../../../fields/Types"; +import { StyleProp } from "../StyleProvider"; type LinkDocument = makeInterface<[typeof documentSchema]>; const LinkDocument = makeInterface(documentSchema); @@ -17,7 +18,7 @@ export class LinkBox extends ViewBoxBaseComponent( public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); } render() { return
+ style={{ background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BackgroundColor) }} > e.stopPropagation()} - style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, "boxShadow") }}> + style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}>
Opt; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text @@ -1599,7 +1600,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) :
; } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 45d943bff..3b6b0259d 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -22,6 +22,7 @@ import { undoBatch } from "../../util/UndoManager"; import { EditableView } from "../EditableView"; import { DocumentManager } from "../../util/DocumentManager"; import { DocumentViewProps } from "../nodes/DocumentView"; +import { StyleProp } from "../StyleProvider"; export const presSchema = createSchema({ presentationTargetDoc: Doc, @@ -78,7 +79,7 @@ export class PresElementBox extends ViewBoxBaseComponent Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight); embedWidth = (): number => this.props.PanelWidth() - 35; styleProvider = (doc: (Doc | undefined), props: Opt, property: string): any => { - if (property === "opacity") return 1; + if (property === StyleProp.Opacity) return 1; return this.props.styleProvider?.(doc, props, property); } /** @@ -326,7 +327,7 @@ export class PresElementBox extends ViewBoxBaseComponent} {miniView ? (null) :
-- cgit v1.2.3-70-g09d2 From fafd62df0a918a14ecc90d99236e5a87918646e1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 11 Dec 2020 14:43:51 -0500 Subject: got rid of ChromeHeight and replaced with HeaderMargin in style provider. made text headers not overlap the tet itself. --- src/client/views/OverlayView.tsx | 1 - src/client/views/StyleProvider.tsx | 38 +++++---- .../views/collections/CollectionStackingView.tsx | 6 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/TreeView.tsx | 7 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 - src/client/views/nodes/DocumentView.tsx | 93 +++++++++++----------- src/client/views/nodes/LinkBox.tsx | 1 - .../views/nodes/formattedText/FormattedTextBox.tsx | 9 ++- 9 files changed, 79 insertions(+), 81 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 124da6016..ee1af8b13 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -183,7 +183,6 @@ export class OverlayView extends React.Component { return
; + const titleView = !showTitle ? (null) :
users.user.email === this.dataDoc.author)?.userColor || (this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)"), pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : undefined, }}> @@ -839,7 +786,7 @@ export class DocumentViewInternal extends DocComponent Field.toString((this.dataDoc || this.props.Document)[showTitle.split(";")[0]] as any as Field)} SetValue={undoBatch((value) => showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true)} /> -
); +
; return this.props.hideTitle || (!showTitle && !showCaption) ? this.contents :
@@ -878,29 +825,21 @@ export class DocumentViewInternal extends DocComponent !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))} - onPointerLeave={action(e => { - let entered = false; - for (let child = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); !entered && child; child = child.parentElement) { - entered = entered || child === this.ContentDiv; - } - !entered && Doc.UnBrushDoc(this.props.Document); - })} + onPointerEnter={e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document)} + onPointerLeave={e => hasDescendantTarget(e.nativeEvent.x, e.nativeEvent.y, this.ContentDiv) && Doc.UnBrushDoc(this.props.Document)} style={{ borderRadius: this.borderRounding, pointerEvents: this.pointerEvents, outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px", border: highlighting && this.borderRounding && highlightStyle === "dashed" ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined, boxShadow, - }} - > + }}> {PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
; } @@ -915,32 +854,23 @@ export class DocumentView extends React.Component { @observable LinkBeingCreated: Opt; // see DocumentLinksButton for explanation of how this works @observable public docView: DocumentViewInternal | undefined | null; + get Document() { return this.props.Document; } + get topMost() { return this.props.renderDepth === 0; } get rootDoc() { return this.docView?.rootDoc || this.Document; } get dataDoc() { return this.docView?.dataDoc || this.Document; } get finalLayoutKey() { return this.docView?.finalLayoutKey || "layout"; } get ContentDiv() { return this.docView?.ContentDiv; } get allLinks() { return this.docView?.allLinks || []; } get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; } - toggleFollowLink = (location: Opt, zoom: boolean, setPushpin: boolean) => this.docView?.toggleFollowLink(location, zoom, setPushpin); - toggleNativeDimensions = () => this.docView?.toggleNativeDimensions(); - contentsActive = () => this.docView?.contentsActive(); - get Document() { return this.props.Document; } - get topMost() { return this.props.renderDepth === 0; } @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } - @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); } @computed get nativeScaling() { - const nativeW = this.nativeWidth; - const nativeH = this.nativeHeight; - let scaling = 1; - if (nativeW && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / nativeH > this.props.PanelWidth() / nativeW)) { - scaling = this.props.PanelWidth() / nativeW; // width-limited or fitWidth - } else if (nativeW && nativeH) { - scaling = this.props.PanelHeight() / nativeH; // height-limited + if (this.nativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.nativeHeight > this.props.PanelWidth() / this.nativeWidth)) { + return this.props.PanelWidth() / this.nativeWidth; // width-limited or fitWidth } - return scaling; + return this.nativeWidth && this.nativeHeight ? this.props.PanelHeight() / this.nativeHeight : 1; // height-limited or unscaled } @computed get panelWidth() { return this.nativeWidth ? this.nativeWidth * this.nativeScaling : this.props.PanelWidth(); } @@ -949,16 +879,17 @@ export class DocumentView extends React.Component { if (this.props.Document._fitWidth) { return Math.min(this.props.PanelHeight(), NumCast(this.props.Document.scrollHeight, this.props.PanelHeight())); } - else return Math.min(this.props.PanelHeight(), this.nativeHeight * this.nativeScaling); + return Math.min(this.props.PanelHeight(), this.nativeHeight * this.nativeScaling); } return this.props.PanelHeight(); } - @computed get Xshift() { return this.nativeWidth ? (this.props.PanelWidth() - this.nativeWidth * this.nativeScaling) / 2 : 0; } @computed get YShift() { return this.nativeWidth && this.nativeHeight && Math.abs(this.Xshift) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.nativeScaling) / 2 : 0; } @computed get centeringX() { return this.props.dontCenter?.includes("x") ? 0 : this.Xshift; } @computed get centeringY() { return this.props.Document._fitWidth || this.props.dontCenter?.includes("y") ? 0 : this.YShift; } + toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight()); + contentsActive = () => this.docView?.contentsActive(); getBounds = () => { if (!this.docView || !this.docView.ContentDiv || this.docView.props.renderDepth === 0 || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts index 20e14a68d..e7cc89697 100644 --- a/src/pen-gestures/GestureUtils.ts +++ b/src/pen-gestures/GestureUtils.ts @@ -8,7 +8,6 @@ export namespace GestureUtils { readonly gesture: Gestures, readonly points: PointData[], readonly bounds: Rect, - readonly callbackFn?: Function, readonly text?: any ) { } } -- cgit v1.2.3-70-g09d2 From 5bbc8dfe46a7bb2a9e1b09a4d67ed68a7533ab78 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 16 Dec 2020 22:35:44 -0500 Subject: cleaned up removing frame animation fields --- src/client/util/InteractionUtils.tsx | 9 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 90 ++++++---------------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- 3 files changed, 26 insertions(+), 75 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index f58277717..01d00db30 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -364,12 +364,9 @@ export namespace InteractionUtils { export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean { switch (type) { // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2 - case PENTYPE: - return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0); - case ERASERTYPE: - return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON); - default: - return e.pointerType === type; + case PENTYPE: return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0); + case ERASERTYPE: return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON); + default: return e.pointerType === type; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 954934dab..d2b3ed53e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -108,6 +108,7 @@ export class CollectionFreeFormView extends CollectionSubView newBox[field]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[`${field}-indexed`]); + CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field]); delete newBox.activeFrame; - newBox.x = x; - newBox.y = y; - newBox._width = w; - newBox._height = h; + CollectionFreeFormDocumentView.animFields.forEach((field, i) => field !== opacity && (newBox[field] = vals[i])); } } if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) { @@ -311,13 +298,9 @@ export class CollectionFreeFormView extends CollectionSubView { const [xp, yp] = this.getTransform().transformPoint(de.x, de.y); - if (this.isAnnotationOverlay !== true && de.complete.linkDragData) { - return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); - } else if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de)) { - return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp); - } else if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) { - return true; - } + if (this.isAnnotationOverlay !== true && de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); + if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de)) return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp); + if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, xp, yp); return false; } @@ -402,10 +385,10 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout); if (this.props.Document._useClusters) { - this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); + this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); const preferredInd = NumCast(doc.cluster); doc.cluster = -1; - this._clusterSets.map((set, i) => set.map(member => { + this._clusterSets.forEach((set, i) => set.forEach(member => { if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { doc.cluster = i; } @@ -413,7 +396,7 @@ export class CollectionFreeFormView extends CollectionSubView preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) { doc.cluster = preferredInd; } - this._clusterSets.map((set, i) => { + this._clusterSets.forEach((set, i) => { if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) { doc.cluster = i; } @@ -434,7 +417,7 @@ export class CollectionFreeFormView extends CollectionSubView doc && this.updateCluster(doc), 0); + setTimeout(() => doc && this.updateCluster(doc)); } else { // choose a cluster color from a palette const colors = ["#da42429e", "#31ea318c", "rgba(197, 87, 20, 0.55)", "#4a7ae2c4", "rgba(216, 9, 255, 0.5)", "#ff7601", "#1dffff", "yellow", "rgba(27, 130, 49, 0.55)", "rgba(0, 0, 0, 0.268)"]; @@ -455,13 +438,6 @@ export class CollectionFreeFormView extends CollectionSubView FieldValue(sd.color) as string); - sets.forEach((st: string, i: number) => { - const words = st.split(","); - words.forEach(word => { - this._wordPalette.set(word, colors[i]); - }); - }); + sets.forEach((st: string, i: number) => st.split(",").forEach(word => this._wordPalette.set(word, colors[i]))); } const inks = this.getActiveDocuments().filter(doc => { if (doc.type === "ink") { @@ -627,25 +592,20 @@ export class CollectionFreeFormView extends CollectionSubView { - if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) return; - - document.removeEventListener("pointermove", this.onPointerMove); - document.removeEventListener("pointerup", this.onPointerUp); - this.removeMoveListeners(); - this.removeEndListeners(); + if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) { + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + this.removeMoveListeners(); + this.removeEndListeners(); + } } onClick = (e: React.MouseEvent) => { if (this.layoutDoc.targetScale && (Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) { - if (Date.now() - this._lastTap < 300) { - runInAction(() => { - DocumentLinksButton.StartLink = undefined; - DocumentLinksButton.StartLinkView = undefined; - }); - const docpt = this.getTransform().transformPoint(e.clientX, e.clientY); - this.scaleAtPt(docpt, 1); + if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a double click + runInAction(() => DocumentLinksButton.StartLink = DocumentLinksButton.StartLinkView = undefined); + this.scaleAtPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1); e.stopPropagation(); e.preventDefault(); } @@ -655,9 +615,6 @@ export class CollectionFreeFormView extends CollectionSubView { - // bcz: theres should be a better way of doing these than referencing these static instances directly - MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2 - const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true); this._lastX = e.clientX; @@ -963,7 +920,6 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; @@ -1227,7 +1182,6 @@ export class CollectionFreeFormView extends CollectionSubView(Document) { - static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"]; // fields that are configured to be animatable using animation frames + public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"]; // fields that are configured to be animatable using animation frames @observable _animPos: number[] | undefined = undefined; @observable _contentView: DocumentView | undefined | null; random(min: number, max: number) { // min should not be equal to max -- cgit v1.2.3-70-g09d2 From b19ccabeea7558e9991571063cc473f381af63fc Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 16 Dec 2020 23:00:15 -0500 Subject: from last --- src/client/views/MainView.tsx | 3 +-- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 10 ++-------- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0390bdf52..dbb449cbe 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -501,7 +501,6 @@ export class MainView extends React.Component { ; } - select = (ctrlPressed: boolean) => { }; @computed get search() { TraceMobx(); @@ -512,7 +511,7 @@ export class MainView extends React.Component { dropAction="move" isSelected={returnTrue} active={returnTrue} - select={this.select} + select={returnTrue} addDocument={undefined} addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d2b3ed53e..f934fcd92 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -183,7 +183,7 @@ export class CollectionFreeFormView extends CollectionSubView delete newBox[`${field}-indexed`]); CollectionFreeFormDocumentView.animFields.forEach(field => delete newBox[field]); delete newBox.activeFrame; - CollectionFreeFormDocumentView.animFields.forEach((field, i) => field !== opacity && (newBox[field] = vals[i])); + CollectionFreeFormDocumentView.animFields.forEach((field, i) => field !== "opacity" && (newBox[field] = vals[i])); } } if (this.Document._currentFrame !== undefined && !this.props.isAnnotationOverlay) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 0823fc83a..bfb6e8fc8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -37,12 +37,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { if (doc.appearFrame === undefined) doc.appearFrame = currTimecode; if (!doc["opacity-indexed"]) { // opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in - const olist = new List(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1)); - doc["opacity-indexed"] = olist; + doc["opacity-indexed"] = new List(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1)); } CollectionFreeFormDocumentView.animFields.forEach(val => doc[val] = ComputedField.MakeInterpolated(val, "activeFrame", doc, currTimecode)); doc.activeFrame = ComputedField.MakeFunction("self.context?._currentFrame||0"); -- cgit v1.2.3-70-g09d2