diff options
Diffstat (limited to 'src')
43 files changed, 373 insertions, 314 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index b7e6b83a0..8054245f5 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -118,7 +118,7 @@ export namespace Utils { } const isTransparentFunctionHack = "isTransparent(__value__)"; - const noRecursionHack = "__noRecursion"; + export const noRecursionHack = "__noRecursion"; export function IsRecursiveFilter(val: string) { return !val.includes(noRecursionHack); } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 007262f9c..ec856e748 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -729,10 +729,20 @@ export namespace Docs { } export function PdfDocument(url: string, options: DocumentOptions = {}) { + const width = options._width || undefined; + const height = options._height || undefined; + const nwid = options._nativeWidth || undefined; + const nhght = options._nativeHeight || undefined; + if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width); return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(url), options); } export function WebDocument(url: string, options: DocumentOptions = {}) { + const width = options._width || undefined; + const height = options._height || undefined; + const nwid = options._nativeWidth || undefined; + const nhght = options._nativeHeight || undefined; + if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width); return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options); } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 66799d62f..bba7616e8 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -420,7 +420,7 @@ export class CurrentUserUtils { ((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0; } if (doc.emptySlide === undefined) { - const textDoc = Docs.Create.TreeDocument([], { title: "Slide", _viewType: CollectionViewType.Tree, _fontSize: "20px", treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "transparent", system: true, cloneFieldFilter: new List<string>(["system"]) }); + const textDoc = Docs.Create.TreeDocument([], { title: "Slide", _viewType: CollectionViewType.Tree, _fontSize: "20px", _autoHeight: true, treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, backgroundColor: "transparent", system: true, cloneFieldFilter: new List<string>(["system"]) }); Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text'); FormattedTextBox.SelectOnLoad = textDoc[Id]; doc.emptySlide = textDoc; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index dbcc49f3d..0cfaebbf2 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,10 +1,10 @@ import { action, observable, ObservableMap } from "mobx"; import { computedFn } from "mobx-utils"; import { Doc, Opt } from "../../fields/Doc"; +import { DocumentType } from "../documents/DocumentTypes"; import { CollectionSchemaView } from "../views/collections/collectionSchema/CollectionSchemaView"; import { CollectionViewType } from "../views/collections/CollectionView"; import { DocumentView } from "../views/nodes/DocumentView"; -import { DocumentType } from "../documents/DocumentTypes"; export namespace SelectionManager { diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx index f519f9ef0..8f3b7c2cd 100644 --- a/src/client/views/AudioWaveform.tsx +++ b/src/client/views/AudioWaveform.tsx @@ -67,7 +67,7 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { ); } ); - }; + } @action createTrimBuckets = () => { @@ -84,7 +84,7 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { (NumCast(this.props.layoutDoc.clipEnd) / this.props.duration) * 100 ); return audioBuckets.slice(start, end); - }; + } render() { const audioBuckets = Cast( @@ -110,16 +110,16 @@ export class AudioWaveform extends React.Component<AudioWaveformProps> { progressColor={Colors.MEDIUM_BLUE} /> ) : ( - <Waveform - color={Colors.MEDIUM_BLUE} - height={this._waveHeight} - barWidth={0.1} - pos={this.props.duration} - duration={this.props.duration} - peaks={this.createTrimBuckets()} - progressColor={Colors.MEDIUM_BLUE} - /> - )} + <Waveform + color={Colors.MEDIUM_BLUE} + height={this._waveHeight} + barWidth={0.1} + pos={this.props.duration} + duration={this.props.duration} + peaks={this.createTrimBuckets()} + progressColor={Colors.MEDIUM_BLUE} + /> + )} </div> ); } diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d9cc29bed..33dff9da5 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,17 +1,17 @@ -import { Doc, Opt, DataSym, AclReadonly, AclAugment, AclPrivate, AclEdit, AclSym, DocListCast, AclAdmin, AclSelfEdit } from '../../fields/Doc'; -import { Touchable } from './Touchable'; -import { computed, action, observable } from 'mobx'; -import { Cast, BoolCast, ScriptCast } from '../../fields/Types'; +import { action, computed, observable } from 'mobx'; +import { DateField } from '../../fields/DateField'; +import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, Opt } from '../../fields/Doc'; import { InkTool } from '../../fields/InkField'; -import { InteractionUtils } from '../util/InteractionUtils'; import { List } from '../../fields/List'; -import { DateField } from '../../fields/DateField'; import { ScriptField } from '../../fields/ScriptField'; -import { GetEffectiveAcl, SharingPermissions, distributeAcls, denormalizeEmail, inheritParentAcls } from '../../fields/util'; -import { CurrentUserUtils } from '../util/CurrentUserUtils'; -import { DocUtils } from '../documents/Documents'; +import { Cast, ScriptCast } from '../../fields/Types'; +import { denormalizeEmail, distributeAcls, GetEffectiveAcl, inheritParentAcls, SharingPermissions } from '../../fields/util'; import { returnFalse } from '../../Utils'; +import { DocUtils } from '../documents/Documents'; +import { CurrentUserUtils } from '../util/CurrentUserUtils'; +import { InteractionUtils } from '../util/InteractionUtils'; import { UndoManager } from '../util/UndoManager'; +import { Touchable } from './Touchable'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) @@ -107,6 +107,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T // key where data is stored @computed get fieldKey() { return this.props.fieldKey; } + isAnyChildContentActive = () => this._isAnyChildContentActive; lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result; @@ -229,10 +230,6 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T } whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive)); - isContentActive = (outsideReaction?: boolean) => (CurrentUserUtils.SelectedTool !== InkTool.None || - (this.props.isContentActive?.() || this.props.Document.forceActive || - this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || - this.props.rootSelected(outsideReaction)) ? true : false) } return Component; }
\ No newline at end of file diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 24f9501ce..b401a7f03 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -31,7 +31,7 @@ export class GestureOverlay extends Touchable { @observable public InkShape: string = ""; @observable public SavedColor?: string; - @observable public SavedWidth?: string; + @observable public SavedWidth?: number; @observable public Tool: ToolglassTools = ToolglassTools.None; @observable private _thumbX?: number; @@ -953,7 +953,7 @@ Scripting.addGlobal(function setPen(width: any, color: any, fill: any, arrowStar Scripting.addGlobal(function resetPen() { runInAction(() => { SetActiveInkColor(GestureOverlay.Instance.SavedColor ?? "rgb(0, 0, 0)"); - SetActiveInkWidth(GestureOverlay.Instance.SavedWidth ?? "2"); + SetActiveInkWidth(GestureOverlay.Instance.SavedWidth?.toString() ?? "2"); }); }, "resets the pen tool"); Scripting.addGlobal(function createText(text: any, x: any, y: any) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index c95e56584..f082ba2c0 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -475,6 +475,7 @@ export class MainView extends React.Component { bringToFront={emptyFunction} select={emptyFunction} isContentActive={returnFalse} + isAnyChildContentActive={returnFalse} isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 1897572f8..eee365ed8 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -77,7 +77,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> { e.stopPropagation(); const sourceAnchorCreator = () => { const annoDoc = this.highlight("rgba(173, 216, 230, 0.75)", true); // hyperlink color - this.props.addDocument(annoDoc); + annoDoc && this.props.addDocument(annoDoc); return annoDoc; }; const targetCreator = (annotationOn: Doc | undefined) => { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 470ae7c77..fa35081bc 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -102,7 +102,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps if (docColor) return docColor; const backColor = backgroundCol(); if (!backColor) return undefined; - return lightOrDark(backColor) + return lightOrDark(backColor); case StyleProp.Hidden: return BoolCast(doc?._hidden); case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + "borderRounding"], doc?._viewType === CollectionViewType.Pile ? "50%" : ""); case StyleProp.TitleHeight: return 15; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 5491a81e6..ff3f92364 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -141,6 +141,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> { onCheckedClick={this.scriptField} onChildClick={this.scriptField} dropAction={undefined} + isAnyChildContentActive={returnFalse} isContentActive={returnTrue} bringToFront={emptyFunction} focus={emptyFunction} diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 77e5132fc..cbfe47338 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -108,6 +108,7 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { bringToFront={emptyFunction} select={emptyFunction} isContentActive={returnFalse} + isAnyChildContentActive={returnFalse} isSelected={returnFalse} docViewPath={returnEmptyDoclist} moveDocument={returnFalse} @@ -120,7 +121,7 @@ export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> { PanelWidth={() => 100} PanelHeight={() => 35} renderDepth={0} - focus={() => undefined} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 1efea96be..6bdeaf722 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -18,6 +18,7 @@ import { SnappingManager } from "../../util/SnappingManager"; import { Transform } from "../../util/Transform"; import { undoBatch } from "../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/global/globalCssVariables.scss'; +import { SchemaTable } from "../collections/collectionSchema/SchemaTable"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import '../DocumentDecorations.scss'; @@ -25,7 +26,6 @@ import { DocumentView } from "../nodes/DocumentView"; import { DefaultStyleProvider } from "../StyleProvider"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { SchemaTable } from "../collections/collectionSchema/SchemaTable"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 export enum ColumnType { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 51e05e278..d98d966d8 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -141,25 +141,26 @@ export class CollectionStackedTimeline extends CollectionSubView< } componentWillUnmount() { document.removeEventListener("keydown", this.keyEvents, true); - if (CollectionStackedTimeline.SelectingRegion === this) + if (CollectionStackedTimeline.SelectingRegion === this) { runInAction( () => (CollectionStackedTimeline.SelectingRegion = undefined) ); + } } anchorStart = (anchor: Doc) => - NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag])); + NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag])) anchorEnd = (anchor: Doc, val: any = null) => { const endVal = NumCast(anchor[this.props.endTag], val); return NumCast( anchor._timecodeToHide, endVal === undefined ? null : endVal ); - }; + } toTimeline = (screen_delta: number, width: number) => { return Math.max( this.trimStart, - Math.min(this.trimEnd, (screen_delta / width) * this.props.trimDuration + this.trimStart)) + Math.min(this.trimEnd, (screen_delta / width) * this.props.trimDuration + this.trimStart)); } rangeClickScript = () => CollectionStackedTimeline.RangeScript; @@ -190,7 +191,7 @@ export class CollectionStackedTimeline extends CollectionSubView< } } } - }; + } getLinkData(l: Doc) { let la1 = l.anchor1 as Doc; @@ -279,12 +280,12 @@ export class CollectionStackedTimeline extends CollectionSubView< this.props.setTime(((clientX - rect.x) / rect.width) * this.duration) : this.props.setTime(((clientX - rect.x) / rect.width) * this.props.trimDuration + this.trimStart) - ) + ); } ); } - }; + } @action trimLeft = (e: React.PointerEvent): void => { @@ -312,7 +313,7 @@ export class CollectionStackedTimeline extends CollectionSubView< } }) ); - }; + } @action trimRight = (e: React.PointerEvent): void => { @@ -340,7 +341,7 @@ export class CollectionStackedTimeline extends CollectionSubView< } }) ); - }; + } @undoBatch @action @@ -395,12 +396,13 @@ export class CollectionStackedTimeline extends CollectionSubView< } } return { select: true }; - }; + } @action clickAnchor = (anchorDoc: Doc, clientX: number) => { - if (anchorDoc.isLinkButton) + if (anchorDoc.isLinkButton) { LinkManager.FollowLink(undefined, anchorDoc, this.props, false); + } const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.25; const endTime = this.anchorEnd(anchorDoc); if ( @@ -415,14 +417,15 @@ export class CollectionStackedTimeline extends CollectionSubView< this.props.setTime(this.toTimeline(clientX - rect.x, rect.width)); } } else { - if (this.layoutDoc.autoPlayAnchors) + if (this.layoutDoc.autoPlayAnchors) { this.props.playFrom(seekTimeInSeconds, endTime); + } else { this.props.setTime(seekTimeInSeconds); } } return { select: true }; - }; + } // makes sure no anchors overlaps each other by setting the correct position and width getLevel = ( @@ -456,17 +459,17 @@ export class CollectionStackedTimeline extends CollectionSubView< placed.push({ anchorStartTime: x1, anchorEndTime: x2, level }); return level; - }; + } dictationHeightPercent = 50; dictationHeight = () => - (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100; + (this.props.PanelHeight() * (100 - this.dictationHeightPercent)) / 100 timelineContentHeight = () => - (this.props.PanelHeight() * this.dictationHeightPercent) / 100; + (this.props.PanelHeight() * this.dictationHeightPercent) / 100 dictationScreenToLocalTransform = () => this.props .ScreenToLocalTransform() - .translate(0, -this.timelineContentHeight()); + .translate(0, -this.timelineContentHeight()) @computed get renderDictation() { const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null); return !dictation ? null : ( @@ -552,7 +555,7 @@ export class CollectionStackedTimeline extends CollectionSubView< const top = (d.level / maxLevel) * this.timelineContentHeight(); const timespan = end - start; const width = (timespan / this.props.trimDuration) * timelineContentWidth; - const height = this.timelineContentHeight() / maxLevel + const height = this.timelineContentHeight() / maxLevel; return this.props.Document.hideAnchors ? null : ( <div className={"collectionStackedTimeline-marker-timeline"} @@ -723,17 +726,19 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> const changeAnchor = (anchor: Doc, left: boolean, time: number) => { const timelineOnly = Cast(anchor[this.props.startTag], "number", null) !== undefined; - if (timelineOnly) + if (timelineOnly) { Doc.SetInPlace( anchor, left ? this.props.startTag : this.props.endTag, time, true ); - else + } + else { left ? (anchor._timecodeToShow = time) : (anchor._timecodeToHide = time); + } return false; }; setupMoveUpEvents( @@ -746,13 +751,13 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> }, emptyFunction ); - }; + } @action computeTitle = () => { const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart; const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart; - return `#${formatTime(start)}-${formatTime(end)}` + return `#${formatTime(start)}-${formatTime(end)}`; } renderInner = computedFn(function ( @@ -824,21 +829,21 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> {inner.view} {!inner.anchor.view || !SelectionManager.IsSelected(inner.anchor.view) ? null : ( - <> - <div - key="left" - className="collectionStackedTimeline-left-resizer" - onPointerDown={(e) => this.onAnchorDown(e, this.props.mark, true)} - /> - <div - key="right" - className="collectionStackedTimeline-resizer" - onPointerDown={(e) => - this.onAnchorDown(e, this.props.mark, false) - } - /> - </> - )} + <> + <div + key="left" + className="collectionStackedTimeline-left-resizer" + onPointerDown={(e) => this.onAnchorDown(e, this.props.mark, true)} + /> + <div + key="right" + className="collectionStackedTimeline-resizer" + onPointerDown={(e) => + this.onAnchorDown(e, this.props.mark, false) + } + /> + </> + )} </> ); } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index b9bc83d49..4fedda1bd 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -144,7 +144,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument, () => this.layoutDoc._columnHeaders = new List() ); this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, - () => this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), + autoHeight => autoHeight && this.props.setHeight(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace("px", "")))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0))))); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 1f4c35daa..b70df93da 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -23,6 +23,7 @@ import ReactLoading from 'react-loading'; export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt<CollectionView>; SetSubView?: (subView: any) => void; + isAnyChildContentActive: () => boolean; } export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) { @@ -490,7 +491,5 @@ import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTex import { CollectionView, CollectionViewType, CollectionViewProps } from "./CollectionView"; import { SelectionManager } from "../../util/SelectionManager"; import { OverlayView } from "../OverlayView"; -import { Hypothesis } from "../../util/HypothesisUtils"; import { GetEffectiveAcl, TraceMobx } from "../../../fields/util"; -import { FilterBox } from "../nodes/FilterBox"; diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss index ec461ab94..d370d21ab 100644 --- a/src/client/views/collections/CollectionTreeView.scss +++ b/src/client/views/collections/CollectionTreeView.scss @@ -1,5 +1,8 @@ @import "../global/globalCssVariables"; +.collectionTreeView-container { + transform-origin: top left; +} .collectionTreeView-dropTarget { border-width: $COLLECTION_BORDER_WIDTH; border-color: transparent; @@ -35,6 +38,11 @@ width: max-content; } + .no-indent-outline { + padding-left: 0; + width: 100%; + } + .editableView-container { font-weight: bold; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index a78034dca..89d42439e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,15 +1,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, reaction, IReactionDisposer, observable } from "mobx"; +import { action, computed, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { DataSym, Doc, DocListCast, HeightSym, Opt, WidthSym, StrListCast } from '../../../fields/Doc'; +import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; -import { List } from '../../../fields/List'; +import { InkTool } from '../../../fields/InkField'; import { Document, listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; import { returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from "../../util/DragManager"; import { SelectionManager } from '../../util/SelectionManager'; @@ -25,9 +26,6 @@ import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; import { TreeView } from "./TreeView"; import React = require("react"); -import { InkTool } from '../../../fields/InkField'; -import { CurrentUserUtils } from '../../util/CurrentUserUtils'; -import { CollectionView, CollectionViewType } from './CollectionView'; const _global = (window /* browser */ || global /* node */) as any; export type collectionTreeViewProps = { @@ -63,7 +61,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll this.props.isSelected(outsideReaction) || this._isAnyChildContentActive || this.props.rootSelected(outsideReaction)) ? true : false) + isDisposing = false; componentWillUnmount() { + this.isDisposing = true; super.componentWillUnmount(); this.treedropDisposer?.(); Object.values(this._disposers).forEach(disposer => disposer?.()); @@ -78,15 +78,16 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll refList: Set<any> = new Set(); observer: any; computeHeight = () => { - const hgt = this.paddingTop() + 26/* bcz: ugh: title bar height hack ... get ref and compute instead */ + - Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0); - this.props.setHeight(hgt); + if (this.isDisposing) return; + const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), this.paddingTop() + this.paddingBot()); + this.layoutDoc._autoHeightMargins = bodyHeight; + this.props.setHeight(this.documentTitleHeight() + bodyHeight); } unobserveHeight = (ref: any) => { this.refList.delete(ref); this.rootDoc.autoHeight && this.computeHeight(); } - observerHeight = (ref: any) => { + observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); this.observer = new _global.ResizeObserver(action((entries: any) => { @@ -201,6 +202,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll NativeWidth={this.documentTitleWidth} NativeHeight={this.documentTitleHeight} focus={this.props.focus} + treeViewDoc={this.props.Document} ScreenToLocalTransform={this.titleTransform} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} @@ -253,14 +255,14 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll true, this.whenChildContentsActiveChanged, this.props.dontRegisterView || Cast(this.props.Document.childDontRegisterViews, "boolean", null), - this.observerHeight, + this.observeHeight, this.unobserveHeight, this.childContextMenuItems() ); } @computed get titleBar() { const hideTitle = this.props.treeViewHideTitle || this.doc.treeViewHideTitle; - return hideTitle ? (null) : (this.doc.treeViewType === "outline" ? this.documentTitle : this.editableTitle)(this.treeChildren); + return hideTitle ? (null) : (this.outlineMode ? this.documentTitle : this.editableTitle)(this.treeChildren); } @computed get renderClearButton() { @@ -270,30 +272,42 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll </button> </div >; } + @computed get nativeWidth() { return Doc.NativeWidth(this.Document, undefined, true); } + @computed get nativeHeight() { return Doc.NativeHeight(this.Document, undefined, true); } + @computed get contentScaling() { + const nw = this.nativeWidth; + const nh = this.nativeHeight; + const hscale = nh ? this.props.PanelHeight() / nh : 1; + const wscale = nw ? this.props.PanelWidth() / nw : 1; + return wscale < hscale ? wscale : hscale; + } paddingX = () => NumCast(this.doc._xPadding, 15); paddingTop = () => NumCast(this.doc._yPadding, 20); + paddingBot = () => NumCast(this.doc._yPadding, 20); documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth()); - documentTitleHeight = () => Math.min(this.layoutDoc?.[HeightSym](), (StrCast(this.layoutDoc?._fontSize) ? Number(StrCast(this.layoutDoc?._fontSize, "32px").replace("px", "")) : NumCast(this.layoutDoc?._fontSize)) * 2); + documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins); titleTransform = () => this.props.ScreenToLocalTransform().translate(-NumCast(this.doc._xPadding, 10), -NumCast(this.doc._yPadding, 20)); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); - panelWidth = () => this.props.PanelWidth() - 2 * this.paddingX(); + panelWidth = () => (this.props.PanelWidth() - 2 * this.paddingX()) * (this.props.scaling?.() || 1); render() { TraceMobx(); const background = () => this.props.styleProvider?.(this.doc, this.props, StyleProp.BackgroundColor); const pointerEvents = () => !this.props.isContentActive() && !SnappingManager.GetIsDragging() ? "none" : undefined; return !(this.doc instanceof Doc) || !this.treeChildren ? (null) : - <div className="collectionTreeView-container" onContextMenu={this.onContextMenu}> + <div className="collectionTreeView-container" + style={this.outlineMode ? { transform: `scale(${this.contentScaling})`, width: `calc(${100 / this.contentScaling}%)` } : {}} + onContextMenu={this.onContextMenu}> <div className="collectionTreeView-dropTarget" - style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} + style={{ background: background(), paddingLeft: `${this.paddingX()}px`, paddingRight: `${this.paddingX()}px`, paddingBottom: `${this.paddingBot()}px`, paddingTop: `${this.paddingTop()}px`, pointerEvents: pointerEvents() }} onWheel={e => e.stopPropagation()} onDrop={this.onTreeDrop} ref={this.createTreeDropTarget}> {this.titleBar} {this.renderClearButton} - <ul className="no-indent"> + <ul className={`no-indent${this.outlineMode ? "-outline" : ""}`} > {this.treeViewElements} </ul> </div > diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index a821aeeea..229e93b9e 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -37,6 +37,7 @@ import { CollectionTreeView } from "./CollectionTreeView"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import './CollectionView.scss'; import { returnEmptyString } from '../../../Utils'; +import { InkTool } from '../../../fields/InkField'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); @@ -119,7 +120,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />; - this.isContentActive(); + //this.isContentActive(); } screenToLocalTransform = () => this.props.renderDepth ? this.props.ScreenToLocalTransform() : this.props.ScreenToLocalTransform().scale(this.props.PanelWidth() / this.bodyPanelWidth()); @@ -253,6 +254,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab @observable _subView: any = undefined; + isContentActive = (outsideReaction?: boolean) => { + return this.props.isContentActive() ? true : false; + } render() { TraceMobx(); const props: SubCollectionViewProps = { @@ -262,6 +266,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab moveDocument: this.moveDocument, removeDocument: this.removeDocument, isContentActive: this.isContentActive, + isAnyChildContentActive: this.isAnyChildContentActive, + whenChildContentsActiveChanged: this.whenChildContentsActiveChanged, PanelWidth: this.bodyPanelWidth, PanelHeight: this.props.PanelHeight, ScreenToLocalTransform: this.screenToLocalTransform, diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f80a2d8b5..28b074d35 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -490,7 +490,8 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> { 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 setHeight={returnFalse} - isContentActive={returnTrue} + isContentActive={returnFalse} + isAnyChildContentActive={returnFalse} select={emptyFunction} dropAction={undefined} isSelected={returnFalse} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 3ee9dbf59..86fd21677 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, simulateMouseClick, Utils, returnOne } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; @@ -296,7 +296,7 @@ export class TreeView extends React.Component<TreeViewProps> { const aspect = Doc.NativeAspect(layoutDoc); if (layoutDoc._fitWidth) return Math.min(this.props.panelWidth() - treeBulletWidth(), layoutDoc[WidthSym]()); if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.panelWidth() - treeBulletWidth())); - return Math.min(this.props.panelWidth() - treeBulletWidth(), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]()); + return Math.min((this.props.panelWidth() - treeBulletWidth()) / (this.props.treeView.props.scaling?.() || 1), Doc.NativeWidth(layoutDoc) ? layoutDoc[WidthSym]() : this.layoutDoc[WidthSym]()); } docHeight = () => { const layoutDoc = this.layoutDoc; @@ -365,7 +365,7 @@ export class TreeView extends React.Component<TreeViewProps> { return rows; } - rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.props.panelWidth() - treeBulletWidth()); + rtfWidth = () => Math.min(this.layoutDoc?.[WidthSym](), (this.props.panelWidth() - treeBulletWidth())) / (this.props.treeView.props.scaling?.() || 1); rtfHeight = () => this.rtfWidth() <= this.layoutDoc?.[WidthSym]() ? Math.min(this.layoutDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT; rtfOutlineHeight = () => Math.max(this.layoutDoc?.[HeightSym](), treeBulletWidth()); expandPanelHeight = () => { @@ -544,7 +544,7 @@ export class TreeView extends React.Component<TreeViewProps> { switch (property.split(":")[0]) { case StyleProp.Opacity: return this.props.treeView.outlineMode ? undefined : 1; case StyleProp.BackgroundColor: return this.selected ? "#7089bb" : StrCast(doc._backgroundColor, StrCast(doc.backgroundColor)); - case StyleProp.DocContents: return testDocProps(props) && !props?.treeViewDoc ? (null) : + case StyleProp.DocContents: return this.props.treeView.outlineMode ? (null) : <div className="treeView-label" style={{ // just render a title for a tree view label (identified by treeViewDoc being set in 'props') maxWidth: props?.PanelWidth() || undefined, background: props?.styleProvider?.(doc, props, StyleProp.BackgroundColor), @@ -646,6 +646,7 @@ export class TreeView extends React.Component<TreeViewProps> { searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={this.props.treeView.props.Document} + ContentScaling={returnOne} />; const buttons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : "")); @@ -702,10 +703,12 @@ export class TreeView extends React.Component<TreeViewProps> { hideDecorationTitle={this.props.treeView.outlineMode} hideResizeHandles={this.props.treeView.outlineMode} focus={this.refocus} + ContentScaling={returnOne} hideLinkButton={BoolCast(this.props.treeView.props.Document.childHideLinkButton)} dontRegisterView={BoolCast(this.props.treeView.props.Document.childDontRegisterViews, this.props.dontRegisterView)} ScreenToLocalTransform={this.docTransform} renderDepth={this.props.renderDepth + 1} + treeViewDoc={this.props.treeView?.props.Document} rootSelected={returnTrue} layerProvider={returnTrue} docViewPath={this.props.treeView.props.docViewPath} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 59891b7a1..16258404d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -2,15 +2,15 @@ import { action, computed, IReactionDisposer, observable, reaction } from "mobx" import { observer } from "mobx-react"; import { Doc } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; +import { List } from "../../../../fields/List"; import { NumCast, StrCast } from "../../../../fields/Types"; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { DocumentType } from "../../../documents/DocumentTypes"; +import { LinkManager } from "../../../util/LinkManager"; import { SnappingManager } from "../../../util/SnappingManager"; import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); -import { LinkManager } from "../../../util/LinkManager"; -import { List } from "../../../fields/List"; export interface CollectionFreeFormLinkViewProps { @@ -177,11 +177,11 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo if (!this.renderData) return (null); const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; LinkManager.currentLink = this.props.LinkDocs[0]; - const linkRelationship = LinkManager.currentLink?.linkRelationship; //get string representing relationship + const linkRelationship = StrCast(LinkManager.currentLink?.linkRelationship); //get string representing relationship const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List<string>; const linkColorList = Doc.UserDoc().linkColorList as List<string>; //access stroke color using index of the relationship in the color list (default black) - const strokeColor = linkRelationshipList.indexOf(linkRelationship) == -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)]; + const strokeColor = linkRelationshipList.indexOf(linkRelationship) === -1 ? "black" : linkColorList[linkRelationshipList.indexOf(linkRelationship)]; return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<> <path className="collectionfreeformlinkview-linkLine" style={{ opacity: this._opacity, strokeDasharray: "2 2", stroke: strokeColor }} d={`M ${pt1[0]} ${pt1[1]} C ${pt1[0] + pt1norm[0]} ${pt1[1] + pt1norm[1]}, ${pt2[0] + pt2norm[0]} ${pt2[1] + pt2norm[1]}, ${pt2[0]} ${pt2[1]}`} /> diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 985d162f9..1c54467c5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; +import { DateField } from "../../../../fields/DateField"; import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc"; import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas"; import { Id } from "../../../../fields/FieldSymbols"; @@ -17,6 +18,7 @@ import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUp import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; +import { DocumentType } from "../../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager, dropActionType } from "../../../util/DragManager"; @@ -48,8 +50,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DateField } from "../../../../fields/DateField"; +import Color = require("color"); export const panZoomSchema = createSchema({ _panX: "number", @@ -117,7 +118,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); } @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); } - @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.isContentActive() || this.props.isContentActive()); } + @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); } @computed get fitToContentVals() { return { bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 }, @@ -170,6 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P getContainerTransform = () => this.cachedGetContainerTransform.copy(); getTransformOverlay = () => this.getContainerTransform().translate(1, 1); getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); + isAnyChildContentActive = () => this.props.isAnyChildContentActive(); addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed this.addDocument(newBox); @@ -1033,7 +1035,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P docFilters={this.childDocFilters} docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} - isContentActive={this.isAnnotationOverlay ? this.props.isContentActive : returnFalse} + isContentActive={returnFalse} isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive} focus={this.focusDocument} addDocTab={this.addDocTab} diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index 1cf466cba..3833f968b 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -194,7 +194,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { const sortIcon = col.desc === undefined ? "caret-right" : col.desc === true ? "caret-down" : "caret-up"; const header = <div className="collectionSchemaView-menuOptions-wrapper" style={{ background: col.color, padding: "2px", display: "flex", cursor: "default", height: "100%", }}> {keysDropdown} - <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "pointer" }}> + <div onClick={e => this.changeSorting(col)} style={{ width: 21, padding: 1, display: "inline", zIndex: 1, background: "inherit", cursor: "pointer" }}> <FontAwesomeIcon icon={sortIcon} size="lg" /> </div> {/* {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} */} @@ -562,7 +562,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> { onPointerDown={this.props.onPointerDown} onClick={this.props.onClick} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.props.onDrop(e, {})} onContextMenu={this.onContextMenu} > {this.reactTable} - {this.props.Document._chromeHidden || this.props.addDocument == returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} + {this.props.Document._chromeHidden || this.props.addDocument === returnFalse ? undefined : <div className="collectionSchemaView-addRow" onClick={this.createRow}>+ new</div>} {!this._showDoc ? (null) : <div className="collectionSchemaView-documentPreview" ref="overlay" style={{ diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index fba95cad2..240a71c3e 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -48,7 +48,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { if (linkRelationshipList && !linkRelationshipList.includes(value)) { linkRelationshipList.push(value); const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")"; - linkColorList.push(randColor) + linkColorList.push(randColor); } this.relationshipButtonColor = "rgb(62, 133, 55)"; setTimeout(action(() => this.relationshipButtonColor = ""), 750); @@ -62,7 +62,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { @action getRelationshipResults = () => { const query = this.relationship; //current content in input box - const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList) + const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); if (linkRelationshipList) { return linkRelationshipList.filter(rel => rel.includes(query)); } @@ -73,7 +73,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> { */ @action toggleRelationshipResults = () => { - this.relationshipSearchVisibility = this.relationshipSearchVisibility == "none" ? "block" : "none"; + this.relationshipSearchVisibility = this.relationshipSearchVisibility === "none" ? "block" : "none"; } @undoBatch diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 8f83f0e6e..53da880e4 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -15,7 +15,7 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear handleResultClick = (e: React.MouseEvent) => { const relationship = (e.target as HTMLParagraphElement).textContent; if (relationship) { - this.props.handleRelationshipSearchChange(relationship) + this.props.handleRelationshipSearchChange(relationship); } } @@ -31,8 +31,8 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear * Render an empty div to increase the height of LinkEditor to accommodate 2+ results */ emptyDiv = () => { - if (this.props.results && this.props.results.length > 2 && this.props.display == "block") { - return <div style={{ height: "50px" }}></div> + if (this.props.results && this.props.results.length > 2 && this.props.display === "block") { + return <div style={{ height: "50px" }} />; } } @@ -47,9 +47,9 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear { // return a dropdown of relationship results if there exist results this.props.results ? this.props.results.map(result => { - return (<p key={result} onClick={this.handleResultClick}> + return <p key={result} onClick={this.handleResultClick}> {result} - </p>) + </p>; }) : <p>No matching relationships</p> } @@ -58,6 +58,6 @@ export class LinkRelationshipSearch extends React.Component<LinkRelationshipSear {/*Render an empty div to increase the height of LinkEditor to accommodate 2+ results */} {this.emptyDiv()} </div> - ) + ); } }
\ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index a3f03fc4b..f5a7e61aa 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -163,7 +163,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< : undefined) ) || this.rootDoc ); - }; + } componentWillUnmount() { Object.values(this._disposers).forEach((disposer) => disposer?.()); @@ -240,7 +240,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this.layoutDoc._currentTimecode = htmlEle.currentTime; } - }; + } // pause play back Pause = action(() => { @@ -252,7 +252,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< playFromTime = (absoluteTime: number) => { this.recordingStart && this.playFrom((absoluteTime - this.recordingStart) / 1000); - }; + } // play back the audio from time @action @@ -277,7 +277,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this._play = setTimeout( () => { this._ended = fullPlay ? true : this._ended; - this.Pause() + this.Pause(); }, (end - start) * 1000 ); // use setTimeout to play a specific duration @@ -286,7 +286,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this.Pause(); } } - }; + } // update the recording time updateRecordTime = () => { @@ -299,7 +299,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< (new Date().getTime() - this._recordStart - this.pauseTime) / 1000; } } - }; + } // starts recording recordAudioAnnotation = async () => { @@ -320,7 +320,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< setTimeout(this.updateRecordTime, 0); this._recorder.start(); setTimeout(() => this._recorder && this.stopRecording(), 60 * 60 * 1000); // stop after an hour - }; + } // context menu specificContextMenu = (e: React.MouseEvent): void => { @@ -336,8 +336,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent< (this.layoutDoc.dontAutoPlayFollowedLinks ? "" : "Don't") + " play when link is selected", event: () => - (this.layoutDoc.dontAutoPlayFollowedLinks = - !this.layoutDoc.dontAutoPlayFollowedLinks), + (this.layoutDoc.dontAutoPlayFollowedLinks = + !this.layoutDoc.dontAutoPlayFollowedLinks), icon: "expand-arrows-alt", }); funcs.push({ @@ -353,7 +353,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< subitems: funcs, icon: "asterisk", }); - }; + } // stops the recording stopRecording = action(() => { @@ -376,12 +376,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this._recorder ? this.stopRecording() : this.recordAudioAnnotation(); e.stopPropagation(); } - }; + } // for play button Play = (e?: any) => { let start; - if (this._ended || this._ele!.currentTime == this.duration) { + if (this._ended || this._ele!.currentTime === this.duration) { start = this._trimStart; this._ended = false; } @@ -391,7 +391,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this.playFrom(start, this._trimEnd, true); e?.stopPropagation?.(); - }; + } // creates a text document for dictation onFile = (e: any) => { @@ -413,14 +413,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent< ); this.props.addDocument?.(newDoc); e.stopPropagation(); - }; + } // ref for updating time setRef = (e: HTMLAudioElement | null) => { e?.addEventListener("timeupdate", this.timecodeChanged); e?.addEventListener("ended", this.Pause); this._ele = e; - }; + } // returns the path of the audio file @computed get path() { @@ -431,16 +431,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent< // returns the html audio element @computed get audio() { - return ( - <audio - ref={this.setRef} - className={`audiobox-control${this.isContentActive() ? "-interactive" : "" - }`} - > - <source src={this.path} type="audio/mpeg" /> - Not supported. - </audio> - ); + return <audio ref={this.setRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}> + <source src={this.path} type="audio/mpeg" /> + Not supported. + </audio>; } // pause the time during recording phase @@ -450,7 +444,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this._paused = true; this._recorder.pause(); e.stopPropagation(); - }; + } // continue the recording @action @@ -459,17 +453,18 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this._paused = false; this._recorder.resume(); e.stopPropagation(); - }; + } playing = () => this.mediaState === "playing"; playLink = (link: Doc) => { const stack = this._stackedTimeline.current; if (link.annotationOn === this.rootDoc) { - if (!this.layoutDoc.dontAutoPlayFollowedLinks) + if (!this.layoutDoc.dontAutoPlayFollowedLinks) { this.playFrom(stack?.anchorStart(link) || 0, stack?.anchorEnd(link)); - else + } else { this._ele!.currentTime = this.layoutDoc._currentTimecode = stack?.anchorStart(link) || 0; + } } else { this.links .filter((l) => l.anchor1 === link || l.anchor2 === link) @@ -478,17 +473,18 @@ export class AudioBox extends ViewBoxAnnotatableComponent< const startTime = stack?.anchorStart(la1) || stack?.anchorStart(la2); const endTime = stack?.anchorEnd(la1) || stack?.anchorEnd(la2); if (startTime !== undefined) { - if (!this.layoutDoc.dontAutoPlayFollowedLinks) + if (!this.layoutDoc.dontAutoPlayFollowedLinks) { endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime); - else + } else { this._ele!.currentTime = this.layoutDoc._currentTimecode = startTime; + } } }); } - }; + } // shows trim controls @action @@ -500,7 +496,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this.Pause(); } this._trimming = true; - }; + } // hides trim controls and displays new clip @action @@ -512,7 +508,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< this.layoutDoc.clipEnd = this._trimEnd; this._trimming = false; this.setAnchorTime(Math.max(Math.min(this._trimEnd, this._ele!.currentTime), this._trimStart)); - }; + } @action setStartTrim = (newStart: number) => { @@ -528,14 +524,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent< timelineWhenChildContentsActiveChanged = (isActive: boolean) => this.props.whenChildContentsActiveChanged( runInAction(() => (this._isAnyChildContentActive = isActive)) - ); + ) timelineScreenToLocal = () => this.props .ScreenToLocalTransform() .translate( -AudioBox.playheadWidth, (-(100 - this.heightPercent) / 200) * this.props.PanelHeight() - ); + ) setAnchorTime = (time: number) => { (this._ele!.currentTime = this.layoutDoc._currentTimecode = time); } @@ -543,7 +539,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< timelineHeight = () => (((this.props.PanelHeight() * this.heightPercent) / 100) * this.heightPercent) / - 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) + 100 // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) timelineWidth = () => this.props.PanelWidth() - AudioBox.playheadWidth; @computed get renderTimeline() { return ( @@ -570,7 +566,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent< ScreenToLocalTransform={this.timelineScreenToLocal} Play={this.Play} Pause={this.Pause} - isContentActive={this.isContentActive} + isContentActive={this.props.isContentActive} + isAnyChildContentActive={this.isAnyChildContentActive} playLink={this.playLink} PanelWidth={this.timelineWidth} PanelHeight={this.timelineHeight} @@ -586,7 +583,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent< render() { const interactive = - SnappingManager.GetIsDragging() || this.isContentActive() + SnappingManager.GetIsDragging() || this.props.isContentActive() ? "-interactive" : ""; return ( @@ -641,76 +638,76 @@ export class AudioBox extends ViewBoxAnnotatableComponent< </div> </div> ) : ( - <button - className={`audiobox-record${interactive}`} - style={{ backgroundColor: Colors.DARK_GRAY }} - > - RECORD - </button> - )} + <button + className={`audiobox-record${interactive}`} + style={{ backgroundColor: Colors.DARK_GRAY }} + > + RECORD + </button> + )} </div> ) : ( - <div - className="audiobox-controls" - style={{ - pointerEvents: - this._isAnyChildContentActive || this.isContentActive() - ? "all" - : "none", - }} - > - <div className="audiobox-dictation" /> <div - className="audiobox-player" - style={{ height: `${AudioBox.heightPercent}%` }} + className="audiobox-controls" + style={{ + pointerEvents: + this._isAnyChildContentActive || this.props.isContentActive() + ? "all" + : "none", + }} > + <div className="audiobox-dictation" /> <div - className="audiobox-buttons" - title={this.mediaState === "paused" ? "play" : "pause"} - onClick={this.mediaState === "paused" ? this.Play : this.Pause} + className="audiobox-player" + style={{ height: `${AudioBox.heightPercent}%` }} > - {" "} - <FontAwesomeIcon - icon={this.mediaState === "paused" ? "play" : "pause"} - size={"1x"} - /> - </div> - <div - className="audiobox-buttons" - title={this._trimming ? "finish" : "trim"} - onClick={this._trimming ? this.finishTrim : this.startTrim} - > - <FontAwesomeIcon - icon={this._trimming ? "check" : "cut"} - size={"1x"} - /> - </div> - <div - className="audiobox-timeline" - style={{ - top: 0, - height: `100%`, - left: AudioBox.playheadWidth, - width: `calc(100% - ${AudioBox.playheadWidth}px)`, - background: "white", - }} - > - {this.renderTimeline} - </div> - {this.audio} - <div className="audioBox-current-time"> - {this._trimming ? - formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) - : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} - </div> - <div className="audioBox-total-time"> - {this._trimming || !this._trimEnd ? - formatTime(Math.round(NumCast(this.duration))) - : formatTime(Math.round(NumCast(this.trimDuration)))} + <div + className="audiobox-buttons" + title={this.mediaState === "paused" ? "play" : "pause"} + onClick={this.mediaState === "paused" ? this.Play : this.Pause} + > + {" "} + <FontAwesomeIcon + icon={this.mediaState === "paused" ? "play" : "pause"} + size={"1x"} + /> + </div> + <div + className="audiobox-buttons" + title={this._trimming ? "finish" : "trim"} + onClick={this._trimming ? this.finishTrim : this.startTrim} + > + <FontAwesomeIcon + icon={this._trimming ? "check" : "cut"} + size={"1x"} + /> + </div> + <div + className="audiobox-timeline" + style={{ + top: 0, + height: `100%`, + left: AudioBox.playheadWidth, + width: `calc(100% - ${AudioBox.playheadWidth}px)`, + background: "white", + }} + > + {this.renderTimeline} + </div> + {this.audio} + <div className="audioBox-current-time"> + {this._trimming ? + formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode))) + : formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this._trimStart)))} + </div> + <div className="audioBox-total-time"> + {this._trimming || !this._trimEnd ? + formatTime(Math.round(NumCast(this.duration))) + : formatTime(Math.round(NumCast(this.trimDuration)))} + </div> </div> </div> - </div> - )} + )} </div> ); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 092823603..9cc4b1f9a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -17,8 +17,8 @@ import { InkingStroke } from "../InkingStroke"; import { StyleProp } from "../StyleProvider"; import "./CollectionFreeFormDocumentView.scss"; import { DocumentView, DocumentViewProps } from "./DocumentView"; -import { FieldViewProps } from "./FieldView"; import React = require("react"); +import Color = require("color"); 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; @@ -164,6 +164,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF PanelWidth: this.panelWidth, PanelHeight: this.panelHeight, }; + const background = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor); + const mixBlendMode = StrCast(this.layoutDoc.mixBlendMode) as any || (background && Color(background).alpha() !== 1 ? "multiply" : undefined); return <div className={"collectionFreeFormDocumentView-container"} style={{ outline: this.Highlight ? "orange solid 2px" : "", @@ -172,7 +174,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF transform: this.transform, transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition), zIndex: this.ZInd, - mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any, + mixBlendMode, display: this.ZInd === -99 ? "none" : undefined }} > <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 153176afc..6708a08ee 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,17 +1,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from "mobx-react"; -import { Doc } from '../../../fields/Doc'; +import { Doc, Opt } from '../../../fields/Doc'; import { documentSchema } from '../../../fields/documentSchemas'; import { createSchema, makeInterface } from '../../../fields/Schema'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, OmitKeys, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { StyleProp } from '../StyleProvider'; import "./ComparisonBox.scss"; -import { DocumentView } from './DocumentView'; +import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import React = require("react"); @@ -71,6 +72,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl delete this.dataDoc[fieldKey]; } + docStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => { + if (property === StyleProp.PointerEvents) return "none"; + return this.props.styleProvider?.(doc, props, property); + } + render() { const clipWidth = NumCast(this.layoutDoc._clipWidth) + "%"; const clearButton = (which: string) => { @@ -84,6 +90,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl const whichDoc = Cast(this.dataDoc[`compareBox-${which}`], Doc, null); return whichDoc ? <> <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} + isContentActive={returnFalse} + isDocumentActive={returnFalse} + styleProvider={this.docStyleProvider} Document={whichDoc} DataDoc={undefined} pointerEvents={"none"} /> @@ -102,7 +111,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl }; return ( - <div className={`comparisonBox${this.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}> + <div className={`comparisonBox${this.props.isContentActive() || SnappingManager.GetIsDragging() ? "-interactive" : ""}` /* change className to easily disable/enable pointer events in CSS */}> {displayBox("after", 1, this.props.PanelWidth() - 3)} <div className="clip-div" style={{ width: clipWidth, transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, "gray") }}> {displayBox("before", 0, 0)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2bd79df64..fda84dd2d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -85,6 +85,7 @@ export interface DocComponentView { reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views menuControls?: () => JSX.Element; // controls to display in the top menu bar when the document is selected. + isAnyChildContentActive?: () => boolean; // is any child content of the document active getKeyFrameEditing?: () => boolean; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown) playFrom?: (time: number, endTime?: number) => void; @@ -184,7 +185,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps private _dropDisposer?: DragManager.DragDropDisposer; private _holdDisposer?: InteractionUtils.MultiTouchEventDisposer; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; - _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class + @observable _componentView: Opt<DocComponentView>; // needs to be accessed from DocumentView wrapper class private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; } public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive @@ -780,8 +781,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; setHeight = (height: number) => this.layoutDoc._height = height; - setContentView = (view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view; - isContentActive = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || this.props.Document.forceActive || this.props.isContentActive() ? true : false; + setContentView = action((view: { getAnchor?: () => Doc, forward?: () => boolean, back?: () => boolean }) => this._componentView = view); + isContentActive = (outsideReaction?: boolean) => { + return CurrentUserUtils.SelectedTool !== InkTool.None || + this.props.Document.forceActive || + this.props.isSelected(outsideReaction) || + this._componentView?.isAnyChildContentActive?.() || + this.props.isContentActive() ? true : false; + } @computed get contents() { TraceMobx(); const audioView = !this.layoutDoc._showAudio ? (null) : @@ -796,7 +803,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps </div>; return <div className="documentView-contentsView" style={{ - pointerEvents: (this.props.contentPointerEvents as any),// || (CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() || this.isContentActive() ? "all" : "none"), + pointerEvents: (this.props.contentPointerEvents as any) || (this.isContentActive() ? "all" : "none"), height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined, }}> <DocumentContentsView key={1} {...this.props} @@ -1053,7 +1060,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } - @computed get shouldNotScale() { return (this.fitWidth && !this.nativeWidth) || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any); } + @computed get shouldNotScale() { return (this.fitWidth && !this.nativeWidth) || this.props.treeViewDoc || [CollectionViewType.Docking].includes(this.Document._viewType as any); } @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); } @computed get effectiveNativeHeight() { return this.shouldNotScale ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); } @computed get nativeScaling() { diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 1e13d1b5a..7ad03e055 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -417,6 +417,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc renderDepth={1} dropAction={this.props.dropAction} ScreenToLocalTransform={this.props.ScreenToLocalTransform} + isAnyChildContentActive={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} isSelected={returnFalse} diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c4e74ebd2..38deb4a73 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -332,9 +332,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { - MarqueeAnnotator.clearAnnotations(this._savedAnnotations) + MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; return true; }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), false); @@ -368,7 +368,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ScreenToLocalTransform={this.screenToLocalTransform} scaling={returnOne} select={emptyFunction} - isContentActive={this.isContentActive} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 8d665b8a6..db1ae0537 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -21,7 +21,7 @@ type LabelDocument = makeInterface<[typeof LabelSchema, typeof documentSchema]>; const LabelDocument = makeInterface(LabelSchema, documentSchema); export interface LabelBoxProps { - label?: string + label?: string; } @observer diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index c65ba9c69..55ea45bb8 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -30,6 +30,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>( dontRegisterView={true} renderDepth={this.props.renderDepth + 1} CollectionView={undefined} + isAnyChildContentActive={returnFalse} isContentActive={this.isContentActiveFunc} addDocument={returnFalse} removeDocument={returnFalse} diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 23236cf20..5e07229c1 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -177,9 +177,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps </>; const searchTitle = `${!this._searching ? "Open" : "Close"} Search Bar`; const curPage = this.Document._curPage || 1; - return !this.isContentActive() ? (null) : + return !this.props.isContentActive() ? (null) : <div className="pdfBox-ui" onKeyDown={e => [KeyCodes.BACKSPACE, KeyCodes.DELETE].includes(e.keyCode) ? e.stopPropagation() : true} - onPointerDown={e => e.stopPropagation()} style={{ display: this.isContentActive() ? "flex" : "none" }}> + onPointerDown={e => e.stopPropagation()} style={{ display: this.props.isContentActive() ? "flex" : "none" }}> <div className="pdfBox-overlayCont" onPointerDown={(e) => e.stopPropagation()} style={{ left: `${this._searching ? 0 : 100}%` }}> <button className="pdfBox-overlayButton" title={searchTitle} /> <input className="pdfBox-searchBar" placeholder="Search" ref={this._searchRef} onChange={this.searchStringChanged} @@ -209,7 +209,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps {this._pageControls ? pageBtns : (null)} </div> <button className="pdfBox-sidebarBtn" title="Toggle Sidebar" - style={{ display: !this.isContentActive() ? "none" : undefined }} + style={{ display: !this.props.isContentActive() ? "none" : undefined }} onPointerDown={this.sidebarBtnDown} > <FontAwesomeIcon icon={"chevron-left"} size="sm" /> </button> @@ -229,7 +229,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps } @computed get renderTitleBox() { - const classname = "pdfBox" + (this.isContentActive() ? "-interactive" : ""); + const classname = "pdfBox" + (this.props.isContentActive() ? "-interactive" : ""); return <div className={classname} > <div className="pdfBox-title-outer"> <strong className="pdfBox-title" >{this.props.Document.title}</strong> @@ -268,7 +268,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps dataDoc={this.dataDoc} pdf={this._pdf!} url={this.pdfUrl!.url.pathname} - isContentActive={this.isContentActive} + isContentActive={this.props.isContentActive} anchorMenuClick={this.anchorMenuClick} loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined} setPdfViewer={this.setPdfViewer} @@ -285,13 +285,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} + setHeight={emptyFunction} nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth)} showSidebar={this.SidebarShown} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} sidebarAddDocument={this.sidebarAddDocument} moveDocument={this.moveDocument} removeDocument={this.removeDocument} - isContentActive={this.isContentActive} /> {this.settingsPanel()} </div>; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index d16b28f32..90de3227f 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -307,7 +307,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive"; const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive; return !field ? <div key="loading">Loading</div> : - <div className="container" key="container" style={{ pointerEvents: this._isAnyChildContentActive || this.isContentActive() ? "all" : "none" }}> + <div className="container" key="container" style={{ mixBlendMode: "multiply", pointerEvents: this.props.isContentActive() ? "all" : "none" }}> <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}> <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef} style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }} @@ -321,7 +321,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp Not supported. </video> {!this.audiopath || this.audiopath === field.url.href ? (null) : - <audio ref={this.setAudioRef} className={`audiobox-control${this.isContentActive() ? "-interactive" : ""}`}> + <audio ref={this.setAudioRef} className={`audiobox-control${this.props.isContentActive() ? "-interactive" : ""}`}> <source src={this.audiopath} type="audio/mpeg" /> Not supported. </audio>} @@ -378,30 +378,30 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp private get uIButtons() { const curTime = (this.layoutDoc._currentTimecode || 0); const nonNativeControls = [ - <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} placement="bottom"> - <div className="videoBox-play" key="play" onPointerDown={this.onPlayDown} > + <Tooltip title={<div className="dash-tooltip">{"playback"}</div>} key="play" placement="bottom"> + <div className="videoBox-play" onPointerDown={this.onPlayDown} > <FontAwesomeIcon icon={this._playing ? "pause" : "play"} size="lg" /> </div> </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} placement="bottom"> + <Tooltip title={<div className="dash-tooltip">{"timecode"}</div>} key="time" placement="bottom"> <div className="videoBox-time" onPointerDown={this.onResetDown} > <span>{formatTime(curTime)}</span> <span style={{ fontSize: 8 }}>{" " + Math.floor((curTime - Math.trunc(curTime)) * 100).toString().padStart(2, "0")}</span> </div> </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} placement="bottom"> + <Tooltip title={<div className="dash-tooltip">{"view full screen"}</div>} key="full" placement="bottom"> <div className="videoBox-full" onPointerDown={this.FullScreen}> <FontAwesomeIcon icon="expand" size="lg" /> </div> </Tooltip>]; return <div className="videoBox-ui"> {[...(VideoBox._nativeControls ? [] : nonNativeControls), - <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} placement="bottom"> + <Tooltip title={<div className="dash-tooltip">{"snapshot current frame"}</div>} key="snap" placement="bottom"> <div className="videoBox-snapshot" onPointerDown={this.onSnapshotDown} > <FontAwesomeIcon icon="camera" size="lg" /> </div> </Tooltip>, - <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} placement="bottom"> + <Tooltip title={<div className="dash-tooltip">{"show annotation timeline"}</div>} key="timeline" placement="bottom"> <div className="videoBox-timelineButton" onPointerDown={this.onTimelineHdlDown}> <FontAwesomeIcon icon="eye" size="lg" /> </div> @@ -429,7 +429,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp setupMoveUpEvents(this, e, action((e: PointerEvent) => { this._clicking = false; - if (this.isContentActive()) { + if (this.props.isContentActive()) { const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100)); } @@ -438,7 +438,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp () => { this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent; setTimeout(action(() => this._clicking = false), 500); - }, this.isContentActive(), this.isContentActive()); + }, this.props.isContentActive(), this.props.isContentActive()); }); onResetDown = (e: React.PointerEvent) => { @@ -529,12 +529,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp playFrom={this.playFrom} setTime={this.setAnchorTime} playing={this.playing} + isAnyChildContentActive={this.isAnyChildContentActive} whenChildContentsActiveChanged={this.timelineWhenChildContentsActiveChanged} removeDocument={this.removeDocument} ScreenToLocalTransform={this.timelineScreenToLocal} Play={this.Play} Pause={this.Pause} - isContentActive={this.isContentActive} playLink={this.playLink} PanelHeight={this.timelineHeight} trimming={false} @@ -552,7 +552,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -576,7 +576,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } marqueeFitScaling = () => (this.props.scaling?.() || 1) * this.heightPercent / 100; marqueeOffset = () => [this.panelWidth() / 2 * (1 - this.heightPercent / 100) / (this.heightPercent / 100), 0]; - timelineDocFilter = () => ["_timelineLabel:true:x"]; + timelineDocFilter = () => [`_timelineLabel:true,${Utils.noRecursionHack}:x`]; render() { const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding); const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad; @@ -598,7 +598,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ScreenToLocalTransform={this.screenToLocalTransform} docFilters={this.timelineDocFilter} select={emptyFunction} - isContentActive={this.isContentActive} scaling={returnOne} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.removeDocument} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index ae6b90e41..e4d4557af 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -88,12 +88,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps this.dataDoc[this.fieldKey + "-sidebar"] = ComputedField.MakeFunction(`copyField(this["${this.fieldKey}-"+urlHash(this["${this.fieldKey}"]?.url?.toString())+"-sidebar"`); }); - this._disposers.selection = reaction(() => this.props.isSelected(), - selected => !selected && setTimeout(() => { - // Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove())); - // this._savedAnnotations.clear(); - }) - ); + this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight, + autoHeight => { + if (autoHeight) { + this.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]); + this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); + } + }); if (this.webField?.href.indexOf("youtube") !== -1) { const youtubeaspect = 400 / 315; @@ -401,7 +402,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps @action onMarqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && this.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { + if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) { setupMoveUpEvents(this, e, action(e => { MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -484,7 +485,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps NumCast(this.layoutDoc.nativeWidth) @computed get content() { - return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")} + return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")} style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / (this.props.scaling?.() || 1)}%`, }}> {this.urlContent} </div>; @@ -529,7 +530,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps docFilters={docFilters || this.props.docFilters} dontRenderDocuments={docFilters ? false : true} select={emptyFunction} - isContentActive={returnFalse} ContentScaling={returnOne} bringToFront={emptyFunction} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} @@ -539,7 +539,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps childPointerEvents={true} pointerEvents={CurrentUserUtils.SelectedTool !== InkTool.None || this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none"} />; return ( - <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.isContentActive() ? "all" : this.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} > + <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.props.isContentActive() ? "all" : this.props.isContentActive() || SnappingManager.GetIsDragging() ? undefined : "none" }} > <div className={`webBox-container`} style={{ pointerEvents }} onContextMenu={this.specificContextMenu}> <base target="_blank" /> <div className={"webBox-outerContent"} ref={this._outerRef} @@ -559,7 +559,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps {renderAnnotations(this.transparentFilter)} </div> {renderAnnotations(this.opaqueFilter)} - {renderAnnotations()} + {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()} {this.annotationLayer} </div> </div> @@ -583,15 +583,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} + setHeight={emptyFunction} nativeWidth={this._previewNativeWidth ?? NumCast(this.layoutDoc._nativeWidth)} showSidebar={this.SidebarShown} sidebarAddDocument={this.sidebarAddDocument} moveDocument={this.moveDocument} removeDocument={this.removeDocument} - isContentActive={this.isContentActive} /> <button className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" - style={{ display: !this.isContentActive() ? "none" : undefined }} + style={{ display: !this.props.isContentActive() ? "none" : undefined }} onPointerDown={this.sidebarBtnDown} > <FontAwesomeIcon style={{ color: "white" }} icon={"chevron-left"} size="sm" /> </button> diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 040e8f0f4..a6887cbba 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -336,7 +336,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon const checkWidth = ScriptField.MakeScript("setStrokeWidth(0, true)")?.script.run().result; const width = 20 + (checkWidth / 100) * 70; const height = 20 + (checkWidth / 100) * 70; - strokeIcon = (<div style={{ borderRadius: "100%", width: width + '%', height: height + '%', backgroundColor: boolResult ? boolResult : "#FFFFFF" }} />) + strokeIcon = (<div style={{ borderRadius: "100%", width: width + '%', height: height + '%', backgroundColor: boolResult ? boolResult : "#FFFFFF" }} />); } const colorOptions: string[] = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', @@ -451,7 +451,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon const script: string = StrCast(this.rootDoc.script); // Script for checking the outcome of the toggle - let checkScript: string = StrCast(this.rootDoc.script) + "('', true)"; + const checkScript: string = StrCast(this.rootDoc.script) + "('', true)"; // Function to run the script const checkResult = ScriptField.MakeScript(checkScript)?.script.run().result; @@ -609,7 +609,7 @@ Scripting.addGlobal(function getActiveTextInfo(info: "family" | "size" | "color" case "color": return style?.activeColors[0]; case "highlight": return style?.activeHighlights[0]; } -}) +}); Scripting.addGlobal(function setAlignment(align: "left" | "right" | "center", checkResult?: boolean) { const editorView = RichTextMenu.Instance?.TextView?.EditorView; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f4053d69f..a9beb67de 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1211,7 +1211,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((e.nativeEvent as any).formattedHandled) { console.log("handled"); } - if (!(e.nativeEvent as any).formattedHandled && this.isContentActive(true)) { + if (!(e.nativeEvent as any).formattedHandled && this.props.isContentActive(true)) { const editor = this._editorView!; const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY }); !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0)))); @@ -1481,7 +1481,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @computed get sidebarHandle() { TraceMobx(); const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length; - return (!annotated && !this.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} + return (!annotated && !this.props.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : "")) @@ -1504,7 +1504,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp sidebarAddDocument={this.sidebarAddDocument} moveDocument={this.moveDocument} removeDocument={this.removeDocument} - isContentActive={this.isContentActive} /> : <ComponentTag {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} @@ -1517,7 +1516,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp scaleField={this.SidebarKey + "-scale"} isAnnotationOverlay={false} select={emptyFunction} - isContentActive={this.isContentActive} scaling={this.sidebarContentScaling} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.sidebarRemDocument} @@ -1539,7 +1537,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp render() { TraceMobx(); const selected = this.props.isSelected(); - const active = this.isContentActive(); + const active = this.props.isContentActive(); const scale = this.props.hideOnLeave ? 1 : (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false); @@ -1551,7 +1549,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : ""; return ( <div className="formattedTextBox-cont" - onWheel={e => this.isContentActive() && e.stopPropagation()} + onWheel={e => this.props.isContentActive() && e.stopPropagation()} style={{ transform: this.props.dontScale ? undefined : `scale(${scale})`, transformOrigin: this.props.dontScale ? undefined : "top left", diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 75e3f81fb..3bf1f0828 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -69,8 +69,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { this._disposer = reaction(() => SelectionManager.Views(), selected => { this._showLinkPopup = false; - console.log("unmount"); - AnchorMenu.Instance.fadeOut(true) + AnchorMenu.Instance.fadeOut(true); }); } @@ -86,6 +85,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { if (!this.Highlight(this.highlightColor, false) && this.Pinned) { this.Highlighting = !this.Highlighting; } + AnchorMenu.Instance.fadeOut(true); } @action @@ -157,7 +157,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { <FontAwesomeIcon icon="link" size="lg" /> </button> </Tooltip>, - <LinkPopup showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} /> + <LinkPopup key="popup" showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} /> ] : [ <Tooltip key="trash" title={<div className="dash-tooltip">{"Remove Link Anchor"}</div>}> <button className="antimodeMenu-button" onPointerDown={this.Delete}> diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 734d9127c..02010e123 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -119,9 +119,11 @@ export class PDFViewer extends React.Component<IViewerProps> { this._mainCont.current?.addEventListener("scroll", e => (e.target as any).scrollLeft = 0); this._disposers.autoHeight = reaction(() => this.props.layoutDoc._autoHeight, - () => { - this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]); - this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); + autoHeight => { + if (autoHeight) { + this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]); + this.props.setHeight(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1)); + } }); this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.props.rootDoc), @@ -512,7 +514,6 @@ export class PDFViewer extends React.Component<IViewerProps> { const renderAnnotations = (docFilters?: () => string[]) => <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} isAnnotationOverlay={true} - isContentActive={returnFalse} fieldKey={this.props.fieldKey + "-annotations"} setPreviewCursor={this.setPreviewCursor} PanelHeight={this.panelHeight} @@ -526,7 +527,7 @@ export class PDFViewer extends React.Component<IViewerProps> { CollectionView={undefined} ScreenToLocalTransform={this.overlayTransform} renderDepth={this.props.renderDepth + 1} - childPointerEvents={true} /> + childPointerEvents={true} />; return <div> <div className={`pdfViewerDash-overlay${CurrentUserUtils.SelectedTool !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`} style={{ @@ -543,7 +544,7 @@ export class PDFViewer extends React.Component<IViewerProps> { transform: `scale(${this._zoomed})` }}> {renderAnnotations(this.opaqueFilter)} - {renderAnnotations()} + {SnappingManager.GetIsDragging() ? (null) : renderAnnotations()} </div> </div>; } diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 07186fe8d..260ddfc90 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -14,7 +14,7 @@ import "./SearchBox.scss"; import { DocumentManager } from '../../util/DocumentManager'; import { DocUtils } from '../../documents/Documents'; -export const searchSchema = createSchema({ +export const searchSchema = createSchema({ Document: Doc }); @@ -109,13 +109,12 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc }); makeLink = action((linkTo: Doc) => { - console.log("[makeLink-1] got here!") console.log(linkTo.title); - if (this.props.linkFrom){ + if (this.props.linkFrom) { const linkFrom = this.props.linkFrom(); - if (linkFrom){ + if (linkFrom) { console.log(linkFrom.title); - DocUtils.MakeLink({doc: linkFrom}, {doc:linkTo}); + DocUtils.MakeLink({ doc: linkFrom }, { doc: linkTo }); } } }); @@ -177,10 +176,10 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc * right side of each search result. */ static formatType(type: String): String { - if (type == "pdf") { + if (type === "pdf") { return "PDF"; } - else if (type == "image") { + else if (type === "image") { return "Img"; } @@ -200,28 +199,25 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc const blockedTypes = [DocumentType.PRESELEMENT, DocumentType.KVP, DocumentType.FILTER, DocumentType.SEARCH, DocumentType.SEARCHITEM, DocumentType.FONTICON, DocumentType.BUTTON, DocumentType.SCRIPTING]; const blockedKeys = ["x", "y", "proto", "width", "autoHeight", "acl-Override", "acl-Public", "context", "zIndex", "height", "text-scrollHeight", "text-height", "cloneFieldFilter", "isPrototype", "text-annotations", "dragFactory-count", "text-noTemplate", "aliases", "system", "layoutKey", "baseProto", "xMargin", "yMargin", "links", "layout", "layout_keyValue", "fitWidth", "viewType", "title-custom", - "panX", "panY", "viewScale"] + "panX", "panY", "viewScale"]; const collection = CollectionDockingView.Instance; query = query.toLowerCase(); - this._results = [] - this._selectedResult = undefined + this._results = []; + this._selectedResult = undefined; if (collection !== undefined) { const docs = DocListCast(collection.rootDoc[Doc.LayoutFieldKey(collection.rootDoc)]); - const docIDs: String[] = [] - console.log(docs.length) + const docIDs: String[] = []; SearchBox.foreachRecursiveDoc(docs, (depth: number, doc: Doc) => { const dtype = StrCast(doc.type, "string") as DocumentType; if (dtype && !blockedTypes.includes(dtype) && !docIDs.includes(doc[Id]) && depth > 0) { const hlights = new Set<string>(); SearchBox.documentKeys(doc).forEach(key => Field.toString(doc[key] as Field).toLowerCase().includes(query) && hlights.add(key)); - blockedKeys.forEach(key => { - hlights.delete(key); - }) + blockedKeys.forEach(key => hlights.delete(key)); Array.from(hlights.keys()).length > 0 && this._results.push([doc, Array.from(hlights.keys())]); } - docIDs.push(doc[Id]) + docIDs.push(doc[Id]); }); } } @@ -245,7 +241,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc submitSearch = async () => { this.resetSearch(); - let query = StrCast(this._searchString); + const query = StrCast(this._searchString); Doc.SetSearchQuery(query); this._results = []; @@ -282,11 +278,9 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc */ @computed public get selectOptions() { - const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"] + const selectValues = ["all", "rtf", "image", "pdf", "web", "video", "audio", "collection"]; - return selectValues.map(value => { - return <option key={value} value={value}>{SearchBox.formatType(value)}</option> - }) + return selectValues.map(value => <option key={value} value={value}>{SearchBox.formatType(value)}</option>); } /** @@ -295,17 +289,17 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc render() { var validResults = 0; - const isLinkSearch:boolean = this.props.linkSearch; + const isLinkSearch: boolean = this.props.linkSearch; const results = this._results.map(result => { var className = "searchBox-results-scroll-view-result"; - if (this._selectedResult == result[0]) { - className += " searchBox-results-scroll-view-result-selected" + if (this._selectedResult === result[0]) { + className += " searchBox-results-scroll-view-result-selected"; } - if (this._docTypeString == "all" || this._docTypeString == result[0].type) { + if (this._docTypeString === "all" || this._docTypeString === result[0].type) { validResults++; return ( <div key={result[0][Id]} onClick={isLinkSearch ? () => this.makeLink(result[0]) : () => this.onResultClick(result[0])} className={className}> @@ -319,25 +313,25 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc {result[1].join(", ")} </div> </div> - ) + ); } return null; - }) + }); results.filter(result => result); return ( <div style={{ pointerEvents: "all" }} className="searchBox-container"> - <div className="searchBox-bar" > - {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}> + <div className="searchBox-bar" > + {isLinkSearch ? (null) : <select name="type" id="searchBox-type" className="searchBox-type" onChange={this.onSelectChange}> {this.selectOptions} </select>} - <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined}} ref={this._inputRef} /> + <input defaultValue={""} autoComplete="off" onChange={this.onInputChange} type="text" placeholder="Search..." id="search-input" className="searchBox-input" style={{ width: isLinkSearch ? "100%" : undefined, borderRadius: isLinkSearch ? "5px" : undefined }} ref={this._inputRef} /> </div > <div className="searchBox-results-container"> <div className="searchBox-results-count"> - {`${validResults}` + " result" + (validResults == 1 ? "" : "s")} + {`${validResults}` + " result" + (validResults === 1 ? "" : "s")} </div> <div className="searchBox-results-scroll-view"> {results} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 17f41fac8..b09ff93d0 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1092,6 +1092,9 @@ export namespace Doc { const isTransparent = (color: string) => color !== "" && (Color(color).alpha() !== 1); return isTransparent(StrCast(doc[key])); } + if (typeof value === "string") { + value = value.replace(`,${Utils.noRecursionHack}`, ""); + } const fieldVal = doc[key]; if (Cast(fieldVal, listSpec("string"), []).length) { const vals = Cast(fieldVal, listSpec("string"), []); |