diff options
Diffstat (limited to 'src/client/views/nodes')
27 files changed, 186 insertions, 236 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 0e3c4462c..5e7f8dfda 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -520,8 +520,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD Document={mark} focus={() => this.playLink(mark)} pointerEvents={true} - NativeHeight={returnZero} - NativeWidth={returnZero} rootSelected={returnFalse} LayoutTemplate={undefined} ContainingCollectionDoc={this.props.Document} @@ -607,8 +605,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${startTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}> <DocumentView {...this.props} Document={l} - NativeHeight={returnZero} - NativeWidth={returnZero} rootSelected={returnFalse} ContainingCollectionDoc={this.props.Document} parentActive={returnTrue} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 16b2f7c2a..bfa66272e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -11,7 +11,7 @@ import { Document } from "../../../fields/documentSchemas"; import { TraceMobx } from "../../../fields/util"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; import { List } from "../../../fields/List"; -import { numberRange, smoothScroll } from "../../../Utils"; +import { numberRange, smoothScroll, returnVal } from "../../../Utils"; import { ComputedField } from "../../../fields/ScriptField"; import { listSpec } from "../../../fields/Schema"; import { DocumentType } from "../../documents/DocumentTypes"; @@ -55,8 +55,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF @computed get freezeDimensions() { return this.props.FreezeDimensions; } @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); } @computed get sizeProvider() { return this.props.sizeProvider?.(this.props.Document, this.props.replica); } - @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } - @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } + @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc._nativeWidth, this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } + @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc._nativeHeight, this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } public static getValues(doc: Doc, time: number) { const timecode = Math.round(time); diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss index eb2d93b9a..679073d44 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.scss +++ b/src/client/views/nodes/ContentFittingDocumentView.scss @@ -3,7 +3,8 @@ .contentFittingDocumentView { position: relative; display: flex; - align-items: center; + width: 100%; + height: 100%; .contentFittingDocumentView-previewDoc { position: relative; diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 6081def5d..75648f9fd 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -6,46 +6,18 @@ import { Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; import { ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; -import { emptyFunction } from "../../../Utils"; +import { emptyFunction, returnVal, OmitKeys } from "../../../Utils"; import { dropActionType } from "../../util/DragManager"; import { CollectionView } from "../collections/CollectionView"; import { DocumentView, DocumentViewProps } from "../nodes/DocumentView"; import "./ContentFittingDocumentView.scss"; interface ContentFittingDocumentViewProps { - Document: Doc; - DataDocument?: Doc; - LayoutDoc?: () => Opt<Doc>; - NativeWidth?: () => number; - NativeHeight?: () => number; - FreezeDimensions?: boolean; - LibraryPath: Doc[]; - renderDepth: number; - fitToBox?: boolean; - layoutKey?: string; - dropAction?: dropActionType; - PanelWidth: () => number; - PanelHeight: () => number; - focus?: (doc: Doc) => void; - CollectionView?: CollectionView; - CollectionDoc?: Doc; - onClick?: ScriptField; - backgroundColor?: (doc: Doc) => string | undefined; - getTransform: () => Transform; - addDocument?: (document: Doc) => boolean; - moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean; - removeDocument?: (document: Doc) => boolean; - active: (outsideReaction: boolean) => boolean; - whenActiveChanged: (isActive: boolean) => void; - addDocTab: (document: Doc, where: string) => boolean; - pinToPres: (document: Doc) => void; - dontRegisterView?: boolean; - rootSelected: (outsideReaction?: boolean) => boolean; - Display?: string; + dontCenter?: boolean; } @observer -export class ContentFittingDocumentView extends React.Component<DocumentViewProps>{ +export class ContentFittingDocumentView extends React.Component<DocumentViewProps & ContentFittingDocumentViewProps> { public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive private get layoutDoc() { return this.props.LayoutTemplate?.() || @@ -53,12 +25,18 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp Doc.Layout(this.props.Document); } @computed get freezeDimensions() { return this.props.FreezeDimensions; } - nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); - nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); + + nativeWidth = () => returnVal(this.props.NativeWidth?.(), + NumCast(this.layoutDoc?._nativeWidth || this.props.DataDoc?.[Doc.LayoutFieldKey(this.layoutDoc) + "-nativeWidth"], + (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth()))) + nativeHeight = () => returnVal(this.props.NativeHeight?.(), + NumCast(this.layoutDoc?._nativeHeight || this.props.DataDoc?.[Doc.LayoutFieldKey(this.layoutDoc) + "-nativeHeight"], + (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight()))) @computed get scaling() { const wscale = this.props.PanelWidth() / this.nativeWidth(); + const hscale = this.props.PanelHeight() / this.nativeHeight(); if (wscale * this.nativeHeight() > this.props.PanelHeight()) { - return (this.props.PanelHeight() / this.nativeHeight()) || 1; + return hscale || 1; } return wscale || 1; } @@ -67,38 +45,37 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp private PanelWidth = () => this.panelWidth; private PanelHeight = () => this.panelHeight; - @computed get panelWidth() { return this.nativeWidth && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); } - @computed get panelHeight() { return this.nativeHeight && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); } + @computed get panelWidth() { return this.nativeWidth() && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); } + @computed get panelHeight() { return this.nativeHeight() && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); } - private getTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling()); - private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth && this.props.display !== "contents" ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; } - private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 && this.props.display !== "contents" ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; } + @computed get childXf() { return this.props.DataDoc ? 1 : 1 / this.contentScaling(); } // this is intended to detect when a document is being rendered inside itself as part of a template, but not as a leaf node where nativeWidth & height would apply. + private getTransform = () => this.props.dontCenter ? + this.props.ScreenToLocalTransform().scale(this.childXf) : + this.props.ScreenToLocalTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(this.childXf) + private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; } + private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; } @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); } render() { TraceMobx(); - return (<div className="contentFittingDocumentView" style={{ - width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(), - height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight(), - display: this.props.display /* just added for grid */ - }}> + return (<div className="contentFittingDocumentView"> {!this.props.Document || !this.props.PanelWidth ? (null) : ( <div className="contentFittingDocumentView-previewDoc" style={{ - transform: `translate(${this.centeringOffset}px, 0px)`, + transform: !this.props.dontCenter ? `translate(${this.centeringOffset}px, ${this.centeringYOffset}px)` : undefined, borderRadius: this.borderRounding, height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight() / this.nativeWidth() * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(), width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth() }}> - <DocumentView {...this.props} + <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} Document={this.props.Document} DataDoc={this.props.DataDoc} LayoutTemplate={this.props.LayoutTemplate} LayoutTemplateString={this.props.LayoutTemplateString} LibraryPath={this.props.LibraryPath} - NativeWidth={this.nativeWidth} - NativeHeight={this.nativeHeight} + // NativeWidth={this.nativeWidth} + // NativeHeight={this.nativeHeight} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} ContentScaling={this.contentScaling} diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index b3b7cc4f3..91f96135f 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -135,8 +135,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do pinToPres={this.props.pinToPres} ScreenToLocalTransform={this.getTransform} renderDepth={containedDoc.type !== DocumentType.DOCHOLDER && !this.props.renderDepth ? 0 : this.props.renderDepth + 1} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={this.pwidth} PanelHeight={this.pheight} focus={this.props.focus} @@ -166,8 +164,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do pinToPres={this.props.pinToPres} ScreenToLocalTransform={this.getTransform} renderDepth={containedDoc.type !== DocumentType.DOCHOLDER && !this.props.renderDepth ? 0 : this.props.renderDepth + 1} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={this.pwidth} PanelHeight={this.pheight} focus={this.props.focus} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 1b2070c0f..67e7c1986 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -64,7 +64,19 @@ interface HTMLtagProps { onClick?: ScriptField; onInput?: ScriptField; } -//"<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'><ImageBox {...props} fieldKey={'data'}/><HTMLspan width='100%' marginTop='50%' height='10%' position='absolute' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}grey'>{this.title}</HTMLspan></HTMLdiv>"@observer + +//"<HTMLdiv borderRadius='100px' onClick={this.bannerColor=this.bannerColor==='red'?'green':'red'} overflow='hidden' position='absolute' width='100%' height='100%' transform='rotate({2*this.x+this.y}deg)'> <ImageBox {...props} fieldKey={'data'}/> <HTMLspan width='200px' top='0' height='35px' textAlign='center' paddingTop='10px' transform='translate(-40px, 45px) rotate(-45deg)' position='absolute' color='{this.bannerColor===`green`?`light`:`dark`}blue' backgroundColor='{this.bannerColor===`green`?`dark`:`light`}blue'> {this.title}</HTMLspan></HTMLdiv>" +//"<HTMLdiv borderRadius='100px' overflow='hidden' position='absolute' width='100%' height='100%' +// transform='rotate({2*this.x+this.y}deg)' +// onClick = { this.bannerColor = this.bannerColor === 'red' ? 'green' : 'red' } > +// <ImageBox {...props} fieldKey={'data'}/> +// <HTMLspan width='200px' top='0' height='35px' textAlign='center' paddingTop='10px' +// transform='translate(-40px, 45px) rotate(-45deg)' position='absolute' +// color='{this.bannerColor===`green`?`light`:`dark`}blue' +// backgroundColor='{this.bannerColor===`green`?`dark`:`light`}blue'> +// {this.title} +// </HTMLspan> +// </HTMLdiv>" @observer export class HTMLtag extends React.Component<HTMLtagProps> { click = (e: React.MouseEvent) => { @@ -136,7 +148,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings { const list = { - ...OmitKeys(this.props, ['parentActive'], "", (obj: any) => obj.active = this.props.parentActive).omit, + ...OmitKeys(this.props, ['parentActive', 'NativeWidth', 'NativeHeight'], "", (obj: any) => obj.active = this.props.parentActive).omit, RootDoc: Cast(this.layoutDoc?.rootDocument, Doc, null) || this.layoutDoc, Document: this.layoutDoc, DataDoc: this.dataDoc, @@ -170,10 +182,10 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo // add onClick function to props const makeFuncProp = (func: string) => { - const splits = layoutFrame.split(`func=`); + const splits = layoutFrame.split(`${func}=`); if (splits.length > 1) { const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] }); - layoutFrame = splits[0] + ` ${func}={props.onClick} ` + splits[1].substring(code[1].end + 1); + layoutFrame = splits[0] + ` ${func}={props.${func}} ` + splits[1].substring(code[1].end + 1); return ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name, value: "string" }); } return undefined; diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 2dd3bba91..430a1aa45 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -61,6 +61,7 @@ width: 100%; height: 100%; display: inline-block; + pointer-events: none; } .documentView-lock { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f6360fc87..89ce32e78 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -11,7 +11,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; -import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils"; +import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, returnVal } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -49,8 +49,8 @@ export interface DocumentViewProps { docFilters: () => string[]; searchFilterDocs: () => Doc[]; FreezeDimensions?: boolean; - NativeWidth: () => number; - NativeHeight: () => number; + NativeWidth?: () => number; + NativeHeight?: () => number; Document: Doc; DataDoc?: Doc; getView?: (view: DocumentView) => any; @@ -119,8 +119,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu public get ContentDiv() { return this._mainCont.current; } @computed get topMost() { return this.props.renderDepth === 0; } @computed get freezeDimensions() { return this.props.FreezeDimensions; } - @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); } - @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); } + @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeWidth"], (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0))); } + @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeHeight"], (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0))); } @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); } @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); } @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); } @@ -172,7 +172,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu me.touchEvent.preventDefault(); e.stopPropagation(); if (RadialMenu.Instance.used) { - this.onContextMenu(me.touches[0]); + this.onContextMenu(undefined, me.touches[0].pageX, me.touches[0].pageY); } } @@ -723,20 +723,21 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } @action - onContextMenu = (e: React.MouseEvent | Touch) => { + onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => { // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 - if (!(e instanceof Touch)) { - if (e.button === 0 && !e.ctrlKey) { + if (e) { + if (e.button === 0 && !e.ctrlKey || e.isDefaultPrevented()) { e.preventDefault(); return; } - e.persist(); e.stopPropagation(); + e.persist(); - if (Math.abs(this._downX - e?.clientX) > 3 || Math.abs(this._downY - e?.clientY) > 3 || - e?.isDefaultPrevented()) { - e?.preventDefault(); - return; + if (!navigator.userAgent.includes("Mozilla")) { + if (Math.abs(this._downX - e?.clientX) > 3 || Math.abs(this._downY - e?.clientY) > 3) { + e?.preventDefault(); + return; + } } e.preventDefault(); } @@ -821,11 +822,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu cm.addItem({ description: "Help...", noexpand: true, subitems: helpItems, icon: "question" }); runInAction(() => { - if (!this.topMost && !(e instanceof Touch)) { - e.stopPropagation(); // DocumentViews should stop propagation of this event + if (!this.topMost) { + e?.stopPropagation(); // DocumentViews should stop propagation of this event } - cm.displayMenu(e.pageX - 15, e.pageY - 15); - !SelectionManager.IsSelected(this, true) && SelectionManager.SelectDoc(this, false); + cm.displayMenu((e?.pageX || pageX || 0) - 15, (e?.pageY || pageY || 0) - 15); + this.isSelected(true) && SelectionManager.SelectDoc(this, false); }); } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index fceeced36..4ec5bc534 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -52,11 +52,10 @@ export interface FieldViewProps { PanelHeight: () => number; PanelPosition?: string; overflow?: boolean; - NativeHeight: () => number; - NativeWidth: () => number; + NativeHeight?: () => number; + NativeWidth?: () => number; setVideoBox?: (player: VideoBox) => void; ContentScaling: () => number; - ChromeHeight?: () => number; childLayoutTemplate?: () => Opt<Doc>; // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 790901a29..eab365445 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -164,8 +164,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc ContainingCollectionView={this.props.ContainingCollectionView} PanelWidth={this.props.PanelWidth} PanelHeight={this.props.PanelHeight} - NativeHeight={returnZero} - NativeWidth={returnZero} LibraryPath={emptyPath} rootSelected={this.props.rootSelected} renderDepth={1} @@ -200,7 +198,7 @@ Scripting.addGlobal(function readFacetData(layoutDoc: Doc, facetHeader: string) const set = new Set<string>(); if (facetHeader === "tags") allCollectionDocs.forEach(child => Field.toString(child[facetHeader] as Field).split(":").forEach(key => set.add(key))); else allCollectionDocs.forEach(child => set.add(Field.toString(child[facetHeader] as Field))); - let facetValues = Array.from(set).filter(v => v); + const facetValues = Array.from(set).filter(v => v); let nonNumbers = 0; facetValues.map(val => Number.isNaN(Number(val)) && nonNumbers++); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 688bac725..ce056b80c 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -11,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, returnOne, returnZero, Utils } from '../../../Utils'; +import { emptyFunction, returnOne, returnZero, Utils, OmitKeys } from '../../../Utils'; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs } from '../../documents/Documents'; @@ -73,10 +73,18 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD } componentDidMount() { - this._pathDisposer = reaction(() => this.paths.length && this.resize(this.paths[0]), - () => true, + this._pathDisposer = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }), + ({ nativeSize, width }) => { + if (this.props.NativeWidth?.() !== 0 || !this.layoutDoc._height) { + this.layoutDoc._nativeWidth = nativeSize.nativeWidth; + this.layoutDoc._nativeHeight = nativeSize.nativeHeight; + this.layoutDoc._nativeOrientation = nativeSize.nativeOrientation; + this.layoutDoc._height = width * nativeSize.nativeHeight / nativeSize.nativeWidth; + } + }, { fireImmediately: true }); } + componentWillUnmount() { this._pathDisposer?.(); } @@ -158,19 +166,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD if (!Doc.UserDoc().noviceMode) { funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" }); funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); - // funcs.push({ - // description: "Reset Native Dimensions", event: action(async () => { - // const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); - // const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); - // if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) { - // this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH; - // this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight(); - // } else { - // this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth(); - // this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW; - // } - // }), icon: "expand-arrows-alt" - // }); const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers..."); const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : []; @@ -249,45 +244,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD } _curSuffix = "_m"; - resize = (imgPath: string) => { - const basePath = imgPath.replace(/_[oms]./, ""); - const curPath = this.dataDoc[this.fieldKey + "-path"]; - const cachedNativeSize = { - width: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0, - height: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0, - }; - const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym](); - const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; - if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) { - if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { - const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; - const orientation = NumCast(this.dataDoc[this.fieldKey + "-nativeOrientation"]); - if (orientation === 6 || rotation === 90 || rotation === 270) { - this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); - this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); - } else { - this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); - this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); - } - const rotatedAspect = NumCast(this.layoutDoc._nativeHeight) / NumCast(this.layoutDoc._nativeWidth); - if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { - this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; - this.dataDoc[this.fieldKey + "-path"] = basePath; - } - } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { - this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width; - this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect; - } - } else if (this.layoutDoc._nativeWidth !== cachedNativeSize.width || this.layoutDoc._nativeHeight !== cachedNativeSize.height) { - !(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc) && setTimeout(() => { - if (!(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc)) { - this.layoutDoc._nativeWidth = cachedNativeSize.width; - this.layoutDoc._nativeHeight = cachedNativeSize.height; - } - }, 0); - } - } - @action onPointerEnter = () => { const self = this; @@ -370,7 +326,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD const pw = this.props.PanelWidth?.() || 50; const nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], pw); const nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1); - return { nativeWidth, nativeHeight }; + const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + "-nativeOrientation"], 1); + return { nativeWidth, nativeHeight, nativeOrientation }; } // this._curSuffix = ""; @@ -391,9 +348,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD const srcpath = this.paths[0]; const fadepath = this.paths[Math.min(1, this.paths.length - 1)]; - const { nativeWidth, nativeHeight } = this.nativeSize; + const { nativeWidth, nativeHeight, nativeOrientation } = this.nativeSize; const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]); - const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1; + const aspect = rotation % 180 ? nativeHeight / nativeWidth : 1; let transformOrigin = "center center"; let transform = `translate(0%, 0%) rotate(${rotation}deg) scale(${aspect})`; if (rotation === 90 || rotation === -270) { @@ -462,12 +419,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD pointerEvents: this.layoutDoc._isBackground ? "none" : undefined, borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px` }} > - <CollectionFreeFormView {...this.props} + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} forceScaling={true} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} - NativeHeight={returnZero} - NativeWidth={returnZero} annotationsKey={this.annotationKey} isAnnotationOverlay={true} focus={this.props.focus} diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 74d10d087..e531083bf 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -71,8 +71,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> { whenActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, - NativeHeight: returnZero, - NativeWidth: returnZero, PanelWidth: this.props.PanelWidth, PanelHeight: this.props.PanelHeight, addDocTab: returnFalse, diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index a067f23af..64ae1051b 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -22,8 +22,6 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>( <CollectionTreeView {...this.props} ChromeHeight={returnZero} overrideDocuments={[this.dataDoc]} - NativeHeight={returnZero} - NativeWidth={returnZero} ignoreFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)} annotationsKey={""} dontRegisterView={true} diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index dddefc17f..42b68e8f4 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -78,7 +78,7 @@ export class LinkDocPreview extends React.Component<Props> { } } width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225)) - 16; - height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)) - 16 + height = () => Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)) - 16; @computed get targetDocView() { return !this._targetDoc ? <div style={{ @@ -107,15 +107,13 @@ export class LinkDocPreview extends React.Component<Props> { searchFilterDocs={returnEmptyDoclist} ContainingCollectionDoc={undefined} ContainingCollectionView={undefined} - renderDepth={0} + renderDepth={-1} PanelWidth={this.width} //Math.min(350, NumCast(target._width, 350))} PanelHeight={this.height} //Math.min(250, NumCast(target._height, 250))} focus={emptyFunction} whenActiveChanged={returnFalse} bringToFront={returnFalse} ContentScaling={returnOne} - NativeWidth={returnZero} - NativeHeight={returnZero} backgroundColor={this.props.backgroundColor} />; } diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index f2ab37984..174bf8eff 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -175,7 +175,7 @@ } .pdfBox-title-outer { - width: 150%; + width: 100%; height: 100%; position: relative; display: grid; @@ -187,14 +187,13 @@ color: lightgray; margin-top: auto; margin-bottom: auto; - transform-origin: 42% 15%; + transform-origin: 50% 50%; width: 100%; - transform: rotate(55deg); - font-size: 200; + transform: rotate(40deg) scale(0.8); + font-size: 80; padding: 5%; overflow: hidden; display: inline-block; - white-space: pre; text-overflow: ellipsis; text-align: center; } @@ -202,6 +201,9 @@ } .pdfBox { + width: 100%; + height: 100%; + pointer-events: none; .pdfViewerDash-text { .textLayer { span { @@ -211,7 +213,15 @@ } } +.pdfBox-background { + width: 100%; + height: 100%; + background: lightGray; +} + .pdfBox-interactive { + width: 100%; + height: 100%; pointer-events: all; .pdfViewerDash-text { .textLayer { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index a2b406c3f..266017b5b 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -191,7 +191,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum onClick={action(() => this._pageControls = !this._pageControls)} /> {this._pageControls ? pageBtns : (null)} </div> - <div className="pdfBox-settingsCont" key="settings" onPointerDown={(e) => e.stopPropagation()}> + {/* <div className="pdfBox-settingsCont" key="settings" onPointerDown={(e) => e.stopPropagation()}> <button className="pdfBox-settingsButton" onClick={action(() => this._flyout = !this._flyout)} title="Open Annotation Settings" > <div className="pdfBox-settingsButton-arrow" style={{ transform: `scaleX(${this._flyout ? -1 : 1})` }} /> <div className="pdfBox-settingsButton-iconCont"> @@ -220,7 +220,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum </button> </div> </div> - </div> + </div> */} </div>); } @@ -236,12 +236,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum @computed get contentScaling() { return this.props.ContentScaling(); } @computed get renderTitleBox() { const classname = "pdfBox" + (this.active() ? "-interactive" : ""); - return <div className={classname} style={{ - width: !this.props.Document._fitWidth ? this.Document._nativeWidth || 0 : `${100 / this.contentScaling}%`, - //height adjusted for mobile (window.screen.width > 600) - height: !this.props.Document._fitWidth && (window.screen.width > 600) ? this.Document._nativeHeight || 0 : `${100 / this.contentScaling}%`, - transform: `scale(${this.contentScaling})` - }} > + return <div className={classname} > <div className="pdfBox-title-outer"> <strong className="pdfBox-title" >{this.props.Document.title}</strong> </div> @@ -252,6 +247,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum @computed get renderPdfView() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField); return <div className={"pdfBox"} onContextMenu={this.specificContextMenu} style={{ height: this.props.Document._scrollTop && !this.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}> + <div className="pdfBox-background"></div> <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded} setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView} renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} @@ -261,7 +257,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select} isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged} isChildActive={this.isChildActive} - fieldKey={this.props.fieldKey} startupLive={this._initialScale < 2.5 || this.props.Document._scrollTop ? true : false} /> + fieldKey={this.props.fieldKey} startupLive={true} /> {this.settingsPanel()} </div>; } @@ -269,8 +265,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum _pdfjsRequested = false; render() { const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null); - if (this.props.isSelected() || this.props.renderDepth === 0 || this.props.Document._scrollY !== undefined) this._everActive = true; - if (pdfUrl && (this._everActive || this.props.Document._scrollTop || (this.dataDoc[this.props.fieldKey + "-nativeWidth"] && this.props.ScreenToLocalTransform().Scale < 2.5))) { + if (this.props.isSelected() || (this.props.active() && this.props.renderDepth === 0) || this.props.Document._scrollY !== undefined) this._everActive = true; + if (pdfUrl && this._everActive) { if (pdfUrl instanceof PdfField && this._pdf) { return this.renderPdfView; } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 07b2d51d1..99fb5d2ce 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -12,7 +12,7 @@ import { PrefetchProxy } from "../../../fields/Proxy"; import { listSpec, makeInterface } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { returnFalse, returnOne } from "../../../Utils"; +import { returnFalse, returnOne, returnZero } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @@ -892,11 +892,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> </div> <div className="effectDirection" style={{ display: effect === 'None' ? "none" : "grid", width: 40 }}> - <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "left" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'left'}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip> - <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "right" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'right'}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip> - <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === "top" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'top'}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip> - <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === "bottom" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'bottom'}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip> - <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection ? "solid 2px black" : "solid 2px #5a9edd", borderRadius: "100%" }} onClick={() => targetDoc.presEffectDirection = false}></div></Tooltip> + <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "left" ? "#5a9edd" : "black", cursor: "pointer" }} onClick={() => targetDoc.presEffectDirection = 'left'}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip> + <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "right" ? "#5a9edd" : "black", cursor: "pointer" }} onClick={() => targetDoc.presEffectDirection = 'right'}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip> + <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === "top" ? "#5a9edd" : "black", cursor: "pointer" }} onClick={() => targetDoc.presEffectDirection = 'top'}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip> + <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === "bottom" ? "#5a9edd" : "black", cursor: "pointer" }} onClick={() => targetDoc.presEffectDirection = 'bottom'}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip> + <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection ? "solid 2px black" : "solid 2px #5a9edd", borderRadius: "100%", cursor: "pointer" }} onClick={() => targetDoc.presEffectDirection = false}></div></Tooltip> </div> </div> <div className="ribbon-final-box"> @@ -1731,6 +1731,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> ContainingCollectionDoc={this.props.Document} PanelWidth={this.props.PanelWidth} PanelHeight={this.panelHeight} + childIgnoreNativeSize={true} moveDocument={returnFalse} childOpacity={returnOne} childLayoutTemplate={this.childLayoutTemplate} diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 5d51c420b..16ce749bc 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -9,7 +9,7 @@ import { InkTool } from "../../../fields/InkField"; import { listSpec, makeInterface } from "../../../fields/Schema"; import { Cast, NumCast } from "../../../fields/Types"; import { VideoField } from "../../../fields/URLField"; -import { emptyFunction, returnFalse, returnOne, returnZero, Utils } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, returnZero, Utils, OmitKeys } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; @@ -169,11 +169,9 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh return (<div className="videoBox" onContextMenu={this.specificContextMenu} style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > <div className="videoBox-viewer" > - <CollectionFreeFormView {...this.props} + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} - NativeHeight={returnZero} - NativeWidth={returnZero} annotationsKey={""} focus={this.props.focus} isSelected={this.props.isSelected} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index d50a10bdd..51506970d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -8,7 +8,7 @@ import { InkTool } from "../../../fields/InkField"; import { createSchema, makeInterface } from "../../../fields/Schema"; import { Cast, StrCast } from "../../../fields/Types"; import { VideoField } from "../../../fields/URLField"; -import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils"; +import { Utils, emptyFunction, returnOne, returnZero, OmitKeys } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; @@ -365,11 +365,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD return (<div className="videoBox" onContextMenu={this.specificContextMenu} style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} > <div className="videoBox-viewer" > - <CollectionFreeFormView {...this.props} + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} - NativeHeight={returnZero} - NativeWidth={returnZero} annotationsKey={this.annotationKey} focus={this.props.focus} isSelected={this.props.isSelected} diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 134860d0a..ea822f553 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -2,15 +2,16 @@ .webBox { - height:100%; + height: 100%; position: relative; display: flex; .pdfViewerDash-dragAnnotationBox { - position:absolute; + position: absolute; background-color: transparent; opacity: 0.1; } + .webBox-annotationLayer { position: absolute; transform-origin: left top; @@ -19,10 +20,12 @@ pointer-events: none; mix-blend-mode: multiply; // bcz: makes text fuzzy! } + .webBox-annotationBox { position: absolute; background-color: rgba(245, 230, 95, 0.616); } + .webBox-container { transform-origin: top left; width: 100%; @@ -33,10 +36,13 @@ top: 0; left: 0; } + .webBox-cont { pointer-events: none; } - .webBox-cont, .webBox-cont-interactive { + + .webBox-cont, + .webBox-cont-interactive { padding: 0vw; position: absolute; top: 0; @@ -45,18 +51,21 @@ height: 100%; transform-origin: top left; overflow: auto; + .webBox-iframe { width: 100%; height: 100%; position: absolute; - top:0; + top: 0; } } + .webBox-cont-interactive { span { user-select: text !important; } } + .webBox-outerContent { width: 100%; height: 100%; @@ -65,8 +74,9 @@ left: 0; overflow: auto; } + div.webBox-outerContent::-webkit-scrollbar-thumb { - display:none; + display: none; } } @@ -78,14 +88,16 @@ .webBox-buttons { margin-left: 44; - background:lightGray; + background: lightGray; width: 100%; } + .webBox-annotationToggle { z-index: 9001; position: absolute; top: 2; left: 2; + cursor: pointer; box-shadow: black 0.3em 0.3em 1em; border-radius: 5px; display: flex; @@ -93,10 +105,12 @@ width: 25px; height: 25px; align-items: center; - > svg { + + >svg { margin: auto; } } + .webBox-annotationToggle:hover { opacity: 1; } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c5d7c3c9f..9620e241c 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction import { observer } from "mobx-react"; import { Dictionary } from "typescript-collections"; import * as WebRequest from 'web-request'; -import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin, DataSym } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin, DataSym, HeightSym, WidthSym } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; import { Id } from "../../../fields/FieldSymbols"; import { HtmlField } from "../../../fields/HtmlField"; @@ -14,7 +14,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { WebField } from "../../../fields/URLField"; import { TraceMobx, GetEffectiveAcl } from "../../../fields/util"; -import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils"; +import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue, OmitKeys } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; @@ -68,6 +68,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum private _iframeDragRef = React.createRef<HTMLDivElement>(); private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void); + constructor(props: any) { + super(props); + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], NumCast(this.Document._nativeWidth, 850)); + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"], NumCast(this.Document._nativeHeight, this.Document[HeightSym]() / this.Document[WidthSym]() * 850)); + } + iframeLoaded = action((e: any) => { const iframe = this._iframeRef.current; if (iframe && iframe.contentDocument) { @@ -369,7 +375,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum @undoBatch @action toggleNativeDimensions = () => { - Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight()); + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0); } specificContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; @@ -646,12 +652,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum height: NumCast(this.layoutDoc.scrollHeight), pointerEvents: this.layoutDoc._isBackground ? "none" : undefined }}> - <CollectionFreeFormView {...this.props} + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} annotationsKey={this.annotationKey} - NativeHeight={returnZero} - NativeWidth={returnZero} VisibleHeight={this.visibleHeiht} focus={this.props.focus} setPreviewCursor={this.setPreviewCursor} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 3b77735a7..90655bad6 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -245,8 +245,6 @@ export class DashDocView extends React.Component<IDashDocView> { addDocTab={this._textBox.props.addDocTab} pinToPres={returnFalse} renderDepth={self._textBox.props.renderDepth + 1} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={finalLayout[WidthSym]} PanelHeight={finalLayout[HeightSym]} focus={this.outerFocus} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index f2658e77e..f14a57e31 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -106,7 +106,10 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna ref={r => { r?.addEventListener("keydown", e => this.fieldSpanKeyDown(e, r)); r?.addEventListener("blur", e => r && this.updateText(r.textContent!, false)); - r?.addEventListener("pointerdown", action((e) => this._showEnumerables = true)); + r?.addEventListener("pointerdown", action((e) => { + this._showEnumerables = true; + e.stopPropagation(); + })); }} > {strVal} </span>; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 311143ff7..97d023673 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -23,7 +23,7 @@ import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { makeInterface } from "../../../../fields/Schema"; import { Cast, DateCast, NumCast, StrCast, ScriptCast, BoolCast } from "../../../../fields/Types"; import { TraceMobx, OVERRIDE_ACL, GetEffectiveAcl } from '../../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents, OmitKeys } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -562,7 +562,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @undoBatch @action toggleNativeDimensions = () => { - Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight()); + Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0); } public static get DefaultLayout(): Doc | string | undefined { @@ -1200,7 +1200,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if (this.props.onClick && e.button === 0 && !this.props.isSelected(false)) { e.preventDefault(); } - if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) { + if (e.button === 0 && (this.props.rootSelected(true) || this.props.isSelected(true)) && !e.altKey && !e.ctrlKey && !e.metaKey) { if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // stop propagation if not in sidebar e.stopPropagation(); // if the text box is selected, then it consumes all down events } @@ -1286,7 +1286,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } onPointerWheel = (e: React.WheelEvent): void => { // if a text note is not selected and scrollable, this prevents us from being able to scroll and zoom out at the same time - if (this.props.isSelected(true) || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { + if ((this.props.rootSelected(true) || this.props.isSelected(true)) || e.currentTarget.scrollHeight > e.currentTarget.clientHeight) { e.stopPropagation(); } } @@ -1562,11 +1562,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> : <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> - <CollectionFreeFormView {...this.props} + <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} PanelHeight={this.props.PanelHeight} PanelWidth={this.sidebarWidth} - NativeHeight={returnZero} - NativeWidth={returnZero} scaleField={this.annotationKey + "-scale"} annotationsKey={this.annotationKey} isAnnotationOverlay={false} diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index b4f648273..6c71f08e7 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -96,37 +96,38 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip.onpointerdown = async (e: PointerEvent) => { const keep = e.target && (e.target as any).type === "checkbox" ? true : false; const textBox = FormattedTextBoxComment.textBox; - if (FormattedTextBoxComment.linkDoc && !keep && textBox) { - if (FormattedTextBoxComment.linkDoc.author) { - - if (FormattedTextBoxComment._deleteRef && FormattedTextBoxComment._deleteRef.contains(e.target as any)) { + const linkDoc = FormattedTextBoxComment.linkDoc; + if (linkDoc && !keep && textBox) { + FormattedTextBoxComment.linkDoc = undefined; + if (linkDoc.author) { + if (FormattedTextBoxComment._deleteRef?.contains(e.target as any)) { this.deleteLink(); } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) { - if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right"); + if (linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right"); } else { - const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc)), textBox.dataDoc) ? - Cast(FormattedTextBoxComment.linkDoc.anchor2, Doc) : (Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc)) - || FormattedTextBoxComment.linkDoc); + const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? + Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) + || linkDoc); const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; - if (FormattedTextBoxComment.linkDoc.follow) { - if (FormattedTextBoxComment.linkDoc.follow === "default") { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); - } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in right tab") { + if (linkDoc.follow) { + if (linkDoc.follow === "default") { + DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); + } else if (linkDoc.follow === "Always open in right tab") { if (target) { textBox.props.addDocTab(target, "add:right"); } - } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in new tab") { + } else if (linkDoc.follow === "Always open in new tab") { if (target) { textBox.props.addDocTab(target, "add"); } } } else { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); + DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false); } } } else { - if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right"); + if (linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right"); } else { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation)); } } @@ -140,7 +141,7 @@ export class FormattedTextBoxComment { e.stopPropagation(); e.preventDefault(); }; - root && root.appendChild(FormattedTextBoxComment.tooltip); + root?.appendChild(FormattedTextBoxComment.tooltip); } } @@ -158,6 +159,7 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.textBox = undefined; FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none"); ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); + FormattedTextBoxComment.linkDoc = undefined; } public static SetState(textBox: any, start: number, end: number, mark: Mark) { FormattedTextBoxComment.textBox = textBox; @@ -312,15 +314,15 @@ export class FormattedTextBoxComment { searchFilterDocs={returnEmptyDoclist} ContainingCollectionDoc={undefined} ContainingCollectionView={undefined} - renderDepth={0} + renderDepth={-1} PanelWidth={() => 175} //Math.min(350, NumCast(target._width, 350))} PanelHeight={() => 175} //Math.min(250, NumCast(target._height, 250))} focus={emptyFunction} whenActiveChanged={returnFalse} bringToFront={returnFalse} ContentScaling={returnOne} - NativeWidth={() => target._nativeWidth ? NumCast(target._nativeWidth) : 0} - NativeHeight={() => target._nativeHeight ? NumCast(target._nativeHeight) : 0} + NativeWidth={target._nativeWidth ? (() => NumCast(target._nativeWidth)) : undefined} + NativeHeight={target._natvieHeight ? (() => NumCast(target._nativeHeight)) : undefined} /> </div> </div>; diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index f0bacb735..a80d2639d 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -145,8 +145,6 @@ export class DashDocView { addDocTab={this._textBox.props.addDocTab} pinToPres={returnFalse} renderDepth={self._textBox.props.renderDepth + 1} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={finalLayout[WidthSym]} PanelHeight={finalLayout[HeightSym]} focus={this.outerFocus} diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index ce784c3d9..066ceb5c8 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -40,10 +40,10 @@ export const marks: { [index: string]: MarkSpec } = { return node.attrs.docref && node.attrs.title ? ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, href: node.attrs.allLinks[0].href, class: "prosemirror-attribution" }, node.attrs.title], ["br"]] : node.attrs.allLinks.length === 1 ? - ["a", { ...node.attrs, class: linkids, dataTargetids: targetids, title: `${node.attrs.title}`, href: node.attrs.allLinks[0].href, style: `text-decoration: ${linkids === " " ? "underline" : undefined}` }, 0] : + ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}`, href: node.attrs.allLinks[0].href, style: `text-decoration: ${linkids === " " ? "underline" : undefined}` }, 0] : ["div", { class: "prosemirror-anchor" }, ["span", { class: "prosemirror-linkBtn" }, - ["a", { ...node.attrs, class: linkids, dataTargetids: targetids, title: `${node.attrs.title}` }, 0], + ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}` }, 0], ["input", { class: "prosemirror-hrefoptions" }], ], ["div", { class: "prosemirror-links" }, ...node.attrs.allLinks.map((item: { href: string, title: string }) => |
