From 5931380effc04d63bb05c47eb6bde7b20a1b214f Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 16 Nov 2023 16:18:32 -0500 Subject: removed touch code that wasn't being used or maintained --- src/client/views/nodes/ComparisonBox.tsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index b09fcd882..ff394e5f5 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -20,7 +20,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent Date: Thu, 30 Nov 2023 20:47:28 -0500 Subject: completed transition from rootDoc => Document, dataDoc, layoutDoc --- src/client/views/DocComponent.tsx | 4 - src/client/views/SidebarAnnos.tsx | 22 ++-- src/client/views/collections/CollectionView.tsx | 32 ++--- src/client/views/nodes/AudioBox.tsx | 18 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/ComparisonBox.tsx | 10 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 12 +- .../nodes/DataVizBox/components/LineChart.tsx | 8 +- src/client/views/nodes/FunctionPlotBox.tsx | 7 +- src/client/views/nodes/ImageBox.tsx | 52 ++++---- src/client/views/nodes/LoadingBox.tsx | 16 +-- src/client/views/nodes/MapBox/MapBox.tsx | 44 +++---- src/client/views/nodes/MapBox/MapBox2.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 34 +++--- src/client/views/nodes/ScreenshotBox.tsx | 24 ++-- src/client/views/nodes/ScriptingBox.tsx | 58 +++++---- src/client/views/nodes/VideoBox.tsx | 36 +++--- src/client/views/nodes/WebBox.tsx | 10 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 131 +++++++++------------ .../formattedText/FormattedTextBoxComment.tsx | 2 +- 20 files changed, 252 insertions(+), 278 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index c04359d80..04956d974 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -96,10 +96,6 @@ export function ViewBoxAnnotatableComponent

() @computed get Document() { return this.props.Document; } - // This is the "The Document" -- it encapsulates, data, layout, and any templates - @computed get rootDoc() { - return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; - } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @computed get layoutDoc() { return Doc.Layout(this.props.Document); diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 1e1b8e0e6..9377aabe9 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -20,8 +20,8 @@ import React = require('react'); interface ExtraProps { fieldKey: string; + Document: Doc; layoutDoc: Doc; - rootDoc: Doc; dataDoc: Doc; // usePanelWidth: boolean; showSidebar: boolean; @@ -42,7 +42,7 @@ export class SidebarAnnos extends React.Component { _stackRef = React.createRef(); @computed get allMetadata() { const keys = new Map>(); - DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => + DocListCast(this.props.Document[this.sidebarKey]).forEach(doc => SearchUtil.documentKeys(doc) .filter(key => key[0] && key[0] !== '_' && key[0] === key[0].toUpperCase()) .map(key => keys.set(key, doc[key])) @@ -51,7 +51,7 @@ export class SidebarAnnos extends React.Component { } @computed get allHashtags() { const keys = new Set(); - DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag))); + DocListCast(this.props.Document[this.sidebarKey]).forEach(doc => StrListCast(doc.tags).forEach(tag => keys.add(tag))); return Array.from(keys.keys()) .filter(key => key[0]) .filter(key => !key.startsWith('_') && (key[0] === '#' || key[0] === key[0].toUpperCase())) @@ -59,7 +59,7 @@ export class SidebarAnnos extends React.Component { } @computed get allUsers() { const keys = new Set(); - DocListCast(this.props.rootDoc[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author))); + DocListCast(this.props.Document[this.sidebarKey]).forEach(doc => keys.add(StrCast(doc.author))); return Array.from(keys.keys()).sort(); } @@ -69,7 +69,7 @@ export class SidebarAnnos extends React.Component { .join(' '); const target = Docs.Create.TextDocument(startup, { title: '-note-', - annotationOn: this.props.rootDoc, + annotationOn: this.props.Document, _width: 200, _height: 50, _layout_fitWidth: true, @@ -147,7 +147,7 @@ export class SidebarAnnos extends React.Component { return target; }; makeDocUnfiltered = (doc: Doc) => { - if (DocListCast(this.props.rootDoc[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) { + if (DocListCast(this.props.Document[this.sidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) { if (this.childFilters()) { // if any child filters exist, get rid of them this.props.layoutDoc._childFilters = new List(); @@ -188,7 +188,7 @@ export class SidebarAnnos extends React.Component { const renderTag = (tag: string) => { const active = this.childFilters().includes(`tags${Doc.FilterSep}${tag}${Doc.FilterSep}check`); return ( -

Doc.setDocFilter(this.props.rootDoc, 'tags', tag, 'check', true, undefined, e.shiftKey)}> +
Doc.setDocFilter(this.props.Document, 'tags', tag, 'check', true, undefined, e.shiftKey)}> {tag}
); @@ -196,7 +196,7 @@ export class SidebarAnnos extends React.Component { const renderMeta = (tag: string, dflt: FieldResult) => { const active = this.childFilters().includes(`${tag}${Doc.FilterSep}${Doc.FilterAny}${Doc.FilterSep}exists`); return ( -
Doc.setDocFilter(this.props.rootDoc, tag, Doc.FilterAny, 'exists', true, undefined, e.shiftKey)}> +
Doc.setDocFilter(this.props.Document, tag, Doc.FilterAny, 'exists', true, undefined, e.shiftKey)}> {tag}
); @@ -204,7 +204,7 @@ export class SidebarAnnos extends React.Component { const renderUsers = (user: string) => { const active = this.childFilters().includes(`author:${user}:check`); return ( -
Doc.setDocFilter(this.props.rootDoc, 'author', user, 'check', true, undefined, e.shiftKey)}> +
Doc.setDocFilter(this.props.Document, 'author', user, 'check', true, undefined, e.shiftKey)}> {user}
); @@ -215,9 +215,9 @@ export class SidebarAnnos extends React.Component { style={{ position: 'absolute', pointerEvents: this.props.isContentActive() ? 'all' : undefined, - top: this.props.rootDoc.type !== DocumentType.RTF && StrCast(this.props.rootDoc._layout_showTitle) === 'title' ? 15 : 0, + top: this.props.Document.type !== DocumentType.RTF && StrCast(this.props.Document._layout_showTitle) === 'title' ? 15 : 0, right: 0, - background: this.props.styleProvider?.(this.props.rootDoc, this.props, StyleProp.WidgetColor), + background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor), width: `100%`, height: '100%', }}> diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 389a9a534..dc2ee63f5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -141,7 +141,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent Doc) { - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._type_collection !== CollectionViewType.Docking && !this.rootDoc.isGroup && !this.rootDoc.annotationOn) { + if (!Doc.IsSystem(this.Document) && this.Document._type_collection !== CollectionViewType.Docking && !this.dataDoc.isGroup && !this.Document.annotationOn) { // prettier-ignore const subItems: ContextMenuProps[] = [ { description: 'Freeform', event: () => func(CollectionViewType.Freeform), icon: 'signature' }, @@ -172,7 +172,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const newRendition = Doc.MakeEmbedding(this.rootDoc); + const newRendition = Doc.MakeEmbedding(this.Document); newRendition._type_collection = vtype; this.props.addDocTab(newRendition, OpenWhere.addRight); return newRendition; @@ -180,18 +180,18 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this.rootDoc.forceActive = !this.rootDoc.forceActive), icon: 'project-diagram' }) : null; - if (this.rootDoc.childLayout instanceof Doc) { - optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' }); + !Doc.noviceMode ? optionItems.splice(0, 0, { description: `${this.Document.forceActive ? 'Select' : 'Force'} Contents Active`, event: () => (this.Document.forceActive = !this.Document.forceActive), icon: 'project-diagram' }) : null; + if (this.Document.childLayout instanceof Doc) { + optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.Document.childLayout as Doc, OpenWhere.addRight), icon: 'project-diagram' }); } - if (this.rootDoc.childClickedOpenTemplateView instanceof Doc) { - optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' }); + if (this.Document.childClickedOpenTemplateView instanceof Doc) { + optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.Document.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' }); } - !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.rootDoc._isLightbox = !this.rootDoc._isLightbox), icon: 'project-diagram' }); + !Doc.noviceMode && optionItems.push({ description: `${this.layoutDoc._isLightbox ? 'Unset' : 'Set'} is Lightbox`, event: () => (this.layoutDoc._isLightbox = !this.layoutDoc._isLightbox), icon: 'project-diagram' }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'hand-point-right' }); - if (!Doc.noviceMode && !this.rootDoc.annotationOn) { + if (!Doc.noviceMode && !this.Document.annotationOn) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; const funcs = [ @@ -203,7 +203,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const embedding = Doc.MakeEmbedding(this.rootDoc); + const embedding = Doc.MakeEmbedding(this.Document); DocUtils.makeCustomViewClicked(embedding, undefined, func.key); this.props.addDocTab(embedding, OpenWhere.addRight); }, @@ -213,16 +213,16 @@ export class CollectionView extends ViewBoxAnnotatableComponent (Doc.GetProto(this.rootDoc)[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))), + event: () => (this.dataDoc[StrCast(childClick.targetScriptKey)] = ObjectField.MakeCopy(ScriptCast(childClick.data))), }) ); - !Doc.IsSystem(this.rootDoc) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); + !Doc.IsSystem(this.Document) && !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } if (!Doc.noviceMode) { const more = cm.findByDescription('More...'); const moreItems = more && 'subitems' in more ? more.subitems : []; - moreItems.push({ description: 'Export Image Hierarchy', icon: 'columns', event: () => ImageUtils.ExportHierarchyToFileSystem(this.rootDoc) }); + moreItems.push({ description: 'Export Image Hierarchy', icon: 'columns', event: () => ImageUtils.ExportHierarchyToFileSystem(this.Document) }); !more && cm.addItem({ description: 'More...', subitems: moreItems, icon: 'hand-point-right' }); } } @@ -232,7 +232,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles); childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle); - childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null); + childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null); isContentActive = (outsideReaction?: boolean) => this._isContentActive; render() { @@ -249,7 +249,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent + style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform && this.layoutDoc._lockedPosition ? 'none' : undefined }}> {this.renderSubView(this.collectionViewType, props)}
); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 807a77233..dacdbe986 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -139,17 +139,17 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); + const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); const textField = Doc.LayoutFieldKey(newDoc); Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc; Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`); Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`); - if (Doc.IsInMyOverlay(this.rootDoc)) { - newDoc.overlayX = this.rootDoc.x; - newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height); + if (Doc.IsInMyOverlay(this.Document)) { + newDoc.overlayX = this.Document.x; + newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height); Doc.AddToMyOverlay(newDoc); } else { this.props.addDocument?.(newDoc); @@ -424,7 +424,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - if (link.annotationOn === this.rootDoc) { + if (link.annotationOn === this.Document) { if (!this.layoutDoc.dontAutoPlayFollowedLinks) { this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link)); } else { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2c53a1d5b..b7cd306ae 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -72,7 +72,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent this.Highlight; // prettier-ignore w_Width = () => this.Width; // prettier-ignore w_Height = () => this.Height; // prettier-ignore - w_AutoDim = () => this.AutoDim; + w_AutoDim = () => this.AutoDim; w_Transition = () => this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore @@ -254,7 +254,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined; - const isGroup = this.Document.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); + const isGroup = this.dataDoc.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined; }; public static CollectionFreeFormDocViewClassName = 'collectionFreeFormDocumentView-container'; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index ff394e5f5..b050e3252 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -44,7 +44,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { if (dropEvent.complete.docDragData) { const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments; - const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey)); + const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.Document, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey)); Doc.SetContainer(droppedDocs.lastElement(), this.dataDoc); !added && e.preventDefault(); e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place @@ -93,18 +93,18 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { const anchor = Docs.Create.ConfigDocument({ - title: 'CompareAnchor:' + this.rootDoc.title, + title: 'CompareAnchor:' + this.Document.title, // set presentation timing properties for restoring view presentation_transition: 1000, - annotationOn: this.rootDoc, + annotationOn: this.Document, }); if (anchor) { if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; /* addAsAnnotation &&*/ this.addDocument(anchor); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), clippable: true } }, this.Document); return anchor; } - return this.rootDoc; + return this.Document; }; @undoBatch diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 1cb0a50f3..cc2c44435 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -35,7 +35,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // all CSV records in the dataset (that aren't an empty row) @computed.struct get records() { - var records = DataVizBox.dataset.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); + var records = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href); return records?.filter(record => Object.keys(record).some(key => record[key])) ?? []; } @@ -75,7 +75,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }; getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => { const anchor = !pinProps - ? this.rootDoc + ? this.Document : this._vizRenderer?.getAnchor(pinProps) ?? Docs.Create.ConfigDocument({ // when we clear selection -> we should have it so chartBox getAnchor returns undefined @@ -99,20 +99,20 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { componentDidMount() { this.props.setContentView?.(this); - if (!DataVizBox.dataset.has(CsvCast(this.rootDoc[this.fieldKey]).url.href)) this.fetchData(); + if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); } fetchData = () => { - DataVizBox.dataset.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests + DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, []); // assign temporary dataset as a lock to prevent duplicate server requests fetch('/csvData?uri=' + this.dataUrl?.url.href) // - .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res)))); + .then(res => res.json().then(action(res => !res.errno && DataVizBox.dataset.set(CsvCast(this.dataDoc[this.fieldKey]).url.href, res)))); }; // toggles for user to decide which chart type to view the data in @computed get renderVizView() { const scale = this.props.NativeDimScaling?.() || 1; const sharedProps = { - rootDoc: this.rootDoc, + rootDoc: this.Document, layoutDoc: this.layoutDoc, records: this.records, axes: this.axes, diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 3de7a0c4a..ad34a0c99 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -23,7 +23,7 @@ export interface SelectedDataPoint extends DataPoint { elem?: d3.Selection; } export interface LineChartProps { - rootDoc: Doc; + Document: Doc; layoutDoc: Doc; axes: string[]; records: { [key: string]: any }[]; @@ -63,7 +63,7 @@ export class LineChart extends React.Component { return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart'; } @computed get parentViz() { - return DocCast(this.props.rootDoc.dataViz_parentViz); + return DocCast(this.props.Document.dataViz_parentViz); // return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links // .filter(link => { // return link.link_anchor_1 == this.props.rootDoc.dataViz_parentViz; @@ -74,7 +74,7 @@ export class LineChart extends React.Component { // return selected x and y axes // otherwise, use the selection of whatever is linked to us const incomingVizBox = DocumentManager.Instance.getFirstDocumentView(this.parentViz)?.ComponentView as DataVizBox; - const highlitedRowIds = NumListCast(incomingVizBox?.rootDoc?.dataViz_highlitedRows); + const highlitedRowIds = NumListCast(incomingVizBox?.layoutDoc?.dataViz_highlitedRows); return this._tableData.filter((record, i) => highlitedRowIds.includes(this._tableDataIds[i])); // get all the datapoints they have selected field set by incoming anchor } @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } { @@ -170,7 +170,7 @@ export class LineChart extends React.Component { // title: 'line doc selection' + this._currSelected?.x, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.rootDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document); anchor.config_dataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; return anchor; }; diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index daf6cd9a6..5ed5fa8fd 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -43,11 +43,8 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent ); } getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { - const anchor = Docs.Create.ConfigDocument({ - // - annotationOn: this.rootDoc, - }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.rootDoc); + const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document }); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.Document); anchor.config_xRange = new List(Array.from(this._plot.options.xAxis.domain)); anchor.config_yRange = new List(Array.from(this._plot.options.yAxis.domain)); if (addAsAnnotation) this.addDocument(anchor); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 19e393968..7e85c33b8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -89,26 +89,26 @@ export class ImageBox extends ViewBoxAnnotatableComponent ({ forceFull: this.props.renderDepth < 1 || this.layoutDoc._showFullRes, - scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.rootDoc._freeform_scale, 1), + scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), selected: this.props.isSelected(), }), ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'), @@ -152,7 +152,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover'; + this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover'; return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop); }, true); } else if (de.altKey || !this.dataDoc[this.fieldKey]) { @@ -177,13 +177,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1); + const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); const nscale = NumCast(this.props.PanelWidth()) / scaling; const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw; - this.rootDoc._freeform_panX = nw * NumCast(this.rootDoc._freeform_panX); - this.rootDoc._freeform_panY = nw * NumCast(this.rootDoc._freeform_panY); + this.layoutDoc._freeform_panX = nw * NumCast(this.layoutDoc._freeform_panX); + this.layoutDoc._freeform_panY = nw * NumCast(this.layoutDoc._freeform_panY); this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined; this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined; this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined; @@ -206,17 +206,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent setTimeout(() => (dv.ComponentView as ImageBox).setNativeSize(), 200)); @@ -263,7 +263,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; }; - getScrollHeight = () => (this.props.layout_fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._freeform_scale, 1) === NumCast(this.rootDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); + getScrollHeight = () => (this.props.layout_fitWidth?.(this.Document) !== false && NumCast(this.layoutDoc._freeform_scale, 1) === NumCast(this.dataDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); @computed private get considerDownloadIcon() { @@ -384,7 +384,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))} + onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, e => (this.layoutDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))} style={{ display: (this.props.isContentActive() !== false && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none', width: 'min(10%, 25px)', @@ -434,7 +434,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}> @@ -481,7 +481,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.props.ScreenToLocalTransform().Scale); marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._freeform_scale, 1) <= NumCast(this.rootDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -529,7 +529,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent () { _timer: any; @observable progress = ''; componentDidMount() { - if (!LoadingBox.CurrentlyLoading?.includes(this.rootDoc)) { - this.rootDoc.loadingError = 'Upload interrupted, please try again'; + if (!LoadingBox.CurrentlyLoading?.includes(this.Document)) { + this.Document.loadingError = 'Upload interrupted, please try again'; } else { const updateFunc = async () => { - const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc[Id])); // We use the guid of the overwriteDoc to track file uploads. + const result = await Networking.QueryYoutubeProgress(StrCast(this.Document[Id])); // We use the guid of the overwriteDoc to track file uploads. runInAction(() => (this.progress = result.progress)); - !this.rootDoc.loadingError && (this._timer = setTimeout(updateFunc, 1000)); + !this.Document.loadingError && (this._timer = setTimeout(updateFunc, 1000)); }; this._timer = setTimeout(updateFunc, 1000); } @@ -74,11 +74,11 @@ export class LoadingBox extends ViewBoxAnnotatableComponent() { render() { return ( -
+
- {StrCast(this.rootDoc.title)} -

{StrCast(this.rootDoc.loadingError, 'Loading ' + (this.progress.replace('[download]', '') || '(can take several minutes)'))}

- {this.rootDoc.loadingError ? null : ( + {StrCast(this.Document.title)} +

{StrCast(this.Document.loadingError, 'Loading ' + (this.progress.replace('[download]', '') || '(can take several minutes)'))}

+ {this.rootDDocumentoc.loadingError ? null : (
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 9b75ca7e3..8d3cd1d96 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -195,7 +195,7 @@ export class MapBox extends ViewBoxAnnotatableComponent @@ -227,7 +227,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); FormattedTextBox.SelectOnLoad = target[Id]; return target; }; @@ -321,7 +321,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); - Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + Doc.setDocFilter(this.layoutDoc, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.layoutDoc, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); const temp = this.selectedPin; if (!this._unmounting) { @@ -369,7 +369,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER const anchor = Docs.Create.ConfigDocument({ - title: 'MapAnchor:' + this.rootDoc.title, - text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location', + title: 'MapAnchor:' + this.Document.title, + text: StrCast(this.selectedPin?.map) || StrCast(this.dataDoc.map) || 'map location', config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude), config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), @@ -466,15 +466,15 @@ export class MapBox extends ViewBoxAnnotatableComponent(); @@ -521,9 +521,9 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); - Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + Doc.setDocFilter(this.layoutDoc, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.layoutDoc, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.layoutDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); this.removePushpin(this.selectedPin); } @@ -611,7 +611,7 @@ export class MapBox extends ViewBoxAnnotatableComponent this.rootDoc.map, + () => this.dataDoc.map, mapLoc => (this.bingSearchBarContents = mapLoc), { fireImmediately: true } ); @@ -636,7 +636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }), + () => ({ lat: this.dataDoc.latitude, lng: this.dataDoc.longitude, zoom: this.dataDoc.map_zoom, mapType: this.dataDoc.map_type }), locationObject => { // if (this._bingMap.current) try { @@ -687,7 +687,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map); + const createPin = () => this.createPushpin(this.dataDoc.latitude, this.dataDoc.longitude, this.dataDoc.map); if (this.bingSearchBarContents) { this.bingSearch().then(createPin); } else createPin(); @@ -703,7 +703,7 @@ export class MapBox extends ViewBoxAnnotatableComponent @@ -495,7 +495,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.rootDoc; + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => AnchorMenu.Instance?.GetAnchor(this._savedAnnotations, addAsAnnotation) ?? this.Document; /** * render contents in allMapMarkers (e.g. images with exifData) into google maps as map marker @@ -577,7 +577,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { @@ -173,7 +173,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { @@ -200,13 +200,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.rootDoc.layout_scrollTop, + () => this.layoutDoc.layout_scrollTop, () => { if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '_panY'])) instanceof ComputedField)) { this.props.Document[this.SidebarKey + '_panY'] = ComputedField.MakeFunction('this.layout_scrollTop'); } - this.props.Document[this.SidebarKey + '_freeform_scale'] = 1; - this.props.Document[this.SidebarKey + '_freeform_panX'] = 0; + this.layoutDoc[this.SidebarKey + '_freeform_scale'] = 1; + this.layoutDoc[this.SidebarKey + '_freeform_panX'] = 0; } ); } @@ -236,12 +236,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent Docs.Create.ConfigDocument({ - title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)), - annotationOn: this.rootDoc, + title: StrCast(this.Document.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)), + annotationOn: this.Document, }); const visibleAnchor = this._pdfViewer?._getAnchor?.(this._pdfViewer.savedAnnotations(), true); const anchor = visibleAnchor ?? docAnchor(); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.rootDoc); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), scrollable: true, pannable: true } }, this.Document); anchor.text = ele?.textContent ?? ''; anchor.text_html = ele?.innerHTML; addAsAnnotation && this.addDocument(anchor); @@ -434,7 +434,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent (this.rootDoc[this.SidebarKey + '_type_collection'] = this.rootDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform); + toggleSidebarType = () => (this.dataDoc[this.SidebarKey + '_type_collection'] = this.dataDoc[this.SidebarKey + '_type_collection'] === CollectionViewType.Freeform ? CollectionViewType.Stacking : CollectionViewType.Freeform); specificContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; const options = cm.findByDescription('Options...'); @@ -473,7 +473,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.sidebarBtnDown(e, true)}> @@ -509,7 +509,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const startTime = Cast(this.layoutDoc._layout_currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined); - return CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.rootDoc; + return CollectionStackedTimeline.createAnchor(this.Document, this.dataDoc, this.annotationKey, startTime, startTime === undefined ? undefined : startTime + 3, undefined, addAsAnnotation) || this.Document; }; videoLoad = () => { @@ -151,7 +151,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }), + // this.layoutDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }), // ({ width, height }) => { // if (this._camera) { // const angle = -Math.abs(1 - width / height); @@ -173,7 +173,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { this._videoRef = r; setTimeout(() => { - if (this.rootDoc.mediaState === media_state.PendingRecording && this._videoRef) { + if (this.layoutDoc.mediaState === media_state.PendingRecording && this._videoRef) { this.toggleRecording(); } }, 100); @@ -202,12 +202,12 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent this._raised = r; @computed get threed() { - // if (this.rootDoc.videoWall) { + // if (this.layoutDoc.videoWall) { // const screens: any[] = []; // const colors = ["yellow", "red", "orange", "brown", "maroon", "gray"]; // let count = 0; // numberRange(this._numScreens).forEach(x => numberRange(this._numScreens).forEach(y => screens.push( - // ))); + // ))); // return { // this._camera = props.camera; // props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2); @@ -250,7 +250,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { if (this.dataDoc[this.fieldKey + '_dictation']) return; - const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.rootDoc.x), NumCast(this.rootDoc.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); + const dictationText = DocUtils.GetNewTextDoc('dictation', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); const textField = Doc.LayoutFieldKey(dictationText); dictationText._layout_autoHeight = false; const dictationTextProto = Doc.GetProto(dictationText); diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index a51a83b26..127edaed7 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -61,7 +61,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent !p.startsWith('_')) @@ -78,30 +78,30 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent p.split(':')[1].trim()); } @computed({ keepAlive: true }) get rawScript() { - return ScriptCast(this.rootDoc[this.fieldKey])?.script.originalScript ?? ''; + return ScriptCast(this.dataDoc[this.fieldKey])?.script.originalScript ?? ''; } @computed({ keepAlive: true }) get functionName() { - return StrCast(this.rootDoc[this.props.fieldKey + '-functionName'], ''); + return StrCast(this.dataDoc[this.fieldKey + '-functionName'], ''); } @computed({ keepAlive: true }) get functionDescription() { - return StrCast(this.rootDoc[this.props.fieldKey + '-functionDescription'], ''); + return StrCast(this.dataDoc[this.fieldKey + '-functionDescription'], ''); } @computed({ keepAlive: true }) get compileParams() { - return Cast(this.rootDoc[this.props.fieldKey + '-params'], listSpec('string'), []); + return Cast(this.dataDoc[this.fieldKey + '-params'], listSpec('string'), []); } set rawScript(value) { - Doc.SetInPlace(this.rootDoc, this.props.fieldKey, new ScriptField(undefined, undefined, value), true); + this.dataDoc[this.fieldKey] = new ScriptField(undefined, undefined, value); } set functionName(value) { - Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionName', value, true); + this.dataDoc[this.fieldKey + '-functionName'] = value; } set functionDescription(value) { - Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-functionDescription', value, true); + this.dataDoc[this.fieldKey + '-functionDescription'] = value; } set compileParams(value) { - Doc.SetInPlace(this.rootDoc, this.props.fieldKey + '-params', new List(value), true); + this.dataDoc[this.fieldKey + '-params'] = new List(value); } getValue(result: any, descrip: boolean) { @@ -165,9 +165,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { - this.rootDoc.layout_fieldKey = 'layout'; - }; + onFinish = () => (this.layoutDoc.layout_fieldKey = 'layout'); // displays error message @action @@ -189,7 +187,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { if (this.onCompile()) { const bindings: { [name: string]: any } = {}; - this.paramsNames.forEach(key => (bindings[key] = this.rootDoc[key])); + this.paramsNames.forEach(key => (bindings[key] = this.dataDoc[key])); // binds vars so user doesnt have to refer to everything as this. - ScriptCast(this.rootDoc[this.fieldKey], null)?.script.run({ ...bindings, self: this.rootDoc, this: this.layoutDoc }, this.onError); + ScriptCast(this.dataDoc[this.fieldKey], null)?.script.run({ ...bindings, this: this.Document }, this.onError); } }; @@ -270,7 +268,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { if (de.complete.docDragData) { - de.complete.docDragData.droppedDocuments.forEach(doc => Doc.SetInPlace(this.rootDoc, fieldKey, doc, true)); + de.complete.docDragData.droppedDocuments.forEach(doc => (this.dataDoc[fieldKey] = doc)); e.stopPropagation(); return true; } @@ -280,7 +278,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { - Doc.SetInPlace(this.rootDoc, this.paramsNames[num], undefined, true); + this.dataDoc[this.paramsNames[num]] = undefined; this.compileParams.splice(num, 1); return true; }; @@ -290,13 +288,13 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { //@ts-ignore const val = e.target.selectedOptions[0].value; - Doc.SetInPlace(this.rootDoc, name, val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true', true); + this.dataDoc[name] = val[0] === 'S' ? val.substring(1) : val[0] === 'N' ? parseInt(val.substring(1)) : val.substring(1) === 'true'; }; // creates a copy of the script document onCopy = () => { - const copy = Doc.MakeCopy(this.rootDoc, true); - copy.x = NumCast(this.dataDoc.x) + NumCast(this.dataDoc._width); + const copy = Doc.MakeCopy(this.Document, true); + copy.x = NumCast(this.Document.x) + NumCast(this.dataDoc._width); this.props.addDocument?.(copy); }; @@ -346,8 +344,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent StrCast(DocCast(this.rootDoc[parameter])?.title, 'undefined')} + contents={StrCast(DocCast(this.dataDoc[parameter])?.title, 'undefined')} + GetValue={() => StrCast(DocCast(this.dataDoc[parameter])?.title, 'undefined')} SetValue={action((value: string) => { const script = CompileScript(value, { addReturn: true, @@ -357,7 +355,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent e.stopPropagation()} onChange={e => this.viewChanged(e, parameter)} - value={typeof this.rootDoc[parameter] === 'string' ? 'S' + StrCast(this.rootDoc[parameter]) : typeof this.rootDoc[parameter] === 'number' ? 'N' + NumCast(this.rootDoc[parameter]) : 'B' + BoolCast(this.rootDoc[parameter])}> + value={typeof this.dataDoc[parameter] === 'string' ? 'S' + StrCast(this.dataDoc[parameter]) : typeof this.dataDoc[parameter] === 'number' ? 'N' + NumCast(this.dataDoc[parameter]) : 'B' + BoolCast(this.dataDoc[parameter])}> {types.map((type, i) => (
)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 8b3531da8..2ac9c7bfb 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { Toggle, ToggleType, Type } from 'browndash-components'; diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index ad5431c8e..545734e5b 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 9e5f09479..9be01df18 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index ad8144466..c5677e2ba 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -12,7 +12,7 @@ import { computePassLayout, computeStarburstLayout } from './collectionFreeForm' import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionPileView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 7fee1cda6..92b5470ae 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 59e0c60b9..e5f71a2f8 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CursorProperty } from 'csstype'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 9bd412fb8..3282eb4b4 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index f082ca0da..40b2f9644 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -24,7 +24,7 @@ import { ViewBoxBaseComponent } from '../DocComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { LoadingBox } from '../nodes/LoadingBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; -import React = require('react'); +import * as React from 'react'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 8d114761a..e65f24702 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -21,7 +21,7 @@ import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './coll import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionTimeView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 1315decb2..5c165fe70 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -26,7 +26,7 @@ import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTreeView.scss'; import { TreeView } from './TreeView'; -import React = require('react'); +import * as React from 'react'; const _global = (window /* browser */ || global) /* node */ as any; export type collectionTreeViewProps = { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index def4beca3..4a1d702b8 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -33,7 +33,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; -import React = require('react'); +import * as React from 'react'; import { Docs } from '../../documents/Documents'; import { ComputedField } from '../../../fields/ScriptField'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 0de1068f7..b5666b917 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -35,7 +35,7 @@ import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; -import React = require('react'); +import * as React from 'react'; export interface TreeViewProps { treeView: CollectionTreeView; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx index 00505dbe3..99ee5ef4e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx @@ -2,7 +2,7 @@ import { observer } from 'mobx-react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; export interface CollectionFreeFormViewBackgroundGridProps { panX: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d6a738084..b8c0967c1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -5,7 +5,7 @@ import { RefField } from '../../../../fields/RefField'; import { listSpec } from '../../../../fields/Schema'; import { Cast, NumCast, StrCast } from '../../../../fields/Types'; import { aggregateBounds } from '../../../../Utils'; -import React = require('react'); +import * as React from 'react'; export interface ViewDefBounds { type: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 0c0d45a30..fac5e849b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -13,7 +13,7 @@ import { SnappingManager } from '../../../util/SnappingManager'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../../nodes/DocumentView'; import './CollectionFreeFormLinkView.scss'; -import React = require('react'); +import * as React from 'react'; export interface CollectionFreeFormLinkViewProps { A: DocumentView; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 420e6a318..779a0bf96 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -5,7 +5,7 @@ import { DocumentManager } from '../../../util/DocumentManager'; import { LightboxView } from '../../LightboxView'; import './CollectionFreeFormLinksView.scss'; import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; -import React = require('react'); +import * as React from 'react'; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index 38aeea152..f54726a00 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -4,7 +4,7 @@ import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; import { CollectionFreeFormView } from './CollectionFreeFormView'; export interface CollectionFreeFormPannableContentsProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 9e8d92d7d..1118c6a72 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -9,7 +9,7 @@ import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; import { CollectionViewProps } from '../CollectionView'; import './CollectionFreeFormView.scss'; -import React = require('react'); +import * as React from 'react'; import v5 = require('uuid/v5'); @observer diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d242b1356..fbad01cad 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -50,7 +50,7 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import React = require('react'); +import * as React from 'react'; export type collectionFreeformViewProps = { NativeWidth?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 607f9fb95..d231197fb 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 18b9b4423..330c13e97 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -24,7 +24,7 @@ import { PreviewCursor } from '../../PreviewCursor'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import React = require('react'); +import * as React from 'react'; import { freeformScrollMode } from '../../../util/SettingsManager'; interface MarqueeViewProps { diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.scss b/src/client/views/collections/collectionLinear/CollectionLinearView.scss index d0c14a21d..3c2f5ccd7 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.scss +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.scss @@ -18,9 +18,9 @@ user-select: none; } - > input:not(:checked) ~ &.true { - background-color: transparent; - } + // > input:not(:checked) ~ &.true { + // background-color: transparent; + // } .collectionLinearView { display: flex; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 030f9953c..029d39f88 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, ObservableMap, observe } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 65e47f441..0e37198bb 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 03697b40a..53f4a4d51 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { IconButton, Size } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index 3082c632d..3d9cf1893 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -6,7 +6,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenu.scss'; import { LinkMenuGroup } from './LinkMenuGroup'; -import React = require('react'); +import * as React from 'react'; import { SettingsManager } from '../../util/SettingsManager'; interface Props { diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 5453ed07b..91142b90b 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -7,7 +7,7 @@ import { LinkManager } from '../../util/LinkManager'; import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; import { LinkMenuItem } from './LinkMenuItem'; -import React = require('react'); +import * as React from 'react'; import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuGroupProps { diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 611771fff..042acff05 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -17,7 +17,7 @@ import { undoBatch } from '../../util/UndoManager'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkMenuItemProps { groupType: string; diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index a36c8d778..5460a6daf 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -10,7 +10,7 @@ import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkPopupProps { linkFrom?: () => Doc | undefined; diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 9662b2fea..3e7f5be74 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; import './LinkEditor.scss'; -import React = require('react'); +import * as React from 'react'; interface link_relationshipSearchProps { results: string[] | undefined; diff --git a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx index a085e4a66..23027808f 100644 --- a/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx +++ b/src/client/views/newlightbox/components/Recommendation/Recommendation.tsx @@ -25,11 +25,13 @@ export const Recommendation = (props: IRecommendation) => { switch (type) { case 'YouTube': console.log('create ', type, 'document'); - doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript }); + doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315 }); + doc.transcript = transcript ? JSON.stringify(transcript) : undefined; break; case 'Video': console.log('create ', type, 'document'); - doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315, transcript }); + doc = Docs.Create.VideoDocument(data, { title: title, _width: 400, _height: 315 }); + doc.transcript = transcript ? JSON.stringify(transcript) : undefined; break; case 'Webpage': console.log('create ', type, 'document'); diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index dacdbe986..8b9c5ae67 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 6195a155d..624f28413 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -14,7 +14,7 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './CollectionFreeFormDocumentView.scss'; import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; -import React = require('react'); +import * as React from 'react'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 2a20d935b..852d39800 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 9fd4fbcaa..72a473114 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -13,7 +13,7 @@ import './ComparisonBox.scss'; import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; @observer export class ComparisonBox extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index 4dbd67485..f9e7a4617 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -277,6 +277,7 @@ export class PieChart extends React.Component { return 'slice'; } ) + // @ts-ignore .attr('d', arc) .on('click', onPointClick) .on('mouseover', onHover) diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4b58bfe48..b0c94a06a 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -46,7 +46,7 @@ import { ScriptingBox } from './ScriptingBox'; import { PresBox } from './trails/PresBox'; import { VideoBox } from './VideoBox'; import { WebBox } from './WebBox'; -import React = require('react'); +import * as React from 'react'; import XRegExp = require('xregexp'); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index ce3650749..9d233ead5 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -15,7 +15,7 @@ import { DocumentView } from './DocumentView'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import { PinProps } from './trails'; -import React = require('react'); +import * as React from 'react'; import _ = require('lodash'); interface DocumentLinksButtonProps { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index bfbe3389f..f6a14eab1 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -51,7 +51,7 @@ import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import React = require('react'); +import * as React from 'react'; const { Howl } = require('howler'); interface Window { diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx index 20afa4565..8d03bf57a 100644 --- a/src/client/views/nodes/FaceRectangle.tsx +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -1,14 +1,14 @@ -import React = require("react"); -import { observer } from "mobx-react"; -import { observable, runInAction } from "mobx"; -import { RectangleTemplate } from "./FaceRectangles"; +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { observable, runInAction } from 'mobx'; +import { RectangleTemplate } from './FaceRectangles'; @observer export default class FaceRectangle extends React.Component<{ rectangle: RectangleTemplate }> { @observable private opacity = 0; componentDidMount() { - setTimeout(() => runInAction(() => this.opacity = 1), 500); + setTimeout(() => runInAction(() => (this.opacity = 1)), 500); } render() { @@ -18,12 +18,11 @@ export default class FaceRectangle extends React.Component<{ rectangle: Rectangl style={{ ...rectangle.style, opacity: this.opacity, - transition: "1s ease opacity", - position: "absolute", - borderRadius: 5 + transition: '1s ease opacity', + position: 'absolute', + borderRadius: 5, }} /> ); } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 0d1e063af..26e720c0d 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,9 +1,9 @@ -import React = require("react"); -import { Doc, DocListCast } from "../../../fields/Doc"; -import { Cast, NumCast } from "../../../fields/Types"; -import { observer } from "mobx-react"; -import { Id } from "../../../fields/FieldSymbols"; -import FaceRectangle from "./FaceRectangle"; +import * as React from 'react'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { Cast, NumCast } from '../../../fields/Types'; +import { observer } from 'mobx-react'; +import { Id } from '../../../fields/FieldSymbols'; +import FaceRectangle from './FaceRectangle'; interface FaceRectanglesProps { document: Doc; @@ -18,7 +18,6 @@ export interface RectangleTemplate { @observer export class FaceRectangles extends React.Component { - render() { const faces = DocListCast(this.props.document.faces); const templates: RectangleTemplate[] = faces.map(faceDoc => { @@ -33,14 +32,15 @@ export class FaceRectangles extends React.Component { } as React.CSSProperties; return { id: rectangle[Id], - style: style + style: style, }; }); return (
- {templates.map(rectangle => )} + {templates.map(rectangle => ( + + ))}
); } - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 219e3025a..f4c5167a5 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; import { DateField } from '../../../fields/DateField'; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index d28d71fe3..336891a18 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -35,7 +35,7 @@ import { FaceRectangles } from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; export const pageSchema = createSchema({ googlePhotosUrl: 'string', diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 0c6377c3a..d2325a807 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -20,7 +20,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { ImageBox } from './ImageBox'; import './KeyValueBox.scss'; import { KeyValuePair } from './KeyValuePair'; -import React = require('react'); +import * as React from 'react'; export type KVPScript = { script: CompiledScript; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 577685636..8f3c75f54 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -12,7 +12,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import React = require('react'); +import * as React from 'react'; import { DocCast } from '../../../fields/Types'; import { Tooltip } from '@material-ui/core'; import { DocumentOptions, FInfo } from '../../documents/Documents'; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index cf157c3a9..d10cbac5e 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -12,7 +12,7 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkDocPreview } from './LinkDocPreview'; -import React = require('react'); +import * as React from 'react'; import globalCssVariables = require('../global/globalCssVariables.scss'); @observer diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 743075c89..ed448ecfb 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { Bezier } from 'bezier-js'; import { computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index c45045a8a..32300d60a 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index ad5324b3e..b5fb6db86 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -18,7 +18,7 @@ import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; -import React = require('react'); +import * as React from 'react'; interface LinkDocPreviewProps { linkDoc?: Doc; diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index f6680aac0..e6c1db0af 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx index 56f0a49b8..590f8735c 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -2,7 +2,7 @@ import { observer } from 'mobx-react'; // import { SettingsManager } from '../../../util/SettingsManager'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; -import React = require('react'); +import * as React from 'react'; import { computed } from 'mobx'; import { MapBox } from './MapBox'; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 9787de0ab..8de8498d7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -31,7 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; import { PinProps, PresBox } from './trails'; -import React = require('react'); +import * as React from 'react'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() { diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index cd1ff17dd..c498a58d6 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -15,11 +15,11 @@ import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from './../FieldView'; import './PhysicsSimulationBox.scss'; import InputField from './PhysicsSimulationInputField'; -import * as questions from './PhysicsSimulationQuestions.json'; -import * as tutorials from './PhysicsSimulationTutorial.json'; +import questions from './PhysicsSimulationQuestions.json'; +import tutorials from './PhysicsSimulationTutorial.json'; import Wall from './PhysicsSimulationWall'; import Weight from './PhysicsSimulationWeight'; -import React = require('react'); +import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx index d595a499e..c704863f5 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationInputField.tsx @@ -1,6 +1,6 @@ import { TextField, InputAdornment } from '@mui/material'; import { Doc } from '../../../../fields/Doc'; -import React = require('react'); +import * as React from 'react'; import TaskAltIcon from '@mui/icons-material/TaskAlt'; import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; import { isNumber } from 'lodash'; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx index 8cc1d0fbf..696352296 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx @@ -1,34 +1,33 @@ -import React = require('react'); +import * as React from 'react'; export interface Force { - magnitude: number; - directionInDegrees: number; + magnitude: number; + directionInDegrees: number; } export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; } export default class Wall extends React.Component { + constructor(props: any) { + super(props); + } - constructor(props: any) { - super(props) - } + wallStyle = { + width: this.props.angleInDegrees == 0 ? this.props.length + '%' : '5px', + height: this.props.angleInDegrees == 0 ? '5px' : this.props.length + '%', + position: 'absolute' as 'absolute', + left: this.props.xPos + '%', + top: this.props.yPos + '%', + backgroundColor: '#6c7b8b', + margin: 0, + padding: 0, + }; - wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px", - height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%", - position: "absolute" as "absolute", - left: this.props.xPos + "%", - top: this.props.yPos + "%", - backgroundColor: "#6c7b8b", - margin: 0, - padding: 0, - }; - - render () { - return (
); - } -}; + render() { + return
; + } +} diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index 2165c8ba9..99333991f 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,7 +1,7 @@ import { computed, IReactionDisposer, reaction } from 'mobx'; import { observer } from 'mobx-react'; import './PhysicsSimulationBox.scss'; -import React = require('react'); +import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 7f0956e51..191877cb5 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,8 +1,8 @@ -import React = require("react"); -import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import "./RadialMenu.scss"; -import { RadialMenuItem, RadialMenuProps } from "./RadialMenuItem"; +import * as React from 'react'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import './RadialMenu.scss'; +import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem'; @observer export class RadialMenu extends React.Component { @@ -23,11 +23,10 @@ export class RadialMenu extends React.Component { public used: boolean = false; - catchTouch = (te: React.TouchEvent) => { te.stopPropagation(); te.preventDefault(); - } + }; @action onPointerDown = (e: PointerEvent) => { @@ -35,8 +34,8 @@ export class RadialMenu extends React.Component { this._mouseX = e.clientX; this._mouseY = e.clientY; this.used = false; - document.addEventListener("pointermove", this.onPointerMove); - } + document.addEventListener('pointermove', this.onPointerMove); + }; @observable private _closest: number = -1; @@ -60,11 +59,10 @@ export class RadialMenu extends React.Component { } } this._closest = closest; - } - else { + } else { this._closest = -1; } - } + }; @action onPointerUp = (e: PointerEvent) => { this.used = true; @@ -75,43 +73,41 @@ export class RadialMenu extends React.Component { this._shouldDisplay = false; } this._shouldDisplay && (this._display = true); - document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener('pointermove', this.onPointerMove); if (this._closest !== -1 && this._items?.length > this._closest) { this._items[this._closest].event(); } - } + }; componentWillUnmount() { - document.removeEventListener("pointerdown", this.onPointerDown); + document.removeEventListener('pointerdown', this.onPointerDown); - document.removeEventListener("pointerup", this.onPointerUp); + document.removeEventListener('pointerup', this.onPointerUp); this._reactionDisposer && this._reactionDisposer(); } @action componentDidMount = () => { - document.addEventListener("pointerdown", this.onPointerDown); - document.addEventListener("pointerup", this.onPointerUp); + document.addEventListener('pointerdown', this.onPointerDown); + document.addEventListener('pointerup', this.onPointerUp); this.previewcircle(); this._reactionDisposer = reaction( () => this._shouldDisplay, - () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true) + () => this._shouldDisplay && !this._mouseDown && runInAction(() => (this._display = true)) ); - } + }; componentDidUpdate = () => { this.previewcircle(); - } + }; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @observable _display: boolean = false; @observable private _yRelativeToTop: boolean = true; - @observable private _width: number = 0; @observable private _height: number = 0; - getItems() { return this._items; } @@ -133,7 +129,7 @@ export class RadialMenu extends React.Component { this._mouseX = x; this._mouseY = y; this._shouldDisplay = true; - } + }; // @computed // get pageX() { // const x = this._pageX; @@ -168,7 +164,7 @@ export class RadialMenu extends React.Component { this.clearItems(); this._display = false; this._shouldDisplay = false; - } + }; @action openMenu = (x: number, y: number) => { @@ -176,56 +172,52 @@ export class RadialMenu extends React.Component { this._pageY = y; this._shouldDisplay; this._display = true; - } + }; @action clearItems() { this._items = []; } - previewcircle() { - if (document.getElementById("newCanvas") !== null) { - const c: any = document.getElementById("newCanvas"); + if (document.getElementById('newCanvas') !== null) { + const c: any = document.getElementById('newCanvas'); if (c.getContext) { - const ctx = c.getContext("2d"); + const ctx = c.getContext('2d'); ctx.beginPath(); ctx.arc(150, 150, 50, 0, 2 * Math.PI); - ctx.fillStyle = "white"; + ctx.fillStyle = 'white'; ctx.fill(); - ctx.font = "12px Arial"; - ctx.fillStyle = "black"; - ctx.textAlign = "center"; - let description = ""; + ctx.font = '12px Arial'; + ctx.fillStyle = 'black'; + ctx.textAlign = 'center'; + let description = ''; if (this._closest !== -1) { description = this._items[this._closest].description; } if (description.length > 15) { description = description.slice(0, 12); - description += "..."; + description += '...'; } ctx.fillText(description, 150, 150, 90); } } } - render() { if (!this._display) { return null; } - const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : - { left: this._pageX - 130, top: this._pageY - 130 }; + const style = this._yRelativeToTop ? { left: this._pageX - 130, top: this._pageY - 130 } : { left: this._pageX - 130, top: this._pageY - 130 }; return ( -
- Your browser does not support the HTML5 canvas tag. + + {' '} + Your browser does not support the HTML5 canvas tag. + {this.menuItems}
- ); } - - -} \ No newline at end of file +} diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index 8876b4879..c931202f1 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -1,8 +1,8 @@ -import React = require("react"); +import * as React from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { observer } from "mobx-react"; -import { UndoManager } from "../../util/UndoManager"; +import { observer } from 'mobx-react'; +import { UndoManager } from '../../util/UndoManager'; export interface RadialMenuProps { description: string; @@ -15,17 +15,15 @@ export interface RadialMenuProps { selected: number; } - @observer export class RadialMenuItem extends React.Component { - componentDidMount = () => { this.setcircle(); - } + }; componentDidUpdate = () => { this.setcircle(); - } + }; handleEvent = async (e: React.PointerEvent) => { this.props.closeMenu && this.props.closeMenu(); @@ -35,38 +33,36 @@ export class RadialMenuItem extends React.Component { } await this.props.event({ x: e.clientX, y: e.clientY }); batch && batch.end(); - } - + }; setcircle() { let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - if (document.getElementById("myCanvas") !== null) { - const c: any = document.getElementById("myCanvas"); - let color = "white"; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + if (document.getElementById('myCanvas') !== null) { + const c: any = document.getElementById('myCanvas'); + let color = 'white'; switch (circlemin % 3) { case 1: - color = "#c2c2c5"; + color = '#c2c2c5'; break; case 0: - color = "#f1efeb"; + color = '#f1efeb'; break; case 2: - color = "lightgray"; + color = 'lightgray'; break; } if (circlemax % 3 === 1 && circlemin === circlemax - 1) { - color = "#c2c2c5"; + color = '#c2c2c5'; } if (this.props.selected === this.props.min) { - color = "#808080"; - + color = '#808080'; } if (c.getContext) { - const ctx = c.getContext("2d"); + const ctx = c.getContext('2d'); ctx.beginPath(); ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI); ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true); @@ -79,35 +75,36 @@ export class RadialMenuItem extends React.Component { calculatorx() { let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + const avg = (circlemin / circlemax + (circlemin + 1) / circlemax) / 2; const degrees = 360 * avg; - const x = 100 * Math.cos(degrees * Math.PI / 180); - const y = -125 * Math.sin(degrees * Math.PI / 180); + const x = 100 * Math.cos((degrees * Math.PI) / 180); + const y = -125 * Math.sin((degrees * Math.PI) / 180); return x; } calculatory() { - let circlemin = 0; let circlemax = 1; - this.props.min ? circlemin = this.props.min : null; - this.props.max ? circlemax = this.props.max : null; - const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2; + this.props.min ? (circlemin = this.props.min) : null; + this.props.max ? (circlemax = this.props.max) : null; + const avg = (circlemin / circlemax + (circlemin + 1) / circlemax) / 2; const degrees = 360 * avg; - const x = 125 * Math.cos(degrees * Math.PI / 180); - const y = -100 * Math.sin(degrees * Math.PI / 180); + const x = 125 * Math.cos((degrees * Math.PI) / 180); + const y = -100 * Math.sin((degrees * Math.PI) / 180); return y; } - render() { return ( -
- Your browser does not support the HTML5 canvas tag. - +
+ + {' '} + Your browser does not support the HTML5 canvas tag. + +
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index c2e204eab..7c21b1893 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // import { Canvas } from '@react-three/fiber'; import { computed, observable, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/ScriptingBox.scss b/src/client/views/nodes/ScriptingBox.scss index 8d76f2b1d..9789da55a 100644 --- a/src/client/views/nodes/ScriptingBox.scss +++ b/src/client/views/nodes/ScriptingBox.scss @@ -32,7 +32,7 @@ .scriptingBox-wrapper { width: 100%; height: 100%; - max-height: calc(100%-30px); + max-height: calc(100% - 30px); display: flex; flex-direction: row; overflow: auto; @@ -42,7 +42,8 @@ overflow: hidden; } - .scriptingBox-textArea, .scriptingBox-textArea-inputs { + .scriptingBox-textArea, + .scriptingBox-textArea-inputs { flex: 70; height: 100%; max-width: 95%; @@ -110,7 +111,7 @@ cursor: pointer; } - .rta__entity>* { + .rta__entity > * { padding-left: 4px; padding-right: 4px; } @@ -125,7 +126,7 @@ .scriptingBox-textArea-inputs { max-width: 100%; height: 40%; - width: 100%; + width: 100%; resize: none; } .scriptingBox-textArea-script { @@ -194,8 +195,8 @@ .scriptingBox-errorMessage { overflow: auto; - background: "red"; - background-color: "red"; + background: 'red'; + background-color: 'red'; height: 45px; } @@ -221,4 +222,4 @@ width: 25%; } } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx index 2a3dd8d2d..a17b1dee9 100644 --- a/src/client/views/nodes/TaskCompletedBox.tsx +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -1,13 +1,11 @@ -import React = require("react"); -import { observer } from "mobx-react"; -import "./TaskCompletedBox.scss"; -import { observable, action } from "mobx"; -import { Fade } from "@material-ui/core"; - +import * as React from 'react'; +import { observer } from 'mobx-react'; +import './TaskCompletedBox.scss'; +import { observable, action } from 'mobx'; +import { Fade } from '@material-ui/core'; @observer export class TaskCompletionBox extends React.Component<{}> { - @observable public static taskCompleted: boolean = false; @observable public static popupX: number = 500; @observable public static popupY: number = 150; @@ -16,15 +14,20 @@ export class TaskCompletionBox extends React.Component<{}> { @action public static toggleTaskCompleted = () => { TaskCompletionBox.taskCompleted = !TaskCompletionBox.taskCompleted; - } + }; render() { - return -
{TaskCompletionBox.textDisplayed}
-
; + return ( + +
+ {TaskCompletionBox.textDisplayed} +
+
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 0f6c6724a..04780155d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index b3afe6ba0..d02e5f3e8 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -36,7 +36,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from './LinkDocPreview'; import { PinProps, PresBox } from './trails'; import './WebBox.scss'; -import React = require('react'); +import * as React from 'react'; const { CreateImage } = require('./WebBoxRenderer'); const _global = (window /* browser */ || global) /* node */ as any; const htmlToText = require('html-to-text'); diff --git a/src/client/views/nodes/formattedText/DashDocCommentView.tsx b/src/client/views/nodes/formattedText/DashDocCommentView.tsx index aa269d8d6..d6b053c8e 100644 --- a/src/client/views/nodes/formattedText/DashDocCommentView.tsx +++ b/src/client/views/nodes/formattedText/DashDocCommentView.tsx @@ -2,7 +2,7 @@ import { TextSelection } from 'prosemirror-state'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { DocServer } from '../../../DocServer'; -import React = require('react'); +import * as React from 'react'; // creates an inline comment in a note when '>>' is typed. // the comment sits on the right side of the note and vertically aligns with its anchor in the text. diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 95743a036..4384c8958 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -11,7 +11,7 @@ import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; export class DashDocView { dom: HTMLSpanElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index a914084f9..16622c258 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -16,7 +16,7 @@ import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableC import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; import { Transform } from '../../../util/Transform'; export class DashFieldView { diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 5e62d94c2..85a33614c 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -7,7 +7,7 @@ import { Doc } from '../../../../fields/Doc'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import React = require('react'); +import * as React from 'react'; export class EquationView { dom: HTMLDivElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 42e8ace6e..2315cdccb 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -72,7 +72,7 @@ import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); -import React = require('react'); +import * as React from 'react'; // setting up cors-anywhere server address const translate = setCORS('http://cors-anywhere.herokuapp.com/'); export const GoogleRef = 'googleDocId'; @@ -1954,7 +1954,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; + const ComponentTag: any = tag === CollectionViewType.Freeform ? CollectionFreeFormView : tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; return ComponentTag === CollectionStackingView ? ( () { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 2303e4126..786988d8b 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx'; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index f8aebd021..0effb2ccc 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -24,7 +24,7 @@ import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; -import React = require('react'); +import * as React from 'react'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index d68859e88..35c27d81b 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction } from 'mobx'; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index e1e87763c..cf19ff6bc 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 038c45582..cce67fed2 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 33a336de3..b2373b190 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -23,7 +23,7 @@ import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import React = require('react'); +import * as React from 'react'; const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer'); const pdfjsLib = require('pdfjs-dist'); const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/search/NaviconButton.scss b/src/client/views/search/NaviconButton.scss index 8a70b29de..13d31bbe9 100644 --- a/src/client/views/search/NaviconButton.scss +++ b/src/client/views/search/NaviconButton.scss @@ -1,4 +1,4 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; $height-icon: 15px; $width-line: 30px; @@ -6,7 +6,7 @@ $height-line: 4px; $transition-time: 0.4s; $rotation: 45deg; -$translateY: ($height-icon / 2); +$translateY: calc($height-icon / 2); $translateX: 0; #hamburger-icon { @@ -25,7 +25,7 @@ $translateX: 0; height: $height-line; position: absolute; left: 0; - border-radius: ($height-line / 2); + border-radius: calc($height-line / 2); transition: all $transition-time; -webkit-transition: all $transition-time; -moz-transition: all $transition-time; @@ -66,4 +66,4 @@ $translateX: 0; transform: scale(1.1); -webkit-transform: scale(1.1); -moz-transform: scale(1.1); -} \ No newline at end of file +} diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 2139919e0..39e778b76 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 524492226..093806127 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -11,7 +11,7 @@ import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; -import React = require('react'); +import * as React from 'react'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts index f035eeb0d..f5e64ae1f 100644 --- a/src/fields/Schema.ts +++ b/src/fields/Schema.ts @@ -94,6 +94,7 @@ export function makeStrictInterface(schema: T): (doc: Doc) } export function createSchema(schema: T): T & { proto: ToConstructor } { + return undefined as any; (schema as any).proto = Doc; return schema as any; } diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index da38fcaee..fd119e0bf 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -12,38 +12,38 @@ import { List } from '../fields/List'; import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; import { Utils } from '../Utils'; -import "./ImageUpload.scss"; +import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -import React = require('react'); +import * as React from 'react'; export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) } const inputRef = React.createRef(); -const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); +const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace('px', '')); @observer export class Uploader extends React.Component { - @observable error: string = ""; - @observable nm: string = "Choose files"; // Text of 'Choose Files' button - @observable process: string = ""; // Current status of upload + @observable error: string = ''; + @observable nm: string = 'Choose files'; // Text of 'Choose Files' button + @observable process: string = ''; // Current status of upload onClick = async () => { try { const col = this.props.Document; await Docs.Prototypes.initialize(); - const imgPrev = document.getElementById("img_preview"); - this.setOpacity(1, "1"); // Slab 1 + const imgPrev = document.getElementById('img_preview'); + this.setOpacity(1, '1'); // Slab 1 if (imgPrev) { const files: FileList | null = inputRef.current!.files; - this.setOpacity(2, "1"); // Slab 2 + this.setOpacity(2, '1'); // Slab 2 if (files && files.length !== 0) { - this.process = "Uploading Files"; + this.process = 'Uploading Files'; for (let index = 0; index < files.length; ++index) { const file = files[index]; - const res = await Networking.UploadFilesToServer({file}); - this.setOpacity(3, "1"); // Slab 3 + const res = await Networking.UploadFilesToServer({ file }); + this.setOpacity(3, '1'); // Slab 3 // For each item that the user has selected res.map(async ({ result }) => { const name = file.name; @@ -53,19 +53,19 @@ export class Uploader extends React.Component { const path = result.accessPaths.agnostic.client; let doc = null; // Case 1: File is a video - if (file.type === "video/mp4") { + if (file.type === 'video/mp4') { doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 2: File is a PDF document - } else if (file.type === "application/pdf") { + } else if (file.type === 'application/pdf') { doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 3: File is another document type (most likely Image) } else { doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); } - this.setOpacity(4, "1"); // Slab 4 - const res = await rp.get(Utils.prepend("/getUserDocumentIds")); + this.setOpacity(4, '1'); // Slab 4 + const res = await rp.get(Utils.prepend('/getUserDocumentIds')); if (!res) { - throw new Error("No user id returned"); + throw new Error('No user id returned'); } const field = await DocServer.GetRefField(JSON.parse(res).userDocumentId); let pending: Opt; @@ -76,19 +76,19 @@ export class Uploader extends React.Component { const data = await Cast(pending.data, listSpec(Doc)); if (data) data.push(doc); else pending.data = new List([doc]); - this.setOpacity(5, "1"); // Slab 5 - this.process = "File " + (index + 1).toString() + " Uploaded"; - this.setOpacity(6, "1"); // Slab 6 + this.setOpacity(5, '1'); // Slab 5 + this.process = 'File ' + (index + 1).toString() + ' Uploaded'; + this.setOpacity(6, '1'); // Slab 6 } - if ((index + 1) === files.length) { - this.process = "Uploads Completed"; - this.setOpacity(7, "1"); // Slab 7 + if (index + 1 === files.length) { + this.process = 'Uploads Completed'; + this.setOpacity(7, '1'); // Slab 7 } }); } // Case in which the user pressed upload and no files were selected } else { - this.process = "No file selected"; + this.process = 'No file selected'; } // Three seconds after upload the menu will reset setTimeout(this.clearUpload, 3000); @@ -96,7 +96,7 @@ export class Uploader extends React.Component { } catch (error) { this.error = JSON.stringify(error); } - } + }; // Updates label after a files is selected (so user knows a file is uploaded) inputLabel = async () => { @@ -105,46 +105,48 @@ export class Uploader extends React.Component { if (files && files.length === 1) { this.nm = files[0].name; } else if (files && files.length > 1) { - this.nm = files.length.toString() + " files selected"; + this.nm = files.length.toString() + ' files selected'; } - } + }; // Loops through load icons, and resets buttons @action clearUpload = () => { for (let i = 1; i < 8; i++) { - this.setOpacity(i, "0.2"); + this.setOpacity(i, '0.2'); } - this.nm = "Choose files"; + this.nm = 'Choose files'; if (inputRef.current) { - inputRef.current.value = ""; + inputRef.current.value = ''; } - this.process = ""; - } + this.process = ''; + }; // Clears the upload and closes the upload menu closeUpload = () => { this.clearUpload(); MobileInterface.Instance.toggleUpload(); - } + }; // Handles the setting of the loading bar setOpacity = (index: number, opacity: string) => { - const slab = document.getElementById("slab" + index); + const slab = document.getElementById('slab' + index); if (slab) slab.style.opacity = opacity; - } + }; // Returns the upload interface for mobile private get uploadInterface() { return (
this.closeUpload()}> - +
- - - + + +
Upload
@@ -167,16 +169,6 @@ export class Uploader extends React.Component { @observable private overlayOpacity = 0.4; render() { - return ( - - ); + return ; } - -} \ No newline at end of file +} diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 6415099fd..2e595e4bc 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,4 +1,4 @@ -import React = require('react'); +import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { DocServer } from '../client/DocServer'; diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts index 1a5934d8f..2450798aa 100644 --- a/src/server/DashSession/DashSessionAgent.ts +++ b/src/server/DashSession/DashSessionAgent.ts @@ -1,18 +1,18 @@ -import { Email, pathFromRoot } from "../ActionUtilities"; -import { red, yellow, green, cyan } from "colors"; -import { get } from "request-promise"; -import { Utils } from "../../Utils"; -import { WebSocket } from "../websocket"; -import { MessageStore } from "../Message"; -import { launchServer, onWindows } from ".."; -import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs"; -import * as Archiver from "archiver"; -import { resolve } from "path"; -import rimraf = require("rimraf"); -import { AppliedSessionAgent, ExitHandler } from "./Session/agents/applied_session_agent"; -import { ServerWorker } from "./Session/agents/server_worker"; -import { Monitor } from "./Session/agents/monitor"; -import { MessageHandler, ErrorLike } from "./Session/agents/promisified_ipc_manager"; +import { Email, pathFromRoot } from '../ActionUtilities'; +import { red, yellow, green, cyan } from 'colors'; +import { get } from 'request-promise'; +import { Utils } from '../../Utils'; +import { WebSocket } from '../websocket'; +import { MessageStore } from '../Message'; +import { launchServer, onWindows } from '..'; +import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from 'fs'; +import * as Archiver from 'archiver'; +import { resolve } from 'path'; +import * as rimraf from 'rimraf'; +import { AppliedSessionAgent, ExitHandler } from './Session/agents/applied_session_agent'; +import { ServerWorker } from './Session/agents/server_worker'; +import { Monitor } from './Session/agents/monitor'; +import { MessageHandler, ErrorLike } from './Session/agents/promisified_ipc_manager'; /** * If we're the monitor (master) thread, we should launch the monitor logic for the session. @@ -20,9 +20,8 @@ import { MessageHandler, ErrorLike } from "./Session/agents/promisified_ipc_mana * our job should be to run the server. */ export class DashSessionAgent extends AppliedSessionAgent { - - private readonly signature = "-Dash Server Session Manager"; - private readonly releaseDesktop = pathFromRoot("../../Desktop"); + private readonly signature = '-Dash Server Session Manager'; + private readonly releaseDesktop = pathFromRoot('../../Desktop'); /** * The core method invoked when the single master thread is initialized. @@ -31,13 +30,13 @@ export class DashSessionAgent extends AppliedSessionAgent { protected async initializeMonitor(monitor: Monitor): Promise { const sessionKey = Utils.GenerateGuid(); await this.dispatchSessionPassword(sessionKey); - monitor.addReplCommand("pull", [], () => monitor.exec("git pull")); - monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand); - monitor.addReplCommand("backup", [], this.backup); - monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); - monitor.on("backup", this.backup); - monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to)); - monitor.on("delete", WebSocket.doDelete); + monitor.addReplCommand('pull', [], () => monitor.exec('git pull')); + monitor.addReplCommand('solr', [/start|stop|index/], this.executeSolrCommand); + monitor.addReplCommand('backup', [], this.backup); + monitor.addReplCommand('debug', [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); + monitor.on('backup', this.backup); + monitor.on('debug', async ({ to }) => this.dispatchZippedDebugBackup(to)); + monitor.on('delete', WebSocket.doDelete); monitor.coreHooks.onCrashDetected(this.dispatchCrashReport); return sessionKey; } @@ -58,13 +57,13 @@ export class DashSessionAgent extends AppliedSessionAgent { private _remoteDebugInstructions: string | undefined; private generateDebugInstructions = (zipName: string, target: string): string => { if (!this._remoteDebugInstructions) { - this._remoteDebugInstructions = readFileSync(resolve(__dirname, "./templates/remote_debug_instructions.txt"), { encoding: "utf8" }); + this._remoteDebugInstructions = readFileSync(resolve(__dirname, './templates/remote_debug_instructions.txt'), { encoding: 'utf8' }); } return this._remoteDebugInstructions .replace(/__zipname__/, zipName) .replace(/__target__/, target) .replace(/__signature__/, this.signature); - } + }; /** * Prepares the body of the email with information regarding a crash event. @@ -72,12 +71,12 @@ export class DashSessionAgent extends AppliedSessionAgent { private _crashInstructions: string | undefined; private generateCrashInstructions({ name, message, stack }: ErrorLike): string { if (!this._crashInstructions) { - this._crashInstructions = readFileSync(resolve(__dirname, "./templates/crash_instructions.txt"), { encoding: "utf8" }); + this._crashInstructions = readFileSync(resolve(__dirname, './templates/crash_instructions.txt'), { encoding: 'utf8' }); } return this._crashInstructions - .replace(/__name__/, name || "[no error name found]") - .replace(/__message__/, message || "[no error message found]") - .replace(/__stack__/, stack || "[no error stack found]") + .replace(/__name__/, name || '[no error name found]') + .replace(/__message__/, message || '[no error message found]') + .replace(/__stack__/, stack || '[no error stack found]') .replace(/__signature__/, this.signature); } @@ -88,23 +87,19 @@ export class DashSessionAgent extends AppliedSessionAgent { private dispatchSessionPassword = async (sessionKey: string): Promise => { const { mainLog } = this.sessionMonitor; const { notificationRecipient } = DashSessionAgent; - mainLog(green("dispatching session key...")); + mainLog(green('dispatching session key...')); const error = await Email.dispatch({ to: notificationRecipient, - subject: "Dash Release Session Admin Authentication Key", - content: [ - `Here's the key for this session (started @ ${new Date().toUTCString()}):`, - sessionKey, - this.signature - ].join("\n\n") + subject: 'Dash Release Session Admin Authentication Key', + content: [`Here's the key for this session (started @ ${new Date().toUTCString()}):`, sessionKey, this.signature].join('\n\n'), }); if (error) { this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} (${yellow(error.message)})`)); - mainLog(red("distribution of session key experienced errors")); + mainLog(red('distribution of session key experienced errors')); } else { - mainLog(green("successfully distributed session key to recipients")); + mainLog(green('successfully distributed session key to recipients')); } - } + }; /** * This sends an email with the generated crash report. @@ -114,37 +109,37 @@ export class DashSessionAgent extends AppliedSessionAgent { const { notificationRecipient } = DashSessionAgent; const error = await Email.dispatch({ to: notificationRecipient, - subject: "Dash Web Server Crash", - content: this.generateCrashInstructions(crashCause) + subject: 'Dash Web Server Crash', + content: this.generateCrashInstructions(crashCause), }); if (error) { this.sessionMonitor.mainLog(red(`dispatch failure @ ${notificationRecipient} ${yellow(`(${error.message})`)}`)); - mainLog(red("distribution of crash notification experienced errors")); + mainLog(red('distribution of crash notification experienced errors')); } else { - mainLog(green("successfully distributed crash notification to recipients")); + mainLog(green('successfully distributed crash notification to recipients')); } - } + }; /** - * Logic for interfacing with Solr. Either starts it, + * Logic for interfacing with Solr. Either starts it, * stops it, or rebuilds its indices. */ private executeSolrCommand = async (args: string[]): Promise => { const { exec, mainLog } = this.sessionMonitor; const action = args[0]; - if (action === "index") { - exec("npx ts-node ./updateSearch.ts", { cwd: pathFromRoot("./src/server") }); + if (action === 'index') { + exec('npx ts-node ./updateSearch.ts', { cwd: pathFromRoot('./src/server') }); } else { - const command = `${onWindows ? "solr.cmd" : "solr"} ${args[0] === "start" ? "start" : "stop -p 8983"}`; - await exec(command, { cwd: "./solr-8.3.1/bin" }); + const command = `${onWindows ? 'solr.cmd' : 'solr'} ${args[0] === 'start' ? 'start' : 'stop -p 8983'}`; + await exec(command, { cwd: './solr-8.3.1/bin' }); try { - await get("http://localhost:8983"); - mainLog(green("successfully connected to 8983 after running solr initialization")); + await get('http://localhost:8983'); + mainLog(green('successfully connected to 8983 after running solr initialization')); } catch { - mainLog(red("unable to connect at 8983 after running solr initialization")); + mainLog(red('unable to connect at 8983 after running solr initialization')); } } - } + }; /** * Broadcast to all clients that their connection @@ -153,16 +148,16 @@ export class DashSessionAgent extends AppliedSessionAgent { private notifyClient: ExitHandler = reason => { const { _socket } = WebSocket; if (_socket) { - const message = typeof reason === "boolean" ? (reason ? "exit" : "temporary") : "crash"; + const message = typeof reason === 'boolean' ? (reason ? 'exit' : 'temporary') : 'crash'; Utils.Emit(_socket, MessageStore.ConnectionTerminated, message); } - } + }; /** * Performs a backup of the database, saved to the desktop subdirectory. * This should work as is only on our specific release server. */ - private backup = async (): Promise => this.sessionMonitor.exec("backup.bat", { cwd: this.releaseDesktop }); + private backup = async (): Promise => this.sessionMonitor.exec('backup.bat', { cwd: this.releaseDesktop }); /** * Compress either a brand new backup or the most recent backup and send it @@ -175,15 +170,17 @@ export class DashSessionAgent extends AppliedSessionAgent { try { // if desired, complete an immediate backup to send await this.backup(); - mainLog("backup complete"); + mainLog('backup complete'); const backupsDirectory = `${this.releaseDesktop}/backups`; // sort all backups by their modified time, and choose the most recent one - const target = readdirSync(backupsDirectory).map(filename => ({ - modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs, - filename - })).sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename; + const target = readdirSync(backupsDirectory) + .map(filename => ({ + modifiedTime: statSync(`${backupsDirectory}/${filename}`).mtimeMs, + filename, + })) + .sort((a, b) => b.modifiedTime - a.modifiedTime)[0].filename; mainLog(`targeting ${target}...`); // create a zip file and to it, write the contents of the backup directory @@ -202,28 +199,25 @@ export class DashSessionAgent extends AppliedSessionAgent { to, subject: `Remote debug: compressed backup of ${target}...`, content: this.generateDebugInstructions(zipName, target), - attachments: [{ filename: zipName, path: zipPath }] + attachments: [{ filename: zipName, path: zipPath }], }); - // since this is intended to be a zero-footprint operation, clean up + // since this is intended to be a zero-footprint operation, clean up // by unlinking both the backup generated earlier in the function and the compressed zip file. // to generate a persistent backup, just run backup. unlinkSync(zipPath); rimraf.sync(targetPath); // indicate success or failure - mainLog(`${error === null ? green("successfully dispatched") : red("failed to dispatch")} ${zipName} to ${cyan(to)}`); + mainLog(`${error === null ? green('successfully dispatched') : red('failed to dispatch')} ${zipName} to ${cyan(to)}`); error && mainLog(red(error.message)); } catch (error: any) { - mainLog(red("unable to dispatch zipped backup...")); + mainLog(red('unable to dispatch zipped backup...')); mainLog(red(error.message)); } } - } export namespace DashSessionAgent { - - export const notificationRecipient = "browndashptc@gmail.com"; - + export const notificationRecipient = 'browndashptc@gmail.com'; } diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 2053ae448..fa29cb7c1 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -14,8 +14,8 @@ import { createIfNotExists } from './ActionUtilities'; import { clientPathToFile, Directory, pathToDirectory, serverPathToFile } from './ApiManagers/UploadManager'; import { resolvedServerUrl } from './server_Initialization'; import { AcceptableMedia, Upload } from './SharedMediaTypes'; -import request = require('request-promise'); -import formidable = require('formidable'); +import * as request from 'request-promise'; +import * as formidable from 'formidable'; import { AzureManager } from './ApiManagers/AzureManager'; import axios from 'axios'; const spawn = require('child_process').spawn; @@ -366,7 +366,7 @@ export namespace DashUploadUtils { } export interface ImageResizer { - width?: any; // sharp.Sharp; + width: number; suffix: SizeSuffix; } @@ -622,7 +622,7 @@ export namespace DashUploadUtils { */ export function imageResampleSizes(ext: string): DashUploadUtils.ImageResizer[] { return [ - { suffix: SizeSuffix.Original }, + { suffix: SizeSuffix.Original, width: 0 }, ...[...(AcceptableMedia.imageFormats.includes(ext.toLowerCase()) ? Object.values(DashUploadUtils.Sizes) : [])].map(({ suffix, width }) => ({ width, suffix, diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 23e4680fd..f5189ddf1 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -13,6 +13,10 @@ declare module 'reveal'; declare module 'react-reveal'; declare module 'react-reveal/makeCarousel'; declare module 'react-resizable-rotatable-draggable'; +declare module 'socket.io-parser' { + type Encoder = any; + type Decoder = any; +} declare module '@react-pdf/renderer' { import * as React from 'react'; diff --git a/tsconfig.json b/tsconfig.json index f1b275954..1e8934ee8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "ES2017", "downlevelIteration": true, "removeComments": true, "experimentalDecorators": true, @@ -11,10 +11,11 @@ "allowJs": true, "sourceMap": true, "outDir": "dist", - "lib": ["dom", "es2015"], + "lib": ["dom", "es2017"], "typeRoots": ["node_modules/@types", "./src/typings"], "types": ["youtube", "node"], - "resolveJsonModule": true + "resolveJsonModule": true, + "moduleResolution": "node" }, // "exclude": [ // "node_modules", diff --git a/webpack.config.js b/webpack.config.js index 01625988c..098604f1f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,23 +1,28 @@ +/* eslint-disable node/no-unpublished-require */ const path = require('path'); const webpack = require('webpack'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const { parsed } = require('dotenv').config(); const plugins = [ - new CopyWebpackPlugin([ - { - from: 'deploy', - to: path.join(__dirname, 'build'), - }, - ]), + // new CopyWebpackPlugin({ + // patterns: [ + // { + // from: 'deploy', + // to: path.join(__dirname, 'build'), + // }, + // ], + // }), new HtmlWebpackPlugin({ title: 'Caching', }), new ForkTsCheckerWebpackPlugin({ tslint: true, - // memoryLimit: 4096, + memoryLimit: 4096, useTypescriptIncrementalApi: true, + tslintAutoFix: true, }), new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), new webpack.ProvidePlugin({ process: 'process/browser' }), @@ -26,12 +31,12 @@ const plugins = [ function transferEnvironmentVariables() { const prefix = '_CLIENT_'; - const { parsed } = require('dotenv').config(); if (!parsed) { return; } const resolvedClientSide = Object.keys(parsed).reduce((mapping, envKey) => { if (envKey.startsWith(prefix)) { + // eslint-disable-next-line mapping[`process.env.${envKey.replace(prefix, '')}`] = JSON.stringify(parsed[envKey]); } return mapping; -- cgit v1.2.3-70-g09d2 From fd54add240b41b3c2ac5f5265438effec045c9d4 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Dec 2023 10:43:25 -0500 Subject: fixed props => _props referneces --- src/client/util/DocumentManager.ts | 22 ++++---- src/client/views/MainView.tsx | 2 + src/client/views/StyleProvider.tsx | 2 +- .../CollectionFreeFormLinkView.tsx | 65 +++++++++++++--------- src/client/views/nodes/ComparisonBox.tsx | 44 +++++++++------ src/client/views/nodes/DocumentIcon.tsx | 31 ++++++++--- src/client/views/nodes/LinkAnchorBox.tsx | 26 ++++++--- src/client/views/nodes/LinkBox.tsx | 48 ++++++++++------ 8 files changed, 150 insertions(+), 90 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7f82ff70a..17c915318 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -90,11 +90,11 @@ export class DocumentManager { @action public AddView = (view: DocumentView) => { - if (view.props.LayoutTemplateString?.includes(KeyValueBox.name)) return; - if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1'; + if (view._props.LayoutTemplateString?.includes(KeyValueBox.name)) return; + if (view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + const viewAnchorIndex = view._props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1'; const link = view.Document; - this.LinkAnchorBoxViews?.filter(dv => Doc.AreProtosEqual(dv.Document, link) && !dv.props.LayoutTemplateString?.includes(viewAnchorIndex)).forEach(otherView => + this.LinkAnchorBoxViews?.filter(dv => Doc.AreProtosEqual(dv.Document, link) && !dv._props.LayoutTemplateString?.includes(viewAnchorIndex)).forEach(otherView => this.LinkedDocumentViews.push({ a: viewAnchorIndex === 'link_anchor_2' ? otherView : view, b: viewAnchorIndex === 'link_anchor_2' ? view : otherView, @@ -117,7 +117,7 @@ export class DocumentManager { }) ); - if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + if (view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { const index = this.LinkAnchorBoxViews.indexOf(view); this.LinkAnchorBoxViews.splice(index, 1); } else { @@ -154,8 +154,8 @@ export class DocumentManager { return passes.reduce( (toReturn, pass) => toReturn ?? - docViewArray.filter(view => view.Document === target).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ?? - docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection), + docViewArray.filter(view => view.Document === target).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection) ?? + docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection), undefined as Opt ); } @@ -163,12 +163,12 @@ export class DocumentManager { public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { const views: DocumentView[] = []; DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view)); - return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); + return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view._props.focus !== returnFalse) || views?.find(view => view._props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); }; public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { if (LightboxView.LightboxDoc) return DocumentManager.Instance.getLightboxDocumentView(toFind, originatingDoc); const views = this.getDocumentViews(toFind); //.filter(view => view.Document !== originatingDoc); - return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); + return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view._props.focus !== returnFalse) || views?.find(view => view._props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); }; public getDocumentViews(toFindIn: Doc): DocumentView[] { const toFind = @@ -304,7 +304,7 @@ export class DocumentManager { await new Promise(res => docView.iconify(res)); options.didMove = true; } - const nextFocus = docView.props.focus(docView.Document, options); // focus the view within its container + const nextFocus = docView._props.focus(docView.Document, options); // focus the view within its container focused = focused || (nextFocus === undefined ? false : true); // keep track of whether focusing on a view needed to actually change anything const { childDocView, viewSpec } = await iterator(docView); if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.Document, docView, contextView, focused }; @@ -345,7 +345,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); - if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) { + if (dv && (!containingDoc || dv._props.docViewPath().lastElement()?.Document === containingDoc)) { DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.Document)); } else { const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc)); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1e4c1e1d3..de3c78e91 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -69,6 +69,7 @@ import { PreviewCursor } from './PreviewCursor'; import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; +import { CollectionFreeFormLinksView } from './collections/collectionFreeForm'; const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @@ -1063,6 +1064,7 @@ export class MainView extends React.Component { {/* */} {this.snapLines} + {this.mapBoxHack} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index f3d515364..3e7e4be90 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -170,7 +170,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?.props.styleProvider?.(docView.props.treeViewDoc, docView.props, StyleProp.BackgroundColor); + const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView._props, StyleProp.BackgroundColor); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : '')); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 5cbea4783..f89e2ba9a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,11 +1,11 @@ -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Field } from '../../../../fields/Doc'; import { Brushed, DocCss } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { Cast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { copyProps, emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { LinkManager } from '../../../util/LinkManager'; import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; @@ -29,6 +29,17 @@ export class CollectionFreeFormLinkView extends React.Component [ - this.props.A.props.ScreenToLocalTransform(), - Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, - Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss], - this.props.B.props.ScreenToLocalTransform(), - Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, - Cast(Cast(Cast(this.props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss], + this._props.A._props.ScreenToLocalTransform(), + Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, + Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss], + this._props.B._props.ScreenToLocalTransform(), + Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, + Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss], ], action(() => { this._start = Date.now(); @@ -53,7 +64,7 @@ export class CollectionFreeFormLinkView extends React.Component { - const { A, B, LinkDocs } = this.props; + const { A, B, LinkDocs } = this._props; const linkDoc = LinkDocs[0]; if (SnappingManager.GetIsDragging() || !A.ContentDiv || !B.ContentDiv) return; setTimeout( @@ -85,9 +96,9 @@ export class CollectionFreeFormLinkView extends React.Component= 0 && mpx <= 1) linkDoc.link_anchor_1_x = mpx * 100; if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_1_y = mpy * 100; if (getComputedStyle(targetAhyperlink).fontSize === '0px') linkDoc.opacity = 0; @@ -100,9 +111,9 @@ export class CollectionFreeFormLinkView extends React.Component= 0 && mpx <= 1) linkDoc.link_anchor_2_x = mpx * 100; if (mpy >= 0 && mpy <= 1) linkDoc.link_anchor_2_y = mpy * 100; if (getComputedStyle(targetBhyperlink).fontSize === '0px') linkDoc.opacity = 0; @@ -115,18 +126,18 @@ export class CollectionFreeFormLinkView extends React.Component { - this.props.LinkDocs[0].link_relationship_OffsetX = NumCast(this.props.LinkDocs[0].link_relationship_OffsetX) + delta[0]; - this.props.LinkDocs[0].link_relationship_OffsetY = NumCast(this.props.LinkDocs[0].link_relationship_OffsetY) + delta[1]; + this._props.LinkDocs[0].link_relationship_OffsetX = NumCast(this._props.LinkDocs[0].link_relationship_OffsetX) + delta[0]; + this._props.LinkDocs[0].link_relationship_OffsetY = NumCast(this._props.LinkDocs[0].link_relationship_OffsetY) + delta[1]; return false; }, emptyFunction, action(() => { SelectionManager.DeselectAll(); - SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true); - LinkManager.currentLink = this.props.LinkDocs[0]; + SelectionManager.SelectSchemaViewDoc(this._props.LinkDocs[0], true); + LinkManager.currentLink = this._props.LinkDocs[0]; this.toggleProperties(); // OverlayView.Instance.addElement( - // { })} // />, { x: 300, y: 300 }); }) @@ -179,15 +190,15 @@ export class CollectionFreeFormLinkView extends React.Component { SelectionManager.DeselectAll(); - SelectionManager.SelectSchemaViewDoc(this.props.LinkDocs[0], true); - LinkManager.currentLink = this.props.LinkDocs[0]; + SelectionManager.SelectSchemaViewDoc(this._props.LinkDocs[0], true); + LinkManager.currentLink = this._props.LinkDocs[0]; this.toggleProperties(); }; @computed.struct get renderData() { this._start; SnappingManager.GetIsDragging(); - const { A, B, LinkDocs } = this.props; + const { A, B, LinkDocs } = this._props; if (!A.ContentDiv || !B.ContentDiv || !LinkDocs.length) return undefined; const acont = A.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); const bcont = B.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); @@ -200,8 +211,8 @@ export class CollectionFreeFormLinkView extends React.Component; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 72a473114..62523ba00 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, computed, makeObservable, observable, override } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; +import { copyProps, emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; @@ -24,14 +24,26 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { this._disposers[disposerId]?.(); @@ -72,7 +84,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (this._animating = '')), 200 @@ -84,9 +96,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - const width = movementX * this.props.ScreenToLocalTransform().Scale + (this.clipWidth / 100) * this.props.PanelWidth(); - if (width && width > 5 && width < this.props.PanelWidth()) { - this.layoutDoc[this.clipWidthKey] = (width * 100) / this.props.PanelWidth(); + const width = movementX * this._props.ScreenToLocalTransform().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); + if (width && width > 5 && width < this._props.PanelWidth()) { + this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth(); } return false; }; @@ -146,7 +158,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent, props: Opt, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; - return this.props.styleProvider?.(doc, props, property); + return this._props.styleProvider?.(doc, props, property); }; moveDoc1 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); @@ -171,7 +183,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent @@ -195,15 +207,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { return ( -
this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}> +
this.registerSliding(e, cover)} ref={ele => this.createDropTarget(ele, which, index)}> {displayDoc(which)}
); }; return ( -
- {displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)} +
+ {displayBox(`${this.fieldKey}_2`, 1, this._props.PanelWidth() - 3)}
{displayBox(`${this.fieldKey}_1`, 0, 0)}
@@ -212,9 +224,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined, + cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined, }} - onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ + onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ >
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index e8d8c05e3..0c780af2a 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -5,20 +5,35 @@ import { DocumentManager } from '../../util/DocumentManager'; import { Transformer, ts } from '../../util/Scripting'; import { Field } from '../../../fields/Doc'; import { Tooltip } from '@mui/material'; -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { Id } from '../../../fields/FieldSymbols'; import { factory } from 'typescript'; import { LightboxView } from '../LightboxView'; import { SettingsManager } from '../../util/SettingsManager'; +import { copyProps } from '../../../Utils'; -@observer -export class DocumentIcon extends React.Component<{ view: DocumentView; index: number }> { +interface DocumentIconProps { + view: DocumentView; + index: number; +} +export class DocumentIcon extends React.Component { @observable _hovered = false; + _prevProps: DocumentIconProps; + @observable _props: DocumentIconProps; + constructor(props: DocumentIconProps) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } + componentDidUpdate() { + copyProps(this); + } + static get DocViews() { - return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v.props.docViewPath())) : DocumentManager.Instance.DocumentViews; + return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews; } render() { - const view = this.props.view; + const view = this._props.view; const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 }; return ( @@ -33,8 +48,8 @@ export class DocumentIcon extends React.Component<{ view: DocumentView; index: n background: SettingsManager.userBackgroundColor, transform: `translate(${(left + right) / 2}px, ${top}px)`, }}> - {this.props.view.Document.title}}> -

d{this.props.index}

+ {this._props.view.Document.title}}> +

d{this._props.index}

); @@ -74,7 +89,7 @@ export class DocumentIconContainer extends React.Component { getVars() { const docs = DocumentIcon.DocViews; const capturedVariables: { [name: string]: Field } = {}; - usedDocuments.forEach(index => (capturedVariables[`d${index}`] = docs.length > index ? docs[index].props.Document : `d${index}`)); + usedDocuments.forEach(index => (capturedVariables[`d${index}`] = docs.length > index ? docs[index].Document : `d${index}`)); return capturedVariables; }, }; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 09ba0bc95..31aa15588 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, makeObservable, observable, override } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; import { NumCast, StrCast } from '../../../fields/Types'; @@ -29,18 +29,26 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { @observable _x = 0; @observable _y = 0; + _prevProps: FieldViewProps; + @override _props: FieldViewProps; + constructor(props: FieldViewProps) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } + componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); } @computed get linkSource() { - return this.props.docViewPath()[this.props.docViewPath().length - 2].Document; // this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.LinkSource); + return this._props.docViewPath()[this._props.docViewPath().length - 2].Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource); } onPointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { if (doubleTap) LinkFollower.FollowLink(this.Document, this.linkSource, false); - else this.props.select(false); + else this._props.select(false); }); }; onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { @@ -68,16 +76,16 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { render() { TraceMobx(); - const small = this.props.PanelWidth() <= 1; // this happens when rendered in a treeView + const small = this._props.PanelWidth() <= 1; // this happens when rendered in a treeView const x = NumCast(this.layoutDoc[this.fieldKey + '_x'], 100); const y = NumCast(this.layoutDoc[this.fieldKey + '_y'], 100); - const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor'); + const background = this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.BackgroundColor + ':anchor'); const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1'; const anchorScale = !this.dataDoc[this.fieldKey + '_useSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25; const targetTitle = StrCast((this.dataDoc[anchor] as Doc)?.title); - const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1') + const selView = SelectionManager.Views().lastElement()?._props.LayoutTemplateString?.includes('link_anchor_1') ? 'link_anchor_1' - : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_2') + : SelectionManager.Views().lastElement()?._props.LayoutTemplateString?.includes('link_anchor_2') ? 'link_anchor_2' : ''; return ( @@ -87,7 +95,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { className={`linkAnchorBox-cont${small ? '-small' : ''}`} onPointerEnter={e => LinkInfo.SetLinkInfo({ - docProps: this.props, + docProps: this._props, linkSrc: this.linkSource, linkDoc: this.Document, showHeader: true, diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index ff2597fb4..acafd6d09 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import { Bezier } from 'bezier-js'; -import { computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { computed, IReactionDisposer, makeObservable, observable, override, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { aggregateBounds, emptyFunction, returnAlways, returnFalse, Utils } from '../../../Utils'; +import { aggregateBounds, copyProps, emptyFunction, returnAlways, returnFalse, Utils } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; import { Transform } from '../../util/Transform'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; @@ -20,21 +20,33 @@ export class LinkBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(LinkBox, fieldKey); } + _prevProps: FieldViewProps; + @override _props: FieldViewProps; + constructor(props: FieldViewProps) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } + + componentDidUpdate() { + copyProps(this); + } + onClickScriptDisable = returnAlways; @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1; - return DocumentManager.Instance.getDocumentView(anchor_1, this.props.docViewPath()[this.props.docViewPath().length - 2]); // this.props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_1, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); } @computed get anchor2() { const anchor2 = DocCast(this.dataDoc.link_anchor_2); const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2; - return DocumentManager.Instance.getDocumentView(anchor_2, this.props.docViewPath()[this.props.docViewPath().length - 2]); // this.props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_2, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { - const a_invXf = this.anchor1.props.ScreenToLocalTransform().inverse(); - const b_invXf = this.anchor2.props.ScreenToLocalTransform().inverse(); + const a_invXf = this.anchor1._props.ScreenToLocalTransform().inverse(); + const b_invXf = this.anchor2._props.ScreenToLocalTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.Document._width), NumCast(this.anchor1.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.Document._width), NumCast(this.anchor2.Document._height)) }; @@ -54,17 +66,17 @@ export class LinkBox extends ViewBoxBaseComponent() { }; disposer: IReactionDisposer | undefined; componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); this.disposer = reaction( () => { if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; - const parxf = this.props.docViewPath()[this.props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; - const this_xf = parxf?.screenToLocalXf ?? Transform.Identity; //this.props.ScreenToLocalTransform(); - const a_invXf = a.props.ScreenToLocalTransform().inverse(); - const b_invXf = b.props.ScreenToLocalTransform().inverse(); + const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; + const this_xf = parxf?.screenToLocalXf ?? Transform.Identity; //this._props.ScreenToLocalTransform(); + const a_invXf = a._props.ScreenToLocalTransform().inverse(); + const b_invXf = b._props.ScreenToLocalTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.Document._width), NumCast(a.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.Document._width), NumCast(b.Document._height)) }; const a_bds = { tl: this_xf.transformPoint(a_scrBds.tl[0], a_scrBds.tl[1]), br: this_xf.transformPoint(a_scrBds.br[0], a_scrBds.br[1]) }; @@ -106,7 +118,7 @@ export class LinkBox extends ViewBoxBaseComponent() { @observable renderProps: { lx: number; rx: number; ty: number; by: number; pts: number[][] } | undefined = undefined; render() { if (this.renderProps) { - const highlight = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Highlighting); + const highlight = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting); const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : undefined; const bez = new Bezier(this.renderProps.pts.map(p => ({ x: p[0], y: p[1] }))); @@ -131,7 +143,7 @@ export class LinkBox extends ViewBoxBaseComponent() { () { />   @@ -154,14 +166,14 @@ export class LinkBox extends ViewBoxBaseComponent() { ); } return ( -
+
Date: Wed, 13 Dec 2023 21:17:50 -0500 Subject: cleaned up props/_props handling by inherting from ObservableReactComponent --- .vscode/settings.json | 4 +- src/Utils.ts | 7 ++- src/client/util/DocumentManager.ts | 3 +- src/client/util/SelectionManager.ts | 22 +++---- src/client/views/AntimodeMenu.tsx | 13 +---- src/client/views/ContextMenu.tsx | 5 +- src/client/views/ContextMenuItem.tsx | 15 ++--- src/client/views/DashboardView.tsx | 4 +- src/client/views/DocComponent.tsx | 43 ++++++-------- src/client/views/DocumentButtonBar.tsx | 8 +-- src/client/views/DocumentDecorations.tsx | 6 +- src/client/views/EditableView.tsx | 14 ++--- src/client/views/MainView.tsx | 47 +++++++-------- src/client/views/MarqueeAnnotator.tsx | 20 +++---- src/client/views/ObservableReactComponent.tsx | 21 +++++++ src/client/views/OverlayView.tsx | 18 ++---- src/client/views/PreviewCursor.tsx | 13 +++-- src/client/views/PropertiesDocContextSelector.tsx | 17 ++---- src/client/views/PropertiesView.tsx | 26 ++++----- src/client/views/ScriptingRepl.tsx | 29 +++------- src/client/views/SidebarAnnos.tsx | 25 ++++---- .../views/collections/CollectionCarousel3DView.tsx | 6 +- .../views/collections/CollectionCarouselView.tsx | 7 ++- .../views/collections/CollectionDockingView.tsx | 15 ++--- .../collections/CollectionMasonryViewFieldRow.tsx | 18 +++--- src/client/views/collections/CollectionMenu.tsx | 2 +- .../views/collections/CollectionNoteTakingView.tsx | 8 ++- .../views/collections/CollectionPileView.tsx | 7 ++- .../collections/CollectionStackedTimeline.tsx | 22 ++----- .../views/collections/CollectionStackingView.tsx | 15 ++--- .../CollectionStackingViewFieldColumn.tsx | 20 +++---- src/client/views/collections/CollectionSubView.tsx | 19 +++--- .../views/collections/CollectionTimeView.tsx | 7 ++- .../views/collections/CollectionTreeView.tsx | 16 ++---- src/client/views/collections/CollectionView.tsx | 26 ++++----- src/client/views/collections/TabDocView.tsx | 41 ++++++------- src/client/views/collections/TreeView.tsx | 23 ++++---- .../CollectionFreeFormInfoState.tsx | 20 +++---- .../CollectionFreeFormInfoUI.tsx | 33 ++++------- .../CollectionFreeFormLinkView.tsx | 15 ++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +---- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 1 - .../collections/collectionFreeForm/MarqueeView.tsx | 23 ++++---- .../collectionGrid/CollectionGridView.tsx | 7 ++- .../collectionLinear/CollectionLinearView.tsx | 19 ++---- .../CollectionMulticolumnView.tsx | 11 +++- .../CollectionMultirowView.tsx | 11 +++- .../collectionSchema/CollectionSchemaView.tsx | 37 +++++------- .../collections/collectionSchema/SchemaRowBox.tsx | 14 ++--- .../collectionSchema/SchemaTableCell.tsx | 67 +++++++++------------- src/client/views/linking/LinkMenu.tsx | 9 +-- src/client/views/linking/LinkMenuItem.tsx | 26 ++++----- src/client/views/nodes/AudioBox.tsx | 20 +++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 29 ++++------ src/client/views/nodes/ComparisonBox.tsx | 20 ++----- src/client/views/nodes/DocumentContentsView.tsx | 32 ++++------- src/client/views/nodes/DocumentIcon.tsx | 26 ++++----- src/client/views/nodes/DocumentLinksButton.tsx | 19 ++---- src/client/views/nodes/DocumentView.tsx | 36 ++++-------- src/client/views/nodes/EquationBox.tsx | 14 +---- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 14 ++--- src/client/views/nodes/FunctionPlotBox.tsx | 14 +---- src/client/views/nodes/ImageBox.tsx | 12 +--- src/client/views/nodes/KeyValueBox.tsx | 27 ++++----- src/client/views/nodes/KeyValuePair.tsx | 29 ++++------ src/client/views/nodes/LabelBox.tsx | 14 ++--- src/client/views/nodes/LinkAnchorBox.tsx | 19 ++---- src/client/views/nodes/LinkBox.tsx | 15 ++--- src/client/views/nodes/LinkDocPreview.tsx | 21 +++---- src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 5 +- src/client/views/nodes/MapBox/MapBox.tsx | 22 +++---- src/client/views/nodes/PDFBox.tsx | 12 +--- src/client/views/nodes/VideoBox.tsx | 13 +---- src/client/views/nodes/WebBox.tsx | 11 +--- src/client/views/nodes/audio/AudioWaveform.tsx | 17 ++---- .../views/nodes/formattedText/DashFieldView.tsx | 18 +++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 15 ++--- .../views/nodes/formattedText/RichTextMenu.tsx | 44 +++++--------- src/client/views/nodes/trails/PresElementBox.tsx | 17 ++---- src/client/views/pdf/AnchorMenu.tsx | 14 ++--- src/client/views/pdf/PDFViewer.tsx | 22 +++---- 81 files changed, 578 insertions(+), 911 deletions(-) create mode 100644 src/client/views/ObservableReactComponent.tsx (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/.vscode/settings.json b/.vscode/settings.json index 8849f30dd..5239d22c0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,7 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "terminal.integrated.shellIntegration.showWelcome": false, + "terminal.integrated.shellIntegration.enabled": true } diff --git a/src/Utils.ts b/src/Utils.ts index d54760100..3a2bbf9a1 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -440,7 +440,12 @@ export namespace Utils { socket.on(message, (room: any) => handler(socket, room)); } } -export function copyProps(thing: { _prevProps: any; props: any; _props: any }) { +export function copyProps(thing: { props: any; _props: any }, prevProps: any) { + Object.keys(prevProps).forEach(action(pkey => + (prevProps)[pkey] !== (thing.props as any)[pkey] && + ((thing._props as any)[pkey] = (thing.props as any)[pkey]))); // prettier-ignore +} +export function copyPropsFull(thing: { _prevProps: any; props: any; _props: any }) { Object.keys(thing._prevProps).forEach(action(pkey => (thing._prevProps as any)[pkey] !== (thing.props as any)[pkey] && ((thing._props as any)[pkey] = (thing.props as any)[pkey]))); // prettier-ignore diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7fcda75cc..4816f3317 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,4 +1,4 @@ -import { action, computed, makeObservable, observable, ObservableSet, observe, reaction } from 'mobx'; +import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -13,7 +13,6 @@ import { LightboxView } from '../views/LightboxView'; import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; -import { LoadingBox } from '../views/nodes/LoadingBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 7cf0d62d0..4bd6647c0 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,4 +1,4 @@ -import { action, makeObservable, observable } from 'mobx'; +import { action, makeObservable, observable, runInAction } from 'mobx'; import { Doc, Opt } from '../../fields/Doc'; import { DocViews } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; @@ -26,13 +26,13 @@ export class SelectionManager { } @action - public static SelectSchemaViewDoc(doc: Opt, deselectAllFirst?: boolean) { + public static SelectSchemaViewDoc = (doc: Opt, deselectAllFirst?: boolean) => { if (deselectAllFirst) this.DeselectAll(); this.Instance.SelectedSchemaDocument = doc; - } + }; @action - public static SelectView(docView: DocumentView, extendSelection: boolean): void { + public static SelectView = (docView: DocumentView | undefined, extendSelection: boolean): void => { if (!docView) this.DeselectAll(); else if (!docView.SELECTED) { if (!extendSelection) this.DeselectAll(); @@ -40,29 +40,29 @@ export class SelectionManager { docView.SELECTED = true; docView._props.whenChildContentsActiveChanged(true); } - } + }; @action - public static DeselectView(docView?: DocumentView): void { + public static DeselectView = (docView?: DocumentView): void => { if (docView && this.Instance.SelectedViews.includes(docView)) { docView.SELECTED = false; this.Instance.SelectedViews.splice(this.Instance.SelectedViews.indexOf(docView), 1); docView._props.whenChildContentsActiveChanged(false); } - } - @action - public static DeselectAll(except?: Doc): void { + }; + + public static DeselectAll = (except?: Doc): void => { const found = this.Instance.SelectedViews.find(dv => dv.Document === except); LinkManager.currentLink = undefined; LinkManager.currentLinkAnchor = undefined; - this.Instance.SelectedSchemaDocument = undefined; + runInAction(() => (this.Instance.SelectedSchemaDocument = undefined)); this.Instance.SelectedViews.forEach(dv => { dv.SELECTED = false; dv._props.whenChildContentsActiveChanged(false); }); this.Instance.SelectedViews.length = 0; if (found) this.SelectView(found, false); - } + }; public static IsSelected = (doc?: Doc) => Array.from(doc?.[DocViews] ?? []).some(dv => dv?.SELECTED); public static get Views() { return this.Instance.SelectedViews; } // prettier-ignore diff --git a/src/client/views/AntimodeMenu.tsx b/src/client/views/AntimodeMenu.tsx index f89624941..4c82b10fd 100644 --- a/src/client/views/AntimodeMenu.tsx +++ b/src/client/views/AntimodeMenu.tsx @@ -1,32 +1,25 @@ import { action, makeObservable, observable, runInAction } from 'mobx'; import * as React from 'react'; import { SettingsManager } from '../util/SettingsManager'; -import { copyProps } from '../../Utils'; import './AntimodeMenu.scss'; +import { ObservableReactComponent } from './ObservableReactComponent'; export interface AntimodeMenuProps {} /** * This is an abstract class that serves as the base for a PDF-style or Marquee-style * menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example. */ -export abstract class AntimodeMenu extends React.Component { +export abstract class AntimodeMenu extends ObservableReactComponent { protected _offsetY: number = 0; protected _offsetX: number = 0; protected _mainCont: React.RefObject = React.createRef(); protected _dragging: boolean = false; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - @observable protected _top: number = -300; @observable protected _left: number = -300; @observable protected _opacity: number = 0; diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index 118a2c5f5..e55bf24a1 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -6,9 +6,10 @@ import { StrCast } from '../../fields/Types'; import { SettingsManager } from '../util/SettingsManager'; import './ContextMenu.scss'; import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem'; +import { ObservableReactComponent } from './ObservableReactComponent'; @observer -export class ContextMenu extends React.Component { +export class ContextMenu extends ObservableReactComponent<{}> { static Instance: ContextMenu; private _ignoreUp = false; @@ -36,8 +37,8 @@ export class ContextMenu extends React.Component { constructor(props: any) { super(props); - makeObservable(this); ContextMenu.Instance = this; + makeObservable(this); } public setIgnoreEvents(ignore: boolean) { diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 59b223c14..3c9d821a9 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -5,7 +5,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { UndoManager } from '../util/UndoManager'; import { SettingsManager } from '../util/SettingsManager'; -import { copyProps } from '../../Utils'; +import { ObservableReactComponent } from './ObservableReactComponent'; export interface OriginalMenuProps { description: string; @@ -27,24 +27,17 @@ export interface SubmenuProps { export type ContextMenuProps = OriginalMenuProps | SubmenuProps; @observer -export class ContextMenuItem extends React.Component { +export class ContextMenuItem extends ObservableReactComponent { @observable private _items: Array = []; @observable private overItem = false; - _prevProps: ContextMenuProps & { selected?: boolean }; - @observable _props: ContextMenuProps & { selected?: boolean }; - constructor(props: ContextMenuProps & { selected?: boolean }) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - componentDidMount() { - runInAction(() => this._items.length = 0); + runInAction(() => (this._items.length = 0)); if ((this.props as SubmenuProps)?.subitems) { (this.props as SubmenuProps).subitems?.forEach(i => runInAction(() => this._items.push(i))); } diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 35c0d617b..85cee83d4 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -27,6 +27,7 @@ import './DashboardView.scss'; import { Colors } from './global/globalEnums'; import { MainViewModal } from './MainViewModal'; import { ButtonType } from './nodes/FontIconBox/FontIconBox'; +import { ObservableReactComponent } from './ObservableReactComponent'; enum DashboardGroup { MyDashboards, @@ -36,9 +37,8 @@ enum DashboardGroup { // DashboardView is the view with the dashboard previews, rendered when the app first loads @observer -export class DashboardView extends React.Component { +export class DashboardView extends ObservableReactComponent<{}> { public static _urlState: HistoryUtil.DocUrl; - constructor(props: any) { super(props); makeObservable(this); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 2ce0c085a..235b0dc68 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,17 +1,17 @@ -import { action, computed, makeObservable, observable, runInAction, untracked } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; +import * as React from 'react'; +import { returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; -import { Cast } from '../../fields/Types'; import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; -import { returnFalse } from '../../Utils'; -import { DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; -import { DocumentView } from './nodes/DocumentView'; -import * as React from 'react'; +import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; +import { DocumentView } from './nodes/DocumentView'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { @@ -20,18 +20,14 @@ export interface DocComponentProps { LayoutTemplateString?: string; } export function DocComponent

() { - class Component extends React.Component> { - @observable _props!: React.PropsWithChildren

; - constructor(props: React.PropsWithChildren

) { + class Component extends ObservableReactComponent> { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } - componentDidUpdate() { - // untracked(() => (this._props = this.props)); - } + //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then - @computed get Document() { + get Document() { return this._props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info @@ -57,24 +53,18 @@ interface ViewBoxBaseProps { renderDepth: number; } export function ViewBoxBaseComponent

() { - class Component extends React.Component> { - @observable _props: React.PropsWithChildren

; - constructor(props: React.PropsWithChildren

) { - super(props); - this._props = props; - makeObservable(this); - } + class Component extends ObservableReactComponent> { //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then //@computed get Document(): T { return schemaCtor(this.props.Document); } get Document() { return this._props.Document; } // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info - get layoutDoc() { + @computed get layoutDoc() { return Doc.Layout(this.Document); } // This is the data part of a document -- ie, the data that is constant across all views of the document - get dataDoc() { + @computed get dataDoc() { return this.Document.isTemplateForField || this.Document.isTemplateDoc ? this._props.TemplateDataDocument ?? this.Document[DocData] : this.Document[DocData]; } // key where data is stored @@ -99,13 +89,12 @@ export interface ViewBoxAnnotatableProps { isAnnotationOverlay?: boolean; } export function ViewBoxAnnotatableComponent

() { - class Component extends React.Component> { - @observable _props: React.PropsWithChildren

; - constructor(props: React.PropsWithChildren

) { + class Component extends ObservableReactComponent> { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } + @observable _annotationKeySuffix = () => 'annotations'; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a8ad4150e..50ca3af06 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -28,6 +28,7 @@ import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { PinProps } from './nodes/trails'; import { TemplateMenu } from './TemplateMenu'; import * as React from 'react'; +import { ObservableReactComponent } from './ObservableReactComponent'; // import * as higflyout from '@hig/flyout'; // export const { anchorPoints } = higflyout; // export const Flyout = higflyout.default; @@ -42,12 +43,11 @@ enum UtilityButtonState { } @observer -export class DocumentButtonBar extends React.Component<{ views: () => (DocumentView | undefined)[]; stack?: any }, {}> { +export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> { private _dragRef = React.createRef(); private _pullAnimating = false; private _pushAnimating = false; private _pullColorAnimating = false; - @observable private pushIcon: IconProp = 'arrow-alt-circle-up'; @observable private pullIcon: IconProp = 'arrow-alt-circle-down'; @observable private pullColor: string = 'white'; @@ -60,12 +60,10 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV public static hasPushedHack = false; public static hasPulledHack = false; - @observable _props: { views: () => (DocumentView | undefined)[] }; constructor(props: { views: () => (DocumentView | undefined)[] }) { super(props); - this._props = props; + DocumentButtonBar.Instance = this; makeObservable(this); - runInAction(() => (DocumentButtonBar.Instance = this)); } public startPullOutcome = action((success: boolean) => { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8bcc1cb56..7003485d2 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -34,6 +34,7 @@ import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import * as React from 'react'; +import { ObservableReactComponent } from './ObservableReactComponent'; interface DocumentDecorationsProps { PanelWidth: number; @@ -42,7 +43,7 @@ interface DocumentDecorationsProps { boundsTop: number; } @observer -export class DocumentDecorations extends React.Component { +export class DocumentDecorations extends ObservableReactComponent { static Instance: DocumentDecorations; private _resizeHdlId = ''; private _keyinput = React.createRef(); @@ -66,11 +67,10 @@ export class DocumentDecorations extends React.Component; constructor(props: React.PropsWithChildren) { super(props); - this._props = props; makeObservable(this); + DocumentDecorations.Instance = this; document.addEventListener('pointermove', // show decorations whenever pointer moves outside of selection bounds. action(e => { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 3db77be71..836a184eb 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,13 +1,13 @@ -import * as React from 'react'; import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../fields/ObjectField'; import './EditableView.scss'; import { DocumentIconContainer } from './nodes/DocumentIcon'; -import { OverlayView } from './OverlayView'; -import { copyProps } from '../../Utils'; import { FieldView, FieldViewProps } from './nodes/FieldView'; +import { ObservableReactComponent } from './ObservableReactComponent'; +import { OverlayView } from './OverlayView'; export interface EditableProps { /** @@ -60,18 +60,15 @@ export interface EditableProps { * of the content, and set the value based on the entered string. */ @observer -export class EditableView extends React.Component { +export class EditableView extends ObservableReactComponent { private _ref = React.createRef(); private _inputref: HTMLInputElement | HTMLTextAreaElement | null = null; _overlayDisposer?: () => void; _editingDisposer?: IReactionDisposer; @observable _editing: boolean = false; - _prevProps: EditableProps; - @observable _props: EditableProps; constructor(props: EditableProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); this._editing = this._props.editing ? true : false; } @@ -96,8 +93,7 @@ export class EditableView extends React.Component { ); } - componentDidUpdate() { - copyProps(this); + componentDidUpdate(prevProps: Readonly) { if (this._editing && this._props.editing === false) { this._inputref?.value && this.finalizeEdit(this._inputref.value, false, true, false); } else if (this._props.editing !== undefined) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4f96b9234..f65675792 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -8,20 +8,19 @@ import { observer } from 'mobx-react'; import 'normalize.css'; import * as React from 'react'; import '../../../node_modules/browndash-components/dist/styles/global.min.css'; +import { Utils, emptyFunction, lightOrDark, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents } from '../../Utils'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { DocCast, StrCast } from '../../fields/Types'; -import { emptyFunction, lightOrDark, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, returnZero, setupMoveUpEvents, Utils } from '../../Utils'; -import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; -import { Docs } from '../documents/Documents'; +import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { Docs } from '../documents/Documents'; import { CaptureManager } from '../util/CaptureManager'; import { DocumentManager } from '../util/DocumentManager'; import { DragManager } from '../util/DragManager'; import { GroupManager } from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; import { Hypothesis } from '../util/HypothesisUtils'; -import { ReportManager } from '../util/reportManager/ReportManager'; import { RTFMarkup } from '../util/RTFMarkup'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { SelectionManager } from '../util/SelectionManager'; @@ -30,13 +29,7 @@ import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; -import { TimelineMenu } from './animationtimeline/TimelineMenu'; -import { CollectionDockingView } from './collections/CollectionDockingView'; -import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; -import { CollectionLinearView } from './collections/collectionLinear'; -import { CollectionMenu } from './collections/CollectionMenu'; -import { TabDocView } from './collections/TabDocView'; -import './collections/TreeView.scss'; +import { ReportManager } from '../util/reportManager/ReportManager'; import { ComponentDecorations } from './ComponentDecorations'; import { ContextMenu } from './ContextMenu'; import { DashboardView } from './DashboardView'; @@ -45,15 +38,24 @@ import { DocumentDecorations } from './DocumentDecorations'; import { GestureOverlay } from './GestureOverlay'; import { KeyManager } from './GlobalKeyHandler'; import { LightboxView } from './LightboxView'; -import { LinkMenu } from './linking/LinkMenu'; import './MainView.scss'; +import { ObservableReactComponent } from './ObservableReactComponent'; +import { OverlayView } from './OverlayView'; +import { PreviewCursor } from './PreviewCursor'; +import { PropertiesView } from './PropertiesView'; +import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; +import { TimelineMenu } from './animationtimeline/TimelineMenu'; +import { CollectionDockingView } from './collections/CollectionDockingView'; +import { CollectionMenu } from './collections/CollectionMenu'; +import { TabDocView } from './collections/TabDocView'; +import './collections/TreeView.scss'; +import { CollectionFreeFormLinksView } from './collections/collectionFreeForm'; +import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; +import { CollectionLinearView } from './collections/collectionLinear'; +import { LinkMenu } from './linking/LinkMenu'; import { AudioBox } from './nodes/AudioBox'; import { DocButtonState } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; -import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; -import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; -import GenerativeFill from './nodes/generativeFill/GenerativeFill'; import { ImageBox } from './nodes/ImageBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview'; @@ -61,20 +63,19 @@ import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu'; import { MapBox } from './nodes/MapBox/MapBox'; import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; +import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; +import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; +import GenerativeFill from './nodes/generativeFill/GenerativeFill'; import { PresBox } from './nodes/trails'; -import { OverlayView } from './OverlayView'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; -import { PreviewCursor } from './PreviewCursor'; -import { PropertiesView } from './PropertiesView'; -import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; -import { CollectionFreeFormLinksView } from './collections/collectionFreeForm'; const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @observer -export class MainView extends React.Component { +export class MainView extends ObservableReactComponent<{}> { public static Instance: MainView; public static Live: boolean = false; private _docBtnRef = React.createRef(); @@ -1064,7 +1065,7 @@ export class MainView extends React.Component { - {this.mapBoxHack} + {/* {this.mapBoxHack} */} {/* */} diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 3f0db4258..2e27d1f70 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -15,6 +15,7 @@ import './MarqueeAnnotator.scss'; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { AnchorMenu } from './pdf/AnchorMenu'; +import { ObservableReactComponent } from './ObservableReactComponent'; const _global = (window /* browser */ || global) /* node */ as any; export interface MarqueeAnnotatorProps { @@ -38,23 +39,18 @@ export interface MarqueeAnnotatorProps { highlightDragSrcColor?: string; } @observer -export class MarqueeAnnotator extends React.Component { +export class MarqueeAnnotator extends ObservableReactComponent { private _start: { x: number; y: number } = { x: 0, y: 0 }; - @observable private _width: number = 0; - @observable private _height: number = 0; - @computed get top() { return Math.min(this._start.y, this._start.y + this._height); } // prettier-ignore - @computed get left() { return Math.min(this._start.x, this._start.x + this._width);} // prettier-ignore - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidMount() { - copyProps(this); - } + + @observable private _width: number = 0; + @observable private _height: number = 0; + @computed get top() { return Math.min(this._start.y, this._start.y + this._height); } // prettier-ignore + @computed get left() { return Math.min(this._start.x, this._start.x + this._width);} // prettier-ignore @action static clearAnnotations(savedAnnotations: ObservableMap) { diff --git a/src/client/views/ObservableReactComponent.tsx b/src/client/views/ObservableReactComponent.tsx new file mode 100644 index 000000000..2d8dc9af9 --- /dev/null +++ b/src/client/views/ObservableReactComponent.tsx @@ -0,0 +1,21 @@ +import { makeObservable, observable } from 'mobx'; +import * as React from 'react'; +import { copyProps } from '../../Utils'; +import './AntimodeMenu.scss'; +export interface AntimodeMenuProps {} + +/** + * This is an abstract class that serves as the base for a PDF-style or Marquee-style + * menu. To use this class, look at PDFMenu.tsx or MarqueeOptionsMenu.tsx for an example. + */ +export abstract class ObservableReactComponent extends React.Component { + @observable _props: React.PropsWithChildren; + constructor(props: React.PropsWithChildren) { + super(props); + this._props = props; + makeObservable(this); + } + componentDidUpdate(prevProps: Readonly): void { + copyProps(this, prevProps); + } +} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 673432a60..915c3c18f 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,9 +1,9 @@ -import { action, computed, makeObservable, observable, toJS } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import ReactLoading from 'react-loading'; -import { Utils, copyProps, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue, setupMoveUpEvents } from '../../Utils'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue, setupMoveUpEvents } from '../../Utils'; import { Doc } from '../../fields/Doc'; import { Height, Width } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -12,6 +12,7 @@ import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { LightboxView } from './LightboxView'; +import { ObservableReactComponent } from './ObservableReactComponent'; import './OverlayView.scss'; import { DefaultStyleProvider } from './StyleProvider'; import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; @@ -34,19 +35,14 @@ export interface OverlayWindowProps { } @observer -export class OverlayWindow extends React.Component { +export class OverlayWindow extends ObservableReactComponent { @observable x: number = 0; @observable y: number = 0; @observable width: number = 0; @observable height: number = 0; - - _prevProps: OverlayWindowProps; - @observable _props: OverlayWindowProps; constructor(props: OverlayWindowProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); - const opts = props.overlayOptions; this.x = opts.x; this.y = opts.y; @@ -54,10 +50,6 @@ export class OverlayWindow extends React.Component { this.height = opts.height || 200; } - componentDidUpdate() { - copyProps(this); - } - onPointerDown = (_: React.PointerEvent) => { document.removeEventListener('pointermove', this.onPointerMove); document.removeEventListener('pointerup', this.onPointerUp); @@ -115,7 +107,7 @@ export class OverlayWindow extends React.Component { } @observer -export class OverlayView extends React.Component { +export class OverlayView extends ObservableReactComponent<{}> { public static Instance: OverlayView; @observable.shallow _elements: JSX.Element[] = []; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 6e1a2cfb1..5ec9a7d46 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -1,17 +1,18 @@ import { action, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, Opt } from '../../fields/Doc'; import { lightOrDark, returnFalse } from '../../Utils'; -import { Docs, DocumentOptions, DocUtils } from '../documents/Documents'; +import { Doc, Opt } from '../../fields/Doc'; +import { DocUtils, Docs, DocumentOptions } from '../documents/Documents'; import { ImageUtils } from '../util/Import & Export/ImageUtils'; import { Transform } from '../util/Transform'; -import { undoBatch, UndoManager } from '../util/UndoManager'; -import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { UndoManager, undoBatch } from '../util/UndoManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; import './PreviewCursor.scss'; +import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @observer -export class PreviewCursor extends React.Component<{}> { +export class PreviewCursor extends ObservableReactComponent<{}> { static _instance: PreviewCursor; public static get Instance() { return PreviewCursor._instance; @@ -28,8 +29,8 @@ export class PreviewCursor extends React.Component<{}> { public Doc: Opt; constructor(props: any) { super(props); - PreviewCursor._instance = this; makeObservable(this); + PreviewCursor._instance = this; this._clickPoint = observable([0, 0]); document.addEventListener('keydown', this.onKeyPress); document.addEventListener('paste', this.paste, true); diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 5bde9d3c4..a710e7816 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -1,14 +1,14 @@ -import { computed, makeObservable, observable } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { Cast, StrCast } from '../../fields/Types'; import { DocFocusOrOpen } from '../util/DocumentManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; +import './PropertiesDocContextSelector.scss'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { DocumentView, OpenWhere } from './nodes/DocumentView'; -import './PropertiesDocContextSelector.scss'; -import { copyProps } from '../../Utils'; type PropertiesDocContextSelectorProps = { DocView?: DocumentView; @@ -18,17 +18,12 @@ type PropertiesDocContextSelectorProps = { }; @observer -export class PropertiesDocContextSelector extends React.Component { - _prevProps: PropertiesDocContextSelectorProps; - @observable _props: PropertiesDocContextSelectorProps; - constructor(props: PropertiesDocContextSelectorProps) { +export class PropertiesDocContextSelector extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + @computed get _docs() { if (!this._props.DocView) return []; const target = this._props.DocView._props.Document; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 442d09739..c857c2d6b 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1,14 +1,15 @@ -import * as React from 'react'; import { IconLookup } from '@fortawesome/fontawesome-svg-core'; import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@mui/material'; import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Type } from 'browndash-components'; import { concat } from 'lodash'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { ColorResult, SketchPicker } from 'react-color'; import * as Icons from 'react-icons/bs'; //{BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs" +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../Utils'; import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc'; import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; @@ -16,8 +17,7 @@ import { InkField } from '../../fields/InkField'; import { List } from '../../fields/List'; import { ComputedField } from '../../fields/ScriptField'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; -import { GetEffectiveAcl, normalizeEmail, SharingPermissions } from '../../fields/util'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../Utils'; +import { GetEffectiveAcl, SharingPermissions, normalizeEmail } from '../../fields/util'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; import { GroupManager } from '../util/GroupManager'; @@ -26,19 +26,20 @@ import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; import { SharingManager } from '../util/SharingManager'; import { Transform } from '../util/Transform'; -import { undoable, undoBatch, UndoManager } from '../util/UndoManager'; +import { UndoManager, undoBatch, undoable } from '../util/UndoManager'; import { EditableView } from './EditableView'; import { FilterPanel } from './FilterPanel'; import { InkStrokeProperties } from './InkStrokeProperties'; -import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; -import { KeyValueBox } from './nodes/KeyValueBox'; -import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; +import { ObservableReactComponent } from './ObservableReactComponent'; import { PropertiesButtons } from './PropertiesButtons'; import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector'; import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import { PropertiesSection } from './PropertiesSection'; import './PropertiesView.scss'; import { DefaultStyleProvider } from './StyleProvider'; +import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; +import { KeyValueBox } from './nodes/KeyValueBox'; +import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; const _global = (window /* browser */ || global) /* node */ as any; interface PropertiesViewProps { @@ -49,15 +50,12 @@ interface PropertiesViewProps { } @observer -export class PropertiesView extends React.Component { +export class PropertiesView extends ObservableReactComponent { private _widthUndo?: UndoManager.Batch; public static Instance: PropertiesView | undefined; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; constructor(props: React.PropsWithChildren) { super(props); - this._props = this._prevProps = props; makeObservable(this); PropertiesView.Instance = this; } @@ -120,10 +118,6 @@ export class PropertiesView extends React.Component { ); } - componentDidUpdate() { - copyProps(this); - } - componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); } diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx index 8251d20dc..5f20bc745 100644 --- a/src/client/views/ScriptingRepl.tsx +++ b/src/client/views/ScriptingRepl.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable, makeObservable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DocumentManager } from '../util/DocumentManager'; @@ -7,29 +7,23 @@ import { CompileScript, Transformer, ts } from '../util/Scripting'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { SettingsManager } from '../util/SettingsManager'; import { undoable } from '../util/UndoManager'; -import { DocumentIconContainer } from './nodes/DocumentIcon'; +import { ObservableReactComponent } from './ObservableReactComponent'; import { OverlayView } from './OverlayView'; import './ScriptingRepl.scss'; -import { copyProps } from '../../Utils'; +import { DocumentIconContainer } from './nodes/DocumentIcon'; interface ReplProps { scrollToBottom: () => void; value: { [key: string]: any }; name?: string; } -export class ScriptingObjectDisplay extends React.Component { +export class ScriptingObjectDisplay extends ObservableReactComponent { @observable collapsed = true; - _prevProps: ReplProps; - @observable _props: ReplProps; - constructor(props: ReplProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate(): void { - copyProps(this); - } @action toggle = () => { @@ -84,17 +78,12 @@ interface replValueProps { name?: string; } @observer -export class ScriptingValueDisplay extends React.Component { - _prevProps: replValueProps; - @observable _props: replValueProps; - constructor(props: replValueProps) { +export class ScriptingValueDisplay extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + render() { const val = this._props.name ? this._props.value[this._props.name] : this._props.value; if (typeof val === 'object') { @@ -126,7 +115,7 @@ export class ScriptingValueDisplay extends React.Component { } @observer -export class ScriptingRepl extends React.Component { +export class ScriptingRepl extends ObservableReactComponent<{}> { constructor(props: any) { super(props); makeObservable(this); diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 19473de2b..0f4a4260c 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -1,22 +1,23 @@ -import { computed, makeObservable, observable } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, returnAll, returnFalse, returnOne, returnZero } from '../../Utils'; import { Doc, DocListCast, Field, FieldResult, StrListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { RichTextField } from '../../fields/RichTextField'; import { DocCast, NumCast, StrCast } from '../../fields/Types'; -import { copyProps, emptyFunction, returnAll, returnFalse, returnOne, returnTrue, returnZero } from '../../Utils'; -import { Docs, DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { DocUtils, Docs } from '../documents/Documents'; import { LinkManager } from '../util/LinkManager'; import { SearchUtil } from '../util/SearchUtil'; import { Transform } from '../util/Transform'; +import { ObservableReactComponent } from './ObservableReactComponent'; +import './SidebarAnnos.scss'; +import { StyleProp } from './StyleProvider'; import { CollectionStackingView } from './collections/CollectionStackingView'; import { FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; -import './SidebarAnnos.scss'; -import { StyleProp } from './StyleProvider'; -import * as React from 'react'; interface ExtraProps { fieldKey: string; @@ -34,18 +35,12 @@ interface ExtraProps { moveDocument: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean, annotationKey?: string) => boolean; } @observer -export class SidebarAnnos extends React.Component { - _prevProps: FieldViewProps & ExtraProps; - @observable _props: FieldViewProps & ExtraProps; - constructor(props: FieldViewProps & ExtraProps) { +export class SidebarAnnos extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); - // this._props.dataDoc[this.sidebarKey] = new List(); // bcz: can't do this here. it blows away existing things and isn't a robust solution for making sure the field exists -- instead this should happen when the document is created and/or shared - } - componentDidUpdate() { - copyProps(this); } + _stackRef = React.createRef(); @computed get allMetadata() { const keys = new Map>(); diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx index f03e38850..a11c53d4d 100644 --- a/src/client/views/collections/CollectionCarousel3DView.tsx +++ b/src/client/views/collections/CollectionCarousel3DView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { computed } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Utils, returnFalse, returnZero } from '../../../Utils'; @@ -19,6 +19,10 @@ export class CollectionCarousel3DView extends CollectionSubView() { @computed get scrollSpeed() { return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed } + constructor(props: any) { + super(props); + makeObservable(this); + } private _dropDisposer?: DragManager.DragDropDisposer; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 299a4d5d3..5d09f14ef 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { computed } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { StopEvent, emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils'; @@ -16,6 +16,11 @@ import { CollectionSubView } from './CollectionSubView'; export class CollectionCarouselView extends CollectionSubView() { private _dropDisposer?: DragManager.DragDropDisposer; + constructor(props: any) { + super(props); + makeObservable(this); + } + componentWillUnmount() { this._dropDisposer?.(); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 4ddf9e69b..0d3ff8bba 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,5 +1,6 @@ -import { action, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx'; +import { action, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import * as GoldenLayout from '../../../client/goldenLayout'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; @@ -10,7 +11,7 @@ import { List } from '../../../fields/List'; import { ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { GetEffectiveAcl, inheritParentAcls } from '../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, copyProps, emptyFunction, incrementTitleCopy } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, incrementTitleCopy } from '../../../Utils'; import { DocServer } from '../../DocServer'; import { Docs } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; @@ -19,6 +20,7 @@ import { DragManager } from '../../util/DragManager'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; +import { SettingsManager } from '../../util/SettingsManager'; import { undoable, undoBatch, UndoManager } from '../../util/UndoManager'; import { DashboardView } from '../DashboardView'; import { LightboxView } from '../LightboxView'; @@ -30,8 +32,6 @@ import './CollectionDockingView.scss'; import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { TabDocView } from './TabDocView'; -import * as React from 'react'; -import { SettingsManager } from '../../util/SettingsManager'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -63,11 +63,8 @@ export class CollectionDockingView extends CollectionSubView() { private _goldenLayout: any = null; static _highlightStyleSheet: any = addStyleSheet(); - _prevProps: SubCollectionViewProps; - @override _props: SubCollectionViewProps; constructor(props: SubCollectionViewProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); if (this._props.renderDepth < 0) runInAction(() => (CollectionDockingView.Instance = this)); //Why is this here? @@ -77,10 +74,6 @@ export class CollectionDockingView extends CollectionSubView() { this.Document.myTrails; // this is equivalent to having a prefetchProxy for myTrails which is needed for the My Trails button in the UI which assumes that Doc.ActiveDashboard.myTrails is legit... } - componentDidUpdate() { - copyProps(this); - } - /** * Switches from dragging a document around a freeform canvas to dragging it as a tab to be docked. * diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 0905aa078..5dba9e72a 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, numberRange, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { ScriptField } from '../../../fields/ScriptField'; -import { emptyFunction, numberRange, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { CompileScript } from '../../util/Scripting'; @@ -14,6 +14,7 @@ import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { CollectionStackingView } from './CollectionStackingView'; import './CollectionStackingView.scss'; @@ -41,19 +42,18 @@ interface CMVFieldRowProps { } @observer -export class CollectionMasonryViewFieldRow extends React.Component { +export class CollectionMasonryViewFieldRow extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + } + @observable private _background = 'inherit'; @observable private _createEmbeddingSelected: boolean = false; @observable private heading: string = ''; @observable private color: string = '#f1efeb'; @observable private collapsed: boolean = false; @observable private _paletteOn = false; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { - super(props); - this._props = props; - makeObservable(this); - } private set _heading(value: string) { runInAction(() => this._props.headingObject && (this._props.headingObject.heading = this.heading = value)); } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 08fcd544e..3ade2ab56 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -9,7 +9,7 @@ import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { RichTextField } from '../../../fields/RichTextField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils'; +import { copyProps, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { SelectionManager } from '../../util/SelectionManager'; diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 702775307..f9d258490 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; @@ -44,6 +44,12 @@ export class CollectionNoteTakingView extends CollectionSubView() { public DividerWidth = 16; @observable docsDraggedRowCol: number[] = []; @observable _scroll = 0; + + constructor(props: any) { + super(props); + makeObservable(this); + } + @computed get chromeHidden() { return BoolCast(this.layoutDoc.chromeHidden) || this.props.onBrowseClick?.() ? true : false; } diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index a0f8b9c89..170b1f1ec 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { ScriptField } from '../../../fields/ScriptField'; @@ -19,6 +19,11 @@ export class CollectionPileView extends CollectionSubView() { _originalChrome: any = ''; _disposers: { [name: string]: IReactionDisposer } = {}; + constructor(props: any) { + super(props); + makeObservable(this); + } + componentDidMount() { if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) { this.Document._freeform_pileEngine = computePassLayout.name; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 1b14b31ac..d37a942d0 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { Cast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { copyProps, emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils'; +import { emptyFunction, formatTime, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnTrue, returnZero, setupMoveUpEvents, smoothScrollHorizontal, StopEvent } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; @@ -26,6 +26,7 @@ import { AudioWaveform } from '../nodes/audio/AudioWaveform'; import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; export type CollectionStackedTimelineProps = { @@ -56,17 +57,10 @@ export enum TrimScope { export class CollectionStackedTimeline extends CollectionSubView() { @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; @observable public static CurrentlyPlaying: DocumentView[]; - - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } static LabelScript: ScriptField; static LabelPlayScript: ScriptField; @@ -697,21 +691,15 @@ interface StackedTimelineAnchorProps { } @observer -class StackedTimelineAnchor extends React.Component { +class StackedTimelineAnchor extends ObservableReactComponent { _lastTimecode: number; _disposer: IReactionDisposer | undefined; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; constructor(props: React.PropsWithChildren) { super(props); - this._props = this._prevProps = props; makeObservable(this); this._lastTimecode = this._props.currentTimecode(); } - componentDidUpdate() { - copyProps(this); - } // updates marker document title to reflect correct timecodes computeTitle = () => { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d6105c184..16adf4b96 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as CSS from 'csstype'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -11,7 +11,7 @@ import { listSpec } from '../../../fields/Schema'; import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType } from '../../documents/DocumentTypes'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -31,7 +31,7 @@ import { StyleProp } from '../StyleProvider'; import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow'; import './CollectionStackingView.scss'; import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { CollectionSubView } from './CollectionSubView'; const _global = (window /* browser */ || global) /* node */ as any; export type collectionStackingViewProps = { @@ -115,22 +115,15 @@ export class CollectionStackingView extends CollectionSubView>; - _props: React.PropsWithChildren>; constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); - if (this.colHeaderData === undefined) { // TODO: what is a layout doc? Is it literally how this document is supposed to be layed out? // here we're making an empty list of column headers (again, what Mehek showed us) this.dataDoc['_' + this.fieldKey + '_columnHeaders'] = new List(); } } - componentDidUpdate() { - copyProps(this); - } // TODO: plj - these are the children children = (docs: Doc[]) => { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 7ea146479..2302bfbc3 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, untracked } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { RichTextField } from '../../../fields/RichTextField'; import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; +import { BoolCast, NumCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, setupMoveUpEvents, returnFalse, returnEmptyString } from '../../../Utils'; +import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; @@ -19,9 +19,9 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; -import './CollectionStackingView.scss'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import { Id } from '../../../fields/FieldSymbols'; +import './CollectionStackingView.scss'; +import { ObservableReactComponent } from '../ObservableReactComponent'; // So this is how we are storing a column interface CSVFieldColumnProps { @@ -49,7 +49,7 @@ interface CSVFieldColumnProps { } @observer -export class CollectionStackingViewFieldColumn extends React.Component { +export class CollectionStackingViewFieldColumn extends ObservableReactComponent { private dropDisposer?: DragManager.DragDropDisposer; private _disposers: { [name: string]: IReactionDisposer } = {}; private _headerRef: React.RefObject = React.createRef(); @@ -58,10 +58,8 @@ export class CollectionStackingViewFieldColumn extends React.Component (this._props = this.props)); - } - @action componentDidMount() { this._disposers.collapser = reaction( diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 79b15fdb1..0131af6f2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,5 +1,7 @@ -import { action, computed, makeObservable, observable, override, runInAction, untracked } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; +import * as React from 'react'; import * as rp from 'request-promise'; +import { Utils, returnFalse } from '../../../Utils'; import CursorField from '../../../fields/CursorField'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate } from '../../../fields/DocSymbols'; @@ -10,21 +12,19 @@ import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; -import { returnFalse, Utils } from '../../../Utils'; import { DocServer } from '../../DocServer'; -import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents'; -import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; +import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils, Docs, DocumentOptions } from '../../documents/Documents'; import { DragManager, dropActionType } from '../../util/DragManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { UndoManager, undoBatch } from '../../util/UndoManager'; import { ViewBoxBaseComponent } from '../DocComponent'; -import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { LoadingBox } from '../nodes/LoadingBox'; +import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; -import * as React from 'react'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; @@ -35,16 +35,11 @@ export function CollectionSubView(moreProps?: X) { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; - @override _props: X & SubCollectionViewProps; constructor(props: any) { super(props); - this._props = props; makeObservable(this); } - componentDidUpdate() { - // untracked(() => (this._props = this.props)); - } @observable _focusFilters: Opt; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it @observable _focusRangeFilters: Opt; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index e65f24702..c440a7e3f 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,5 +1,5 @@ import { toUpper } from 'lodash'; -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; @@ -32,6 +32,11 @@ export class CollectionTimeView extends CollectionSubView() { @observable _viewDefDivClick: Opt; @observable _focusPivotField: Opt; + constructor(props: any) { + super(props); + makeObservable(this); + } + async componentDidMount() { this.props.setContentView?.(this); runInAction(() => { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 658d60523..7f8d42088 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,6 @@ -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -7,7 +8,7 @@ import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; +import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -23,10 +24,9 @@ import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { CollectionSubView } from './CollectionSubView'; import './CollectionTreeView.scss'; import { TreeView } from './TreeView'; -import * as React from 'react'; const _global = (window /* browser */ || global) /* node */ as any; export type collectionTreeViewProps = { @@ -59,16 +59,10 @@ export class CollectionTreeView extends CollectionSubView = new Set(); // list of tree view items to monitor for height changes private observer: any; // observer for monitoring tree view items. - _prevProps: React.PropsWithChildren>; - @override _props: React.PropsWithChildren>; - constructor(props: React.PropsWithChildren>) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } get dataDoc() { return this._props.TemplateDataDocument || this.Document; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e84c12e02..f1ef52e60 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,14 +1,14 @@ -import { IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx'; +import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnEmptyString } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { ObjectField } from '../../../fields/ObjectField'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, returnEmptyString } from '../../../Utils'; -import { DocUtils } from '../../documents/Documents'; import { CollectionViewType } from '../../documents/DocumentTypes'; +import { DocUtils } from '../../documents/Documents'; import { dropActionType } from '../../util/DragManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { ContextMenu } from '../ContextMenu'; @@ -19,19 +19,19 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -import { CollectionGridView } from './collectionGrid/CollectionGridView'; -import { CollectionLinearView } from './collectionLinear'; -import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; -import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; import { CollectionNoteTakingView } from './CollectionNoteTakingView'; import { CollectionPileView } from './CollectionPileView'; -import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; import { CollectionStackingView } from './CollectionStackingView'; import { SubCollectionViewProps } from './CollectionSubView'; import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from './CollectionTreeView'; import './CollectionView.scss'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionGridView } from './collectionGrid/CollectionGridView'; +import { CollectionLinearView } from './collectionLinear'; +import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; +import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; +import { CollectionSchemaView } from './collectionSchema/CollectionSchemaView'; const path = require('path'); interface CollectionViewProps_ extends FieldViewProps { @@ -78,16 +78,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent; - @override _props: React.PropsWithChildren; constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); - runInAction(() => (this._annotationKeySuffix = returnEmptyString)); - } - componentDidUpdate() { - copyProps(this); + this._annotationKeySuffix = returnEmptyString; } componentDidMount() { diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 8bc0f62dc..2eb13fd2f 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -2,40 +2,41 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Popup, Type } from 'browndash-components'; import { clamp } from 'lodash'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableSet, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; +import { DashColor, Utils, emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { FieldId } from '../../../fields/RefField'; +import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { copyProps, DashColor, emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../../Utils'; import { DocServer } from '../../DocServer'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { undoable, UndoManager } from '../../util/UndoManager'; +import { UndoManager, undoable } from '../../util/UndoManager'; import { DashboardView } from '../DashboardView'; -import { Colors } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; +import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; +import { Colors } from '../global/globalEnums'; import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; -import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; +import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; -import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { CollectionDockingView } from './CollectionDockingView'; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; -import * as React from 'react'; -import { Docs } from '../../documents/Documents'; -import { ComputedField } from '../../../fields/ScriptField'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -44,16 +45,13 @@ interface TabDocViewProps { glContainer: any; } @observer -export class TabDocView extends React.Component { +export class TabDocView extends ObservableReactComponent { static _allTabs = new ObservableSet(); _mainCont: HTMLDivElement | null = null; _tabReaction: IReactionDisposer | undefined; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } @@ -341,9 +339,8 @@ export class TabDocView extends React.Component { // { fireImmediately: true }); runInAction(() => TabDocView._allTabs.add(this)); } - componentDidUpdate() { + componentDidUpdate(prevProps: Readonly) { this._view && DocumentManager.Instance.AddView(this._view); - copyProps(this); } componentWillUnmount() { @@ -521,14 +518,14 @@ interface TabMiniThumbProps { miniTop: () => number; miniLeft: () => number; } -@observer + class TabMiniThumb extends React.Component { render() { return

; } } @observer -export class TabMinimapView extends React.Component { +export class TabMinimapView extends ObservableReactComponent { static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { switch (property.split(':')[0]) { @@ -556,12 +553,6 @@ export class TabMinimapView extends React.Component { } }; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { - super(props); - this._props = props; - makeObservable(this); - } @computed get renderBounds() { const compView = this._props.tabView()?.ComponentView as CollectionFreeFormView; const bounds = compView?.freeformData?.(true)?.bounds; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 224d74882..52ecdfbec 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -1,8 +1,10 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IconButton, Size } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -12,9 +14,8 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils, Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; @@ -22,19 +23,19 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SettingsManager } from '../../util/SettingsManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { undoable, undoBatch, UndoManager } from '../../util/UndoManager'; +import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; +import { StyleProp } from '../StyleProvider'; import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; +import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; -import { KeyValueBox } from '../nodes/KeyValueBox'; -import { StyleProp } from '../StyleProvider'; import { CollectionTreeView, TreeViewType } from './CollectionTreeView'; import { CollectionView } from './CollectionView'; import { TreeSort } from './TreeSort'; import './TreeView.scss'; -import * as React from 'react'; const { default: { TREE_BULLET_WIDTH } } = require('../global/globalCssVariables.module.scss'); // prettier-ignore export interface TreeViewProps { @@ -86,7 +87,7 @@ const treeBulletWidth = function () { * treeView_ExpandedView : name of field whose contents are being displayed as the document's subtree */ @observer -export class TreeView extends React.Component { +export class TreeView extends ObservableReactComponent { static _editTitleOnLoad: Opt<{ id: string; parent: TreeView | CollectionTreeView | undefined }>; static _openTitleScript: Opt; static _openLevelScript: Opt; @@ -254,11 +255,8 @@ export class TreeView extends React.Component { static GetRunningChildren = new Map(); static ToggleChildrenRun = new Map void>(); - _prevProps: TreeViewProps; - @observable _props: TreeViewProps; constructor(props: TreeViewProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); if (!TreeView._openLevelScript) { TreeView._openTitleScript = ScriptField.MakeScript('scriptContext.setEditTitle(documentView)', { scriptContext: 'any', documentView: 'any' }); @@ -297,8 +295,7 @@ export class TreeView extends React.Component { this._props.hierarchyIndex !== undefined && this._props.RemFromMap?.(this.Document, this._props.hierarchyIndex); } - componentDidUpdate() { - copyProps(this); + componentDidUpdate(prevProps: Readonly) { this._disposers.opening = reaction( () => this.treeViewOpen, open => !open && (this._renderCount = 20) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx index dd7e12e41..0d5fcdaeb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx @@ -1,8 +1,9 @@ -import { IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { copyProps } from '../../../../Utils'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; import './CollectionFreeFormView.scss'; +import { copyProps } from '../../../../Utils'; /** * An Fsa Arc. The first array element is a test condition function that will be observed. @@ -47,14 +48,11 @@ export interface CollectionFreeFormInfoStateProps { } @observer -export class CollectionFreeFormInfoState extends React.Component { +export class CollectionFreeFormInfoState extends ObservableReactComponent { _disposers: IReactionDisposer[] = []; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } @@ -62,7 +60,7 @@ export class CollectionFreeFormInfoState extends React.Component this.State[key]); + return Object.keys(this.State ?? []).map(key => this.State?.[key]); } clearState = () => this._disposers.map(disposer => disposer()); @@ -84,8 +82,8 @@ export class CollectionFreeFormInfoState extends React.Component) { + copyProps(this, prevProps); this.clearState(); this.initState(); } @@ -93,6 +91,6 @@ export class CollectionFreeFormInfoState extends React.Component{this.State[StateMessage]}
; + return
{this.State?.[StateMessage]}
; } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index f0a052c1d..4d3752c02 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -1,21 +1,13 @@ -import { IReactionDisposer, computed, observable, reaction, action, runInAction, makeObservable } from 'mobx'; +import { IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc } from '../../../../fields/Doc'; -import { ScriptField } from '../../../../fields/ScriptField'; -import { PresBox } from '../../nodes/trails/PresBox'; -import './CollectionFreeFormView.scss'; import * as React from 'react'; -import { CollectionFreeFormView } from './CollectionFreeFormView'; -import { NumCast } from '../../../../fields/Types'; +import { Doc } from '../../../../fields/Doc'; import { LinkManager } from '../../../util/LinkManager'; -import { InkTool } from '../../../../fields/InkField'; -import { LinkDocPreview } from '../../nodes/LinkDocPreview'; -import { DocumentLinksButton, DocButtonState } from '../../nodes/DocumentLinksButton'; -import { DocumentManager } from '../../../util/DocumentManager'; -import { CollectionFreeFormInfoState, infoState, StateMessage, infoArc, StateEntryFunc, InfoState } from './CollectionFreeFormInfoState'; -import { string32 } from 'pdfjs-dist/types/src/shared/util'; -import { any } from 'bluebird'; -import { copyProps } from '../../../../Utils'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { DocButtonState } from '../../nodes/DocumentLinksButton'; +import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; +import { CollectionFreeFormView } from './CollectionFreeFormView'; +import './CollectionFreeFormView.scss'; export interface CollectionFreeFormInfoUIProps { Document: Doc; @@ -23,7 +15,7 @@ export interface CollectionFreeFormInfoUIProps { } @observer -export class CollectionFreeFormInfoUI extends React.Component { +export class CollectionFreeFormInfoUI extends ObservableReactComponent { private _disposers: { [name: string]: IReactionDisposer } = {}; @observable _currState: infoState | undefined = undefined; @@ -33,17 +25,12 @@ export class CollectionFreeFormInfoUI extends React.Component; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + + constructor(props: any) { super(props); - this._props = this._prevProps = this.props; makeObservable(this); this.currState = this.setupStates(); } - componentDidUpdate() { - copyProps(this); - } setCurrState = (state: infoState) => { if (state) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index be3d2439c..6337c8d34 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,19 +1,20 @@ import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, Field } from '../../../../fields/Doc'; import { Brushed, DocCss } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { Cast, NumCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { LinkManager } from '../../../util/LinkManager'; import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../../nodes/DocumentView'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; import './CollectionFreeFormLinkView.scss'; -import * as React from 'react'; export interface CollectionFreeFormLinkViewProps { A: DocumentView; @@ -24,22 +25,16 @@ export interface CollectionFreeFormLinkViewProps { // props.screentolocatransform @observer -export class CollectionFreeFormLinkView extends React.Component { +export class CollectionFreeFormLinkView extends ObservableReactComponent { @observable _opacity: number = 0; @observable _start = 0; _anchorDisposer: IReactionDisposer | undefined; _timeout: NodeJS.Timeout | undefined; - _prevProps: CollectionFreeFormLinkViewProps; - @observable _props: CollectionFreeFormLinkViewProps; - constructor(props: CollectionFreeFormLinkViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } componentWillUnmount() { this._anchorDisposer?.(); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index aa40fb809..1f4688729 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,6 +1,6 @@ import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, toJS } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, toJS } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -16,7 +16,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../ import { ImageField } from '../../../../fields/URLField'; import { TraceMobx } from '../../../../fields/util'; import { GestureUtils } from '../../../../pen-gestures/GestureUtils'; -import { aggregateBounds, copyProps, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; import { Docs, DocUtils } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -43,7 +43,7 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../../nodes/trails/PresBox'; import { CreateImage } from '../../nodes/WebBoxRenderer'; import { StyleProp } from '../../StyleProvider'; -import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; import { CollectionFreeFormBackgroundGrid } from './CollectionFreeFormBackgroundGrid'; import { CollectionFreeFormInfoUI } from './CollectionFreeFormInfoUI'; @@ -72,17 +72,10 @@ export class CollectionFreeFormView extends CollectionSubView>; - @override _props: React.PropsWithChildren>; constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - @observable public static ShowPresPaths = false; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index 825bd5f19..7aa68b0d9 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -20,7 +20,6 @@ export class MarqueeOptionsMenu extends AntimodeMenu { public isShown = () => this._opacity > 0; constructor(props: Readonly<{}>) { super(props); - MarqueeOptionsMenu.Instance = this; } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 10beb120a..2c65726b2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,5 +1,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Utils, intersectRect, lightOrDark, returnFalse } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; @@ -7,25 +9,24 @@ import { InkData, InkField, InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { RichTextField } from '../../../../fields/RichTextField'; import { Cast, FieldValue, NumCast, StrCast } from '../../../../fields/Types'; -import { ImageField, nullAudio } from '../../../../fields/URLField'; +import { ImageField } from '../../../../fields/URLField'; import { GetEffectiveAcl } from '../../../../fields/util'; -import { intersectRect, lightOrDark, returnFalse, Utils } from '../../../../Utils'; import { CognitiveServices } from '../../../cognitive_services/CognitiveServices'; -import { Docs, DocumentOptions, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocUtils, Docs, DocumentOptions } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; +import { freeformScrollMode } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { undoBatch, UndoManager } from '../../../util/UndoManager'; +import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { PreviewCursor } from '../../PreviewCursor'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; -import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; -import { PreviewCursor } from '../../PreviewCursor'; +import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import * as React from 'react'; -import { freeformScrollMode } from '../../../util/SettingsManager'; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -51,16 +52,14 @@ export interface MarqueeViewBounds { } @observer -export class MarqueeView extends React.Component { +export class MarqueeView extends ObservableReactComponent { public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) { const ps = NumCast(pinDoc._freeform_scale, 1); return { left: NumCast(pinDoc._freeform_panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._freeform_panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps }; } - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 697a11ccc..1e19964d7 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -1,4 +1,4 @@ -import { action, computed, Lambda, observable, reaction } from 'mobx'; +import { action, computed, Lambda, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Opt } from '../../../../fields/Doc'; @@ -27,6 +27,11 @@ export class CollectionGridView extends CollectionSubView() { @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll private dropLocation: object = {}; // sets the drop location for external drops + constructor(props: any) { + super(props); + makeObservable(this); + } + onChildClickHandler = () => ScriptCast(this.Document.onChildClick); @computed get numCols() { diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index a9782f699..f1fb68003 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -1,26 +1,26 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Toggle, ToggleType, Type } from 'browndash-components'; -import { action, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx'; +import { IReactionDisposer, action, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { Utils, emptyFunction, returnEmptyDoclist, returnTrue } from '../../../../Utils'; import { Doc, Opt } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnTrue, Utils } from '../../../../Utils'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { BranchingTrailManager } from '../../../util/BranchingTrailManager'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; +import { UndoStack } from '../../UndoStack'; import { DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { DocumentView } from '../../nodes/DocumentView'; import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup'; -import { UndoStack } from '../../UndoStack'; import { CollectionStackedTimeline } from '../CollectionStackedTimeline'; -import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import { CollectionSubView } from '../CollectionSubView'; import './CollectionLinearView.scss'; /** @@ -33,24 +33,15 @@ import './CollectionLinearView.scss'; */ @observer export class CollectionLinearView extends CollectionSubView() { - @observable public addMenuToggle = React.createRef(); - @observable private _selectedIndex = -1; private _dropDisposer?: DragManager.DragDropDisposer; private _widthDisposer?: IReactionDisposer; private _selectedDisposer?: IReactionDisposer; - _prevProps: SubCollectionViewProps; - @override _props: SubCollectionViewProps; - constructor(props: SubCollectionViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - componentWillUnmount() { this._dropDisposer?.(); this._widthDisposer?.(); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 037786abf..b951a4b17 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { Button } from 'browndash-components'; -import { action, computed } from 'mobx'; +import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../../fields/Doc'; @@ -37,6 +37,11 @@ const resizerWidth = 8; @observer export class CollectionMulticolumnView extends CollectionSubView() { + constructor(props: any) { + super(props); + makeObservable(this); + } + /** * @returns the list of layout documents whose width unit is * *, denoting that it will be displayed with a ratio, not fixed pixel, value @@ -238,8 +243,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive - ? true - : undefined; + ? true + : undefined; }; getDisplayDoc = (childLayout: Doc) => { const width = () => this.lookupPixels(childLayout); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index bbf3481dd..f1c6c6e1e 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,4 +1,4 @@ -import { action, computed } from 'mobx'; +import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../../fields/Doc'; @@ -33,6 +33,11 @@ const resizerHeight = 8; @observer export class CollectionMultirowView extends CollectionSubView() { + constructor(props: any) { + super(props); + makeObservable(this); + } + /** * @returns the list of layout documents whose width unit is * *, denoting that it will be displayed with a ratio, not fixed pixel, value @@ -234,8 +239,8 @@ export class CollectionMultirowView extends CollectionSubView() { return this.props.isContentActive?.() === false || childDocsActive === false ? false // : this.props.isDocumentActive?.() && childDocsActive - ? true - : undefined; + ? true + : undefined; }; getDisplayDoc = (layout: Doc) => { const height = () => this.lookupPixels(layout); diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 276415d56..2546f5b02 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -1,13 +1,13 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, makeObservable, observable, ObservableMap, observe, override } from 'mobx'; +import { action, computed, makeObservable, observable, ObservableMap, observe } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Field, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnEmptyString, returnFalse, returnIgnore, returnNever, returnTrue, setupMoveUpEvents, smoothScroll } from '../../../../Utils'; import { Docs, DocumentOptions, DocUtils, FInfo } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; @@ -18,8 +18,9 @@ import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; import { DocFocusOptions, DocumentView, DocumentViewProps } from '../../nodes/DocumentView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; -import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; +import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; @@ -57,6 +58,11 @@ export class CollectionSchemaView extends CollectionSubView() { private _tableContentRef: HTMLDivElement | null = null; private _menuTarget = React.createRef(); + constructor(props: any) { + super(props); + makeObservable(this); + } + static _rowHeight: number = 50; static _rowSingleLineHeight: number = 32; public static _minColWidth: number = 25; @@ -79,18 +85,6 @@ export class CollectionSchemaView extends CollectionSubView() { @observable _filterSearchValue: string = ''; @observable _selectedCell: [Doc, number] | undefined = undefined; - _prevProps: SubCollectionViewProps; - @override _props: SubCollectionViewProps; - constructor(props: SubCollectionViewProps) { - super(props); - this._props = this._prevProps = props; - makeObservable(this); - } - - componentDidUpdate() { - copyProps(this); - } - // target HTMLelement portal for showing a popup menu to edit cell values. public get MenuTarget() { return this._menuTarget.current; @@ -959,17 +953,12 @@ interface CollectionSchemaViewDocProps { } @observer -class CollectionSchemaViewDoc extends React.Component { - _prevProps: CollectionSchemaViewDocProps; - @observable _props; - constructor(props: CollectionSchemaViewDocProps) { +class CollectionSchemaViewDoc extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + tableWidthFunc = () => this._props.schema.tableWidth; screenToLocalXf = () => this._props.schema._props.ScreenToLocalTransform().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 737d7e0f4..5a3be826b 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -1,13 +1,13 @@ -import * as React from 'react'; import { IconButton, Size } from 'browndash-components'; -import { computed, makeObservable, override } from 'mobx'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; +import * as React from 'react'; import { CgClose } from 'react-icons/cg'; import { FaExternalLinkAlt } from 'react-icons/fa'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; import { BoolCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnFalse, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; @@ -30,16 +30,10 @@ export class SchemaRowBox extends ViewBoxBaseComponent this._ref?.getBoundingClientRect(); diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index bcfe2c232..85269028b 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -1,27 +1,28 @@ -import * as React from 'react'; -import Select, { MenuPlacement } from 'react-select'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import { extname } from 'path'; +import * as React from 'react'; import DatePicker from 'react-datepicker'; +import Select from 'react-select'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../../Utils'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field } from '../../../../fields/Doc'; import { RichTextField } from '../../../../fields/RichTextField'; import { BoolCast, Cast, DateCast, DocCast, FieldValue, StrCast } from '../../../../fields/Types'; import { ImageField } from '../../../../fields/URLField'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero, Utils } from '../../../../Utils'; import { FInfo } from '../../../documents/Documents'; import { DocFocusOrOpen } from '../../../util/DocumentManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch } from '../../../util/UndoManager'; +import { undoBatch, undoable } from '../../../util/UndoManager'; import { EditableView } from '../../EditableView'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; import { OpenWhere } from '../../nodes/DocumentView'; -import { FieldView, FieldViewProps } from '../../nodes/FieldView'; -import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; +import { FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; -import { DefaultStyleProvider } from '../../StyleProvider'; -import { CollectionSchemaView, ColumnType, FInfotoColType } from './CollectionSchemaView'; +import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; +import { ColumnType, FInfotoColType } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; export interface SchemaTableCellProps { @@ -47,7 +48,12 @@ export interface SchemaTableCellProps { } @observer -export class SchemaTableCell extends React.Component { +export class SchemaTableCell extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + } + static addFieldDoc = (doc: Doc, where: OpenWhere) => { DocFocusOrOpen(doc); return true; @@ -95,12 +101,6 @@ export class SchemaTableCell extends React.Component { return { color, textDecoration, fieldProps, cursor, pointerEvents }; } - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { - super(props); - this._props = props; - } - @computed get selected() { const selected: [Doc, number] | undefined = this._props.selectedCell(); return this._props.isRowActive() && selected?.[0] === this._props.Document && selected[1] === this._props.col; @@ -182,16 +182,14 @@ export class SchemaTableCell extends React.Component { // mj: most of this is adapted from old schema code so I'm not sure what it does tbh @observer -export class SchemaImageCell extends React.Component { - @observable _previewRef: HTMLImageElement | undefined = undefined; - - _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { +export class SchemaImageCell extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } + @observable _previewRef: HTMLImageElement | undefined = undefined; + choosePath(url: URL) { if (url.protocol === 'data') return url.href; // if the url ises the data protocol, just return the href if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href); // otherwise, put it through the cors proxy erver @@ -251,16 +249,13 @@ export class SchemaImageCell extends React.Component { } @observer -export class SchemaDateCell extends React.Component { - @observable _pickingDate: boolean = false; - - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { +export class SchemaDateCell extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } + @observable _pickingDate: boolean = false; @computed get date(): DateField { // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. return DateCast(this._props.Document[this._props.fieldKey]); @@ -282,11 +277,9 @@ export class SchemaDateCell extends React.Component { } } @observer -export class SchemaRTFCell extends React.Component { - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { +export class SchemaRTFCell extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } @@ -306,11 +299,9 @@ export class SchemaRTFCell extends React.Component { } } @observer -export class SchemaBoolCell extends React.Component { - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { +export class SchemaBoolCell extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } @@ -352,11 +343,9 @@ export class SchemaBoolCell extends React.Component { } } @observer -export class SchemaEnumerationCell extends React.Component { - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { +export class SchemaEnumerationCell extends ObservableReactComponent { + constructor(props: any) { super(props); - this._props = props; makeObservable(this); } diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index af22f41e1..b7376e901 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -1,13 +1,14 @@ import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView } from '../nodes/DocumentView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenu.scss'; import { LinkMenuGroup } from './LinkMenuGroup'; -import * as React from 'react'; -import { SettingsManager } from '../../util/SettingsManager'; interface Props { docView: DocumentView; @@ -20,10 +21,10 @@ interface Props { * the outermost component for the link menu of a node that contains a list of its linked nodes */ @observer -export class LinkMenu extends React.Component { +export class LinkMenu extends ObservableReactComponent { _editorRef = React.createRef(); @observable _linkMenuRef = React.createRef(); - constructor(props: Props) { + constructor(props: any) { super(props); makeObservable(this); } diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index d77525e04..06073b52c 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,23 +1,24 @@ -import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, observable, makeObservable } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; -import { emptyFunction, returnFalse, setupMoveUpEvents, copyProps } from '../../../Utils'; -import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; -import { undoBatch } from '../../util/UndoManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; -import { LinkDocPreview, LinkInfo } from '../nodes/LinkDocPreview'; +import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import * as React from 'react'; +import { undoBatch } from '../../util/UndoManager'; +import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuItemProps { groupType: string; @@ -50,20 +51,13 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume } @observer -export class LinkMenuItem extends React.Component { +export class LinkMenuItem extends ObservableReactComponent { private _drag = React.createRef(); _editRef = React.createRef(); - - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } @observable private _showMore: boolean = false; @action toggleShowMore(e: React.PointerEvent) { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 0c671f7e3..567cf193e 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc } from '../../../fields/Doc'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DateCast, NumCast } from '../../../fields/Types'; import { AudioField, nullAudio } from '../../../fields/URLField'; -import { copyProps, emptyFunction, formatTime, returnFalse, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, formatTime, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; @@ -17,7 +17,7 @@ import { undoBatch } from '../../util/UndoManager'; import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import './AudioBox.scss'; import { DocFocusOptions } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; @@ -54,19 +54,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { return FieldView.LayoutString(AudioBox, fieldKey); } - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + public static Enabled = false; + + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - public static Enabled = false; - static topControlsHeight = 30; // height of upper controls above timeline static bottomControlsHeight = 20; // height of lower controls below timeline diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 8e7a6914f..c97c879af 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,21 +1,21 @@ -import { action, computed, observable, makeObservable, reaction, runInAction, override } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { OmitKeys, numberRange } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, numberRange, OmitKeys } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; -import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; -import * as React from 'react'; -import { ScriptingGlobals } from '../../util/ScriptingGlobals'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { x: number; @@ -37,11 +37,8 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView } @observer export class CollectionFreeFormDocumentViewWrapper extends DocComponent() implements CollectionFreeFormDocumentViewProps { - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } @observable X = this.props.x; @@ -79,7 +76,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent this.Highlight; // prettier-ignore w_Width = () => this.Width; // prettier-ignore w_Height = () => this.Height; // prettier-ignore - w_AutoDim = () => this.AutoDim; + w_AutoDim = () => this.AutoDim; // prettier-ignore w_Transition = () => this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore @@ -87,7 +84,6 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent this._props.autoDim ? this._props.PanelHeight?.() : this.Height; // prettier-ignore componentDidUpdate() { - copyProps(this); this.WrapperKeys.forEach(action(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower]))); } render() { @@ -124,6 +120,10 @@ export interface CollectionFreeFormDocumentViewProps { @observer export class CollectionFreeFormDocumentView extends DocComponent() { + constructor(props: any) { + super(props); + makeObservable(this); + } get displayName() { // this makes mobx trace() statements more descriptive return 'CollectionFreeFormDocumentView(' + this.Document.title + ')'; } // prettier-ignore @@ -143,13 +143,6 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames - _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { - super(props); - this._props = Object.assign({}, props); - makeObservable(this); - } - get CollectionFreeFormView() { return this._props.CollectionFreeFormView; } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 62523ba00..de382fca5 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,10 +1,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, makeObservable, observable, override } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { copyProps, emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils'; -import { Docs, DocUtils } from '../../documents/Documents'; +import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; @@ -13,7 +14,6 @@ import './ComparisonBox.scss'; import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; -import * as React from 'react'; @observer export class ComparisonBox extends ViewBoxAnnotatableComponent() { @@ -21,20 +21,12 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { } @observer -export class DocumentContentsView extends React.Component< +export class DocumentContentsView extends ObservableReactComponent< DocumentViewProps & FieldViewProps & { setHeight?: (height: number) => void; layout_fieldKey: string; } > { - @observable _props!: DocumentViewProps & - FieldViewProps & { - setHeight?: (height: number) => void; - layout_fieldKey: string; - }; constructor(props: any) { super(props); - this._props = props; makeObservable(this); } - componentDidUpdate(prevProps: Readonly void) | undefined; layout_fieldKey: string }>, prevState: Readonly<{}>, snapshot?: any): void { - // untracked(() => (this._props = this.props)); - // Object.keys(prevProps).forEach(pkey => (prevProps as any)[pkey] !== (this._props as any)[pkey] && console.log(pkey + ' ' + (prevProps as any)[pkey] + ' ' + (this._props as any)[pkey])); - } - @computed get layout(): string { TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index 9ec4d8c13..dfd610581 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -1,34 +1,28 @@ +import { Tooltip } from '@mui/material'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { DocumentView } from './DocumentView'; -import { DocumentManager } from '../../util/DocumentManager'; -import { Transformer, ts } from '../../util/Scripting'; +import { factory } from 'typescript'; import { Field } from '../../../fields/Doc'; -import { Tooltip } from '@mui/material'; -import { action, makeObservable, observable } from 'mobx'; import { Id } from '../../../fields/FieldSymbols'; -import { factory } from 'typescript'; -import { LightboxView } from '../LightboxView'; +import { DocumentManager } from '../../util/DocumentManager'; +import { Transformer, ts } from '../../util/Scripting'; import { SettingsManager } from '../../util/SettingsManager'; -import { copyProps } from '../../../Utils'; +import { LightboxView } from '../LightboxView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; +import { DocumentView } from './DocumentView'; interface DocumentIconProps { view: DocumentView; index: number; } @observer -export class DocumentIcon extends React.Component { +export class DocumentIcon extends ObservableReactComponent { @observable _hovered = false; - _prevProps: DocumentIconProps; - @observable _props: DocumentIconProps; - constructor(props: DocumentIconProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } static get DocViews() { return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews; diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 19b43fd52..165057d21 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -2,20 +2,21 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { StopEvent, emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; -import { copyProps, emptyFunction, returnFalse, setupMoveUpEvents, StopEvent } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { Hypothesis } from '../../util/HypothesisUtils'; import { LinkManager } from '../../util/LinkManager'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { UndoManager, undoBatch } from '../../util/UndoManager'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import './DocumentLinksButton.scss'; import { DocumentView } from './DocumentView'; import { LinkDescriptionPopup } from './LinkDescriptionPopup'; import { TaskCompletionBox } from './TaskCompletedBox'; import { PinProps } from './trails'; -import * as React from 'react'; interface DocumentLinksButtonProps { View: DocumentView; @@ -44,26 +45,18 @@ export class DocButtonState { } } @observer -export class DocumentLinksButton extends React.Component { +export class DocumentLinksButton extends ObservableReactComponent { private _linkButton = React.createRef(); public static get StartLink() { return DocButtonState.Instance.StartLink; } // prettier-ignore public static set StartLink(value) { runInAction(() => (DocButtonState.Instance.StartLink = value)); } // prettier-ignore @observable public static StartLinkView: DocumentView | undefined = undefined; @observable public static AnnotationId: string | undefined = undefined; @observable public static AnnotationUri: string | undefined = undefined; - - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - @undoBatch onLinkButtonMoved = (e: PointerEvent) => { if (this._props.InMenu && this._props.StartLink) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 08ee708f7..343f770d5 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,9 +1,11 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Dropdown, DropdownType, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction, untracked } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; // import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal'; +import * as React from 'react'; +import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; @@ -15,12 +17,11 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; -import { copyProps, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick, Utils } from '../../../Utils'; -import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { DocServer } from '../../DocServer'; -import { DocOptions, Docs, DocUtils, FInfo } from '../../documents/Documents'; -import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; +import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; +import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; +import { DocOptions, DocUtils, Docs, FInfo } from '../../documents/Documents'; import { DictationManager } from '../../util/DictationManager'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; @@ -32,13 +33,14 @@ import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; +import { UndoManager, undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from '../DocComponent'; import { EditableView } from '../EditableView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { UndoStack } from '../UndoStack'; import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; @@ -46,12 +48,11 @@ import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView' import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; import { FieldViewProps } from './FieldView'; -import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; +import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import * as React from 'react'; const { Howl } = require('howler'); interface Window { @@ -253,20 +254,11 @@ export class DocumentViewInternal extends DocComponent(); private _titleRef = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; - - @override _props: DocumentViewInternalProps; - _prevProps: DocumentViewInternalProps; - - constructor(props: DocumentViewInternalProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - // untracked(() => (this._props = this._props)); - } - @observable _componentView: Opt; // needs to be accessed from DocumentView wrapper class @observable _animateScaleTime: Opt; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; @@ -1329,19 +1321,13 @@ export class DocumentViewInternal extends DocComponent { +export class DocumentView extends ObservableReactComponent { public static ROOT_DIV = 'documentView-effectsWrapper'; - @observable _props: DocumentViewProps; - _prevProps: DocumentViewProps; constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } @observable _selected = false; public get SELECTED() { diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 02ed56333..ff92c701f 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -1,5 +1,4 @@ -import EquationEditor from './formattedText/EquationEditor'; -import { action, makeObservable, override, reaction } from 'mobx'; +import { action, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Id } from '../../../fields/FieldSymbols'; @@ -11,7 +10,7 @@ import { ViewBoxBaseComponent } from '../DocComponent'; import { LightboxView } from '../LightboxView'; import './EquationBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; -import { copyProps } from '../../../Utils'; +import EquationEditor from './formattedText/EquationEditor'; @observer export class EquationBox extends ViewBoxBaseComponent() { @@ -21,18 +20,11 @@ export class EquationBox extends ViewBoxBaseComponent() { public static SelectOnLoad: string = ''; _ref: React.RefObject = React.createRef(); - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - componentDidMount() { this._props.setContentView?.(this); if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) { diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index d8b1f125c..5a8665aaf 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -1,13 +1,13 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, ColorPicker, Dropdown, DropdownType, EditableText, IconButton, IListItemProps, MultiToggle, NumberDropdown, NumberDropdownType, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; -import { computed, makeObservable, observable, override } from 'mobx'; +import { computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; @@ -45,16 +45,11 @@ export class FontIconBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FontIconBox, fieldKey); } - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } // // This controls whether fontIconButtons will display labels under their icons or not // @@ -64,6 +59,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { public static set ShowIconLabels(show: boolean) { Doc.UserDoc()._showLabel = show; } + @observable noTooltip = false; showTemplate = (): void => { const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null); diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index a04c27e01..29bffb583 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -1,15 +1,12 @@ import functionPlot from 'function-plot'; -import { action, computed, makeObservable, override, reaction } from 'mobx'; +import { computed, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { documentSchema } from '../../../fields/documentSchemas'; -import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; -import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; +import { listSpec } from '../../../fields/Schema'; import { Cast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { copyProps } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; @@ -27,19 +24,12 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent _plotId = ''; _plotEle: any; - _prevProps: React.PropsWithChildren; - @override _props: React.PropsWithChildren; constructor(props: React.PropsWithChildren) { super(props); - this._props = this._prevProps = props; makeObservable(this); this._plotId = 'graph' + FunctionPlotBox.GraphCount++; } - componentDidUpdate() { - copyProps(this); - } - componentDidMount() { this._props.setContentView?.(this); reaction( diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 091c1a32f..b1ccd38ba 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, override, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { extname } from 'path'; import * as React from 'react'; @@ -12,7 +12,7 @@ import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; +import { DashColor, emptyFunction, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; @@ -55,19 +55,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent(); @observable _curSuffix = ''; - _prevProps: ViewBoxAnnotatableProps & FieldViewProps; - @override _props: ViewBoxAnnotatableProps & FieldViewProps; constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { super(props); - this._props = this._prevProps = props; - makeObservable(this); this._props.setContentView?.(this); } - componentDidUpdate() { - copyProps(this); - } - protected createDropTarget = (ele: HTMLDivElement) => { this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.Document)); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 9aab53daf..73fdc3a23 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -1,26 +1,27 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { returnAlways, returnTrue } from '../../../Utils'; import { Doc, Field, FieldResult } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { RichTextField } from '../../../fields/RichTextField'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { DocCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; -import { copyProps, returnAll, returnAlways, returnTrue } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { SetupDrag } from '../../util/DragManager'; -import { CompiledScript, CompileScript, ScriptOptions } from '../../util/Scripting'; +import { CompileScript, CompiledScript, ScriptOptions } from '../../util/Scripting'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentIconContainer } from './DocumentIcon'; import { OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; -import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { ImageBox } from './ImageBox'; import './KeyValueBox.scss'; import { KeyValuePair } from './KeyValuePair'; -import * as React from 'react'; +import { FormattedTextBox } from './formattedText/FormattedTextBox'; export type KVPScript = { script: CompiledScript; @@ -28,28 +29,20 @@ export type KVPScript = { onDelegate: boolean; }; @observer -export class KeyValueBox extends React.Component { +export class KeyValueBox extends ObservableReactComponent { public static LayoutString() { return FieldView.LayoutString(KeyValueBox, 'data'); } + constructor(props: any) { + super(props); + makeObservable(this); + } private _mainCont = React.createRef(); private _keyHeader = React.createRef(); private _keyInput = React.createRef(); private _valInput = React.createRef(); - _prevProps: FieldViewProps; - @observable _props: FieldViewProps; - constructor(props: FieldViewProps) { - super(props); - this._props = this._prevProps = props; - makeObservable(this); - } - - componentDidUpdate() { - copyProps(this); - } - componentDidMount() { this._props.setContentView?.(this); } diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 40991f371..fd8d8ef56 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,21 +1,23 @@ -import { action, makeObservable, observable, toJS } from 'mobx'; +import { Tooltip } from '@mui/material'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import { ObservableGroupMap } from 'mobx-utils'; +import * as React from 'react'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils'; import { Doc, Field } from '../../../fields/Doc'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils'; +import { DocCast } from '../../../fields/Types'; +import { DocumentOptions, FInfo } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { OpenWhere, OpenWhereMod } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { OpenWhere } from './DocumentView'; +import { FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import * as React from 'react'; -import { DocCast } from '../../../fields/Types'; -import { Tooltip } from '@mui/material'; -import { DocumentOptions, FInfo } from '../../documents/Documents'; +import { ObservableReactComponent } from '../ObservableReactComponent'; // Represents one row in a key value plane @@ -29,22 +31,15 @@ export interface KeyValuePairProps { addDocTab: (doc: Doc, where: OpenWhere) => boolean; } @observer -export class KeyValuePair extends React.Component { +export class KeyValuePair extends ObservableReactComponent { @observable private isPointerOver = false; @observable public isChecked = false; private checkbox = React.createRef(); - - _prevProps: KeyValuePairProps; - @observable _props: KeyValuePairProps; - constructor(props: KeyValuePairProps) { + constructor(props:any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } @action handleCheck = (e: React.ChangeEvent) => { diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 52ca8b5b1..934bce448 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -1,11 +1,10 @@ -import { action, computed, makeObservable, observable, override } from 'mobx'; +import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; -import { Cast, StrCast, NumCast, BoolCast } from '../../../fields/Types'; -import { copyProps } from '../../../Utils'; +import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; @@ -31,16 +30,11 @@ export class LabelBox extends ViewBoxBaseComponent; - @override _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + componentDidMount() { this._props.setContentView?.(this); } diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index a7e905fca..b86ba72a0 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,9 +1,9 @@ -import { action, computed, makeObservable, observable, override } from 'mobx'; -import { observer } from 'mobx-react'; +import { action, computed, makeObservable } from 'mobx'; +import * as React from 'react'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; @@ -12,11 +12,7 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; -import * as React from 'react'; -const { - default: { MEDIUM_GRAY }, -} = require('../global/globalCssVariables.module.scss'); -@observer +const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore export class LinkAnchorBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); @@ -26,14 +22,9 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { _ref = React.createRef(); _isOpen = false; _timeout: NodeJS.Timeout | undefined; - @observable _x = 0; - @observable _y = 0; - _prevProps: FieldViewProps; - @override _props: FieldViewProps; - constructor(props: FieldViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index acafd6d09..134f2e14a 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; import { Bezier } from 'bezier-js'; -import { computed, IReactionDisposer, makeObservable, observable, override, reaction } from 'mobx'; +import { computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, StrCast } from '../../../fields/Types'; -import { aggregateBounds, copyProps, emptyFunction, returnAlways, returnFalse, Utils } from '../../../Utils'; +import { aggregateBounds, emptyFunction, returnAlways, returnFalse, Utils } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; import { Transform } from '../../util/Transform'; import { CollectionFreeFormView } from '../collections/collectionFreeForm'; @@ -20,18 +20,11 @@ export class LinkBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(LinkBox, fieldKey); } - _prevProps: FieldViewProps; - @override _props: FieldViewProps; - constructor(props: FieldViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - onClickScriptDisable = returnAlways; @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 108930ad9..fa7a55bc7 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -19,6 +19,7 @@ import { Transform } from '../../util/Transform'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import * as React from 'react'; +import { ObservableReactComponent } from '../ObservableReactComponent'; export class LinkInfo { private static _instance: Opt; @@ -49,15 +50,7 @@ interface LinkDocPreviewProps { noPreview?: boolean; } @observer -export class LinkDocPreview extends React.Component { - _prevProps: LinkDocPreviewProps; - @observable _props: LinkDocPreviewProps; - constructor(props: LinkDocPreviewProps) { - super(props); - this._props = this._prevProps = props; - makeObservable(this); - } - +export class LinkDocPreview extends ObservableReactComponent { _infoRef = React.createRef(); _linkDocRef = React.createRef(); @observable _targetDoc: Opt = undefined; @@ -66,6 +59,10 @@ export class LinkDocPreview extends React.Component { @observable _linkSrc: Opt = undefined; @observable _toolTipText = ''; @observable _hrefInd = 0; + constructor(props: any) { + super(props); + makeObservable(this); + } @action init() { @@ -84,9 +81,9 @@ export class LinkDocPreview extends React.Component { this._toolTipText = ''; this.updateHref(); } - componentDidUpdate(props: any) { - copyProps(this); - if (props.linkSrc !== this._props.linkSrc || props.linkDoc !== this._props.linkDoc || props.hrefs !== this._props.hrefs) this.init(); + componentDidUpdate(prevProps: Readonly) { + copyProps(this, prevProps); + if (prevProps.linkSrc !== this._props.linkSrc || prevProps.linkDoc !== this._props.linkDoc || prevProps.hrefs !== this._props.hrefs) this.init(); } componentDidMount() { this.init(); diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index ee1ea3ceb..b458e5a28 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,9 +1,9 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, Opt } from '../../../../fields/Doc'; +import * as React from 'react'; import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; import { SelectionManager } from '../../../util/SelectionManager'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; // import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; @@ -36,7 +36,6 @@ export class MapAnchorMenu extends AntimodeMenu { constructor(props: Readonly<{}>) { super(props); - MapAnchorMenu.Instance = this; MapAnchorMenu.Instance._canFade = false; } diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 98a302834..a420e0101 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,24 +1,24 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import BingMapsReact from 'bingmaps-react'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, override, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; -import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { Transform } from '../../../util/Transform'; -import { undoable, UndoManager } from '../../../util/UndoManager'; -import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { UndoManager, undoable } from '../../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; -import { Colors } from '../../global/globalEnums'; import { SidebarAnnos } from '../../SidebarAnnos'; +import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; @@ -67,18 +67,12 @@ export class MapBox extends ViewBoxAnnotatableComponent = React.createRef(); private _disposers: { [key: string]: IReactionDisposer } = {}; - _unmounting = false; - _prevProps: ViewBoxAnnotatableProps & FieldViewProps; - @override _props: ViewBoxAnnotatableProps & FieldViewProps; - constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + _unmounting = false; @observable private _savedAnnotations = new ObservableMap(); @computed get allSidebarDocs() { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index a453210eb..213f88177 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,8 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; @@ -10,7 +11,7 @@ import { ComputedField } from '../../../fields/ScriptField'; import { Cast, FieldValue, ImageCast, NumCast, StrCast } from '../../../fields/Types'; import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { copyProps, emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; @@ -31,7 +32,6 @@ import { FieldView, FieldViewProps } from './FieldView'; import { ImageBox } from './ImageBox'; import './PDFBox.scss'; import { PinProps, PresBox } from './trails'; -import * as React from 'react'; @observer export class PDFBox extends ViewBoxAnnotatableComponent() { @@ -58,11 +58,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent (this._pdf = pdf))); } } - componentDidUpdate() { - copyProps(this); - } replaceCanvases = (oldDiv: HTMLElement, newDiv: HTMLElement) => { if (oldDiv.childNodes) { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index a4f4897ba..ebe86318d 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, override, reaction, runInAction, untracked } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; import { observer } from 'mobx-react'; import { basename } from 'path'; +import * as React from 'react'; import { Doc, StrListCast } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; -import { copyProps, emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; @@ -68,19 +68,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 995f9f6e0..2f92f1edb 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as WebRequest from 'web-request'; @@ -13,7 +13,7 @@ import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast, StrCast, WebCast } from '../../../fields/Types'; import { ImageField, WebField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, copyProps, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; @@ -98,19 +98,12 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (!this._searching && !clear) { diff --git a/src/client/views/nodes/audio/AudioWaveform.tsx b/src/client/views/nodes/audio/AudioWaveform.tsx index 1b1a85800..01392c4a5 100644 --- a/src/client/views/nodes/audio/AudioWaveform.tsx +++ b/src/client/views/nodes/audio/AudioWaveform.tsx @@ -1,15 +1,16 @@ import axios from 'axios'; -import { computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { computed, IReactionDisposer, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, NumListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; -import { copyProps, numberRange } from '../../../../Utils'; +import { numberRange } from '../../../../Utils'; import { Colors } from './../../global/globalEnums'; import './AudioWaveform.scss'; import { WaveCanvas } from './WaveCanvas'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; /** * AudioWaveform @@ -35,21 +36,15 @@ export interface AudioWaveformProps { } @observer -export class AudioWaveform extends React.Component { +export class AudioWaveform extends ObservableReactComponent { public static NUMBER_OF_BUCKETS = 100; // number of buckets data is divided into to draw waveform lines _disposer: IReactionDisposer | undefined; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - get waveHeight() { return Math.max(50, this._props.PanelHeight); } diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index e2cceb906..555b752f0 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -2,22 +2,23 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { listSpec } from '../../../../fields/Schema'; import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; -import { Cast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; +import { Cast } from '../../../../fields/Types'; +import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { CollectionViewType } from '../../../documents/DocumentTypes'; +import { Transform } from '../../../util/Transform'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import { SchemaTableCell } from '../../collections/collectionSchema/SchemaTableCell'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; import { OpenWhere } from '../DocumentView'; import './DashFieldView.scss'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; -import { Transform } from '../../../util/Transform'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -92,7 +93,7 @@ interface IDashFieldViewInternal { } @observer -export class DashFieldViewInternal extends React.Component { +export class DashFieldViewInternal extends ObservableReactComponent { _reactionDisposer: IReactionDisposer | undefined; _textBoxDoc: Doc; _fieldKey: string; @@ -100,11 +101,8 @@ export class DashFieldViewInternal extends React.Component, prevState: Readonly<{}>, snapshot?: any): void { - copyProps(this); - } + componentWillUnmount() { this._reactionDisposer?.(); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 56bf15b09..997c3f86d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { isEqual } from 'lodash'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { baseKeymap, selectAll } from 'prosemirror-commands'; import { history } from 'prosemirror-history'; @@ -14,7 +14,7 @@ import { EditorView } from 'prosemirror-view'; import { BsMarkdownFill } from 'react-icons/bs'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; @@ -24,7 +24,7 @@ import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, copyProps, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT'; import { DocServer } from '../../../DocServer'; @@ -55,7 +55,7 @@ import { StyleProp } from '../../StyleProvider'; import { media_state } from '../AudioBox'; import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import { LinkDocPreview, LinkInfo } from '../LinkDocPreview'; +import { LinkInfo } from '../LinkDocPreview'; import { PinProps, PresBox } from '../trails'; import { DashDocCommentView } from './DashDocCommentView'; import { DashDocView } from './DashDocView'; @@ -208,20 +208,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent; - @override _props: React.PropsWithChildren; constructor(props: React.PropsWithChildren) { super(props); - this._props = this._prevProps = props; makeObservable(this); FormattedTextBox.Instance = this; this._recordingStart = Date.now(); } - componentDidUpdate() { - copyProps(this); - } - // removes all hyperlink anchors for the removed linkDoc // TODO: bcz: Argh... if a section of text has multiple anchors, this should just remove the intended one. // but since removing one anchor from the list of attr anchors isn't implemented, this will end up removing nothing. diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 7de1eb717..4881070fd 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -1,21 +1,22 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { lift, wrapIn } from 'prosemirror-commands'; import { Mark, MarkType, Node as ProsNode, ResolvedPos } from 'prosemirror-model'; import { wrapInList } from 'prosemirror-schema-list'; import { EditorState, NodeSelection, TextSelection } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { BoolCast, Cast, StrCast } from '../../../../fields/Types'; -import { copyProps, numberRange } from '../../../../Utils'; +import { numberRange } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { LinkManager } from '../../../util/LinkManager'; import { SelectionManager } from '../../../util/SelectionManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { ObservableReactComponent } from '../../ObservableReactComponent'; import { EquationBox } from '../EquationBox'; import { FieldViewProps } from '../FieldView'; import { FormattedTextBox } from './FormattedTextBox'; @@ -63,18 +64,13 @@ export class RichTextMenu extends AntimodeMenu { @observable private showLinkDropdown: boolean = false; _reaction: IReactionDisposer | undefined; - _prevProps: AntimodeMenuProps; - @override _props: AntimodeMenuProps; constructor(props: AntimodeMenuProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); - runInAction(() => { - RichTextMenu.Instance = this; - this.updateMenu(undefined, undefined, props, this.layoutDoc); - this._canFade = false; - this.Pinned = true; - }); + RichTextMenu.Instance = this; + this.updateMenu(undefined, undefined, props, this.layoutDoc); + this._canFade = false; + this.Pinned = true; } @computed get noAutoLink() { @@ -111,9 +107,6 @@ export class RichTextMenu extends AntimodeMenu { return BoolCast(this.layoutDoc?.layout_centered); } _disposer: IReactionDisposer | undefined; - componentDidUpdate() { - copyProps(this); - } componentDidMount() { this._disposer = reaction( () => SelectionManager.Views.slice(), @@ -368,7 +361,7 @@ export class RichTextMenu extends AntimodeMenu { } else if (SelectionManager.Views.some(dv => dv.ComponentView instanceof EquationBox)) { SelectionManager.Views.forEach(dv => (dv.Document._text_fontSize = fontSize)); } else Doc.UserDoc().fontSize = fontSize; - this.updateMenu(this.view, undefined, this._props, this.layoutDoc); + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); }; setFontFamily = (family: string) => { @@ -377,7 +370,7 @@ export class RichTextMenu extends AntimodeMenu { this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true); this.view.focus(); } else Doc.UserDoc().fontFamily = family; - this.updateMenu(this.view, undefined, this._props, this.layoutDoc); + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); }; setHighlight(color: string) { @@ -386,7 +379,7 @@ export class RichTextMenu extends AntimodeMenu { this.setMark(highlightMark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(highlightMark)), true); this.view.focus(); } else Doc.UserDoc()._fontHighlight = color; - this.updateMenu(this.view, undefined, this._props, this.layoutDoc); + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); } setColor(color: string) { @@ -395,7 +388,7 @@ export class RichTextMenu extends AntimodeMenu { this.setMark(colorMark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(colorMark)), true); this.view.focus(); } else Doc.UserDoc().fontColor = color; - this.updateMenu(this.view, undefined, this._props, this.layoutDoc); + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); } // TODO: remove doesn't work @@ -436,7 +429,7 @@ export class RichTextMenu extends AntimodeMenu { } } this.view.focus(); - this.updateMenu(this.view, undefined, this._props, this.layoutDoc); + this.updateMenu(this.view, undefined, this.props, this.layoutDoc); }; insertSummarizer(state: EditorState, dispatch: any) { @@ -818,22 +811,15 @@ interface ButtonDropdownProps { } @observer -export class ButtonDropdown extends React.Component { +export class ButtonDropdown extends ObservableReactComponent { @observable private showDropdown: boolean = false; private ref: HTMLDivElement | null = null; - _prevProps: React.PropsWithChildren; - @observable _props: React.PropsWithChildren; - constructor(props: React.PropsWithChildren) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } - componentDidMount() { document.addEventListener('pointerdown', this.onBlur); } diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 9fcb496b8..ec5d090dd 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -1,12 +1,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { action, computed, IReactionDisposer, makeObservable, observable, override, reaction, runInAction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { copyProps, emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; @@ -24,7 +25,6 @@ import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; -import * as React from 'react'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -41,19 +41,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { readonly expandViewHeight = 100; readonly collapsedHeight = 35; - @observable _dragging = false; - - _prevProps: FieldViewProps; - @override _props: FieldViewProps; - constructor(props: FieldViewProps) { + constructor(props: any) { super(props); - this._props = this._prevProps = props; makeObservable(this); } - componentDidUpdate() { - copyProps(this); - } + @observable _dragging = false; // the presentation view that renders this slide @computed get presBoxView() { diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 0627876fa..a8c83ded6 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, Group, IconButton, Popup, Size, Toggle, ToggleType, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, override, reaction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { ColorResult } from 'react-color'; +import { Utils, returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; -import { copyProps, returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from '../../../Utils'; -import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; +import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT'; import { DocumentType } from '../../documents/DocumentTypes'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; @@ -23,18 +23,12 @@ export class AnchorMenu extends AntimodeMenu { private _commentRef = React.createRef(); private _cropRef = React.createRef(); - _prevProps: AntimodeMenuProps; - @override _props: AntimodeMenuProps; constructor(props: AntimodeMenuProps) { super(props); - this._props = this._prevProps = props; makeObservable(this); AnchorMenu.Instance = this; AnchorMenu.Instance._canFade = false; } - componentDidUpdate() { - copyProps(this); - } @observable private highlightColor: string = 'rgba(245, 230, 95, 0.616)'; diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index a581e9df6..e342c25b3 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,13 +1,16 @@ import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as Pdfjs from 'pdfjs-dist'; import 'pdfjs-dist/web/pdf_viewer.css'; +import * as PDFJSViewer from 'pdfjs-dist/web/pdf_viewer.mjs'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Height } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, copyProps, emptyFunction, returnAll, returnFalse, returnNone, returnZero, smoothScroll, Utils } from '../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnAll, returnFalse, returnNone, returnZero, smoothScroll, Utils } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -16,15 +19,13 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; -import { LinkDocPreview, LinkInfo } from '../nodes/LinkDocPreview'; +import { LinkInfo } from '../nodes/LinkDocPreview'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import * as React from 'react'; -import * as Pdfjs from 'pdfjs-dist'; -import * as PDFJSViewer from 'pdfjs-dist/web/pdf_viewer.mjs'; const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; @@ -49,14 +50,11 @@ interface IViewerProps extends FieldViewProps { * Handles rendering and virtualization of the pdf */ @observer -export class PDFViewer extends React.Component { +export class PDFViewer extends ObservableReactComponent { static _annotationStyle: any = addStyleSheet(); - _prevProps: IViewerProps; - @observable _props: IViewerProps; - constructor(props: IViewerProps) { + constructor(props: any) { super(props); - this._prevProps = this._props = props; makeObservable(this); } @@ -66,10 +64,6 @@ export class PDFViewer extends React.Component { @observable _showWaiting = true; @observable Index: number = -1; - componentDidUpdate() { - copyProps(this); - } - private _pdfViewer: any; private _styleRule: any; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer -- cgit v1.2.3-70-g09d2 From 2ea594a4c1ff221200e0795fb07d30b603177a67 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 3 Jan 2024 23:44:28 -0500 Subject: cleaned up screenToLocalTransform in several places by making it additional methods. cleaned up styleProider api a bit to take DocumentViewInternalProps, not DocumentViewProps.. --- src/client/util/HypothesisUtils.ts | 2 +- src/client/views/DocComponent.tsx | 10 ++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 16 +-- src/client/views/GestureOverlay.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/InkingStroke.tsx | 23 ++--- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/StyleProvider.tsx | 13 +-- .../views/collections/CollectionCarouselView.tsx | 5 +- .../views/collections/CollectionNoteTakingView.tsx | 18 ++-- .../collections/CollectionStackedTimeline.tsx | 11 ++- .../views/collections/CollectionStackingView.tsx | 12 +-- .../views/collections/CollectionTimeView.tsx | 1 - .../views/collections/CollectionTreeView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 7 +- src/client/views/collections/TreeView.tsx | 18 ++-- .../CollectionFreeFormLinkView.tsx | 10 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 94 +++++++++--------- .../collectionGrid/CollectionGridView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.tsx | 21 ++-- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +- src/client/views/nodes/ComparisonBox.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 48 +++++---- src/client/views/nodes/ImageBox.tsx | 6 +- src/client/views/nodes/LinkBox.tsx | 10 +- src/client/views/nodes/MapBox/MapBox.tsx | 8 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 12 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 109 +-------------------- .../views/nodes/importBox/ImportElementBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 4 +- src/client/views/nodes/trails/PresElementBox.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 15 +-- 44 files changed, 230 insertions(+), 315 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 0ae23d793..f46c2d431 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -180,7 +180,7 @@ export namespace Hypothesis { }) ); const targetView: Opt = DocumentManager.Instance.getFirstDocumentView(target); - const position = targetView?.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const position = targetView?.screenToViewTransform().inverse().transformPoint(0, 0); targetView && position && simulateMouseClick(targetView.ContentDiv!, position[0], position[1], position[0], position[1], false); }, 300); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b5bd17572..dfc298840 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -12,12 +12,14 @@ import { DocumentManager } from '../util/DocumentManager'; import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { DocumentView } from './nodes/DocumentView'; +import { Transform } from '../util/Transform'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { Document: Doc; LayoutTemplate?: () => Opt; LayoutTemplateString?: string; + ScreenToLocalTransform: () => Transform; } export function DocComponent

() { class Component extends ObservableReactComponent> { @@ -26,6 +28,8 @@ export function DocComponent

() { makeObservable(this); } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -50,10 +54,13 @@ interface ViewBoxBaseProps { fieldKey: string; isSelected: () => boolean; isContentActive: () => boolean | undefined; + ScreenToLocalTransform: () => Transform; renderDepth: number; } export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -83,6 +90,7 @@ export interface ViewBoxAnnotatableProps { isContentActive: () => boolean | undefined; select: (isCtrlPressed: boolean) => void; whenChildContentsActiveChanged: (isActive: boolean) => void; + ScreenToLocalTransform: () => Transform; isSelected: () => boolean; renderDepth: number; isAnnotationOverlay?: boolean; @@ -94,6 +102,8 @@ export function ViewBoxAnnotatableComponent

() makeObservable(this); } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + @observable _annotationKeySuffix = () => 'annotations'; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index e6d53e727..bb28d9ec9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -305,7 +305,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( if (this._dragRef.current) { const dragDocView = this.view0!; const dragData = new DragManager.DocumentDragData([dragDocView.Document]); - const [left, top] = dragDocView.screenToNativeLocalTransform().inverse().transformPoint(0, 0); + const [left, top] = dragDocView.screenToContentsTransform().inverse().transformPoint(0, 0); dragData.defaultDropAction = 'embed'; dragData.canEmbed = true; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 583a7c447..ced8799bf 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -77,7 +77,7 @@ export class DocumentDecorations extends ObservableReactComponent center.x+x || this.Bounds.r < center.x+x || this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); @@ -208,7 +208,7 @@ export class DocumentDecorations extends ObservableReactComponent dv.Document), dragDocView._props.dropAction ); - dragData.offset = dragDocView.screenToNativeLocalTransform().transformDirection(e.x - left, e.y - top); + dragData.offset = dragDocView.screenToContentsTransform().transformDirection(e.x - left, e.y - top); dragData.moveDocument = dragDocView._props.moveDocument; dragData.removeDocument = dragDocView._props.removeDocument; dragData.isDocDecorationMove = true; @@ -353,7 +353,7 @@ export class DocumentDecorations extends ObservableReactComponent { - const newloccentern = seldocview.screenToNativeLocalTransform().transformPoint(rotCenter[0], rotCenter[1]); + const newloccentern = seldocview.screenToContentsTransform().transformPoint(rotCenter[0], rotCenter[1]); const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2]; const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI); seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); @@ -385,7 +385,7 @@ export class DocumentDecorations extends ObservableReactComponent { const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI; - const localRotCtr = dv._props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y); + const localRotCtr = dv.screenToViewTransform().transformPoint(rcScreen.X, rcScreen.Y); const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2]; const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot); const unrotatedDocPos = { x: NumCast(dv.Document.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.Document.y) + localRotCtrOffset[1] - startRotCtr.y }; @@ -462,7 +462,7 @@ export class DocumentDecorations extends ObservableReactComponent { @@ -530,7 +530,7 @@ export class DocumentDecorations extends ObservableReactComponent 135 && seldocview.CollectionFreeFormDocumentView; const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? - const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToNativeLocalTransform().inverse().RotateDeg : 0; + const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 65aadc148..b1b04237c 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -385,7 +385,7 @@ export class GestureOverlay extends ObservableReactComponent dv.Document[Id]).join(':'); SelectionManager.Views.length && navigator.clipboard.writeText(text); DocumentDecorations.Instance.onCloseClick(true); @@ -312,7 +312,7 @@ export class KeyManager { case 'c': if ((document.activeElement as any)?.type !== 'text' && !AnchorMenu.Instance.Active && DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) { const bds = DocumentDecorations.Instance.Bounds; - const pt = SelectionManager.Views[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); + const pt = SelectionManager.Views[0].screenToViewTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); const text = `__DashCloneId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.Views.map(dv => dv.Document[Id]).join(':'); SelectionManager.Views.length && navigator.clipboard.writeText(text); stopPropagation = false; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 95c677845..c652e8966 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -45,6 +45,7 @@ import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; +import { Transform } from '../util/Transform'; const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer export class InkingStroke extends ViewBoxBaseComponent() { @@ -73,10 +74,6 @@ export class InkingStroke extends ViewBoxBaseComponent() { Object.keys(this._disposers).forEach(key => this._disposers[key]()); } - // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke - // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); - getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const subAnchor = this._subContentView?.getAnchor?.(addAsAnnotation); if (subAnchor !== this.Document && subAnchor) return subAnchor; @@ -129,7 +126,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -181,7 +178,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { */ ptFromScreen = (scrPt: { X: number; Y: number }) => { const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y); + const docPt = this.ScreenToLocalBoxXf().transformPoint(scrPt.X, scrPt.Y); const inkPt = { X: (docPt[0] - inkStrokeWidth / 2) / inkScaleX + inkStrokeWidth / 2 + inkLeft, Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop, @@ -199,7 +196,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2, }; - const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y); + const scrPt = this.ScreenToLocalBoxXf().inverse().transformPoint(docPt.X, docPt.Y); return { X: scrPt[0], Y: scrPt[1] }; }; @@ -213,7 +210,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { snapPt = (scrPt: { X: number; Y: number }, excludeSegs?: number[]) => { const { inkData } = this.inkScaledData(); const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []); - return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale }; + return { nearestPt, distance: distance * this.ScreenToLocalBoxXf().inverse().Scale }; }; /** @@ -250,7 +247,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -275,7 +272,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); return inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -291,9 +288,9 @@ export class InkingStroke extends ViewBoxBaseComponent() { componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); - const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke + const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.ScreenToLocalBoxXf().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke - const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); + const screenInkWidth = this.ScreenToLocalBoxXf().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); const startMarker = StrCast(this.layoutDoc.stroke_startMarker); const endMarker = StrCast(this.layoutDoc.stroke_endMarker); @@ -329,7 +326,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { false )} - +

); }; diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 9f3786d8e..ed09d3bf3 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -158,7 +158,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { const marqueeContainer = this.props.marqueeContainer; - const containerXf = this.props.isNativeScaled ? this.props.docView().screenToNativeLocalTransform() : this.props.docView().props.ScreenToLocalTransform(); + const containerXf = this.props.isNativeScaled ? this.props.docView().screenToContentsTransform() : this.props.docView().screenToViewTransform(); const boundingRect = marqueeContainer.getBoundingClientRect(); const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 }; const downVec = Utils.rotPt(down[0] - center.x, diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 835e61d55..ce69dcc41 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -20,7 +20,7 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { DocumentViewProps } from './nodes/DocumentView'; +import { DocumentViewInternalProps, DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PropertiesView } from './PropertiesView'; @@ -37,7 +37,6 @@ export enum StyleProp { BackgroundColor = 'backgroundColor', // background color of a document view FillColor = 'fillColor', // fill color of an ink stroke or shape WidgetColor = 'widgetColor', // color to display UI widgets on a document view -- used for the sidebar divider dragger on a text note - HideLinkBtn = 'hideLinkButton', // hides the blue-dot link button. used when a document acts like a button PointerEvents = 'pointerEvents', // pointer events for DocumentView -- inherits pointer events if not specified Decorations = 'decorations', // additional decoration to display above a DocumentView -- currently only used to display a Lock for making things background HeaderMargin = 'headerMargin', // margin at top of documentview, typically for displaying a title -- doc contents will start below that @@ -81,11 +80,10 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // -export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; const docProps = testDocProps(props) ? props : undefined; const fieldProps = testFieldProps(props) ? props : undefined; - const selected = property.includes(':selected'); const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isContent = property.includes(':content'); @@ -138,14 +136,13 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView._props, StyleProp.BackgroundColor); + const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView.docView?._props, StyleProp.BackgroundColor); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : '')); @@ -373,7 +370,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, /** * add hide button decorations for the "Dashboards" flyout TreeView */ -export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { +export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { if (doc && property.split(':')[0] === StyleProp.Decorations) { return doc._type_collection === CollectionViewType.Docking || Doc.IsSystem(doc) ? null diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index b6acf3153..fb57a668e 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -7,10 +7,11 @@ import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; import { CollectionSubView } from './CollectionSubView'; +import { FieldViewProps } from '../nodes/FieldView'; @observer export class CollectionCarouselView extends CollectionSubView() { @@ -40,7 +41,7 @@ export class CollectionCarouselView extends CollectionSubView() { e.stopPropagation(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; }; - captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption-' + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this.props.styleProvider?.(this.layoutDoc, captionProps, property); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 0744814dd..527b72213 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -18,7 +18,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -195,7 +195,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const top = found.getBoundingClientRect().top; - const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); + const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0 && Math.ceil(this.props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) { let focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); @@ -204,7 +204,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } }; - styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { switch (property) { case StyleProp.BoxShadow: if (doc && DragManager.docsBeingDragged.includes(doc)) { @@ -282,7 +282,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const y = this._scroll; // required for document decorations to update when the text box container is scrolled const { translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined); // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off - return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale); + return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.ScreenToLocalBoxXf().Scale); } // how to get the width of a document. Currently returns the width of the column (minus margins) @@ -341,10 +341,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { onPointerMove = (force: boolean, ex: number, ey: number) => { if (this.childDocList?.includes(DragManager.DocDragData?.draggedDocuments?.lastElement() as any) || force || SnappingManager.CanEmbed) { // get the current docs for the column based on the mouse's x coordinate - const xCoord = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[0] - 2 * this.gridGap; + const xCoord = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[0] - 2 * this.gridGap; const colDocs = this.getDocsFromXCoord(xCoord); // get the index for where you need to insert the doc you are currently dragging - const clientY = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[1]; + const clientY = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[1]; let dropInd = -1; let pos0 = (this.refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2; colDocs.forEach((doc, i) => { @@ -437,7 +437,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (rowCol[0] <= 0) { docs.splice(0, 0, ...newDocs); } else { - const colDocs = this.getDocsFromXCoord(this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]); + const colDocs = this.getDocsFromXCoord(this.ScreenToLocalBoxXf().transformPoint(de.x, de.y)[0]); const previousDoc = colDocs[rowCol[0] - 1]; const previousDocIndex = docs.indexOf(previousDoc); docs.splice(previousDocIndex + 1, 0, ...newDocs); @@ -546,7 +546,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { yMargin={this.yMargin} type={type} createDropTarget={this.createDashEventsTarget} - screenToLocalTransform={this.props.ScreenToLocalTransform} + screenToLocalTransform={this.ScreenToLocalBoxXf} editableViewProps={this.editableViewProps} /> ); @@ -586,7 +586,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // setColumnStartXCoords is used to update column widths when using the drag handlers between columns @action setColumnStartXCoords = (movementXScreen: number, colIndex: number) => { - const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0]; + const movementX = this.ScreenToLocalBoxXf().transformDirection(movementXScreen, 0)[0]; const leftHeader = this.colHeaderData[colIndex]; const rightHeader = this.colHeaderData[colIndex + 1]; leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth); diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index a63688354..d99b4f9de 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -23,11 +23,12 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; +import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; +import { FieldViewProps } from '../nodes/FieldView'; export type CollectionStackedTimelineProps = { Play: () => void; @@ -367,7 +368,7 @@ export class CollectionStackedTimeline extends CollectionSubView { @@ -502,7 +503,7 @@ export class CollectionStackedTimeline extends CollectionSubView this._props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight); + dictationScreenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this.timelineContentHeight); isContentActive = () => this._props.isSelected() || this._props.isContentActive(); @@ -672,7 +673,7 @@ interface StackedTimelineAnchorProps { width: number; height: number; toTimeline: (screen_delta: number, width: number) => number; - styleProvider?: (doc: Opt, props: Opt, property: string) => any; + styleProvider?: StyleProviderFunc; playLink: (linkDoc: Doc, options: DocFocusOptions) => void; setTime: (time: number) => void; startTag: string; @@ -695,7 +696,7 @@ class StackedTimelineAnchor extends ObservableReactComponent node.id === doc[Id]); if (found) { const top = found.getBoundingClientRect().top; - const localTop = this._props.ScreenToLocalTransform().transformPoint(0, top); + const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0) { let focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); @@ -265,7 +265,7 @@ export class CollectionStackingView extends CollectionSubView, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === StyleProp.Opacity && doc) { if (this._props.childOpacity) { return this._props.childOpacity(); @@ -370,7 +370,7 @@ export class CollectionStackingView extends CollectionSubView ); }; @@ -611,7 +611,7 @@ export class CollectionStackingView extends CollectionSubView ); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 7bbdb7073..7036ec41c 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -211,7 +211,6 @@ export class CollectionTimeView extends CollectionSubView() { Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' })); docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' }); ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' }); - const pt = this._props.ScreenToLocalTransform().inverse().transformPoint(x, y); ContextMenu.Instance.displayMenu(x, y, ':'); }; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7f8d42088..18e0b98ef 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -154,7 +154,7 @@ export class CollectionTreeView extends CollectionSubView this._props.ScreenToLocalTransform().translate(0, -this._headerHeight); + screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight); @action remove = (doc: Doc | Doc[]): boolean => { @@ -312,7 +312,7 @@ export class CollectionTreeView extends CollectionSubView (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this._props.ScreenToLocalTransform().Scale))} + ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale))} key={this.Document[Id]} style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c2f5ab2c0..4a239e4b1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -112,7 +112,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this._props.renderDepth ? this._props.ScreenToLocalTransform() : this._props.ScreenToLocalTransform().scale(this._props.PanelWidth() / this.bodyPanelWidth())); + screenToLocalTransform = () => (this._props.renderDepth ? this.ScreenToLocalBoxXf() : this.ScreenToLocalBoxXf().scale(this._props.PanelWidth() / this.bodyPanelWidth())); // prettier-ignore private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => { TraceMobx(); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index ac0ce7a2a..80808be92 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,7 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -37,6 +37,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { FieldViewProps } from '../nodes/FieldView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -426,7 +427,7 @@ export class TabDocView extends ObservableReactComponent { ScreenToLocalTransform = () => { this._forceInvalidateScreenToLocal; const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement); - return CollectionDockingView.Instance?._props.ScreenToLocalTransform().translate(-translateX, -translateY) ?? Transform.Identity(); + return CollectionDockingView.Instance?.ScreenToLocalBoxXf().translate(-translateX, -translateY) ?? Transform.Identity(); }; PanelWidth = () => this._panelWidth; PanelHeight = () => this._panelHeight; @@ -527,7 +528,7 @@ class TabMiniThumb extends React.Component { } @observer export class TabMinimapView extends ObservableReactComponent { - static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { + static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { switch (property.split(':')[0]) { default: diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index f2ceaa681..01b80e209 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -27,7 +27,7 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; @@ -172,6 +172,8 @@ export class TreeView extends ObservableReactComponent { return this._docRef?.IsSelected; } + ScreenToLocalTransform = () => this._props.ScreenToLocalTransform(); + childDocList(field: string) { const layout = Cast(Doc.LayoutField(this.Document), Doc, null); return DocListCast(this._props.dataDoc?.[field], DocListCast(layout?.[field], DocListCast(this.Document[field]))); @@ -447,11 +449,11 @@ export class TreeView extends ObservableReactComponent { } refTransform = (ref: HTMLDivElement | undefined | null) => { - if (!ref) return this._props.ScreenToLocalTransform(); + if (!ref) return this.ScreenToLocalTransform(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ref); const outerXf = Utils.GetScreenTransform(this.treeView.MainEle()); - const offset = this._props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - return this._props.ScreenToLocalTransform().translate(offset[0], offset[1]); + const offset = this.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.ScreenToLocalTransform().translate(offset[0], offset[1]); }; docTransform = () => this.refTransform(this._dref?.ContentRef?.current); getTransform = () => this.refTransform(this._tref.current); @@ -511,7 +513,7 @@ export class TreeView extends ObservableReactComponent { this._props.dragAction, this._props.addDocTab, this.titleStyleProvider, - this._props.ScreenToLocalTransform, + this.ScreenToLocalTransform, this._props.isContentActive, expandedWidth, this._props.renderDepth, @@ -671,7 +673,7 @@ export class TreeView extends ObservableReactComponent { StrCast(this.Document.childDragAction, this._props.dragAction) as dropActionType, this._props.addDocTab, this.titleStyleProvider, - this._props.ScreenToLocalTransform, + this.ScreenToLocalTransform, this._props.isContentActive, this._props.panelWidth, this._props.renderDepth, @@ -865,7 +867,7 @@ export class TreeView extends ObservableReactComponent { e.preventDefault(); } }; - titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView const treeView = this.treeView; @@ -897,7 +899,7 @@ export class TreeView extends ObservableReactComponent { } return treeView._props.styleProvider?.(doc, props, property); }; - embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 6131fe037..5204633ea 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -22,8 +22,6 @@ export interface CollectionFreeFormLinkViewProps { LinkDocs: Doc[]; } -// props.screentolocatransform - @observer export class CollectionFreeFormLinkView extends ObservableReactComponent { @observable _opacity: number = 0; @@ -42,10 +40,10 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent [ - this._props.A._props.ScreenToLocalTransform(), + this._props.A.screenToViewTransform(), Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss], - this._props.B._props.ScreenToLocalTransform(), + this._props.B.screenToViewTransform(), Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss], ], @@ -91,7 +89,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent= 0 && mpx <= 1) linkDoc.link_anchor_1_x = mpx * 100; @@ -106,7 +104,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent= 0 && mpx <= 1) linkDoc.link_anchor_2_x = mpx * 100; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 44654c8fe..0128647a4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,7 +38,7 @@ import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } fr import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../../nodes/trails/PresBox'; @@ -172,10 +172,9 @@ export class CollectionFreeFormView extends CollectionSubView this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); PanZoomCenterXf = () => this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; - ScreenToLocalXf = () => this.screenToLocalXf.copy(); + ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy(); getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); isAnyChildContentActive = () => this._props.isAnyChildContentActive(); addLiveTextBox = (newDoc: Doc) => { @@ -329,13 +328,13 @@ export class CollectionFreeFormView extends CollectionSubView res(dv)); }); - internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) { + internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) { if (!super.onInternalDrop(e, de)) return false; const refDoc = docDragData.droppedDocuments[0]; - const [xpo, ypo] = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y); - const z = NumCast(refDoc.z); - const x = (z ? xpo : xp) - docDragData.offset[0]; - const y = (z ? ypo : yp) - docDragData.offset[1]; + const fromScreenXf = NumCast(refDoc.z) ? this.ScreenToLocalBoxXf() : this.screenToFreeformContentsXf; + const [xpo, ypo] = fromScreenXf.transformPoint(de.x, de.y); + const x = xpo - docDragData.offset[0]; + const y = ypo - docDragData.offset[1]; const zsorted = this.childLayoutPairs .map(pair => pair.layout) .slice() @@ -347,7 +346,7 @@ export class CollectionFreeFormView extends CollectionSubView { const dropDoc = dropCreator(annotationOn); if (dropDoc) { @@ -408,20 +408,21 @@ export class CollectionFreeFormView extends CollectionSubView { - const [xp, yp] = this.screenToLocalXf.transformPoint(de.x, de.y); - if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData, xp, yp); - else if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); - else if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, xp, yp); + if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de, de.complete.annoDragData); + else if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData); + else if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData); return false; }; - onExternalDrop = (e: React.DragEvent) => (([x, y]) => super.onExternalDrop(e, { x, y }))(this.screenToLocalXf.transformPoint(e.pageX, e.pageY)); + onExternalDrop = (e: React.DragEvent) => (([x, y]) => super.onExternalDrop(e, { x, y }))(this.screenToFreeformContentsXf.transformPoint(e.pageX, e.pageY)); static overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { const doc2Layout = Doc.Layout(doc2); @@ -489,7 +489,7 @@ export class CollectionFreeFormView extends CollectionSubView v.ContentDiv!), de, @@ -586,7 +586,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { + clusterStyleProvider = (doc: Opt, props: Opt, property: string) => { let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (doc && this.childDocList?.includes(doc)) switch (property) { @@ -643,7 +643,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? 1 / 1.05 : 1.05; if (deltaScale < 0) deltaScale = -deltaScale; - const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY); + const [x, y] = this.screenToFreeformContentsXf.transformPoint(pointX, pointY); const invTransform = this.panZoomXf.inverse(); if (deltaScale * invTransform.Scale > 20) { deltaScale = 20 / invTransform.Scale; @@ -982,7 +982,7 @@ export class CollectionFreeFormView extends CollectionSubView { - const pt = this.screenToLocalXf.transformPoint(NumCast(doc.x), NumCast(doc.y)); + const pt = this.screenToFreeformContentsXf.transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; doc.y = pt[1]; return doc; @@ -1437,7 +1437,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._hideInfo = true); - infoUI = () => (this._hideInfo || this.Document.annotationOn ? null : ); + infoUI = () => (this._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : ); componentDidMount() { this._props.setContentView?.(this); @@ -1601,7 +1601,7 @@ export class CollectionFreeFormView extends CollectionSubView { const childDocs = this.childDocs.slice(); childDocs.forEach(doc => { - const scr = this.screenToLocalXf.inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); + const scr = this.screenToFreeformContentsXf.inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = scr?.[0]; doc.y = scr?.[1]; }); @@ -1713,7 +1713,7 @@ export class CollectionFreeFormView extends CollectionSubView ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); const isDocInView = (doc: Doc, rect: { left: number; top: number; width: number; height: number }) => intersectRect(docDims(doc), rect); @@ -1725,7 +1725,7 @@ export class CollectionFreeFormView extends CollectionSubView !doc.isGroup && (snapToDraggedDoc || (SnappingManager.IsResizing !== doc && !DragManager.docsBeingDragged.includes(doc)))) .forEach(doc => { @@ -1822,8 +1822,8 @@ export class CollectionFreeFormView extends CollectionSubView @@ -1859,7 +1859,7 @@ export class CollectionFreeFormView extends CollectionSubView Math.max(0, this._props.PanelWidth() - 30); lightboxPanelHeight = () => Math.max(0, this._props.PanelHeight() - 30); - lightboxScreenToLocal = () => this._props.ScreenToLocalTransform().translate(-15, -15); + lightboxScreenToLocal = () => this.ScreenToLocalBoxXf().translate(-15, -15); onPassiveWheel = (e: WheelEvent) => { const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling; @@ -1950,7 +1950,7 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY } while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview - ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); + ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); Doc.linkFollowHighlight(dv?.props.Document, false); } }); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 0f750c4f8..d078e1d4f 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -130,7 +130,7 @@ export class CollectionGridView extends CollectionSubView() { * Maps the x- and y- coordinates of the event to a grid cell. */ screenToCell(sx: number, sy: number) { - const pt = this._props.ScreenToLocalTransform().transformPoint(sx, sy); + const pt = this.ScreenToLocalBoxXf().transformPoint(sx, sy); const x = Math.floor(pt[0] / this.colWidthPlusGap); const y = Math.floor((pt[1] + this._scroll) / this.rowHeight); return { x, y }; @@ -159,7 +159,7 @@ export class CollectionGridView extends CollectionSubView() { const xypos = this.flexGrid ? layout : this.unflexedPosition(this.renderedLayoutList.findIndex(l => l.i === layout.i)); const pos = { x: xypos.x * this.colWidthPlusGap + this.margin, y: xypos.y * this.rowHeightPlusGap + this.margin - this._scroll }; - return this._props.ScreenToLocalTransform().translate(-pos.x, -pos.y); + return this.ScreenToLocalBoxXf().translate(-pos.x, -pos.y); }; /** @@ -390,7 +390,7 @@ export class CollectionGridView extends CollectionSubView() { numCols={this.numCols} rowHeight={this.rowHeight} setLayout={this.setLayout} - transformScale={this._props.ScreenToLocalTransform().Scale} + transformScale={this.ScreenToLocalBoxXf().Scale} compactType={this.compaction} // determines whether nodes should remain in position, be bound to the top, or to the left preventCollision={BoolCast(this.Document.gridPreventCollision)} // determines whether nodes should move out of the way (i.e. collide) when other nodes are dragged over them margin={this.margin} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 5bea59e7b..563084af8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -189,7 +189,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this._props.ScreenToLocalTransform().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); + return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); } offset += this.lookupPixels(candidate) + resizerWidth; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 3043eb0f8..bf0d39197 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -184,7 +184,7 @@ export class CollectionMultirowView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this._props.ScreenToLocalTransform().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); + return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); } offset += this.lookupPixels(candidate) + resizerHeight; } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 2546f5b02..492aed0ea 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,7 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -24,6 +24,7 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; +import { FieldViewProps } from '../../nodes/FieldView'; export enum ColumnType { Number, @@ -321,8 +322,8 @@ export class CollectionSchemaView extends CollectionSubView() { change = this._displayColumnWidths[shrinking] - CollectionSchemaView._minColWidth; } - this._displayColumnWidths[shrinking] -= change * this._props.ScreenToLocalTransform().Scale; - this._displayColumnWidths[growing] += change * this._props.ScreenToLocalTransform().Scale; + this._displayColumnWidths[shrinking] -= change * this.ScreenToLocalBoxXf().Scale; + this._displayColumnWidths[growing] += change * this.ScreenToLocalBoxXf().Scale; return false; } @@ -379,7 +380,7 @@ export class CollectionSchemaView extends CollectionSubView() { @action highlightDropColumn = (e: PointerEvent) => { e.stopPropagation(); - const mouseX = this._props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; + const mouseX = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY)[0]; const index = this.findDropIndex(mouseX); this._colEles.forEach((colRef, i) => { let leftStyle = ''; @@ -439,7 +440,7 @@ export class CollectionSchemaView extends CollectionSubView() { onInternalDrop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.columnDragData) { - const mouseX = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]; + const mouseX = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y)[0]; const index = this.findDropIndex(mouseX); this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex); @@ -483,7 +484,7 @@ export class CollectionSchemaView extends CollectionSubView() { const nativeWidth = this._previewRef!.getBoundingClientRect(); const minWidth = 40; const maxWidth = 1000; - const movedWidth = this._props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; + const movedWidth = this.ScreenToLocalBoxXf().transformDirection(nativeWidth.right - e.clientX, 0)[0]; const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth; this.layoutDoc.schema_previewWidth = width; return false; @@ -507,7 +508,7 @@ export class CollectionSchemaView extends CollectionSubView() { const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); - const localRect = this._props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height); + const localRect = this.ScreenToLocalBoxXf().transformBounds(rect.left, rect.top, rect.width, rect.height); if (localRect.y < this.rowHeightFunc() || localRect.y + localRect.height > this._props.PanelHeight()) { let focusSpeed = options.zoomTime ?? 50; smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - this.rowHeightFunc(), options.easeFunc); @@ -829,7 +830,7 @@ export class CollectionSchemaView extends CollectionSubView() { rowHeightFunc = () => (BoolCast(this.layoutDoc._schema_singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight); sortedDocsFunc = () => this.sortedDocs; isContentActive = () => this._props.isSelected() || this._props.isContentActive(); - screenToLocal = () => this._props.ScreenToLocalTransform().translate(-this.tableWidth, 0); + screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; render() { return ( @@ -960,8 +961,8 @@ class CollectionSchemaViewDoc extends ObservableReactComponent this._props.schema.tableWidth; - screenToLocalXf = () => this._props.schema._props.ScreenToLocalTransform().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); - noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { + screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); + noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { if (property === StyleProp.Opacity) return 1; return DefaultStyleProvider(doc, props, property); }; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 567cf193e..908cd5dc0 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -460,7 +460,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @action timelineWhenChildContentsActiveChanged = (isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)); - timelineScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight); + timelineScreenToLocal = () => this.ScreenToLocalBoxXf().translate(0, -AudioBox.topControlsHeight); setPlayheadTime = (time: number) => (this._ele!.currentTime /*= this.layoutDoc._layout_currentTimecode*/ = time); @@ -564,7 +564,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { this._dropDisposer = DragManager.MakeDropTarget( r, (e, de) => { - const [xp, yp] = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y); + const [xp, yp] = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y); de.complete.docDragData && this.timeline?.internalDocDrop(e, de, de.complete.docDragData, xp); }, this.layoutDoc, diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 324a4b8d1..ad5aabc21 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -15,7 +15,8 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { FieldViewProps } from './FieldView'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { x: number; @@ -148,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === this.layoutDoc) { switch (property) { case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children @@ -229,7 +230,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { const topDoc = this.Document; const containerDocView = this._props.docViewPath().lastElement(); - const screenXf = containerDocView?.screenToNativeLocalTransform(); + const screenXf = containerDocView?.screenToContentsTransform(); if (screenXf) { SelectionManager.DeselectAll(); if (topDoc.z) { @@ -251,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { - const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); + const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y); this._props.Document.x = this._props.w_X() + locX; this._props.Document.y = this._props.w_Y() + locY; }; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index de382fca5..5e7e568b0 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, DocumentViewProps } from './DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -88,7 +88,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - const width = movementX * this._props.ScreenToLocalTransform().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); + const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); if (width && width > 5 && width < this._props.PanelWidth()) { this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth(); } @@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent this.clearDoc(which) ); }; - docStyleProvider = (doc: Opt, props: Opt, property: string): any => { + docStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; return this._props.styleProvider?.(doc, props, property); }; diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 5365fe1b2..ed44d9269 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -80,7 +80,7 @@ export class TableBox extends ObservableReactComponent { }; @computed get viewScale() { - return this._props.docView?.()?._props.ScreenToLocalTransform().Scale || 1; + return this._props.docView?.()?.screenToViewTransform().Scale || 1; } @computed get rowHeight() { console.log('scale = ' + this.viewScale + ' table = ' + this._tableHeight + ' ids = ' + this._tableDataIds.length); diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 165057d21..c549a146a 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -257,7 +257,7 @@ export class DocumentLinksButton extends ObservableReactComponent Opt; -export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; +export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { fieldKey?: string; annotationKey?: string; @@ -394,11 +394,9 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const [left, top] = this._props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); - dragData.offset = this._props - .ScreenToLocalTransform() - .scale(this.NativeDimScaling) - .transformDirection(x - left, y - top); + const screenXf = this.props.DocumentView().screenToViewTransform(); + const [left, top] = screenXf.inverse().transformPoint(0, 0); + dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; @@ -881,7 +879,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - contentScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); + screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -925,7 +923,7 @@ export class DocumentViewInternal extends DocComponent this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -1073,7 +1071,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); @observable _changingTitleField = false; @observable _dropDownInnerWidth = 0; fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { @@ -1431,11 +1429,20 @@ export class DocumentView extends ObservableReactComponent { return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.IsSelected ? ':selected' : '')); + return ( + this._props.hideLinkButton || + this._props.renderDepth === -1 || // + (this.IsSelected && this._props.renderDepth) || + !this._isHovering || + (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || + SnappingManager.IsDragging || + SnappingManager.IsResizing + ); } - hideLinkCount = () => false; // this._props.renderDepth === -1 || (this.IsSelected && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; + hideLinkCount = () => (this.hideLinkButton ? true : false); + @computed get linkCountView() { - return ; + return ; } @computed get docViewPath(): DocumentView[] { return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this]; @@ -1508,7 +1515,7 @@ export class DocumentView extends ObservableReactComponent { if (this.docView._componentView?.screenBounds?.()) { return this.docView._componentView.screenBounds(); } - const xf = this.docView._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); + const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { @@ -1566,7 +1573,7 @@ export class DocumentView extends ObservableReactComponent { }; layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); - scaleToScreenSpace = () => this._props.ScreenToLocalTransform().Scale; + screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { @@ -1589,7 +1596,14 @@ export class DocumentView extends ObservableReactComponent { PanelHeight = () => this.panelHeight; NativeDimScaling = () => this.nativeScaling; selfView = () => this; - screenToNativeLocalTransform = () => + /** + * @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView) + */ + screenToViewTransform = () => this._props.ScreenToLocalTransform(); + /** + * @returns Transform to the coordinate system of the contents of the document view (includes native dimension scaling and centering) + */ + screenToContentsTransform = () => this._props .ScreenToLocalTransform() .translate(-this.centeringX, -this.centeringY) @@ -1676,7 +1690,7 @@ export class DocumentView extends ObservableReactComponent { isSelected={this.isSelected} select={this.select} layout_fitWidth={this.layout_fitWidthFunc} - ScreenToLocalTransform={this.screenToNativeLocalTransform} + ScreenToLocalTransform={this.screenToContentsTransform} focus={this._props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} /> diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 28c614786..a5853499f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -90,7 +90,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent ({ forceFull: this._props.renderDepth < 1 || this.layoutDoc._showFullRes, - scrSize: (this._props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), + scrSize: (this.ScreenToLocalBoxXf().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), selected: this._props.isSelected(), }), ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'), @@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const scaling = (this._props.DocumentView?.()._props.ScreenToLocalTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); + const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); const nscale = NumCast(this._props.PanelWidth()) / scaling; const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; @@ -366,7 +366,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } - screenToLocalTransform = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this._props.ScreenToLocalTransform().Scale); + screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 134f2e14a..7f1d41547 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -38,8 +38,8 @@ export class LinkBox extends ViewBoxBaseComponent() { } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { - const a_invXf = this.anchor1._props.ScreenToLocalTransform().inverse(); - const b_invXf = this.anchor2._props.ScreenToLocalTransform().inverse(); + const a_invXf = this.anchor1.screenToViewTransform().inverse(); + const b_invXf = this.anchor2.screenToViewTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.Document._width), NumCast(this.anchor1.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.Document._width), NumCast(this.anchor2.Document._height)) }; @@ -67,9 +67,9 @@ export class LinkBox extends ViewBoxBaseComponent() { const b = (this.anchor2 ?? this.anchor1)!; const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; - const this_xf = parxf?.screenToLocalXf ?? Transform.Identity; //this._props.ScreenToLocalTransform(); - const a_invXf = a._props.ScreenToLocalTransform().inverse(); - const b_invXf = b._props.ScreenToLocalTransform().inverse(); + const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); + const a_invXf = a.screenToViewTransform().inverse(); + const b_invXf = b.screenToViewTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.Document._width), NumCast(a.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.Document._width), NumCast(b.Document._height)) }; const a_bds = { tl: this_xf.transformPoint(a_scrBds.tl[0], a_scrBds.tl[1]), br: this_xf.transformPoint(a_scrBds.br[0], a_scrBds.br[1]) }; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index ffd52fb0e..41befbbfe 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -431,7 +431,7 @@ export class MapBox extends ViewBoxAnnotatableComponent this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; infoWidth = () => this._props.PanelWidth() / 5; @@ -531,7 +531,7 @@ export class MapBox extends ViewBoxAnnotatableComponent string[]) => null; return ( diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 722a347f1..9734d9db1 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -517,7 +517,7 @@ // panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); // panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); -// scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); +// scrollXf = () => this.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); // transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; // opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; // infoWidth = () => this._props.PanelWidth() / 5; diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 2c31bbab7..8b22a1531 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -280,7 +280,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; infoWidth = () => this._props.PanelWidth() / 5; @@ -401,7 +401,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this.sidebarNativeHeight; sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey); - sidebarScreenToLocal = () => this._props.ScreenToLocalTransform().translate((this.sidebarWidth() - this._props.PanelWidth()) / this.pdfScale, 0); + sidebarScreenToLocal = () => this.ScreenToLocalBoxXf().translate((this.sidebarWidth() - this._props.PanelWidth()) / this.pdfScale, 0); @computed get sidebarCollection() { const renderComponent = (tag: string) => { const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : CollectionStackingView; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 36527c311..f74e6fb2b 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -313,7 +313,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent <> {this.threed} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 7ab954b3f..ce73d9f37 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -682,7 +682,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { action(encodeURIComponent => { this._clicking = false; if (this._props.isContentActive()) { - // const local = this._props.ScreenToLocalTransform().scale(this._props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); + // const local = this.ScreenToLocalTransform().scale(this._props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); // this.layoutDoc._layout_timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this._props.PanelHeight() * 100)); this.layoutDoc._layout_timelineHeightPercent = 80; @@ -922,7 +922,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { // renders video controls componentUI = (boundsLeft: number, boundsTop: number) => { - const xf = this._props.ScreenToLocalTransform().inverse(); + const xf = this.ScreenToLocalBoxXf().inverse(); const height = this._props.PanelHeight(); const vidHeight = (height * this.heightPercent) / 100 / this.scaling(); const vidWidth = this._props.PanelWidth() / this.scaling(); @@ -940,7 +940,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() {
{ if (this._mainCont.current && selRange) { - if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToNativeLocalTransform().RotateDeg)}deg)`; + if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -258,7 +258,7 @@ export class WebBox extends ViewBoxAnnotatableComponent 25) return
; + if (this.ScreenToLocalBoxXf().Scale > 25) return
; setTimeout( action(() => { if (this._initialScroll === undefined && !this._webPageHasBeenRendered) { @@ -1061,11 +1061,11 @@ export class WebBox extends ViewBoxAnnotatableComponent) => void) => (this._setPreviewCursor = func); panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc)) return 'none'; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 8bf8abafa..66802d198 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,7 +1,6 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { isEqual } from 'lodash'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { baseKeymap, selectAll } from 'prosemirror-commands'; @@ -21,12 +20,10 @@ import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from '../../../../fields/RichTextField'; -import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; -import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -46,7 +43,6 @@ import { CollectionTreeView } from '../../collections/CollectionTreeView'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; -import { DocumentButtonBar } from '../../DocumentButtonBar'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; @@ -71,9 +67,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -export const GoogleRef = 'googleDocId'; // import * as applyDevTools from 'prosemirror-dev-tools'; -type PullHandler = (exportState: Opt, dataDoc: Doc) => void; export interface FormattedTextBoxProps {} @observer @@ -1189,15 +1183,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent DocumentButtonBar.Instance, - instance => { - if (instance) { - this.pullFromGoogleDoc(this.checkState); - this.dataDoc[GoogleRef] && this.dataDoc.googleDocUnchanged && runInAction(() => (instance.isAnimatingFetch = true)); - } - } - ); this._disposers.editorState = reaction( () => { const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc; @@ -1218,24 +1203,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._props.Document[Pulls], - () => { - if (!DocumentButtonBar.hasPulledHack) { - DocumentButtonBar.hasPulledHack = true; - this.pullFromGoogleDoc(this.dataDoc.googleDocUnchanged ? this.checkState : this.updateState); - } - } - ); - this._disposers.pushDoc = reaction( - () => this._props.Document[Pushes], - () => { - if (!DocumentButtonBar.hasPushedHack) { - DocumentButtonBar.hasPushedHack = true; - this.pushToGoogleDoc(); - } - } - ); this._disposers.search = reaction( () => Doc.IsSearchMatch(this.Document), @@ -1295,80 +1262,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this.pullFromGoogleDoc(async (exportState: Opt, dataDoc: Doc) => { - const modes = GoogleApiClientUtils.Docs.WriteMode; - let mode = modes.Replace; - let reference: Opt = Cast(this.dataDoc[GoogleRef], 'string'); - if (!reference) { - mode = modes.Insert; - reference = { title: StrCast(this.dataDoc.title) }; - } - const redo = async () => { - if (this._editorView && reference) { - const content = await RichTextUtils.GoogleDocs.Export(this._editorView.state); - const response = await GoogleApiClientUtils.Docs.write({ reference, content, mode }); - response?.documentId && (this.dataDoc[GoogleRef] = response.documentId); - const pushSuccess = response !== undefined && !('errors' in response); - dataDoc.googleDocUnchanged = pushSuccess; - DocumentButtonBar.Instance.startPushOutcome(pushSuccess); - } - }; - const undo = () => { - if (exportState && reference) { - const content: GoogleApiClientUtils.Docs.Content = { - text: exportState.text, - requests: [], - }; - GoogleApiClientUtils.Docs.write({ reference, content, mode }); - } - }; - UndoManager.AddEvent({ undo, redo, prop: '' }); - redo(); - }); - }; - - pullFromGoogleDoc = async (handler: PullHandler) => { - const dataDoc = this.dataDoc; - const documentId = StrCast(dataDoc[GoogleRef]); - let exportState: Opt; - if (documentId) { - exportState = await RichTextUtils.GoogleDocs.Import(documentId, dataDoc); - } - exportState && UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls); - }; - - updateState = (exportState: Opt, dataDoc: Doc) => { - let pullSuccess = false; - if (exportState !== undefined) { - pullSuccess = true; - dataDoc[this.fieldKey] = new RichTextField(JSON.stringify(exportState.state.toJSON())); - setTimeout(() => { - if (this._editorView) { - const state = this._editorView.state; - const end = state.doc.content.size - 1; - this._editorView.dispatch(state.tr.setSelection(TextSelection.create(state.doc, end, end))); - } - }, 0); - dataDoc.title = exportState.title; - this.dataDoc.title_custom = true; - dataDoc.googleDocUnchanged = true; - } else { - delete dataDoc[GoogleRef]; - } - DocumentButtonBar.Instance.startPullOutcome(pullSuccess); - }; - - checkState = (exportState: Opt, dataDoc: Doc) => { - if (exportState && this._editorView) { - const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); - const equalTitles = dataDoc.title === exportState.title; - const unchanged = equalContent && equalTitles; - dataDoc.googleDocUnchanged = unchanged; - DocumentButtonBar.Instance.setPullState(unchanged); - } - }; - clipboardTextSerializer = (slice: Slice): string => { let text = '', separated = true; @@ -1462,7 +1355,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined; if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) { const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE); - const scrollPos = scrollRef.scrollTop + shift * self._props.ScreenToLocalTransform().Scale; + const scrollPos = scrollRef.scrollTop + shift * self.ScreenToLocalBoxXf().Scale; if (this._focusSpeed !== undefined) { scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed, scrollRef, scrollPos, 'ease', this._scrollStopper)); } else { diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index 1a92acea1..7d0086c0c 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -13,7 +13,7 @@ export class ImportElementBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImportElementBox, fieldKey); } - screenToLocalXf = () => this._props.ScreenToLocalTransform().scale(1 * (this._props.NativeDimScaling?.() || 1)); + screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { return (
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0305689e7..6fa64a765 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -979,7 +979,7 @@ export class PresBox extends ViewBoxBaseComponent() { enterMinimize = () => { this.updateCurrentPresentation(this.Document); clearTimeout(this._presTimer); - const pt = this._props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const pt = this.ScreenToLocalBoxXf().inverse().transformPoint(0, 0); this._props.removeDocument?.(this.layoutDoc); return PresBox.OpenPresMinimized(this.Document, [pt[0] + (this._props.PanelWidth() - 250), pt[1] + 10]); }; @@ -1076,7 +1076,7 @@ export class PresBox extends ViewBoxBaseComponent() { childLayoutTemplate = () => Docs.Create.PresElementBoxDocument(); removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.Document, this.fieldKey, doc); - getTransform = () => this._props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight + getTransform = () => this.ScreenToLocalBoxXf().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight panelHeight = () => this._props.PanelHeight() - 40; /** * For sorting the array so that the order is maintained when it is dropped. diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index ec5d090dd..4945d66c8 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocumentView, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; @@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton); embedHeight = () => this.collapsedHeight + this.expandViewHeight; embedWidth = () => this._props.PanelWidth() / 2; - styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property); }; /** diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f41094010..4a7e35c16 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -17,11 +17,11 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp, testDocProps } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; @@ -53,7 +53,7 @@ interface IViewerProps extends FieldViewProps { export class PDFViewer extends ObservableReactComponent { static _annotationStyle: any = addStyleSheet(); - constructor(props: any) { + constructor(props: IViewerProps) { super(props); makeObservable(this); } @@ -419,7 +419,7 @@ export class PDFViewer extends ObservableReactComponent { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { - this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToNativeLocalTransform().RotateDeg)}deg)`; + this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { @@ -491,16 +491,17 @@ export class PDFViewer extends ObservableReactComponent { } getScrollHeight = () => this._scrollHeight; - scrollXf = () => (this._mainCont.current ? this._props.ScreenToLocalTransform().translate(0, NumCast(this._props.layoutDoc._layout_scrollTop)) : this._props.ScreenToLocalTransform()); + scrollXf = () => this._props.ScreenToLocalTransform().translate(0, this._mainCont.current ? NumCast(this._props.layoutDoc._layout_scrollTop) : 0); overlayTransform = () => this.scrollXf().scale(1 / NumCast(this._props.layoutDoc._freeform_scale, 1)); panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { + const docProps = testDocProps(props) ? props : undefined; if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; - const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; + const isInk = doc.layout_isSvg && !docProps?.LayoutTemplateString; return isInk ? 'visiblePainted' : 'all'; } return this._props.styleProvider?.(doc, props, property); -- cgit v1.2.3-70-g09d2 From 5b5730a7df073659cbb6c326f748f7fcbe6625e8 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 18 Jan 2024 15:05:53 -0500 Subject: lots of changes to try to simplify API for viewPaths and related --- src/Utils.ts | 3 +- src/client/documents/Documents.ts | 6 +- src/client/util/CurrentUserUtils.ts | 4 +- src/client/util/DocumentManager.ts | 15 +- .../util/Import & Export/DirectoryImportBox.tsx | 2 +- src/client/views/DocComponent.tsx | 56 +++- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 6 +- src/client/views/GestureOverlay.tsx | 2 +- src/client/views/InkControlPtHandles.tsx | 12 +- src/client/views/InkStrokeProperties.ts | 3 +- src/client/views/InkTangentHandles.tsx | 4 +- src/client/views/InkingStroke.tsx | 9 +- src/client/views/LightboxView.tsx | 2 +- src/client/views/MainView.tsx | 47 +--- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/OverlayView.tsx | 2 +- src/client/views/PreviewCursor.tsx | 25 +- src/client/views/PropertiesButtons.tsx | 46 ++- src/client/views/PropertiesDocContextSelector.tsx | 2 +- src/client/views/PropertiesView.tsx | 2 +- src/client/views/StyleProvider.tsx | 33 ++- src/client/views/TemplateMenu.tsx | 2 - .../views/collections/CollectionCarouselView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 2 - .../views/collections/CollectionNoteTakingView.tsx | 10 +- .../views/collections/CollectionPileView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 4 +- .../views/collections/CollectionStackingView.tsx | 12 +- src/client/views/collections/CollectionSubView.tsx | 4 +- .../views/collections/CollectionTreeView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 10 +- src/client/views/collections/TabDocView.tsx | 9 +- src/client/views/collections/TreeView.tsx | 12 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 51 ++-- .../collectionLinear/CollectionLinearView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 6 +- .../CollectionMultirowView.tsx | 7 +- .../collectionSchema/CollectionSchemaView.tsx | 7 +- .../collections/collectionSchema/SchemaRowBox.tsx | 8 +- .../collectionSchema/SchemaTableCell.tsx | 1 - src/client/views/global/globalScripts.ts | 4 +- src/client/views/linking/LinkMenuItem.tsx | 4 +- src/client/views/linking/LinkPopup.tsx | 2 - src/client/views/newlightbox/NewLightboxView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 8 +- src/client/views/nodes/ComparisonBox.tsx | 5 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 41 +-- src/client/views/nodes/DocumentContentsView.tsx | 11 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 308 +++++++++++---------- src/client/views/nodes/EquationBox.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 9 +- src/client/views/nodes/ImageBox.tsx | 8 +- src/client/views/nodes/KeyValuePair.tsx | 65 ++--- src/client/views/nodes/LinkAnchorBox.tsx | 14 +- src/client/views/nodes/LinkBox.tsx | 9 +- src/client/views/nodes/LinkDocPreview.tsx | 12 +- src/client/views/nodes/MapBox/MapBox.tsx | 4 +- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 4 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 4 +- src/client/views/nodes/PDFBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 18 +- src/client/views/nodes/WebBox.tsx | 36 +-- .../views/nodes/formattedText/DashDocView.tsx | 4 +- .../views/nodes/formattedText/DashFieldView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 16 +- .../formattedText/FormattedTextBoxComment.tsx | 3 +- src/client/views/nodes/trails/PresBox.tsx | 12 +- src/client/views/nodes/trails/PresElementBox.tsx | 10 +- src/client/views/pdf/PDFViewer.tsx | 12 +- src/client/views/topbar/TopBar.tsx | 2 - src/mobile/MobileInterface.tsx | 2 +- src/server/DashStats.ts | 4 +- 77 files changed, 566 insertions(+), 537 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index b5c218e01..852083834 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -7,6 +7,7 @@ import { Socket } from '../node_modules/socket.io/dist/index'; import { DocumentType } from './client/documents/DocumentTypes'; import { Colors } from './client/views/global/globalEnums'; import { Message } from './server/Message'; +import { DocumentView } from './client/views/nodes/DocumentView'; export namespace Utils { export let CLICK_TIME = 300; @@ -583,7 +584,7 @@ export function returnEmptyDoclist() { return [] as any[]; } -export let emptyPath = []; +export let emptyPath: DocumentView[] = []; export function emptyFunction() { return undefined; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 92a9ddfe8..40cffcf45 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -244,7 +244,6 @@ export class DocumentOptions { _layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); _layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow'); layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow - layout_maxAutoHeight?: NUMt = new NumInfo('maximum height for newly created (eg, from pasting) text documents', false); _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); _layout_curPage?: NUMt = new NumInfo('current page of a PDF or other? paginated document', false); _layout_currentTimecode?: NUMt = new NumInfo('the current timecode of a time-based document (e.g., current time of a video) value is in seconds', false); @@ -290,7 +289,7 @@ export class DocumentOptions { dontPlayLinkOnSelect?: BOOLt = new BoolInfo('whether an audio/video should start playing when a link is followed to it.'); openFactoryLocation?: string; // an OpenWhere value to place the factory created document openFactoryAsDelegate?: boolean; // - updateContentsScript?: ScriptField; // reactive script invoked when viewing a document that can update contents of a collection (or do anything) + onViewMounted?: ScriptField; // reactive script invoked Doc is viewed (used by showBackLinks view to update collection of links to Doc) toolTip?: string; // tooltip to display on hover toolType?: string; // type of pen tool expertMode?: BOOLt = new BoolInfo('something available only in expert (not novice) mode'); @@ -1895,12 +1894,11 @@ export namespace DocUtils { } } - export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) { + export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, backgroundColor?: string) { const tbox = Docs.Create.TextDocument('', { _xMargin: noMargins ? 0 : undefined, _yMargin: noMargins ? 0 : undefined, annotationOn, - layout_maxAutoHeight: maxHeight, backgroundColor, _width: width || 200, _height: 35, diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 4391e87d6..2dfd91314 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -111,7 +111,7 @@ export class CurrentUserUtils { const tempClicks = DocCast(doc[field]); const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true}; const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [ - { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.Document.target).then((target) => target && (target.proto.data = new List([self])))"}, + { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.containerViewPath().lastElement()?.Document.target).then((target) => target && (target.proto.data = new List([self])))"}, { opts: { title: "Open Detail On Right", targetScriptKey: "onChildDoubleClick"}, script: `openDoc(this.doubleClickView.${OpenWhere.addRight})`}]; const reqdClickList = reqdTempOpts.map(opts => { const allOpts = {...reqdClickOpts, ...opts.opts}; @@ -285,7 +285,7 @@ export class CurrentUserUtils { treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, dropAction:'move', treeView_Type: TreeViewType.outline, backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true - }, funcs: {title: 'this.text?.Text'}}, + }, funcs: {title: 'pptSlide'}},//'this.text?.Text'}}, ]; emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, thing.scripts, thing.funcs)); diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7fef5cc79..07357a764 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -153,8 +153,8 @@ export class DocumentManager { return passes.reduce( (toReturn, pass) => toReturn ?? - docViewArray.filter(view => view.Document === target).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection) ?? - docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection), + docViewArray.filter(view => view.Document === target).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection) ?? + docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection), undefined as Opt ); } @@ -224,7 +224,7 @@ export class DocumentManager { } public static removeOverlayViews() { - DocumentManager._overlayViews?.forEach(action(view => (view.textHtmlOverlay = undefined))); + DocumentManager._overlayViews?.forEach(view => view.setTextHtmlOverlay(undefined, undefined)); DocumentManager._overlayViews?.clear(); } static _overlayViews = new ObservableSet(); @@ -274,7 +274,7 @@ export class DocumentManager { // even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox) const target = DocCast(targetDoc.annotationOn, targetDoc); const contextView = this.getDocumentView(DocCast(target.embedContainer)); - if (contextView?.docView?._componentView?.addDocTab?.(target, OpenWhere.lightbox)) { + if (contextView?.ComponentView?.addDocTab?.(target, OpenWhere.lightbox)) { await new Promise(waitres => setTimeout(() => waitres())); } } @@ -327,15 +327,12 @@ export class DocumentManager { if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && targetDoc.text_html) { // if the docView is a text anchor, the contextView is the PDF/Web/Text doc - contextView.htmlOverlayEffect = options.effect; - contextView.textHtmlOverlayTime = options.zoomTime; - contextView.textHtmlOverlay = StrCast(targetDoc.text_html); + contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect); DocumentManager._overlayViews.add(contextView); } Doc.AddUnHighlightWatcher(() => { docView.Document[Animation] = undefined; DocumentManager.removeOverlayViews(); - contextView && (contextView.htmlOverlayEffect = undefined); }); } } @@ -344,7 +341,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); - if (dv && (!containingDoc || dv._props.docViewPath().lastElement()?.Document === containingDoc)) { + if (dv && (!containingDoc || dv.containerViewPath?.().lastElement()?.Document === containingDoc)) { DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.Document)); } else { const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc)); diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index b6dbea33a..398ba3c04 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -156,7 +156,7 @@ // x: NumCast(doc.x), // y: NumCast(doc.y) + offset, // }; -// const parent = this.props.DocumentView?.()._props.docViewPath().lastElement(); +// const parent = this.props.DocumentView?.().containerViewPath().lastElement(); // if (parent?.Document.type === DocumentType.COL) { // let importContainer: Doc; // if (docs.length < 50) { diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index dfc298840..fb8ef7c36 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,6 +1,6 @@ import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; -import { returnFalse } from '../../Utils'; +import { emptyPath, returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; @@ -9,17 +9,20 @@ import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; +import { Transform } from '../util/Transform'; import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { DocumentView } from './nodes/DocumentView'; -import { Transform } from '../util/Transform'; -/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) +/** + * DocComponent returns a generic React base class used by Doc views (not the 'Box' views that render the contents of Doc views) + * (e.g.,CollectionFreeFormDocumentView, DocumentViewInternal) + * + * */ export interface DocComponentProps { Document: Doc; LayoutTemplate?: () => Opt; LayoutTemplateString?: string; - ScreenToLocalTransform: () => Transform; } export function DocComponent

() { class Component extends ObservableReactComponent> { @@ -28,8 +31,6 @@ export function DocComponent

() { makeObservable(this); } - ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); - //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -46,21 +47,40 @@ export function DocComponent

() { return Component; } -/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. InkingStroke, ColorBox) -interface ViewBoxBaseProps { +/** + * ViewBoxBaseComponent - base class for non-annotatable views that render the interior contents of a DocumentView + * (e.g. InkingStroke, ColorBox) + */ +export interface ViewBoxBaseProps { Document: Doc; TemplateDataDocument?: Doc; DocumentView?: () => DocumentView; + containerViewPath?: () => DocumentView[]; fieldKey: string; isSelected: () => boolean; isContentActive: () => boolean | undefined; ScreenToLocalTransform: () => Transform; renderDepth: number; } +function returnEmptyDocViewList() { + return [] as DocumentView[]; +} export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + get DocumentView() { + return this._props.DocumentView; + } + get docViewPath() { + return this.DocumentView?.().docViewPath ?? emptyPath; + } + get docViewPathFunc() { + return this.DocumentView?.().docViewPathFunc ?? returnEmptyDocViewList; + } + get containerViewPath() { + return this._props.containerViewPath; + } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -81,10 +101,15 @@ export function ViewBoxBaseComponent

() { return Component; } -/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image) +/** + * DocAnnotatableComponent - base class for annotatable views that render the interior contents of a DocumentView + * (e.g., PdfBox, ImageBox) + * These views should be interactive (respond to pointerEvents) when their conatainer DocumentView is selected + */ export interface ViewBoxAnnotatableProps { Document: Doc; TemplateDataDocument?: Doc; + DocumentView?: () => DocumentView; fieldKey: string; filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) isContentActive: () => boolean | undefined; @@ -106,6 +131,19 @@ export function ViewBoxAnnotatableComponent

() @observable _annotationKeySuffix = () => 'annotations'; @observable _isAnyChildContentActive = false; + + get DocumentView() { + return this._props.DocumentView; + } + get docViewPath() { + return this.DocumentView?.().docViewPath ?? emptyPath; + } + get docViewPathFunc() { + return this.DocumentView?.().docViewPathFunc ?? returnEmptyDocViewList; + } + get containerViewPath() { + return this.DocumentView?.().containerViewPath ?? returnEmptyDocViewList; + } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document() { return this._props.Document; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index bb28d9ec9..8a4b42ae0 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -72,7 +72,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (

this._props.views().map(view => view?.docView?.toggleFollowLink(undefined, false)))}> + onClick={undoBatch(e => this._props.views().map(view => view?.toggleFollowLink(undefined, false)))}>
{followBtn( true, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 788e78ed2..c96253405 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -303,7 +303,7 @@ export class DocumentDecorations extends ObservableReactComponent SelectionManager.Views?.[0]?._props.docViewPath?.().lastElement()?.select(false); + onSelectContainerDocClick = () => SelectionManager.Views?.[0]?.containerViewPath?.().lastElement()?.select(false); /** * sets up events when user clicks on the border radius editor */ @@ -677,7 +677,7 @@ export class DocumentDecorations extends ObservableReactComponent { - const collectionAcl = docView._props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView._props.docViewPath().lastElement().dataDoc) : AclEdit; + const collectionAcl = docView.containerViewPath?.()?.lastElement() ? GetEffectiveAcl(docView.containerViewPath?.().lastElement().dataDoc) : AclEdit; return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.Document) !== AclAdmin; }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( @@ -805,7 +805,7 @@ export class DocumentDecorations extends ObservableReactComponent )} - {seldocview._props.renderDepth <= 1 || !seldocview._props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} + {seldocview._props.renderDepth <= 1 || !seldocview.containerViewPath?.().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectContainerDocClick, 'tap to select containing document')} {useRounding && (
{ @observable private _overControl = -1; get docView() { - return this.props.inkView.props.docViewPath().lastElement(); + return this.props.inkView.DocumentView?.(); } componentDidMount() { @@ -58,11 +58,11 @@ export class InkControlPtHandles extends React.Component { if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('drag ink ctrl pt'); const inkMoveEnd = ptFromScreen({ X: delta[0], Y: delta[1] }); const inkMoveStart = ptFromScreen({ X: 0, Y: 0 }); - InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk); + this.docView && InkStrokeProperties.Instance.moveControlPtHandle(this.docView, inkMoveEnd.X - inkMoveStart.X, inkMoveEnd.Y - inkMoveStart.Y, controlIndex, origInk); return false; }), action(() => { - if (this.props.inkView.controlUndo) { + if (this.props.inkView.controlUndo && this.docView) { InkStrokeProperties.Instance.snapControl(this.docView, controlIndex); } this.props.inkView.controlUndo?.end(); @@ -78,11 +78,11 @@ export class InkControlPtHandles extends React.Component { } else { if (brokenIndices?.includes(equivIndex)) { if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); - InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB); + this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, equivIndex, handleIndexA, handleIndexB); } if (equivIndex !== controlIndex && brokenIndices?.includes(controlIndex)) { if (!this.props.inkView.controlUndo) this.props.inkView.controlUndo = UndoManager.StartBatch('make smooth'); - InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB); + this.docView && InkStrokeProperties.Instance.snapHandleTangent(this.docView, controlIndex, handleIndexA, handleIndexB); } } this.props.inkView.controlUndo?.end(); @@ -113,7 +113,7 @@ export class InkControlPtHandles extends React.Component { @action onDelete = (e: KeyboardEvent) => { if (['-', 'Backspace', 'Delete'].includes(e.key)) { - InkStrokeProperties.Instance.deletePoints(this.docView, e.shiftKey); + this.docView && InkStrokeProperties.Instance.deletePoints(this.docView, e.shiftKey); e.stopPropagation(); } }; diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index f31ea2994..52ea89cde 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -241,6 +241,7 @@ export class InkStrokeProperties { */ @undoBatch moveControlPtHandle = (inkView: DocumentView, deltaX: number, deltaY: number, controlIndex: number, origInk?: InkData) => + inkView && this.applyFunction(inkView, (view: DocumentView, ink: InkData) => { const order = controlIndex % 4; const closed = InkingStroke.IsClosed(ink); @@ -369,7 +370,7 @@ export class InkStrokeProperties { snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => { const containingCollection = inkView.CollectionFreeFormView; - const containingDocView = containingCollection?.props.DocumentView?.(); + const containingDocView = containingCollection?.DocumentView?.(); containingCollection?.childDocs .filter(doc => doc.type === DocumentType.INK) .forEach(doc => { diff --git a/src/client/views/InkTangentHandles.tsx b/src/client/views/InkTangentHandles.tsx index a00c26a07..c20399698 100644 --- a/src/client/views/InkTangentHandles.tsx +++ b/src/client/views/InkTangentHandles.tsx @@ -23,7 +23,7 @@ export interface InkHandlesProps { @observer export class InkTangentHandles extends React.Component { get docView() { - return this.props.inkView.props.docViewPath().lastElement(); + return this.props.inkView.DocumentView?.(); } /** * Handles the movement of a selected handle point when the user clicks and drags. @@ -42,7 +42,7 @@ export class InkTangentHandles extends React.Component { if (e.altKey) this.onBreakTangent(controlIndex); const inkMoveEnd = this.props.inkView.ptFromScreen({ X: delta[0], Y: delta[1] }); const inkMoveStart = this.props.inkView.ptFromScreen({ X: 0, Y: 0 }); - InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex); + this.docView && InkStrokeProperties.Instance.moveTangentHandle(this.docView, -(inkMoveEnd.X - inkMoveStart.X), -(inkMoveEnd.Y - inkMoveStart.Y), handleIndex, oppositeHandleIndex, controlIndex); return false; }), action(() => { diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index c652e8966..11b05352d 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -34,7 +34,7 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; -import { ViewBoxBaseComponent } from './DocComponent'; +import { ViewBoxBaseComponent, ViewBoxBaseProps } from './DocComponent'; import { Colors } from './global/globalEnums'; import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; @@ -48,7 +48,7 @@ import { StyleProp } from './StyleProvider'; import { Transform } from '../util/Transform'; const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer -export class InkingStroke extends ViewBoxBaseComponent() { +export class InkingStroke extends ViewBoxBaseComponent() { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); @@ -122,7 +122,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { @action onPointerDown = (e: React.PointerEvent) => { this._handledClick = false; - const inkView = this._props.docViewPath().lastElement(); + const inkView = this.DocumentView?.(); + if (!inkView) return; const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => @@ -162,7 +163,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { InkStrokeProperties.Instance._currentPoint = -1; this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView if (isEditing) { - this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this._props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); + this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(inkView, this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); } } }), diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index ab3be3d7a..aec9e32fc 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -257,7 +257,7 @@ export class LightboxView extends ObservableReactComponent { styleProvider={DefaultStyleProvider} ScreenToLocalTransform={this.lightboxScreenToLocal} renderDepth={0} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 35ffab337..cd6aeea41 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -606,7 +606,7 @@ export class MainView extends ObservableReactComponent<{}> { Document={this.headerBarDoc} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} styleProvider={DefaultStyleProvider} addDocument={this.addHeaderDoc} removeDocument={this.removeHeaderDoc} @@ -641,7 +641,7 @@ export class MainView extends ObservableReactComponent<{}> { addDocument={undefined} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} styleProvider={this._hideUI ? DefaultStyleProvider : undefined} isContentActive={returnTrue} removeDocument={undefined} @@ -735,7 +735,7 @@ export class MainView extends ObservableReactComponent<{}> { addDocument={undefined} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={TabDocView.PinDoc} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} styleProvider={this._sidebarContent.proto === Doc.MyDashboards || this._sidebarContent.proto === Doc.MyFilesystem || this._sidebarContent.proto === Doc.MyTrails ? DashboardStyleProvider : DefaultStyleProvider} removeDocument={returnFalse} ScreenToLocalTransform={this.mainContainerXf} @@ -769,7 +769,7 @@ export class MainView extends ObservableReactComponent<{}> { PanelWidth={this.leftMenuWidth} PanelHeight={this.leftMenuHeight} renderDepth={0} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} focus={emptyFunction} styleProvider={DefaultStyleProvider} isContentActive={returnTrue} @@ -900,14 +900,13 @@ export class MainView extends ObservableReactComponent<{}> { Document={Doc.MyDockedBtns} fieldKey="data" dropAction="embed" - setHeight={returnFalse} styleProvider={DefaultStyleProvider} bringToFront={emptyFunction} select={emptyFunction} isAnyChildContentActive={returnFalse} isContentActive={emptyFunction} isSelected={returnFalse} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} addDocument={this.addButtonDoc} addDocTab={DocumentViewInternal.addDocTabFunc} @@ -969,41 +968,6 @@ export class MainView extends ObservableReactComponent<{}> { ); } - @observable mapBoxHackBool = false; - @computed get mapBoxHack() { - return this.mapBoxHackBool ? null : ( - r && (this.mapBoxHackBool = true))} - fieldKey="data" - select={returnFalse} - isSelected={returnFalse} - Document={this.headerBarDoc} - addDocTab={returnFalse} - pinToPres={emptyFunction} - docViewPath={returnEmptyDoclist} - styleProvider={DefaultStyleProvider} - addDocument={returnFalse} - removeDocument={returnFalse} - fitContentsToBox={returnTrue} - isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events) - isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive - ScreenToLocalTransform={Transform.Identity} - childHideResizeHandles={true} - childDragAction="move" - dontRegisterView={true} - PanelWidth={this.headerBarDocWidth} - PanelHeight={this.headerBarDocHeight} - renderDepth={0} - focus={emptyFunction} - whenChildContentsActiveChanged={emptyFunction} - bringToFront={emptyFunction} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - /> - ); - } - render() { return (
{ - {/* {this.mapBoxHack} */} diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 9d828364d..cfdc648b4 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -198,7 +198,7 @@ export class MarqueeAnnotator extends ObservableReactComponent this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true); // hyperlink color const targetCreator = (annotationOn: Doc | undefined) => { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 915c3c18f..89527c415 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -234,7 +234,7 @@ export class OverlayView extends ObservableReactComponent<{}> { whenChildContentsActiveChanged={emptyFunction} focus={emptyFunction} styleProvider={DefaultStyleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} addDocTab={DocumentViewInternal.addDocTabFunc} pinToPres={emptyFunction} childFilters={returnEmptyFilter} diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index a69a5f5e8..456b753b4 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -60,18 +60,17 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } else if (re.test(plain)) { const url = plain; if (!url.startsWith(window.location.href)) { - undoBatch( - () => - this._addDocument?.( - Docs.Create.WebDocument(url, { - title: url, - _width: 500, - _height: 300, - data_useCors: true, - x: newPoint[0], - y: newPoint[1], - }) - ) + undoBatch(() => + this._addDocument?.( + Docs.Create.WebDocument(url, { + title: url, + _width: 500, + _height: 300, + data_useCors: true, + x: newPoint[0], + y: newPoint[1], + }) + ) )(); } else alert('cannot paste dash into itself'); } else if (plain.startsWith('__DashDocId(') || plain.startsWith('__DashCloneId(')) { @@ -86,7 +85,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { } else { FormattedTextBox.PasteOnLoad = e; if (e.clipboardData.getData('dash/pdfAnchor')) e.preventDefault(); - UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined, 750)), 'paste'); + UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined)), 'paste'); } } //pasting in images diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 5905f8dbc..bba6285c2 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -345,9 +345,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @undoBatch handlePerspectiveChange = (e: any) => { this.selectedDoc && (this.selectedDoc._type_collection = e.target.value); - SelectionManager.Views.filter(dv => dv.docView) - .map(dv => dv.docView!) - .forEach(docView => (docView.layoutDoc._type_collection = e.target.value)); + SelectionManager.Views.forEach(docView => (docView.layoutDoc._type_collection = e.target.value)); }; @computed get onClickVal() { const linkButton = IsFollowLinkScript(this.selectedDoc.onClick); @@ -408,28 +406,26 @@ export class PropertiesButtons extends React.Component<{}, {}> { @undoBatch @action handleOptionChange = (onClick: string) => { - SelectionManager.Views.filter(dv => dv.docView) - .map(dv => dv.docView!) - .forEach(docView => { - const linkButton = IsFollowLinkScript(docView.Document.onClick); - docView.noOnClick(); - switch (onClick) { - case 'enterPortal': - docView.makeIntoPortal(); - break; - case 'toggleDetail': - docView.setToggleDetail(); - break; - case 'linkInPlace': - docView.toggleFollowLink(false, false); - docView.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined; - break; - case 'linkOnRight': - docView.toggleFollowLink(false, false); - docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined; - break; - } - }); + SelectionManager.Views.forEach(docView => { + const linkButton = IsFollowLinkScript(docView.Document.onClick); + docView.noOnClick(); + switch (onClick) { + case 'enterPortal': + docView.makeIntoPortal(); + break; + case 'toggleDetail': + docView.setToggleDetail(); + break; + case 'linkInPlace': + docView.toggleFollowLink(false, false); + docView.Document.followLinkLocation = linkButton ? OpenWhere.lightbox : undefined; + break; + case 'linkOnRight': + docView.toggleFollowLink(false, false); + docView.Document.followLinkLocation = linkButton ? OpenWhere.addRight : undefined; + break; + } + }); }; @undoBatch diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index a710e7816..54f141a36 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -27,7 +27,7 @@ export class PropertiesDocContextSelector extends ObservableReactComponent embedding.embedContainer && embedding.embedContainer instanceof Doc).reduce((set, embedding) => set.add(Cast(embedding.embedContainer, Doc, null)), new Set()); const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.proto_embeddings)); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 2fcb5d12a..13057ffbf 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -299,7 +299,7 @@ export class PropertiesView extends ObservableReactComponent, props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; const docProps = testDocProps(props) ? props : undefined; const fieldProps = testFieldProps(props) ? props : undefined; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); + const isNonTransparent = property.includes(':nonTransparent'); + const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent'); const isContent = property.includes(':content'); const isAnnotated = property.includes(':annotated'); const isInk = () => doc?._layout_isSvg && !docProps?.LayoutTemplateString; @@ -95,7 +97,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt doc && BoolCast(doc._lockedPosition); const titleHeight = () => props?.styleProvider?.(doc, props, StyleProp.TitleHeight); - const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor); + const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor + ':nonTransparent' + (isNonTransparentLevel + 1)); const color = () => props?.styleProvider?.(doc, props, StyleProp.Color); const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity); const layout_showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle); @@ -140,7 +142,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; - const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView.docView?._props, StyleProp.BackgroundColor); + const parView = props?.DocumentView?.(); + const backColor = backgroundCol(); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : '')); @@ -198,18 +200,18 @@ export function DefaultStyleProvider(doc: Opt, props: Opt = StrCast(doc?.[fieldKey + '_backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : '')); + let docColor: Opt = StrCast(doc?.[fieldKey + 'backgroundColor'], StrCast(doc?._backgroundColor, isCaption ? 'rgba(0,0,0,0.4)' : '')); // prettier-ignore switch (doc?.type) { case DocumentType.PRESELEMENT: docColor = docColor || ""; break; case DocumentType.PRES: docColor = docColor || 'transparent'; break; case DocumentType.FONTICON: docColor = boxBackground ? undefined : docColor || Colors.DARK_GRAY; break; - case DocumentType.RTF: docColor = docColor || Colors.LIGHT_GRAY; break; + case DocumentType.RTF: docColor = docColor || Colors.LIGHT_GRAY; break; case DocumentType.LINK: docColor = (isAnchor ? docColor : undefined); break; case DocumentType.INK: docColor = doc?.stroke_isInkMask ? 'rgba(0,0,0,0.7)' : undefined; break; case DocumentType.EQUATION: docColor = docColor || 'transparent'; break; case DocumentType.LABEL: docColor = docColor || Colors.LIGHT_GRAY; break; - case DocumentType.BUTTON: docColor = docColor || Colors.LIGHT_GRAY; break; + case DocumentType.BUTTON: docColor = docColor || Colors.LIGHT_GRAY; break; case DocumentType.IMG: case DocumentType.WEB: case DocumentType.PDF: @@ -230,6 +232,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt, props: Opt { - if (props?.docViewPath().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) { + if (props?.DocumentView?.().containerViewPath?.().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) { return doc?.pointerEvents !== 'none' ? null : (
toggleLockedPosition(doc)}> @@ -321,7 +326,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length) .map(dv => ({ text: StrCast(dv?.Document.title), @@ -339,7 +344,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt{StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations_text']).lastElement()}
}> -
DocumentManager.Instance.getFirstDocumentView(doc)?.docView?.playAnnotation()}> +
DocumentManager.Instance.getFirstDocumentView(doc)?.playAnnotation()}>
@@ -374,7 +379,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, /** * add hide button decorations for the "Dashboards" flyout TreeView */ -export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { +export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { if (doc && property.split(':')[0] === StyleProp.Decorations) { return doc._type_collection === CollectionViewType.Docking || Doc.IsSystem(doc) ? null diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index b42f3c1e9..e5154efcb 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -114,8 +114,6 @@ export class TemplateMenu extends React.Component { , property: string): any => { + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption-' + property] ? this._props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this._props.styleProvider?.(this.layoutDoc, captionProps, property); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 874cdffd9..1f867fc44 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -431,7 +431,7 @@ export class CollectionDockingView extends CollectionSubView() { }; public CaptureThumbnail() { - const content = this._props.DocumentView?.()?.ContentDiv; + const content = this.DocumentView?.()?.ContentDiv; if (content) { const _width = Number(getComputedStyle(content).width.replace('px', '')); const _height = Number(getComputedStyle(content).height.replace('px', '')); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 98ae01591..a54a5ec81 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -97,14 +97,12 @@ export class CollectionMenu extends AntimodeMenu { Document={selDoc} fieldKey="data" dropAction="embed" - setHeight={returnFalse} styleProvider={DefaultStyleProvider} bringToFront={emptyFunction} select={emptyFunction} isContentActive={returnTrue} isAnyChildContentActive={returnFalse} isSelected={returnFalse} - docViewPath={returnEmptyDoclist} moveDocument={returnFalse} addDocument={returnFalse} addDocTab={DocumentViewInternal.addDocTabFunc} diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 302ccd2db..0795104d9 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -18,7 +18,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -203,7 +203,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } }; - styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { switch (property) { case StyleProp.BoxShadow: if (doc && DragManager.docsBeingDragged.includes(doc)) { @@ -238,7 +238,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelWidth={width} PanelHeight={height} styleProvider={this.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.docViewPathFunc} layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} @@ -511,7 +511,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { action((entries: any) => { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.IsLightboxDocView(this.docViewPath)) { this._props.setHeight?.(height); } } @@ -643,7 +643,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { onDragOver={e => this.onPointerMove(true, e.clientX, e.clientY)} onDrop={this.onExternalDrop.bind(this)} onContextMenu={this.onContextMenu} - onWheel={e => this._props.isContentActive(true) && e.stopPropagation()}> + onWheel={e => this._props.isContentActive() && e.stopPropagation()}> {this.renderedSections}
); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index b1d379631..d0df77cbe 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -48,7 +48,7 @@ export class CollectionPileView extends CollectionSubView() { removePileDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDoc: (doc: Doc | Doc[]) => boolean) => { (doc instanceof Doc ? [doc] : doc).forEach(d => Doc.deiconifyView(d)); const ret = this._props.moveDocument?.(doc, targetCollection, addDoc) || false; - if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this._props.DocumentView?.()._props.removeDocument?.(this.Document); + if (ret && !DocListCast(this.dataDoc[this.fieldKey ?? 'data']).length) this.DocumentView?.()._props.removeDocument?.(this.Document); return ret; }; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 22a67c501..1239a038a 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -23,7 +23,7 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; @@ -825,7 +825,7 @@ class StackedTimelineAnchor extends ObservableReactComponent (anchor.view = r))} Document={mark} TemplateDataDocument={undefined} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} pointerEvents={this.noEvents ? returnNone : undefined} styleProvider={this._props.styleProvider} renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 995f071ca..11ca62b39 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -24,7 +24,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { LightboxView } from '../LightboxView'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -265,7 +265,7 @@ export class CollectionStackingView extends CollectionSubView, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === StyleProp.Opacity && doc) { if (this._props.childOpacity) { return this._props.childOpacity(); @@ -325,9 +325,9 @@ export class CollectionStackingView extends CollectionSubView { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.IsLightboxDocView(this.docViewPath)) { this._props.setHeight?.(height); } } @@ -681,7 +681,7 @@ export class CollectionStackingView extends CollectionSubView(moreProps?: X) { - class CollectionSubView extends ViewBoxBaseComponent() { + class CollectionSubView extends ViewBoxBaseComponent() { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 18e0b98ef..76b934802 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -169,7 +169,7 @@ export class CollectionTreeView extends CollectionSubView 0 && prev) { FormattedTextBox.SetSelectOnLoad(prev); - DocumentManager.Instance.getDocumentView(prev, this._props.DocumentView?.())?.select(false); + DocumentManager.Instance.getDocumentView(prev, this.DocumentView?.())?.select(false); } return true; } @@ -347,7 +347,7 @@ export class CollectionTreeView extends CollectionSubView this._props.childLayoutTemplate?.() || Cast(this.Document.childLayoutTemplate, Doc, null); isContentActive = (outsideReaction?: boolean) => this._isContentActive; - pointerEvents = () => { - const viewPath = this._props.DocumentView?.()?._props.docViewPath(); - return ( - this.layoutDoc._lockedPosition && // - viewPath?.lastElement()?.Document?._type_collection === CollectionViewType.Freeform - ); - }; + pointerEvents = () => + this.layoutDoc._lockedPosition && // + this.Document?._type_collection === CollectionViewType.Freeform; render() { TraceMobx(); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 80808be92..2441c67e6 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,7 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -469,7 +469,7 @@ export class TabDocView extends ObservableReactComponent { dontCenter={'y'} whenChildContentsActiveChanged={this.whenChildContentActiveChanges} focus={this.focusFunc} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} bringToFront={emptyFunction} pinToPres={TabDocView.PinDoc} /> @@ -528,7 +528,7 @@ class TabMiniThumb extends React.Component { } @observer export class TabMinimapView extends ObservableReactComponent { - static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { + static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { switch (property.split(':')[0]) { default: @@ -595,10 +595,9 @@ export class TabMinimapView extends ObservableReactComponent { const ind = DocListCast(this.dataDoc[key]).indexOf(doc instanceof Doc ? doc : doc.lastElement()); const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true); - res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView._props.DocumentView?.())?.select(false); + res && ind > 0 && DocumentManager.Instance.getDocumentView(DocListCast(this.dataDoc[key])[ind - 1], this.treeView.DocumentView?.())?.select(false); return res; }; @@ -867,7 +867,7 @@ export class TreeView extends ObservableReactComponent { e.preventDefault(); } }; - titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView const treeView = this.treeView; @@ -899,7 +899,7 @@ export class TreeView extends ObservableReactComponent { } return treeView._props.styleProvider?.(doc, props, property); }; - embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; @@ -977,7 +977,7 @@ export class TreeView extends ObservableReactComponent { hideResizeHandles={this.treeView.outlineMode} styleProvider={this.titleStyleProvider} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - docViewPath={this.treeView._props.docViewPath} + containerViewPath={this.treeView.docViewPathFunc} treeViewDoc={this.treeView.Document} addDocument={undefined} addDocTab={this._props.addDocTab} @@ -1084,7 +1084,7 @@ export class TreeView extends ObservableReactComponent { ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} treeViewDoc={this.treeView?.Document} - docViewPath={this.treeView._props.docViewPath} + containerViewPath={this.treeView.docViewPathFunc} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8268a47d8..a8f22aaae 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,7 +38,7 @@ import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } fr import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../../nodes/trails/PresBox'; @@ -162,7 +162,7 @@ export class CollectionFreeFormView extends CollectionSubView { SelectionManager.DeselectAll(); - docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true)); + docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).forEach(dv => dv && SelectionManager.SelectView(dv, true)); }; addDocument = (newBox: Doc | Doc[]) => { let retVal = false; @@ -409,7 +409,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); - const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this._props.DocumentView?.())!); + const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!); const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); de.moveDocument = this._props.moveDocument; @@ -586,7 +586,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { + clusterStyleProvider = (doc: Opt, props: Opt, property: string) => { let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (doc && this.childDocList?.includes(doc)) switch (property) { @@ -629,7 +629,7 @@ export class CollectionFreeFormView extends CollectionSubView { - this._deleteList.forEach(ink => ink.props.removeDocument?.(ink.Document)); + this._deleteList.forEach(ink => ink._props.removeDocument?.(ink.Document)); this._deleteList = []; this._batch?.end(); }; @@ -714,7 +714,7 @@ export class CollectionFreeFormView extends CollectionSubView DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())) + .map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) .filter( @@ -905,7 +905,7 @@ export class CollectionFreeFormView extends CollectionSubView doc.type === DocumentType.INK && !doc.dontIntersect) .forEach(doc => { - const otherInk = DocumentManager.Instance.getDocumentView(doc, this._props.DocumentView?.())?.ComponentView as InkingStroke; + const otherInk = DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())?.ComponentView as InkingStroke; const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] }; const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point)); const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt)); @@ -979,7 +979,7 @@ export class CollectionFreeFormView extends CollectionSubView { - const collectionDoc = this._props.docViewPath().lastElement().Document; + const collectionDoc = this.Document; if (collectionDoc?._type_collection !== CollectionViewType.Freeform) { this.setPan( NumCast(this.layoutDoc[this.panXFieldKey]) + ((this._props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale @@ -1244,7 +1244,7 @@ export class CollectionFreeFormView extends CollectionSubView CollectionFreeFormView.UpdateIcon( this.layoutDoc[Id] + '-icon' + new Date().getTime(), - this._props.docViewPath().lastElement().ContentDiv!, + this.DocumentView?.().ContentDiv!, NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._height), this._props.PanelWidth(), @@ -1741,7 +1741,7 @@ export class CollectionFreeFormView extends CollectionSubView this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0; incrementalRender = action(() => { - if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath())) { + if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath)) { const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); const loadIncrement = 5; for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { @@ -1755,7 +1755,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.underlayViews} {this.contentViews} @@ -1896,6 +1896,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (!focused) { const selfFfview = !dv.Document.isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined; - let containers = dv.props.docViewPath(); + let containers = dv.containerViewPath?.() ?? []; let parFfview = dv.CollectionFreeFormView; for (var cont of containers) { parFfview = parFfview ?? cont.CollectionFreeFormView; } - while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; + while (parFfview?.Document.isGroup) parFfview = parFfview.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); - Doc.linkFollowHighlight(dv?.props.Document, false); + Doc.linkFollowHighlight(dv?.Document, false); } }); } @@ -1968,13 +1969,13 @@ ScriptingGlobals.add(function curKeyFrame(readOnly: boolean) { }); ScriptingGlobals.add(function pinWithView(pinContent: boolean) { SelectionManager.Views.forEach(view => - view.props.pinToPres(view.Document, { + view._props.pinToPres(view.Document, { currentFrame: Cast(view.Document.currentFrame, 'number', null), pinData: { poslayoutview: pinContent, dataview: pinContent, }, - pinViewport: MarqueeView.CurViewBounds(view.Document, view.props.PanelWidth(), view.props.PanelHeight()), + pinViewport: MarqueeView.CurViewBounds(view.Document, view._props.PanelWidth(), view._props.PanelHeight()), }) ); }); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index d105b04f7..54ade031b 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -147,8 +147,8 @@ export class CollectionLinearView extends CollectionSubView() { switch (doc.layout) { case '': return this.getLinkUI(); case '': return this.getCurrentlyPlayingUI(); - case '': return ; - case '': return Doc.UserDoc().isBranchingMode ? : null; + case '': return ; + case '': return Doc.UserDoc().isBranchingMode ? : null; } const nested = doc._type_collection === CollectionViewType.Linear; @@ -189,7 +189,7 @@ export class CollectionLinearView extends CollectionSubView() { dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this._props.styleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={this.docViewPathFunc} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} childFilters={this._props.childFilters} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 563084af8..dd1305465 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -127,7 +127,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._xMargin); + return this._props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._xMargin); } } @@ -259,14 +259,14 @@ export class CollectionMulticolumnView extends CollectionSubView() { Document={childLayout} TemplateDataDocument={childLayout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.docViewPathFunc} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} PanelWidth={width} PanelHeight={height} rootSelected={this.rootSelected} - dragAction={(this._props.Document.childDragAction ?? this._props.childDragAction) as dropActionType} + dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} suppressSetHeight={true} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index bf0d39197..48c4173d6 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -122,7 +122,7 @@ export class CollectionMultirowView extends CollectionSubView() { private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation.heightSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this._props.Document._yMargin); + return this._props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this.Document._yMargin); } } @@ -254,14 +254,14 @@ export class CollectionMultirowView extends CollectionSubView() { Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - docViewPath={this._props.docViewPath} + containerViewPath={this.docViewPathFunc} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} PanelWidth={width} PanelHeight={height} rootSelected={this.rootSelected} - dropAction={StrCast(this.Document.childDragAction) as dropActionType} + dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} @@ -270,7 +270,6 @@ export class CollectionMultirowView extends CollectionSubView() { hideResizeHandles={layout.layout_fitWidth || this._props.childHideResizeHandles ? true : false} hideDecorationTitle={this._props.childHideDecorationTitle} fitContentsToBox={this._props.fitContentsToBox} - dragAction={this._props.childDragAction} focus={this._props.focus} childFilters={this.childDocFilters} childFiltersByRanges={this.childDocRangeFilters} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 492aed0ea..09352d7a4 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,7 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -907,7 +907,7 @@ export class CollectionSchemaView extends CollectionSubView() { childFiltersByRanges={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} moveDocument={this._props.moveDocument} addDocument={this.addRow} removeDocument={this._props.removeDocument} @@ -962,7 +962,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent this._props.schema.tableWidth; screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); - noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { + noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { if (property === StyleProp.Opacity) return 1; return DefaultStyleProvider(doc, props, property); }; @@ -971,6 +971,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent() { +export class SchemaRowBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string, rowIndex: number) { return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`); } @@ -38,11 +38,11 @@ export class SchemaRowBox extends ViewBoxBaseComponent this._ref?.getBoundingClientRect(); @computed get schemaView() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.ComponentView as CollectionSchemaView; + return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionSchemaView; } @computed get schemaDoc() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this.DocumentView?.().containerViewPath?.().lastElement()?.Document; } @computed get rowIndex() { diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 85269028b..422c4155d 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -77,7 +77,6 @@ export class SchemaTableCell extends ObservableReactComponent dv.ComponentView instanceof InkingStroke) && SetActiveFillColor(color ?? 'transparent'); selectedViews.forEach(dv => { const fieldKey = dv.Document.type === DocumentType.INK ? 'fillColor' : 'backgroundColor'; - const layoutFrameNumber = Cast(dv._props.docViewPath().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const layoutFrameNumber = Cast(dv.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values const contentFrameNumber = Cast(dv.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed if (contentFrameNumber !== undefined) { const obj: { [key: string]: Opt } = {}; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 85e97f95f..dc4aee1ca 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -136,6 +136,7 @@ export class LinkMenuItem extends ObservableReactComponent { deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this._props.linkDoc)))); @observable _hover = false; + docView = () => this.props.docView; render() { const destinationIcon = Doc.toIcon(this._props.destinationDoc) as any as IconProp; @@ -179,7 +180,8 @@ export class LinkMenuItem extends ObservableReactComponent { this._props.linkDoc && this._props.clearLinkEditor && LinkInfo.SetLinkInfo({ - docProps: this._props.docView._props, + DocumentView: this.docView, + styleProvider: this._props.docView._props.styleProvider, linkSrc: this._props.sourceDoc, linkDoc: this._props.linkDoc, showHeader: false, diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 7e344dd7a..31841c596 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -69,7 +69,6 @@ export class LinkPopup extends React.Component { isSelected={returnTrue} isContentActive={returnTrue} select={returnTrue} - setHeight={returnFalse} addDocument={undefined} addDocTab={returnTrue} pinToPres={emptyFunction} @@ -81,7 +80,6 @@ export class LinkPopup extends React.Component { PanelHeight={this.getPHeight} renderDepth={0} focus={emptyFunction} - docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} childFilters={returnEmptyFilter} diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index 3d159c3e3..6760a0b1e 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -302,7 +302,7 @@ export class NewLightboxView extends React.Component { styleProvider={DefaultStyleProvider} ScreenToLocalTransform={this.newLightboxScreenToLocal} renderDepth={0} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} childFilters={this.docFilters} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 908cd5dc0..1729af191 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -211,7 +211,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { // removes from currently playing display @action removeCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (CollectionStackedTimeline.CurrentlyPlaying && docView) { const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView); index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1); @@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { // adds doc to currently playing display @action addCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (!CollectionStackedTimeline.CurrentlyPlaying) { CollectionStackedTimeline.CurrentlyPlaying = []; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index ad5aabc21..83cabf355 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -15,7 +15,7 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import { FieldViewProps } from './FieldView'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { @@ -149,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === this.layoutDoc) { switch (property) { case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children @@ -229,7 +229,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { const topDoc = this.Document; - const containerDocView = this._props.docViewPath().lastElement(); + const containerDocView = this._props.containerViewPath?.().lastElement(); const screenXf = containerDocView?.screenToContentsTransform(); if (screenXf) { SelectionManager.DeselectAll(); @@ -252,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { - const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y); + const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); this._props.Document.x = this._props.w_X() + locX; this._props.Document.y = this._props.w_Y() + locY; }; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 5e7e568b0..b171db17c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView'; +import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent this.clearDoc(which) ); }; - docStyleProvider = (doc: Opt, props: Opt, property: string): any => { + docStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; return this._props.styleProvider?.(doc, props, property); }; @@ -178,6 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class DataVizBox extends ViewBoxAnnotatableComponent() { private _mainCont: React.RefObject = React.createRef(); - private _ffref = React.createRef(); private _marqueeref = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; - @observable schemaDataVizChildren: any = undefined; + @observable _schemaDataVizChildren: any = undefined; @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); + + constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { + super(props); + makeObservable(this); + this._props.setContentView?.(this); + } + @computed get annotationLayer() { TraceMobx(); return
; } marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.Document._freeform_scale, 1) <= NumCast(this.Document.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -211,12 +216,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { .ScreenToLocalTransform() .scale(this._props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); - const fullWidth = this._props.width; - const mapWidth = fullWidth! - this.sidebarWidth(); + const fullWidth = NumCast(this.layoutDoc._width); + const mapWidth = fullWidth - this.sidebarWidth(); if (this.sidebarWidth() + localDelta[0] > 0) { this.layoutDoc._layout_showSidebar = true; - this.layoutDoc._width = fullWidth! + localDelta[0]; - this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%'; + this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; + this.layoutDoc._width = fullWidth + localDelta[0]; } else { this.layoutDoc._layout_showSidebar = false; this.layoutDoc._width = mapWidth; @@ -269,12 +274,12 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { axes: this.axes, //width: this.SidebarShown? this._props.PanelWidth()*.9/1.2: this._props.PanelWidth() * 0.9, height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9, - width: (this._props.PanelWidth() / scale) * 0.9, + width: ((this._props.PanelWidth() - this.sidebarWidth()) / scale) * 0.9, margin: { top: 10, right: 25, bottom: 75, left: 45 }, }; if (!this.records.length) return 'no data/visualization'; switch (this.dataVizView) { - case DataVizView.TABLE: return ; + case DataVizView.TABLE: return ; case DataVizView.LINECHART: return (this._vizRenderer = r ?? undefined)} vizBox={this} />; case DataVizView.HISTOGRAM: return (this._vizRenderer = r ?? undefined)} />; case DataVizView.PIECHART: return (this._vizRenderer = r ?? undefined)} @@ -285,7 +290,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @action onPointerDown = (e: React.PointerEvent): void => { if ((this.Document._freeform_scale || 1) !== 1) return; - if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this._props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeing = [e.clientX, e.clientY]; @@ -345,7 +350,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { render() { if (this.layoutDoc && this.layoutDoc.dataViz_asSchema) { - this.schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length; + this._schemaDataVizChildren = DocListCast(DocCast(this.layoutDoc.dataViz_asSchema)[Doc.LayoutFieldKey(DocCast(this.layoutDoc.dataViz_asSchema))]).length; this.updateSchemaViz(); } @@ -366,7 +371,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }} onWheel={e => e.stopPropagation()} ref={this._mainCont}> -
+
(this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz === DataVizView.TABLE} /> (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz === DataVizView.LINECHART} /> (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz === DataVizView.HISTOGRAM} /> @@ -414,7 +419,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() {
{this.sidebarHandle} {this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( () { scrollTop={0} annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)} scaling={returnOne} - docView={this._props.DocumentView!} + docView={this.DocumentView} addDocument={this.sidebarAddDocument} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 4cc7fe4c8..0d76959af 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -116,11 +116,12 @@ export class HTMLtag extends React.Component { @observer export class DocumentContentsView extends ObservableReactComponent< - DocumentViewProps & - FieldViewProps & { - setHeight?: (height: number) => void; - layout_fieldKey: string; - } + FieldViewProps & { + layout_fieldKey: string; + LayoutTemplateString?: string; + onClick?: () => ScriptField; + LayoutTemplate?: () => Opt; + } > { constructor(props: any) { super(props); diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index dfd610581..25f56e69a 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -25,7 +25,7 @@ export class DocumentIcon extends ObservableReactComponent { } static get DocViews() { - return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v._props.docViewPath())) : DocumentManager.Instance.DocumentViews; + return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v.docViewPath)) : DocumentManager.Instance.DocumentViews; } render() { const view = this._props.view; diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index c549a146a..f5949a451 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -152,8 +152,8 @@ export class DocumentLinksButton extends ObservableReactComponent Opt; -export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; +export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { fieldKey?: string; annotationKey?: string; @@ -143,20 +143,31 @@ export interface DocComponentView { snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; } -// These props are passed to both FieldViews and DocumentViews +/** + * props that DocumentViews, DocumentInternalViews and FieldViews all can use + * */ export interface DocumentViewSharedProps { - renderDepth: number; Document: Doc; TemplateDataDocument?: Doc; + renderDepth: number; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document - DocumentView?: () => DocumentView; + treeViewDoc?: Doc; + xPadding?: number; + yPadding?: number; + dontRegisterView?: boolean; + dropAction?: dropActionType; + dragAction?: dropActionType; + forceAutoHeight?: boolean; + ignoreAutoHeight?: boolean; + disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active setContentView?: (view: DocComponentView) => any; PanelWidth: () => number; PanelHeight: () => number; - docViewPath: () => DocumentView[]; + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive: () => boolean | undefined; // whether document contents should handle pointer events childFilters: () => string[]; childFiltersByRanges: () => string[]; styleProvider: Opt; @@ -178,29 +189,12 @@ export interface DocumentViewSharedProps { waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; defaultDoubleClick?: () => 'default' | 'ignore' | undefined; pointerEvents?: () => Opt; - treeViewDoc?: Doc; - xPadding?: number; - yPadding?: number; - dontRegisterView?: boolean; - childHideDecorationTitle?: boolean; - childHideResizeHandles?: boolean; - childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. - dropAction?: dropActionType; - dragAction?: dropActionType; - dragWhenActive?: boolean; - dontHideOnDrag?: boolean; - hideLinkButton?: boolean; - hideCaptions?: boolean; - ignoreAutoHeight?: boolean; - forceAutoHeight?: boolean; - suppressSetHeight?: boolean; - disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. - onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected } -// these props are specific to DocuentViews +/** + * props that are used by DocumentViews and DocumentInternalViews but not by the contents of those views (FieldViews). + */ export interface DocumentViewProps extends DocumentViewSharedProps { - // properties specific to DocumentViews but not to FieldView hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings @@ -209,15 +203,22 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideOpenButton?: boolean; hideDeleteButton?: boolean; hideLinkAnchors?: boolean; + hideLinkButton?: boolean; + hideCaptions?: boolean; contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents LayoutTemplateString?: string; dontCenter?: 'x' | 'y' | 'xy'; - isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events - isContentActive: () => boolean | undefined; // whether document contents should handle pointer events + childHideDecorationTitle?: boolean; + childHideResizeHandles?: boolean; + childDragAction?: dropActionType; // allows child documents to be dragged out of collection without holding the embedKey or dragging the doc decorations title bar. + dragWhenActive?: boolean; + dontHideOnDrag?: boolean; + suppressSetHeight?: boolean; + onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected NativeWidth?: () => number; NativeHeight?: () => number; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to FieldViewProps LayoutTemplate?: () => Opt; + containerViewPath?: () => DocumentView[]; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; onClick?: () => ScriptField; onDoubleClick?: () => ScriptField; @@ -229,12 +230,18 @@ export interface DocumentViewProps extends DocumentViewSharedProps { dragEnding?: () => void; } -// these props are only available in DocumentViewIntenral -export interface DocumentViewInternalProps extends DocumentViewProps { - isSelected: () => boolean; +/** + * props used by DocInternalViews and FieldViews but not DocumentViews + * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop + */ +export interface DocumentViewInternalSharedProps { + DocumentView?: () => DocumentView; select: (ctrlPressed: boolean, shiftPress?: boolean) => void; - DocumentView: () => DocumentView; - viewPath: () => DocumentView[]; + isSelected: () => boolean; + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal +} +export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { + docViewPath: () => DocumentView[]; } @observer @@ -265,17 +272,24 @@ export class DocumentViewInternal extends DocComponent; + return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowTitle) as Opt; } @computed get NativeDimScaling() { return this._props.NativeDimScaling?.() || 1; @@ -284,32 +298,32 @@ export class DocumentViewInternal extends DocComponent this._props.styleProvider?.(this.Document, this._props, StyleProp.PointerEvents), + () => this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.PointerEvents), pointerevents => (this._pointerEvents = pointerevents), { fireImmediately: true } ); @@ -378,32 +392,32 @@ export class DocumentViewInternal extends DocComponent disposer?.()); } startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) { if (this._mainCont.current) { - const views = SelectionManager.Views.filter(dv => dv.docView?._mainCont.current); - const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()]; + const views = SelectionManager.Views.filter(dv => dv.ContentDiv); + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.DocumentView()]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const screenXf = this.props.DocumentView().screenToViewTransform(); + const screenXf = this.DocumentView().screenToViewTransform(); const [left, top] = screenXf.inverse().transformPoint(0, 0); dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; dragData.moveDocument = this._props.moveDocument; - dragData.draggedViews = [this._props.DocumentView()]; + dragData.draggedViews = [this.DocumentView()]; dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false; DragManager.StartDocumentDrag( - selected.map(dv => dv.docView!._mainCont.current!), + selected.map(dv => dv.ContentDiv!), dragData, x, y, @@ -443,7 +457,7 @@ export class DocumentViewInternal extends DocComponent this.onDoubleClickHandler.script.run( { this: this.Document, scriptContext: this._props.scriptContext, - documentView: this._props.DocumentView(), + documentView: this.DocumentView(), clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); @@ -451,7 +465,7 @@ export class DocumentViewInternal extends DocComponent LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); SelectionManager.DeselectAll(); - Doc.UnBrushDoc(this._props.Document); + Doc.UnBrushDoc(this.Document); } else { this._singleClickFunc?.(); } @@ -474,7 +488,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this._props.DocumentView()._props.bringToFront(this.Document, true) : + clickFunc ?? (() => (sendToBack ? this.DocumentView()._props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this._props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -522,7 +536,7 @@ export class DocumentViewInternal extends DocComponent this._props.removeDocument?.(this._props.Document); + @undoBatch deleteClicked = () => this._props.removeDocument?.(this.Document); @undoBatch setToggleDetail = () => (this.Document.onClick = ScriptField.MakeScript( `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) @@ -612,7 +626,7 @@ export class DocumentViewInternal extends DocComponent { if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; - if (this._props.Document === Doc.ActiveDashboard) { + if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); e.preventDefault(); alert( @@ -634,7 +648,7 @@ export class DocumentViewInternal extends DocComponent { - const portalLink = this.allLinks.find(d => d.link_anchor_1 === this._props.Document && d.link_relationship === 'portal to:portal from'); + const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( - this._props.Document, + this.Document, Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: Math.max(NumCast(this.layoutDoc._height), NumCast(this.layoutDoc._width) + 10), _isLightbox: true, _layout_fitWidth: true, - title: StrCast(this._props.Document.title) + ' [Portal]', + title: StrCast(this.Document.title) + ' [Portal]', }), { link_relationship: 'portal to:portal from' } ); @@ -686,7 +700,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this._props.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -719,14 +733,14 @@ export class DocumentViewInternal extends DocComponent cm.addItem({ description: label, event: () => customScripts[i]?.script.run({ documentView: this, this: this.Document, scriptContext: this._props.scriptContext }), icon: 'sticky-note' }) ); this._props.contextMenuItems?.().forEach(item => item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.Document, scriptContext: this._props.scriptContext }), icon: item.icon as IconProp })); - if (!this._props.Document.isFolder) { - const templateDoc = Cast(this._props.Document[StrCast(this._props.Document.layout_fieldKey)], Doc, null); + if (!this.Document.isFolder) { + const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null); const appearance = cm.findByDescription('Appearance...'); const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : []; @@ -764,7 +778,7 @@ export class DocumentViewInternal extends DocComponent this.toggleFollowLink(false, false), icon: 'link' }); - !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this._props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); + !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } else if (LinkManager.Links(this.Document).length) { onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' }); @@ -786,15 +800,15 @@ export class DocumentViewInternal extends DocComponent Doc.MakeMetadataFieldTemplate(this._props.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); + moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); moreItems.push({ description: `${this.Document._chromeHidden ? 'Show' : 'Hide'} Chrome`, event: () => (this.Document._chromeHidden = !this.Document._chromeHidden), icon: 'project-diagram' }); - if (Cast(Doc.GetProto(this._props.Document).data, listSpec(Doc))) { - moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this._props.Document }).then(console.log), icon: 'caret-square-right' }); - moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this._props.Document), icon: 'caret-square-right' }); - moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this._props.Document), icon: 'caret-square-right' }); + if (Cast(Doc.GetProto(this.Document).data, listSpec(Doc))) { + moreItems.push({ description: 'Export to Google Photos Album', event: () => GooglePhotos.Export.CollectionToAlbum({ collection: this.Document }).then(console.log), icon: 'caret-square-right' }); + moreItems.push({ description: 'Tag Child Images via Google Photos', event: () => GooglePhotos.Query.TagChildImages(this.Document), icon: 'caret-square-right' }); + moreItems.push({ description: 'Write Back Link to Album', event: () => GooglePhotos.Transactions.AddTextEnrichment(this.Document), icon: 'caret-square-right' }); } - moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this._props.Document)), icon: 'fingerprint' }); + moreItems.push({ description: 'Copy ID', event: () => Utils.CopyText(Doc.globalServerPath(this.Document)), icon: 'fingerprint' }); } } @@ -802,14 +816,14 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this._props.Document) }); - (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._props.DocumentView()), icon: 'users' }); - if (this._props.removeDocument && Doc.ActiveDashboard !== this._props.Document) { + constantItems.push({ description: 'Zip Export', icon: 'download', event: async () => Doc.Zip(this.Document) }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.DocumentView()), icon: 'users' }); + if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); } } - constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this._props.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' }); + constantItems.push({ description: 'Show Metadata', event: () => this._props.addDocTab(this.Document, OpenWhere.addRightKeyvalue), icon: 'table-columns' }); cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); @@ -820,7 +834,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin); + screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -912,7 +926,6 @@ export class DocumentViewInternal extends DocComponent this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -976,7 +989,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); @observable _changingTitleField = false; @observable _dropDownInnerWidth = 0; fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { @@ -1266,10 +1279,10 @@ export class DocumentViewInternal extends DocComponent { @computed public static get exploreMode() { return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } - @observable public docView: DocumentViewInternal | undefined | null = undefined; - @observable public textHtmlOverlay: Opt = undefined; - @observable public textHtmlOverlayTime: Opt = undefined; + @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; + @observable private _htmlOverlayText: Opt = undefined; @observable private _isHovering = false; + private _htmlOverlayEffect: Opt; - public htmlOverlayEffect: Opt; public get displayName() { - return 'DocumentView(' + this._props.Document?.title + ')'; + return 'DocumentView(' + this.Document?.title + ')'; } // this makes mobx trace() statements more descriptive public ContentRef = React.createRef(); public ViewTimer: NodeJS.Timeout | undefined; // timer for res @@ -1349,10 +1361,26 @@ export class DocumentView extends ObservableReactComponent { this.ViewTimer && clearTimeout(this.ViewTimer); this.layoutDoc._viewTransition = undefined; }; - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource); - - public showContextMenu = (pageX: number, pageY: number) => this.docView?.onContextMenu(undefined, pageX, pageY); - + playAnnotation = () => this._docViewInternal?.playAnnotation(); + noOnClick = () => this._docViewInternal?.noOnClick(); + makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); + setToggleDetail = () => this._docViewInternal?.setToggleDetail(); + onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); + cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); + public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + + public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); + + public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { + this._htmlOverlayText = text; + this._htmlOverlayEffect = effect; + }); + public setAnimateScaling = action((scale: number, time?: number) => { + if (this._docViewInternal) { + this._docViewInternal._animateScalingTo = scale; + this._docViewInternal._animateScaleTime = time; + } + }); public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); this.Document[Animation] = presEffect; @@ -1391,10 +1419,11 @@ export class DocumentView extends ObservableReactComponent { DocServer.GetRefField(docId).then(docx => LightboxView.Instance.SetLightboxDoc( (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, updateContentsScript: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) ) ); } + toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); get Document() { return this._props.Document; @@ -1403,19 +1432,19 @@ export class DocumentView extends ObservableReactComponent { return this._props.renderDepth === 0; } get dataDoc() { - return this.docView?.dataDoc ?? this.Document; + return this._docViewInternal?.dataDoc ?? this.Document; } get ContentDiv() { - return this.docView?.ContentDiv; + return this._docViewInternal?.ContentDiv; } get ComponentView() { - return this.docView?._componentView; + return this._docViewInternal?._componentView; } get allLinks() { - return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); + return (this._docViewInternal?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); } get LayoutFieldKey() { - return this.docView?.LayoutFieldKey || 'layout'; + return this._docViewInternal?.LayoutFieldKey || 'layout'; } @computed get layout_fitWidth() { return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; @@ -1439,8 +1468,17 @@ export class DocumentView extends ObservableReactComponent { @computed get linkCountView() { return ; } + /** + * path of DocumentViews terminating in the DocumentView that contains this DocumentView + */ + @computed get containerViewPath() { + return this._props.containerViewPath; + } + /** + * path of DocumentViews terminating in this DocumentView + */ @computed get docViewPath(): DocumentView[] { - return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this]; + return this.containerViewPath ? [...this.containerViewPath(), this] : [this]; } @computed get layoutDoc() { return Doc.Layout(this.Document, this._props.LayoutTemplate?.()); @@ -1502,19 +1540,19 @@ export class DocumentView extends ObservableReactComponent { return this._props.CollectionFreeFormDocumentView?.(); } - public toggleNativeDimensions = () => this.docView && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); + public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this._docViewInternal.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); public getBounds = () => { - if (!this.docView?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this._props.Document, Doc.UserDoc())) { + if (!this._docViewInternal?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { return undefined; } - if (this.docView._componentView?.screenBounds?.()) { - return this.docView._componentView.screenBounds(); + if (this._docViewInternal._componentView?.screenBounds?.()) { + return this._docViewInternal._componentView.screenBounds(); } - const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse(); + const xf = this._docViewInternal._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); + if (this._docViewInternal._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + const docuBox = this._docViewInternal.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } return { left, top, right, bottom }; @@ -1522,11 +1560,11 @@ export class DocumentView extends ObservableReactComponent { public iconify(finished?: () => void, animateTime?: number) { this.ComponentView?.updateIcon?.(); - const animTime = this.docView?._animateScaleTime; - runInAction(() => this.docView && animateTime !== undefined && (this.docView._animateScaleTime = animateTime)); + const animTime = this._docViewInternal?._animateScaleTime; + runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime)); const finalFinished = action(() => { finished?.(); - this.docView && (this.docView._animateScaleTime = animTime); + this._docViewInternal && (this._docViewInternal._animateScaleTime = animTime); }); const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null); if (layout_fieldKey !== 'layout_icon') { @@ -1541,12 +1579,12 @@ export class DocumentView extends ObservableReactComponent { } @undoBatch setCustomView = (custom: boolean, layout: string): void => { - Doc.setNativeView(this._props.Document); - custom && DocUtils.makeCustomViewClicked(this._props.Document, Docs.Create.StackingDocument, layout, undefined); + Doc.setNativeView(this.Document); + custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined); }; switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { - runInAction(() => this.docView && (this.docView._animateScalingTo = 0.1)); // shrink doc + runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc setTimeout( action(() => { if (useExistingLayout && custom && this.Document['layout_' + view]) { @@ -1554,16 +1592,16 @@ export class DocumentView extends ObservableReactComponent { } else { this.setCustomView(custom, view); } - this.docView && (this.docView._animateScalingTo = 1); // expand it + this._docViewInternal && (this._docViewInternal._animateScalingTo = 1); // expand it setTimeout( action(() => { - this.docView && (this.docView._animateScalingTo = 0); + this._docViewInternal && (this._docViewInternal._animateScalingTo = 0); finished?.(); }), - this.docView ? Math.max(0, this.docView.animateScaleTime - 10) : 0 + this._docViewInternal ? Math.max(0, this._docViewInternal.animateScaleTime - 10) : 0 ); }), - this.docView ? Math.max(0, this.docView?.animateScaleTime - 10) : 0 + this._docViewInternal ? Math.max(0, this._docViewInternal?.animateScaleTime - 10) : 0 ); }; @@ -1606,29 +1644,21 @@ export class DocumentView extends ObservableReactComponent { componentDidMount() { runInAction(() => this.Document[DocViews].add(this)); - this._disposers.updateContentsScript = reaction(() => ScriptCast(this.Document.updateContentsScript)?.script?.run({ this: this.Document }).result, emptyFunction); - this._disposers.height = reaction( - // increase max auto height if document has been resized to be greater than current max - () => NumCast(this.layoutDoc._height), - action(height => { - const docMax = NumCast(this.layoutDoc.layout_maxAutoHeight); - if (docMax && docMax < height) this.layoutDoc.layout_maxAutoHeight = height; - }) - ); - !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); + this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); } componentWillUnmount() { - this.Document[DocViews].delete(this); + runInAction(() => this.Document[DocViews].delete(this)); Object.values(this._disposers).forEach(disposer => disposer?.()); - !BoolCast(this._props.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. // unfortunately, CSS can't transition animate any properties for something that is display 'none'. // so we need to first activate the div, then, after a render timeout, start the opacity transition. @observable enableHtmlOverlayTransitions: boolean = false; @computed get htmlOverlay() { - const effect = StrCast(this.htmlOverlayEffect?.presentation_effect, StrCast(this.htmlOverlayEffect?.followLinkAnimEffect)); + const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect)); return (
{ setTimeout(action(() => (this.enableHtmlOverlayTransitions = val))); } }} - style={{ display: !this.textHtmlOverlay ? 'none' : undefined }}> + style={{ display: !this._htmlOverlayText ? 'none' : undefined }}>
{DocumentViewInternal.AnimationEffect(
- console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this.textHtmlOverlay)} /> + console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} />
, - { ...(this.htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, + { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Zoom } as any as Doc, this.Document )}
@@ -1663,7 +1693,7 @@ export class DocumentView extends ObservableReactComponent { return (
(this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))}> - {!this._props.Document || !this._props.PanelWidth() ? null : ( + {!this.Document || !this._props.PanelWidth() ? null : (
{ { layout_fitWidth={this.layout_fitWidthFunc} ScreenToLocalTransform={this.screenToContentsTransform} focus={this._props.focus || emptyFunction} - ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} + ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))} /> {this.htmlOverlay} {this.infoUI} diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index ff92c701f..ebad257ac 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -27,7 +27,7 @@ export class EquationBox extends ViewBoxBaseComponent() { componentDidMount() { this._props.setContentView?.(this); - if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) { + if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { this._props.select(false); this._ref.current!.mathField.focus(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 008f10f26..b456807d7 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -6,23 +6,18 @@ import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; import { WebField } from '../../../fields/URLField'; -import { DocumentViewSharedProps } from './DocumentView'; +import { DocumentView, DocumentViewInternalSharedProps, DocumentViewSharedProps } from './DocumentView'; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // -export interface FieldViewProps extends DocumentViewSharedProps { +export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInternalSharedProps { // FieldView specific props that are not part of DocumentView props fieldKey: string; - select: (isCtrlPressed: boolean) => void; - isContentActive: (outsideReaction?: boolean) => boolean | undefined; - isDocumentActive?: () => boolean | undefined; - isSelected: () => boolean; setHeight?: (height: number) => void; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal NOTE: Must also be added to DocumentViewInternalsProps onBrowseClick?: () => ScriptField | undefined; onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; pointerEvents?: () => Opt; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index a5853499f..4483d12ce 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); + const scaling = (this.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); const nscale = NumCast(this._props.PanelWidth()) / scaling; const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; @@ -368,7 +368,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -444,7 +444,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent {this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( { }; render() { - const props: FieldViewProps = { - Document: this._props.doc, - childFilters: returnEmptyFilter, - childFiltersByRanges: returnEmptyFilter, - searchFilterDocs: returnEmptyDoclist, - styleProvider: DefaultStyleProvider, - docViewPath: returnEmptyDoclist, - fieldKey: this._props.keyName, - isSelected: returnFalse, - setHeight: returnFalse, - select: emptyFunction, - bringToFront: emptyFunction, - renderDepth: 1, - isContentActive: returnFalse, - whenChildContentsActiveChanged: emptyFunction, - ScreenToLocalTransform: Transform.Identity, - focus: emptyFunction, - PanelWidth: this._props.PanelWidth, - PanelHeight: this._props.PanelHeight, - addDocTab: returnFalse, - pinToPres: returnZero, - }; // let fieldKey = Object.keys(props.Document).indexOf(props.fieldKey) !== -1 ? props.fieldKey : "(" + props.fieldKey + ")"; let protoCount = 0; - let doc: Doc | undefined = props.Document; + let doc = this._props.doc; while (doc) { - if (Object.keys(doc).includes(props.fieldKey)) { + if (Object.keys(doc).includes(this._props.keyName)) { break; } protoCount++; @@ -106,17 +84,17 @@ export class KeyValuePair extends ObservableReactComponent { style={hover} className="keyValuePair-td-key-delete" onClick={undoBatch(() => { - if (Object.keys(props.Document).indexOf(props.fieldKey) !== -1) { - delete props.Document[props.fieldKey]; - } else delete DocCast(props.Document.proto)?.[props.fieldKey]; + if (Object.keys(this._props.doc).indexOf(this._props.keyName) !== -1) { + delete this._props.doc[this._props.keyName]; + } else delete DocCast(this._props.doc.proto)?.[this._props.keyName]; })}> X - pair[0].replace(/^_/, '') === props.fieldKey)?.[1].description ?? ''}> -
+ pair[0].replace(/^_/, '') === this._props.keyName)?.[1].description ?? ''}> +
{'('.repeat(parenCount)} - {props.fieldKey} + {this._props.keyName} {')'.repeat(parenCount)}
@@ -124,7 +102,32 @@ export class KeyValuePair extends ObservableReactComponent {
- Field.toKeyValueString(props.Document, props.fieldKey)} SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} /> + Field.toKeyValueString(this._props.doc, this._props.keyName)} + SetValue={(value: string) => KeyValueBox.SetField(this._props.doc, this._props.keyName, value)} + />
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index b86ba72a0..864c1955b 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -7,13 +7,13 @@ import { TraceMobx } from '../../../fields/util'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; -import { ViewBoxBaseComponent } from '../DocComponent'; +import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore -export class LinkAnchorBox extends ViewBoxBaseComponent() { +export class LinkAnchorBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } @@ -33,12 +33,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { } @computed get linkSource() { - return this._props.docViewPath()[this._props.docViewPath().length - 2].Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource); + return this.containerViewPath?.().lastElement().Document; // this._props.styleProvider?.(this.dataDoc, this._props, StyleProp.LinkSource); } onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { - if (doubleTap) LinkFollower.FollowLink(this.Document, this.linkSource, false); + const linkSource = this.linkSource; + linkSource && setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { + if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); else this._props.select(false); }); }; @@ -86,7 +87,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { className={`linkAnchorBox-cont${small ? '-small' : ''}`} onPointerEnter={e => LinkInfo.SetLinkInfo({ - docProps: this._props, + DocumentView: this.DocumentView, + styleProvider: this._props.styleProvider, linkSrc: this.linkSource, linkDoc: this.Document, showHeader: true, diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 7f1d41547..4221f464d 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent() { @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1; - return DocumentManager.Instance.getDocumentView(anchor_1, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_1, this.containerViewPath?.().lastElement()); } @computed get anchor2() { const anchor2 = DocCast(this.dataDoc.link_anchor_2); const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2; - return DocumentManager.Instance.getDocumentView(anchor_2, this._props.docViewPath()[this._props.docViewPath().length - 2]); // this._props.docViewPath().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_2, this.containerViewPath?.().lastElement()); } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { @@ -66,7 +66,7 @@ export class LinkBox extends ViewBoxBaseComponent() { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; - const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; + const parxf = this.containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); const a_invXf = a.screenToViewTransform().inverse(); const b_invXf = b.screenToViewTransform().inverse(); @@ -161,12 +161,11 @@ export class LinkBox extends ViewBoxBaseComponent() { return (
; @@ -43,7 +44,8 @@ export class LinkInfo { interface LinkDocPreviewProps { linkDoc?: Doc; linkSrc?: Doc; - docProps: DocumentViewSharedProps; + DocumentView?: () => DocumentView; + styleProvider?: StyleProviderFunc; location: number[]; hrefs?: string[]; showHeader?: boolean; @@ -152,7 +154,7 @@ export class LinkDocPreview extends ObservableReactComponent { LinkManager.currentLink = this._linkDoc; LinkManager.currentLinkAnchor = this._linkSrc; - this._props.docProps.DocumentView?.().select(false); + this._props.DocumentView?.().select(false); if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) { SettingsManager.Instance.propertiesWidth = 250; } @@ -269,8 +271,8 @@ export class LinkDocPreview extends ObservableReactComponent { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { diff --git a/src/client/views/nodes/MapBox/MapPushpinBox.tsx b/src/client/views/nodes/MapBox/MapPushpinBox.tsx index 34e237007..fc5b4dd18 100644 --- a/src/client/views/nodes/MapBox/MapPushpinBox.tsx +++ b/src/client/views/nodes/MapBox/MapPushpinBox.tsx @@ -18,10 +18,10 @@ export class MapPushpinBox extends ViewBoxBaseComponent() { } get mapBoxView() { - return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; + return this.DocumentView?.()?.containerViewPath?.().lastElement()?.ComponentView as MapBox; } get mapBox() { - return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this.DocumentView?.().containerViewPath?.().lastElement()?.Document; } render() { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index ea8496c99..e079f7457 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -228,11 +228,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, 'yellow'); FormattedTextBox.SetSelectOnLoad(target); return target; }; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 959d5d88d..71c1b6a4c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -102,7 +102,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { // currently we render pdf icons as text labels - const docViewContent = this._props.docViewPath().lastElement().ContentDiv!; + const docViewContent = this.DocumentView?.().ContentDiv!; const filename = this.layoutDoc[Id] + '-icon' + new Date().getTime(); this._pdfViewer?._mainCont.current && CollectionFreeFormView.UpdateIcon( @@ -304,7 +304,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { this._pdfViewer = pdfViewer; - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (this._initialScrollTarget && docView) { this.focus(this._initialScrollTarget, { instant: true }); this._initialScrollTarget = undefined; @@ -525,7 +525,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent ) : ( -
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> () { +export class VideoBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } @@ -608,7 +608,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { // removes from currently playing display @action removeCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (CollectionStackedTimeline.CurrentlyPlaying && docView) { const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView); index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1); @@ -617,7 +617,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { // adds doc to currently playing display @action addCurrentlyPlaying = () => { - const docView = this._props.DocumentView?.(); + const docView = this.DocumentView?.(); if (!CollectionStackedTimeline.CurrentlyPlaying) { CollectionStackedTimeline.CurrentlyPlaying = []; } @@ -749,7 +749,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { // starts marquee selection marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -941,7 +941,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { style={{ pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, - overflow: this._props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined, + overflow: this.DocumentView?.().layout_fitWidth ? 'auto' : undefined, }}>
() {
{this.annotationLayer} - {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : ( () { annotationLayerScrollTop={0} scaling={returnOne} annotationLayerScaling={this._props.NativeDimScaling} - docView={this._props.DocumentView!} + docView={this.DocumentView} containerOffset={this.marqueeOffset} addDocument={this.addDocWithTimecode} finishMarquee={this.finishMarquee} @@ -1004,7 +1004,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { } @computed get UIButtons() { - const bounds = this._props.docViewPath().lastElement().getBounds(); + const bounds = this.DocumentView?.().getBounds(); const width = (bounds?.right || 0) - (bounds?.left || 0); const curTime = NumCast(this.layoutDoc._layout_currentTimecode); return ( diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c3be2b390..86709e4d7 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -33,7 +33,7 @@ import { Annotation } from '../pdf/Annotation'; import { GPTPopup } from '../pdf/GPTPopup/GPTPopup'; import { SidebarAnnos } from '../SidebarAnnos'; import { StyleProp } from '../StyleProvider'; -import { DocComponentView, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocComponentView, DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { LinkInfo } from './LinkDocPreview'; import { PinProps, PresBox } from './trails'; @@ -250,7 +250,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (this._mainCont.current && selRange) { - if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; + if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -274,7 +274,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (Doc.AreProtosEqual(doc, this.Document)) return new Promise>(res => res(this._props.DocumentView?.())); - if (this.Document.layout_fieldKey === 'layout_icon') this._props.DocumentView?.().iconify(); + if (Doc.AreProtosEqual(doc, this.Document)) return new Promise>(res => res(this.DocumentView?.())); + if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify(); const webUrl = WebCast(doc.config_data)?.url; if (this._url && webUrl && webUrl.href !== this._url) this.setData(webUrl.href); if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); @@ -343,7 +344,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._getAnchor = AnchorMenu.Instance?.GetAnchor; // need to save AnchorMenu's getAnchor since a subsequent selection on another doc will overwrite this value this._textAnnotationCreator = undefined; - this._props.docViewPath().lastElement()?.docView?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. + this.DocumentView?.()?.cleanupPointerEvents(); // pointerup events aren't generated on containing document view, so we have to invoke it here. if (this._iframe?.contentWindow && this._iframe.contentDocument && !this._iframe.contentWindow.getSelection()?.isCollapsed) { const mainContBounds = Utils.GetScreenTransform(this._mainCont.current!); const scale = (this._props.NativeDimScaling?.() || 1) * mainContBounds.scale; @@ -364,7 +365,8 @@ export class WebBox extends ViewBoxAnnotatableComponent iframeHeight ? iframeHeight : scrollTop; - if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this._props.docViewPath()))) { + if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { this.layoutDoc.thumb = undefined; this.layoutDoc.thumbScrollTop = undefined; this.layoutDoc.thumbNativeWidth = undefined; @@ -723,10 +725,11 @@ export class WebBox extends ViewBoxAnnotatableComponent { const sel = this._url ? this._iframe?.contentDocument?.getSelection() : window.document.getSelection(); this._textAnnotationCreator = undefined; - if (sel?.empty) sel.empty(); // Chrome + if (sel?.empty) + sel.empty(); // Chrome else if (sel?.removeAllRanges) sel.removeAllRanges(); // Firefox this.marqueeing = [e.clientX, e.clientY]; - if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -750,7 +753,8 @@ export class WebBox extends ViewBoxAnnotatableComponent { // if menu comes up right away, the down event can still be active causing a menu item to be selected this.specificContextMenu(undefined as any); - this._props.docViewPath().lastElement().docView?.onContextMenu(undefined, x, y); + this.DocumentView?.().onContextMenu(undefined, x, y); }); } } @@ -908,7 +912,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { e.stopPropagation(); } }; @@ -1065,7 +1069,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this._sidebarRef.current?.anchorMenuClick; transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc)) return 'none'; } @@ -1099,7 +1103,7 @@ export class WebBox extends ViewBoxAnnotatableComponent {this.webpage}
- {!this._mainCont.current || !this._annotationLayer.current ? null : ( + {!this._mainCont.current || !this.DocumentView || !this._annotationLayer.current ? null : (
{ - let container = this._props.tbox._props.DocumentView?.()._props.docViewPath().lastElement(); + let container = this._props.tbox.containerViewPath?.().lastElement(); if (container) { const embedding = Doc.MakeEmbedding(container.Document); embedding._type_collection = CollectionViewType.Time; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ae26f170b..6a6cec094 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -42,7 +42,7 @@ import { CollectionStackingView } from '../../collections/CollectionStackingView import { CollectionTreeView } from '../../collections/CollectionTreeView'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; -import { ViewBoxAnnotatableComponent } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; @@ -71,7 +71,7 @@ import { SummaryView } from './SummaryView'; export interface FormattedTextBoxProps {} @observer -export class FormattedTextBox extends ViewBoxAnnotatableComponent() { +export class FormattedTextBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } @@ -123,7 +123,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this.getAnchor(true), targetCreator), e.pageX, e.pageY); + DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.DocumentView?.()!, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY); }); const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to); this._props.rootSelected?.() && AnchorMenu.Instance.jumpTo(coordsB.left, coordsB.bottom); @@ -1410,7 +1410,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent 0 && !state.doc.resolve(xpos).node()?.isTextblock) { @@ -1764,7 +1764,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent p + toHgt(child), margins); - const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.layout_maxAutoHeight, proseHeight), proseHeight); + const scrollHeight = this.ProseRef && proseHeight; if (this._props.setHeight && scrollHeight && !this._props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation const setScrollHeight = () => (this.dataDoc[this.fieldKey + '_scrollHeight'] = scrollHeight); @@ -1852,7 +1852,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ) : ( -
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this._props.DocumentView?.()!, false), true)}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - Math.max(0, nbef - 1))), diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 6fa64a765..645ac08e1 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -294,13 +294,9 @@ export class PresBox extends ViewBoxBaseComponent() { listItemDoc.presentation_effect = this.activeItem.presBulletEffect; listItemDoc.presentation_transition = 500; targetView?.setAnimEffect(listItemDoc, 500); - if (targetView?.docView && this.activeItem.presBulletExpand) { - targetView.docView._animateScalingTo = 1.2; - targetView.docView._animateScaleTime = 400; - Doc.AddUnHighlightWatcher(() => { - targetView.docView!._animateScaleTime = undefined; - targetView!.docView!._animateScalingTo = 0; - }); + if (targetView && this.activeItem.presBulletExpand) { + targetView.setAnimateScaling(1.2, 400); + Doc.AddUnHighlightWatcher(() => targetView?.setAnimateScaling(0, undefined)); } listItemDoc.opacity = undefined; this.activeItem.presentation_indexed = presIndexed + 1; @@ -2622,7 +2618,7 @@ export class PresBox extends ViewBoxBaseComponent() { ScreenToLocalTransform={this.getTransform} AddToMap={this.AddToMap} RemFromMap={this.RemFromMap} - hierarchyIndex={emptyPath} + hierarchyIndex={emptyPath as any as number[]} /> ) : null}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 4945d66c8..8cf01b9de 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; @@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // the presentation view that renders this slide @computed get presBoxView() { - return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as PresBox; + return this.containerViewPath?.().lastElement()?.ComponentView as PresBox; } // the presentation view document that renders this slide @@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton); embedHeight = () => this.collapsedHeight + this.expandViewHeight; embedWidth = () => this._props.PanelWidth() / 2; - styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property); }; /** @@ -116,7 +116,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { hideLinkButton={true} ScreenToLocalTransform={Transform.Identity} renderDepth={this._props.renderDepth + 1} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} childFilters={this._props.childFilters} childFiltersByRanges={this._props.childFiltersByRanges} searchFilterDocs={this._props.searchFilterDocs} @@ -196,7 +196,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { const dragArray = this.presBoxView?._dragArray ?? []; const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.slideDoc); - dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this._props.DocumentView?.()?._props.treeViewDoc; + dragData.treeViewDoc = this.presBox?._type_collection === CollectionViewType.Tree ? this.presBox : undefined; // this.DocumentView?.()?._props.treeViewDoc; dragData.moveDocument = this._props.moveDocument; const dragItem: HTMLElement[] = []; const classesToRestore = new Map(); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 4a7e35c16..89e5944f2 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -17,7 +17,7 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import { ObservableReactComponent } from '../ObservableReactComponent'; @@ -30,7 +30,7 @@ const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; // The workerSrc property shall be specified. -Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.269/build/pdf.worker.mjs'; +Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.379/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { Document: Doc; @@ -364,10 +364,10 @@ export class PDFViewer extends ObservableReactComponent { this._downX = e.clientX; this._downY = e.clientY; if ((this._props.Document._freeform_scale || 1) !== 1) return; - if ((e.button !== 0 || e.altKey) && this._props.isContentActive(true)) { + if ((e.button !== 0 || e.altKey) && this._props.isContentActive()) { this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Document); } - if (!e.altKey && e.button === 0 && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this._props.select(false); MarqueeAnnotator.clearAnnotations(this._savedAnnotations); this._marqueeref.current?.onInitiateSelection([e.clientX, e.clientY]); @@ -465,7 +465,7 @@ export class PDFViewer extends ObservableReactComponent { @action onZoomWheel = (e: React.WheelEvent) => { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { e.stopPropagation(); if (e.ctrlKey) { const curScale = Number(this._pdfViewer.currentScaleValue); @@ -497,7 +497,7 @@ export class PDFViewer extends ObservableReactComponent { panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { const docProps = testDocProps(props) ? props : undefined; if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 575d5849e..188b2eba4 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -102,14 +102,12 @@ export class TopBar extends React.Component { Document={selDoc} fieldKey="data" dropAction="embed" - setHeight={returnFalse} styleProvider={DefaultStyleProvider} bringToFront={emptyFunction} select={emptyFunction} isContentActive={returnTrue} isAnyChildContentActive={returnFalse} isSelected={returnFalse} - docViewPath={returnEmptyDoclist} moveDocument={returnFalse} addDocument={returnFalse} addDocTab={DocumentViewInternal.addDocTabFunc} diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index a1ce55314..9d68ea731 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -396,7 +396,7 @@ export class MobileInterface extends React.Component { isContentActive={emptyFunction} focus={emptyFunction} styleProvider={this.whitebackground} - docViewPath={returnEmptyDoclist} + containerViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} childFilters={returnEmptyFilter} diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts index b6164832f..a9e6af67c 100644 --- a/src/server/DashStats.ts +++ b/src/server/DashStats.ts @@ -15,7 +15,8 @@ export namespace DashStats { export const SAMPLING_INTERVAL = 1000; // in milliseconds (ms) - Time interval to update the frontend. export const RATE_INTERVAL = 10; // in seconds (s) - Used to calculate rate - const statsCSVFilename = './src/server/stats/userLoginStats.csv'; + const statsCSVDirectory = './src/server/stats/'; + const statsCSVFilename = statsCSVDirectory + 'userLoginStats.csv'; const columns = ['USERNAME', 'ACTION', 'TIME']; /** @@ -153,6 +154,7 @@ export namespace DashStats { TIME: currentDate.toISOString(), }; + if (!fs.existsSync(statsCSVDirectory)) fs.mkdirSync(statsCSVDirectory); let statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' }); statsFile.write(convertToCSV(toWrite)); statsFile.end(); -- cgit v1.2.3-70-g09d2 From 533051fbf278fb7109d898c9299f8e724902c138 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 22 Jan 2024 13:34:34 -0500 Subject: cleaned up viewPath methods and LightboxView's containment api --- src/client/util/DocumentManager.ts | 10 +++++----- src/client/views/DocComponent.tsx | 10 ++-------- src/client/views/LightboxView.tsx | 2 +- src/client/views/StyleProvider.tsx | 3 ++- src/client/views/collections/CollectionNoteTakingView.tsx | 4 ++-- src/client/views/collections/CollectionStackingView.tsx | 4 ++-- src/client/views/collections/TreeView.tsx | 4 ++-- .../collectionFreeForm/CollectionFreeFormLinksView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +++--- .../collections/collectionLinear/CollectionLinearView.tsx | 2 +- .../collectionMulticolumn/CollectionMulticolumnView.tsx | 2 +- .../collectionMulticolumn/CollectionMultirowView.tsx | 2 +- .../collections/collectionSchema/CollectionSchemaView.tsx | 2 +- src/client/views/nodes/ComparisonBox.tsx | 2 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 12 +++--------- src/client/views/nodes/EquationBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/nodes/formattedText/DashDocView.tsx | 2 +- src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 20 files changed, 33 insertions(+), 44 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 07357a764..e81a99e40 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -30,7 +30,7 @@ export class DocumentManager { @observable.shallow public LinkAnchorBoxViews: DocumentView[] = []; @observable.shallow public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = []; @computed public get DocumentViews() { - return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath))); + return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.Contains(view))); } public AddDocumentView(dv: DocumentView) { this._documentViews.add(dv); @@ -161,7 +161,7 @@ export class DocumentManager { public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { const views: DocumentView[] = []; - DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view)); + DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.Contains(view) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view)); return views?.find(view => view.ContentDiv?.getBoundingClientRect().width /*&& view._props.focus !== returnFalse) || views?.find(view => view._props.focus !== returnFalse*/) || (views.length ? views[0] : undefined); }; public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt = undefined): DocumentView | undefined => { @@ -179,8 +179,8 @@ export class DocumentManager { toFindIn; const toReturn: DocumentView[] = []; - const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); - const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); + const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.Contains(view)); + const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.Contains(view)); // heuristic to return the "best" documents first: // choose a document in the lightbox first @@ -237,7 +237,7 @@ export class DocumentManager { // traverses down through the viewPath of contexts to the view: // focusing on each context public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => { - const docViewPath = targetDocView.docViewPath.slice(); + const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView]; let rootContextView = docViewPath.shift(); await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); if (options.toggleTarget && (!options.didMove || targetDocView.Document.hidden)) targetDocView.Document.hidden = !targetDocView.Document.hidden; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index fb8ef7c36..4400b3576 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -73,10 +73,7 @@ export function ViewBoxBaseComponent

() { return this._props.DocumentView; } get docViewPath() { - return this.DocumentView?.().docViewPath ?? emptyPath; - } - get docViewPathFunc() { - return this.DocumentView?.().docViewPathFunc ?? returnEmptyDocViewList; + return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; } get containerViewPath() { return this._props.containerViewPath; @@ -136,10 +133,7 @@ export function ViewBoxAnnotatableComponent

() return this._props.DocumentView; } get docViewPath() { - return this.DocumentView?.().docViewPath ?? emptyPath; - } - get docViewPathFunc() { - return this.DocumentView?.().docViewPathFunc ?? returnEmptyDocViewList; + return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; } get containerViewPath() { return this.DocumentView?.().containerViewPath ?? returnEmptyDocViewList; diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index aec9e32fc..3b86d24a6 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -34,7 +34,7 @@ const savedKeys = ['freeform_panX', 'freeform_panY', 'freeform_scale', 'layout_s type LightboxSavedState = { [key: string]: FieldResult; }; // prettier-ignore @observer export class LightboxView extends ObservableReactComponent { - public static IsLightboxDocView(path: DocumentView[]) { return (path ?? []).includes(LightboxView.Instance?._docView!); } // prettier-ignore + public static Contains(view?:DocumentView) { return view && LightboxView.Instance?._docView&& (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView); } // prettier-ignore public static get LightboxDoc() { return LightboxView.Instance?._doc; } // prettier-ignore static Instance: LightboxView; private _path: { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 572971391..491a72c08 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -291,6 +291,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, } }; const filter = () => { + const docView = props?.DocumentView?.(); const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard)); const showFilterIcon = StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length @@ -326,7 +327,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, "this view inherits filters from one of its parents"} color={SettingsManager.userColor} background={showFilterIcon} - items={[ ...(dashView ? [dashView]: []), ...(props?.DocumentView?.().docViewPath??[])] + items={[ ...(dashView ? [dashView]: []), ...(docView?.containerViewPath?.()??[]), ...(docView ? [docView]:[])] .filter(dv => StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length) .map(dv => ({ text: StrCast(dv?.Document.title), diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 0795104d9..92c8e1256 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -238,7 +238,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelWidth={width} PanelHeight={height} styleProvider={this.styleProvider} - containerViewPath={this.docViewPathFunc} + containerViewPath={this.docViewPath} layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} @@ -511,7 +511,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { action((entries: any) => { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this.docViewPath)) { + if (!LightboxView.Contains(this.DocumentView?.())) { this._props.setHeight?.(height); } } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 11ca62b39..0a0218124 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -327,7 +327,7 @@ export class CollectionStackingView extends CollectionSubView { if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) { const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))); - if (!LightboxView.IsLightboxDocView(this.docViewPath)) { + if (!LightboxView.Contains(this.DocumentView?.())) { this._props.setHeight?.(height); } } diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 205d536de..41720d0dd 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -977,7 +977,7 @@ export class TreeView extends ObservableReactComponent { hideResizeHandles={this.treeView.outlineMode} styleProvider={this.titleStyleProvider} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - containerViewPath={this.treeView.docViewPathFunc} + containerViewPath={this.treeView.docViewPath} treeViewDoc={this.treeView.Document} addDocument={undefined} addDocTab={this._props.addDocTab} @@ -1084,7 +1084,7 @@ export class TreeView extends ObservableReactComponent { ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} treeViewDoc={this.treeView?.Document} - containerViewPath={this.treeView.docViewPathFunc} + containerViewPath={this.treeView.docViewPath} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 95d521f65..e5b6c366f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -11,7 +11,7 @@ import './CollectionFreeFormLinksView.scss'; export class CollectionFreeFormLinksView extends React.Component { @computed get uniqueConnections() { return Array.from(new Set(DocumentManager.Instance.LinkedDocumentViews)) - .filter(c => !LightboxView.LightboxDoc || (LightboxView.IsLightboxDocView(c.a.docViewPath) && LightboxView.IsLightboxDocView(c.b.docViewPath))) + .filter(c => !LightboxView.LightboxDoc || (LightboxView.Contains(c.a) && LightboxView.Contains(c.b))) .map(c => ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c0104d0f8..d2d931869 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1244,7 +1244,7 @@ export class CollectionFreeFormView extends CollectionSubView this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])).length !== 0; incrementalRender = action(() => { - if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath)) { + if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) { const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id])); const loadIncrement = 5; for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) { @@ -1888,7 +1888,7 @@ export class CollectionFreeFormView extends CollectionSubView { } static get DocViews() { - return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.IsLightboxDocView(v.docViewPath)) : DocumentManager.Instance.DocumentViews; + return LightboxView.LightboxDoc ? DocumentManager.Instance.DocumentViews.filter(v => LightboxView.Contains(v)) : DocumentManager.Instance.DocumentViews; } render() { const view = this._props.view; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c2b9dcbbd..4e13b0ccb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1469,17 +1469,11 @@ export class DocumentView extends ObservableReactComponent { return ; } /** - * path of DocumentViews terminating in the DocumentView that contains this DocumentView + * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg) */ @computed get containerViewPath() { return this._props.containerViewPath; } - /** - * path of DocumentViews terminating in this DocumentView - */ - @computed get docViewPath(): DocumentView[] { - return this.containerViewPath ? [...this.containerViewPath(), this] : [this]; - } @computed get layoutDoc() { return Doc.Layout(this.Document, this._props.LayoutTemplate?.()); } @@ -1607,7 +1601,7 @@ export class DocumentView extends ObservableReactComponent { layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; - docViewPathFunc = () => this.docViewPath; + docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); @@ -1706,7 +1700,7 @@ export class DocumentView extends ObservableReactComponent { () { componentDidMount() { this._props.setContentView?.(this); - if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { + if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) { this._props.select(false); this._ref.current!.mathField.focus(); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 86709e4d7..b62d32503 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -558,7 +558,7 @@ export class WebBox extends ViewBoxAnnotatableComponent iframeHeight ? iframeHeight : scrollTop; - if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.docViewPath))) { + if (!LinkInfo.Instance?.LinkInfo && this._outerRef.current && newScrollTop !== this.layoutDoc.thumbScrollTop && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) { this.layoutDoc.thumb = undefined; this.layoutDoc.thumbScrollTop = undefined; this.layoutDoc.thumbNativeWidth = undefined; diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index cc58c2071..61576a498 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -207,7 +207,7 @@ export class DashDocViewInternal extends ObservableReactComponent Date: Mon, 22 Jan 2024 21:45:28 -0500 Subject: fixed schema rows to render, fix for resizing docs from left side. all locking docs in non freeform view. fix for labelBox with multiple rows to keep top rows. cleaned up docViewPath/containerViewPath & --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/DocComponent.tsx | 20 +------- src/client/views/DocumentDecorations.tsx | 9 ++-- src/client/views/MainView.tsx | 7 +-- src/client/views/MarqueeAnnotator.tsx | 6 +-- src/client/views/StyleProvider.tsx | 56 +++++++--------------- .../views/collections/CollectionNoteTakingView.tsx | 7 ++- .../views/collections/CollectionStackingView.tsx | 15 +++--- src/client/views/collections/CollectionSubView.tsx | 4 ++ src/client/views/collections/TabDocView.tsx | 4 +- src/client/views/collections/TreeView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 17 ++++--- .../collectionLinear/CollectionLinearView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.scss | 3 +- .../collectionSchema/CollectionSchemaView.tsx | 2 +- .../collections/collectionSchema/SchemaRowBox.tsx | 18 ++++++- .../views/nodes/CollectionFreeFormDocumentView.tsx | 14 ++++-- src/client/views/nodes/ComparisonBox.tsx | 7 ++- src/client/views/nodes/DocumentContentsView.tsx | 12 ++--- src/client/views/nodes/DocumentView.tsx | 29 +++++------ src/client/views/nodes/LabelBox.scss | 5 +- src/client/views/nodes/LabelBox.tsx | 4 +- src/client/views/nodes/LinkAnchorBox.tsx | 11 +++-- src/client/views/nodes/LinkBox.tsx | 6 +-- src/client/views/nodes/PDFBox.tsx | 1 + .../views/nodes/formattedText/DashDocView.tsx | 7 ++- .../views/nodes/formattedText/DashFieldView.tsx | 2 +- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 13 ++--- src/client/views/topbar/TopBar.tsx | 3 +- src/fields/Doc.ts | 5 ++ 33 files changed, 143 insertions(+), 158 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 7d9cb36c5..0b15e3add 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -192,7 +192,7 @@ export class CurrentUserUtils { {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); }; const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({ - textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 24, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts + textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px", _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts }); const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG, _width: 360 / 4, _height: 270 / 4, _layout_showTitle: "title", ...opts }); const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts }); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 4400b3576..6aba4a042 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,6 +1,6 @@ import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; -import { emptyPath, returnFalse } from '../../Utils'; +import { returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; @@ -41,7 +41,7 @@ export function DocComponent

() { } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this._props.Document[DocData] as Doc; + return this._props.Document[DocData]; } } return Component; @@ -55,16 +55,12 @@ export interface ViewBoxBaseProps { Document: Doc; TemplateDataDocument?: Doc; DocumentView?: () => DocumentView; - containerViewPath?: () => DocumentView[]; fieldKey: string; isSelected: () => boolean; isContentActive: () => boolean | undefined; ScreenToLocalTransform: () => Transform; renderDepth: number; } -function returnEmptyDocViewList() { - return [] as DocumentView[]; -} export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); @@ -72,12 +68,6 @@ export function ViewBoxBaseComponent

() { get DocumentView() { return this._props.DocumentView; } - get docViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; - } - get containerViewPath() { - return this._props.containerViewPath; - } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -132,12 +122,6 @@ export function ViewBoxAnnotatableComponent

() get DocumentView() { return this._props.DocumentView; } - get docViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; - } - get containerViewPath() { - return this.DocumentView?.().containerViewPath ?? returnEmptyDocViewList; - } //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document() { return this._props.Document; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c96253405..8db972ef0 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -344,10 +344,7 @@ export class DocumentDecorations extends ObservableReactComponent UndoManager.RunInBatch( - () => SelectionManager.Docs.forEach(doc => - doc._pointerEvents = (doc._lockedPosition = !doc._lockedPosition)? 'none' : undefined ), - 'toggleBackground' ) // prettier-ignore + e => UndoManager.RunInBatch(() => SelectionManager.Docs.forEach(doc => Doc.toggleLockedPosition(doc)), 'toggleBackground') ); e.stopPropagation(); }; @@ -530,7 +527,7 @@ export class DocumentDecorations extends ObservableReactComponent 135 && seldocview.CollectionFreeFormDocumentView; + const useLock = bounds.r - bounds.x > 135; const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index cd6aeea41..d700ea020 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -56,13 +56,11 @@ import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; import { AudioBox } from './nodes/AudioBox'; import { DocButtonState } from './nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview'; import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu'; -import { MapBox } from './nodes/MapBox/MapBox'; -import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @@ -898,6 +896,7 @@ export class MainView extends ObservableReactComponent<{}> {

{ isAnyChildContentActive={returnFalse} isContentActive={emptyFunction} isSelected={returnFalse} - containerViewPath={returnEmptyDoclist} moveDocument={this.moveButtonDoc} addDocument={this.addButtonDoc} addDocTab={DocumentViewInternal.addDocTabFunc} @@ -1021,7 +1019,6 @@ export class MainView extends ObservableReactComponent<{}> { - diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index cfdc648b4..d0516336c 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -66,7 +66,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { if (!e.aborted && e.linkDocument) { Doc.GetProto(e.linkDocument).link_relationship = 'cropped image'; - Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView().Document.title; + Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.Document.title; Doc.GetProto(e.linkDocument).link_displayLine = false; } }, @@ -256,7 +256,7 @@ export class MarqueeAnnotator extends ObservableReactComponent (copy.style[prop as any] = marqueeStyle[prop as any])); copy.className = 'marqueeAnnotator-annotationBox'; copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px'; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 491a72c08..1cb5ff249 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -20,7 +20,6 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PropertiesView } from './PropertiesView'; @@ -51,21 +50,7 @@ export enum StyleProp { } function toggleLockedPosition(doc: Doc) { - UndoManager.RunInBatch( - () => - runInAction(() => { - doc._lockedPosition = !doc._lockedPosition; - doc._pointerEvents = doc._lockedPosition ? 'none' : undefined; - }), - 'toggleBackground' - ); -} - -export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentViewProps { - return toBeDetermined?.isContentActive ? toBeDetermined : undefined; -} -export function testFieldProps(toBeDetermined: any): toBeDetermined is FieldViewProps { - return toBeDetermined?.isContentActive ? toBeDetermined : undefined; + UndoManager.RunInBatch(() => Doc.toggleLockedPosition(doc), 'toggleBackground'); } export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { @@ -82,19 +67,17 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { // export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; - const docProps = testDocProps(props) ? props : undefined; - const fieldProps = testFieldProps(props) ? props : undefined; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isNonTransparent = property.includes(':nonTransparent'); const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent'); const isContent = property.includes(':content'); const isAnnotated = property.includes(':annotated'); - const isInk = () => doc?._layout_isSvg && !docProps?.LayoutTemplateString; + const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString; const isOpen = property.includes(':open'); const isEmpty = property.includes(':empty'); const boxBackground = property.includes(':box'); - const fieldKey = fieldProps?.fieldKey ? fieldProps.fieldKey + '_' : isCaption ? 'caption_' : ''; + const fieldKey = props?.fieldKey ? props.fieldKey + '_' : isCaption ? 'caption_' : ''; const lockedPosition = () => doc && BoolCast(doc._lockedPosition); const titleHeight = () => props?.styleProvider?.(doc, props, StyleProp.TitleHeight); const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor + ':nonTransparent' + (isNonTransparentLevel + 1)); @@ -137,20 +120,19 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, return undefined; case StyleProp.DocContents:return undefined; case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey'; - case StyleProp.Opacity: return docProps?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null)); + case StyleProp.Opacity: return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null)); case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(doc?._text_fontSize, StrCast(Doc.UserDoc().fontSize))); case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily))); case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight))); case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent')); case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); - case StyleProp.TitleHeight: - return (props?.DocumentView?.().screenToViewTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30) + case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30); case StyleProp.ShowTitle: return ( (doc && - !docProps?.LayoutTemplateString && + !props?.LayoutTemplateString && !doc.presentation_targetDoc && - !docProps?.LayoutTemplateString?.includes(KeyValueBox.name) && + !props?.LayoutTemplateString?.includes(KeyValueBox.name) && props?.layout_showTitle?.() !== '' && StrCast( doc._layout_showTitle, @@ -169,7 +151,6 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, if (doc?.type === DocumentType.FONTICON) return SettingsManager.userColor; const docColor: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; - const parView = props?.DocumentView?.(); const backColor = backgroundCol(); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: @@ -247,7 +228,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, doc?.layout_boxShadow, doc?._type_collection === CollectionViewType.Pile ? '4px 4px 10px 2px' - : lockedPosition() || doc?.isGroup || docProps?.LayoutTemplateString + : lockedPosition() || doc?.isGroup || props?.LayoutTemplateString ? undefined // groups have no drop shadow -- they're supposed to be "invisible". LayoutString's imply collection is being rendered as something else (e.g., title of a Slide) : `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}` ); @@ -257,10 +238,10 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, default: return doc.z ? `#9c9396 ${StrCast(doc?.layout_boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow - : props?.DocumentView?.().containerViewPath?.().lastElement()?.Document._freeform_useClusters - ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent + : props?.containerViewPath?.().lastElement()?.Document._freeform_useClusters + ? `${backgroundCol()} ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : NumCast(doc.group, -1) !== -1 - ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent + ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : lockedPosition() ? undefined // if it's a background & has a cluster color, make the shadow spread really big : StrCast(doc.layout_fieldKey).includes('_inline') // if doc is an inline document in a text box @@ -271,8 +252,8 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, } } case StyleProp.PointerEvents: - if (StrCast(doc?.pointerEvents) && !docProps?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc - if (docProps?.DocumentView?.()._props.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all'; + if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc + if (props?.LayoutTemplateString?.includes(KeyValueBox.name)) return 'all'; if (SnappingManager.ExploreMode || doc?.layout_unrendered) return isInk() ? 'visiblePainted' : 'all'; if (props?.pointerEvents?.() === 'none') return 'none'; if (opacity() === 0) return 'none'; @@ -281,22 +262,17 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, if (props?.isDocumentActive?.() && !props.treeViewDoc) return isInk() ? 'visiblePainted' : 'all'; return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active case StyleProp.Decorations: - const lock = () => { - if (props?.DocumentView?.().containerViewPath?.().lastElement()?.Document?._type_collection === CollectionViewType.Freeform) { - return doc?.pointerEvents !== 'none' ? null : ( + const lock = () => doc?.pointerEvents !== 'none' ? null : (
toggleLockedPosition(doc)}>
); - } - }; const filter = () => { - const docView = props?.DocumentView?.(); const dashView = untracked(() => DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard)); const showFilterIcon = StrListCast(doc?._childFilters).length || StrListCast(doc?._childFiltersByRanges).length ? 'green' // #18c718bd' //'hasFilter' - : docProps?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || docProps?.childFiltersByRanges().length + : props?.childFilters?.().filter(f => Utils.IsRecursiveFilter(f) && f !== Utils.noDragDocsFilter).length || props?.childFiltersByRanges().length ? 'orange' //'inheritsFilter' : undefined; return !showFilterIcon ? null : ( @@ -327,7 +303,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, "this view inherits filters from one of its parents"} color={SettingsManager.userColor} background={showFilterIcon} - items={[ ...(dashView ? [dashView]: []), ...(docView?.containerViewPath?.()??[]), ...(docView ? [docView]:[])] + items={[ ...(dashView ? [dashView]: []), ...(props?.docViewPath?.()??[])] .filter(dv => StrListCast(dv?.Document.childFilters).length || StrListCast(dv?.Document.childRangeFilters).length) .map(dv => ({ text: StrCast(dv?.Document.title), diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 92c8e1256..363db8850 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -238,7 +238,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelWidth={width} PanelHeight={height} styleProvider={this.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} layout_fitWidth={this._props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} @@ -407,10 +407,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { @undoBatch onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.ctrlKey || docView.Document._createDocOnCR) && ['Enter'].includes(e.key)) { + if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); - const newDoc = Doc.MakeCopy(docView.Document, true); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 0a0218124..9384b7088 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -278,16 +278,15 @@ export class CollectionStackingView extends CollectionSubView { - const docView = fieldProps.DocumentView?.(); - if (docView && ['Enter'].includes(e.key) && e.ctrlKey) { + if (['Enter'].includes(e.key) && e.ctrlKey) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + const layout_fieldKey = StrCast(fieldProps.fieldKey); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); + const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); @@ -327,7 +326,7 @@ export class CollectionStackingView extends CollectionSubView boolean; @@ -69,6 +70,9 @@ export function CollectionSubView(moreProps?: X) { : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } + get childContainerViewPath() { + return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; + } // this returns whether either the collection is selected, or the template that it is part of is selected rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 2441c67e6..f00e42360 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,7 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -595,7 +595,7 @@ export class TabMinimapView extends ObservableReactComponent { hideResizeHandles={this.treeView.outlineMode} styleProvider={this.titleStyleProvider} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - containerViewPath={this.treeView.docViewPath} + containerViewPath={this.treeView.childContainerViewPath} treeViewDoc={this.treeView.Document} addDocument={undefined} addDocTab={this._props.addDocTab} @@ -1084,7 +1084,7 @@ export class TreeView extends ObservableReactComponent { ScreenToLocalTransform={this.docTransform} renderDepth={this._props.renderDepth + 1} treeViewDoc={this.treeView?.Document} - containerViewPath={this.treeView.docViewPath} + containerViewPath={this.treeView.childContainerViewPath} childFilters={returnEmptyFilter} childFiltersByRanges={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3eaf1876c..c4358747b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1170,18 +1170,17 @@ export class CollectionFreeFormView extends CollectionSubView { - const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { + if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layout_fieldKey = StrCast(docView.LayoutFieldKey); - const newDoc = Doc.MakeCopy(docView.Document, true); - const dataField = docView.Document[Doc.LayoutFieldKey(newDoc)]; + const layout_fieldKey = StrCast(fieldProps.fieldKey); + const newDoc = Doc.MakeCopy(fieldProps.Document, true); + const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)]; newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; - if (below) newDoc.y = NumCast(docView.Document.y) + NumCast(docView.Document._height) + 10; - else newDoc.x = NumCast(docView.Document.x) + NumCast(docView.Document._width) + 10; - if (layout_fieldKey !== 'layout' && docView.Document[layout_fieldKey] instanceof Doc) { - newDoc[layout_fieldKey] = docView.Document[layout_fieldKey]; + if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10; + else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10; + if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index 4f4c674ea..72bdb9b6b 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -189,7 +189,7 @@ export class CollectionLinearView extends CollectionSubView() { dontRegisterView={BoolCast(this.Document.childDontRegisterViews)} focus={emptyFunction} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} childFilters={this._props.childFilters} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 1fd514ccb..40b4151fe 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -259,7 +259,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { Document={childLayout} TemplateDataDocument={childLayout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 98e39cd36..04a4042f1 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -254,7 +254,7 @@ export class CollectionMultirowView extends CollectionSubView() { Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} styleProvider={this._props.styleProvider} - containerViewPath={this.docViewPath} + containerViewPath={this.childContainerViewPath} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 02131ae22..29d121974 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -210,8 +210,9 @@ border: 1px solid $medium-gray; overflow-x: hidden; overflow-y: auto; - padding: 5px; display: inline-flex; + padding: 0; + align-items: center; } .schema-row { diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index e22a666c5..227274a53 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -971,7 +971,7 @@ class CollectionSchemaViewDoc extends ObservableReactComponent + : } + size={Size.XSMALL} + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + undoable(e => { + e.stopPropagation(); + Doc.toggleLockedPosition(this.Document); + }, 'Delete Row') + ) + }> } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 83cabf355..73709c17e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -12,6 +12,7 @@ import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { DocComponent } from '../DocComponent'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; @@ -37,7 +38,7 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentViewWrapper extends DocComponent() implements CollectionFreeFormDocumentViewProps { +export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent implements CollectionFreeFormDocumentViewProps { constructor(props: any) { super(props); makeObservable(this); @@ -59,6 +60,9 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent key.startsWith('w_')).map(key => key.replace('w_', '')) .map(key => ({upper:key, lower:key[0].toLowerCase() + key.substring(1)})); // prettier-ignore @@ -227,7 +231,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + float = () => { const topDoc = this.Document; const containerDocView = this._props.containerViewPath?.().lastElement(); const screenXf = containerDocView?.screenToContentsTransform(); @@ -253,8 +257,8 @@ export class CollectionFreeFormDocumentView extends DocComponent { const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); - this._props.Document.x = this._props.w_X() + locX; - this._props.Document.y = this._props.w_Y() + locY; + this.Document.x = this._props.w_X() + locX; + this.Document.y = this._props.w_Y() + locY; }; screenToLocalTransform = () => this._props @@ -288,7 +292,7 @@ export class CollectionFreeFormDocumentView extends DocComponent - {this._props.RenderCutoffProvider(this._props.Document) ? ( + {this._props.RenderCutoffProvider(this.Document) ? (
) : ( diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index e707bb836..500eb52ac 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView } from './DocumentView'; +import { DocumentView, returnEmptyDocViewList } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -152,6 +152,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); @@ -178,7 +181,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { @observer export class DocumentContentsView extends ObservableReactComponent< FieldViewProps & { - layout_fieldKey: string; - LayoutTemplateString?: string; onClick?: () => ScriptField; LayoutTemplate?: () => Opt; } @@ -132,8 +130,8 @@ export class DocumentContentsView extends ObservableReactComponent< TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '

awaiting layout

'; - if (this._props.layout_fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layout_fieldKey ? this._props.layout_fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); + if (this._props.fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.fieldKey ? this._props.fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); if (layout === undefined) return this._props.Document.data ? "" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '

Loading layout

'; @@ -141,12 +139,12 @@ export class DocumentContentsView extends ObservableReactComponent< get layoutDoc() { // bcz: replaced this with below : is it correct? change was made to accommodate passing fieldKey's from a layout script - // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined); + // const template: Doc = this._props.LayoutTemplate?.() || Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); const template: Doc = this._props.LayoutTemplate?.() || (this._props.LayoutTemplateString && this._props.Document) || - (this._props.layout_fieldKey && StrCast(this._props.Document[this._props.layout_fieldKey]) && this._props.Document) || - Doc.Layout(this._props.Document, this._props.layout_fieldKey ? Cast(this._props.Document[this._props.layout_fieldKey], Doc, null) : undefined); + (this._props.fieldKey && StrCast(this._props.Document[this._props.fieldKey]) && this._props.Document) || + Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); return Doc.expandTemplateLayout(template, this._props.Document); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4e13b0ccb..444c300f3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -89,6 +89,9 @@ export enum OpenWhere { addRightKeyvalue = 'add:right:keyValue', } +export function returnEmptyDocViewList() { + return [] as DocumentView[]; +} export interface DocFocusOptions { willPan?: boolean; // determines whether to pan to target document willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document @@ -148,6 +151,7 @@ export interface DocComponentView { * */ export interface DocumentViewSharedProps { Document: Doc; + LayoutTemplateString?: string; TemplateDataDocument?: Doc; renderDepth: number; scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document @@ -161,6 +165,7 @@ export interface DocumentViewSharedProps { ignoreAutoHeight?: boolean; disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; + containerViewPath?: () => DocumentView[]; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document isGroupActive?: () => string | undefined; // is this document part of a group that is active setContentView?: (view: DocComponentView) => any; @@ -206,7 +211,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideLinkButton?: boolean; hideCaptions?: boolean; contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents - LayoutTemplateString?: string; dontCenter?: 'x' | 'y' | 'xy'; childHideDecorationTitle?: boolean; childHideResizeHandles?: boolean; @@ -218,7 +222,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { NativeWidth?: () => number; NativeHeight?: () => number; LayoutTemplate?: () => Opt; - containerViewPath?: () => DocumentView[]; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; onClick?: () => ScriptField; onDoubleClick?: () => ScriptField; @@ -235,13 +238,13 @@ export interface DocumentViewProps extends DocumentViewSharedProps { * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop */ export interface DocumentViewInternalSharedProps { - DocumentView: () => DocumentView; select: (ctrlPressed: boolean, shiftPress?: boolean) => void; isSelected: () => boolean; + docViewPath: () => DocumentView[]; NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal } export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { - docViewPath: () => DocumentView[]; + docViewPublic: () => DocumentView; } @observer @@ -276,7 +279,7 @@ export class DocumentViewInternal extends DocComponent { - const targetMatch = - Doc.AreProtosEqual(anchor, this.Document) || // anchor is this document, so anchor's properties apply to this document - (DocCast(anchor)?.layout_unrendered && Doc.AreProtosEqual(DocCast(anchor.annotationOn), this.Document)) // the anchor is an layout_unrendered annotation on this document, so anchor properties apply to this document - ? true - : false; - return targetMatch && PresBox.restoreTargetDocView(docView, anchor, focusSpeed) ? focusSpeed : undefined; - }; - // switches text input focus to the title bar of the document (and displays the title bar if it hadn't been) setTitleFocus = () => { if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title'; @@ -923,8 +917,8 @@ export class DocumentViewInternal extends DocComponent {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints}
@@ -1699,7 +1692,7 @@ export class DocumentView extends ObservableReactComponent { }}> span { + max-height: 100%; // make sure top of text is in view, otherwise it would center on middle of large text span + } } .labelBox-params { @@ -29,4 +32,4 @@ width: 100%; background: lightgray; border: dimgray solid 1px; -} \ No newline at end of file +} diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 934bce448..cc7c15a10 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -1,7 +1,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc, DocListCast, Field } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types'; @@ -43,7 +43,7 @@ export class LabelBox extends ViewBoxBaseComponent { diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 864c1955b..362a7def1 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -33,15 +33,16 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { const linkSource = this.linkSource; - linkSource && setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { - if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); - else this._props.select(false); - }); + linkSource && + setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, (e, doubleTap) => { + if (doubleTap) LinkFollower.FollowLink(this.Document, linkSource, false); + else this._props.select(false); + }); }; onPointerMove = action((e: PointerEvent, down: number[], delta: number[]) => { const cdiv = this._ref?.current?.parentElement; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 4221f464d..ba34255dc 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -29,12 +29,12 @@ export class LinkBox extends ViewBoxBaseComponent() { @computed get anchor1() { const anchor1 = DocCast(this.dataDoc.link_anchor_1); const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1; - return DocumentManager.Instance.getDocumentView(anchor_1, this.containerViewPath?.().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_1, this.DocumentView?.().containerViewPath?.().lastElement()); } @computed get anchor2() { const anchor2 = DocCast(this.dataDoc.link_anchor_2); const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2; - return DocumentManager.Instance.getDocumentView(anchor_2, this.containerViewPath?.().lastElement()); + return DocumentManager.Instance.getDocumentView(anchor_2, this.DocumentView?.().containerViewPath?.().lastElement()); } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { @@ -66,7 +66,7 @@ export class LinkBox extends ViewBoxBaseComponent() { const a = (this.anchor1 ?? this.anchor2)!; const b = (this.anchor2 ?? this.anchor1)!; - const parxf = this.containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; + const parxf = this.DocumentView?.().containerViewPath?.().lastElement().ComponentView as CollectionFreeFormView; const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); const a_invXf = a.screenToViewTransform().inverse(); const b_invXf = b.screenToViewTransform().inverse(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 71c1b6a4c..7696a45a0 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -581,6 +581,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent Object.values(this._disposers).forEach(disposer => disposer?.()); isContentActive = () => this._props.tbox._props.isContentActive() || this._props.tbox.isAnyChildContentActive?.(); @@ -207,7 +210,7 @@ export class DashDocViewInternal extends ObservableReactComponent { - let container = this._props.tbox.containerViewPath?.().lastElement(); + let container = this._props.tbox.DocumentView?.().containerViewPath?.().lastElement(); if (container) { const embedding = Doc.MakeEmbedding(container.Document); embedding._type_collection = CollectionViewType.Time; diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 8cf01b9de..4bc79176e 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -50,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { // the presentation view that renders this slide @computed get presBoxView() { - return this.containerViewPath?.().lastElement()?.ComponentView as PresBox; + return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as PresBox; } // the presentation view document that renders this slide diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 89e5944f2..01590749e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -21,11 +21,12 @@ import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { StyleProp, testDocProps } from '../StyleProvider'; +import { StyleProp } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; +import { PDFBox } from '../nodes/PDFBox'; const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; @@ -33,6 +34,7 @@ const _global = (window /* browser */ || global) /* node */ as any; Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.0.379/build/pdf.worker.mjs'; interface IViewerProps extends FieldViewProps { + pdfBox: PDFBox; Document: Doc; dataDoc: Doc; layoutDoc: Doc; @@ -313,7 +315,7 @@ export class PDFViewer extends ObservableReactComponent { this._ignoreScroll = false; if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio this._scrollTimer = setTimeout(() => { - DocUtils.MakeLinkToActiveAudio(() => this._props.DocumentView?.().ComponentView?.getAnchor!(true)!, false); + DocUtils.MakeLinkToActiveAudio(() => this._props.pdfBox.getAnchor(true)!, false); this._scrollTimer = undefined; }, 200); } @@ -419,7 +421,7 @@ export class PDFViewer extends ObservableReactComponent { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { - this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; + this._mainCont.current.style.transform = `rotate(${NumCast(this._props.pdfBox.ScreenToLocalBoxXf().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { @@ -499,9 +501,8 @@ export class PDFViewer extends ObservableReactComponent { opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { - const docProps = testDocProps(props) ? props : undefined; if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; - const isInk = doc.layout_isSvg && !docProps?.LayoutTemplateString; + const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; return isInk ? 'visiblePainted' : 'all'; } return this._props.styleProvider?.(doc, props, property); @@ -589,7 +590,7 @@ export class PDFViewer extends ObservableReactComponent { isNativeScaled={true} annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)} addDocument={this.addDocumentWrapper} - docView={this._props.DocumentView!} + docView={this._props.pdfBox.DocumentView!} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} selectionText={this.selectionText} diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 188b2eba4..5828313c8 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -22,7 +22,7 @@ import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionLinearView } from '../collections/collectionLinear'; import { DashboardView } from '../DashboardView'; import { Colors } from '../global/globalEnums'; -import { DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; @@ -100,6 +100,7 @@ export class TopBar extends React.Component {
Date: Tue, 23 Jan 2024 16:11:42 -0500 Subject: reorganization of DocumentView, DocumentViewInternal and FieldView methods and props. fix for selection bug after following a link. migrating to use [DocData] instad of GetProto() --- src/client/documents/Documents.ts | 15 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/DocumentManager.ts | 19 +- src/client/util/DragManager.ts | 7 +- src/client/util/DropConverter.ts | 9 +- src/client/util/HypothesisUtils.ts | 18 +- src/client/util/LinkFollower.ts | 9 +- src/client/util/LinkManager.ts | 12 +- src/client/util/SearchUtil.ts | 155 +-- src/client/util/SettingsManager.tsx | 5 +- src/client/views/DashboardView.tsx | 12 +- src/client/views/DocComponent.tsx | 125 +- src/client/views/DocumentDecorations.tsx | 16 +- src/client/views/InkingStroke.tsx | 14 +- src/client/views/LightboxView.tsx | 2 +- src/client/views/MainView.tsx | 29 +- src/client/views/MarqueeAnnotator.tsx | 9 +- src/client/views/PropertiesView.tsx | 5 +- src/client/views/ScriptBox.tsx | 5 +- src/client/views/SidebarAnnos.tsx | 9 +- src/client/views/StyleProvider.tsx | 12 +- src/client/views/TemplateMenu.tsx | 6 +- .../views/collections/CollectionCalendarView.tsx | 4 +- .../views/collections/CollectionCarousel3DView.tsx | 7 +- .../views/collections/CollectionCarouselView.tsx | 6 +- .../views/collections/CollectionDockingView.tsx | 18 +- src/client/views/collections/CollectionMenu.tsx | 25 +- .../views/collections/CollectionNoteTakingView.tsx | 20 +- .../collections/CollectionStackedTimeline.tsx | 27 +- .../views/collections/CollectionStackingView.tsx | 28 +- src/client/views/collections/CollectionSubView.tsx | 33 +- .../views/collections/CollectionTimeView.tsx | 7 +- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 7 +- src/client/views/collections/TabDocView.tsx | 10 +- src/client/views/collections/TreeView.tsx | 19 +- .../CollectionFreeFormLinkView.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 90 +- .../collections/collectionFreeForm/MarqueeView.tsx | 7 +- .../collectionGrid/CollectionGridView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 4 +- .../CollectionMultirowView.tsx | 4 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 6 +- .../collectionMulticolumn/MultirowResizer.tsx | 6 +- .../collectionSchema/CollectionSchemaView.tsx | 10 +- .../collections/collectionSchema/SchemaRowBox.tsx | 10 +- .../collectionSchema/SchemaTableCell.tsx | 5 +- src/client/views/linking/LinkMenu.tsx | 2 +- src/client/views/linking/LinkMenuGroup.tsx | 12 +- src/client/views/newlightbox/NewLightboxView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 15 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 10 +- src/client/views/nodes/ComparisonBox.tsx | 15 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 16 +- src/client/views/nodes/DocumentContentsView.tsx | 29 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 40 +- src/client/views/nodes/DocumentView.tsx | 1214 ++++++++------------ src/client/views/nodes/EquationBox.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 109 +- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 2 +- src/client/views/nodes/FunctionPlotBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 25 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 4 +- src/client/views/nodes/LabelBox.tsx | 23 +- src/client/views/nodes/LinkAnchorBox.tsx | 10 +- src/client/views/nodes/LinkBox.tsx | 7 +- src/client/views/nodes/LinkDescriptionPopup.tsx | 31 +- src/client/views/nodes/LinkDocPreview.tsx | 6 +- src/client/views/nodes/MapBox/MapBox.tsx | 16 +- src/client/views/nodes/MapBox/MapBox2.tsx | 12 +- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 5 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 26 +- src/client/views/nodes/PDFBox.tsx | 28 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 12 +- src/client/views/nodes/ScreenshotBox.tsx | 13 +- src/client/views/nodes/ScriptingBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 42 +- src/client/views/nodes/WebBox.tsx | 20 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 10 +- .../views/nodes/formattedText/DashDocView.tsx | 12 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 45 +- .../views/nodes/importBox/ImportElementBox.tsx | 6 +- src/client/views/nodes/trails/PresBox.tsx | 37 +- src/client/views/nodes/trails/PresElementBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 9 +- src/client/views/search/SearchBox.tsx | 8 +- src/client/views/selectedDoc/SelectedDocView.tsx | 8 +- src/client/views/webcam/DashWebRTCVideo.tsx | 16 +- src/fields/Doc.ts | 52 +- 91 files changed, 1304 insertions(+), 1527 deletions(-) (limited to 'src/client/views/nodes/ComparisonBox.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 40cffcf45..bcc016391 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -205,6 +205,7 @@ export class DocumentOptions { type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection _type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection title?: STRt = new StrInfo('title of document', true); + title_custom?: BOOLt = new BoolInfo('whether title is a default or has been intentionally set'); caption?: RichTextField; author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable author_date?: DATEt = new DateInfo('date the document was created', true); @@ -1454,17 +1455,17 @@ export namespace DocUtils { TaskCompletionBox.popupY = showPopup[1] - 33; TaskCompletionBox.taskCompleted = true; - LinkDescriptionPopup.popupX = showPopup[0]; - LinkDescriptionPopup.popupY = showPopup[1]; - LinkDescriptionPopup.descriptionPopup = true; + LinkDescriptionPopup.Instance.popupX = showPopup[0]; + LinkDescriptionPopup.Instance.popupY = showPopup[1]; + LinkDescriptionPopup.Instance.display = true; const rect = document.body.getBoundingClientRect(); - if (LinkDescriptionPopup.popupX + 200 > rect.width) { - LinkDescriptionPopup.popupX -= 190; + if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) { + LinkDescriptionPopup.Instance.popupX -= 190; TaskCompletionBox.popupX -= 40; } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; + if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) { + LinkDescriptionPopup.Instance.popupY -= 40; TaskCompletionBox.popupY -= 40; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 0b15e3add..c4af20b9b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -275,7 +275,7 @@ export class CurrentUserUtils { {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, }}, {key: "Screengrab", creator: Docs.Create.ScreenshotDocument, opts: { _width: 400, _height: 200 }}, {key: "WebCam", creator: opts => Docs.Create.WebCamDocument("", opts), opts: { _width: 400, _height: 200, recording:true, isSystem: true, cloneFieldFilter: new List(["isSystem"]) }}, - {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, + {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeView_HideUnrendered: true}}, diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index e81a99e40..f730d17fe 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,6 +1,7 @@ +import { Howl } from 'howler'; import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; +import { AclAdmin, AclEdit, Animation, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; @@ -10,13 +11,13 @@ import { CollectionViewType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { TabDocView } from '../views/collections/TabDocView'; import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { FocusViewOptions } from '../views/nodes/FieldView'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; -import { Howl } from 'howler'; export class DocumentManager { private static _instance: DocumentManager; @@ -135,7 +136,7 @@ export class DocumentManager { }); if (toReturn.length === 0) { DocumentManager.Instance.DocumentViews.forEach(view => { - if (Doc.GetProto(view.Document)?.[Id] === id) { + if (view.Document[DocData]?.[Id] === id) { toReturn.push(view); } }); @@ -236,7 +237,7 @@ export class DocumentManager { // shows a documentView by: // traverses down through the viewPath of contexts to the view: // focusing on each context - public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => { + public showDocumentView = async (targetDocView: DocumentView, options: FocusViewOptions) => { const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView]; let rootContextView = docViewPath.shift(); await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); @@ -252,7 +253,7 @@ export class DocumentManager { // and finally restoring the targetDoc to the viewSpec specified by the last document which may either be the targetDoc, or a viewSpec that describes the targetDoc configuration public showDocument = async ( targetDoc: Doc, // document to display - options: DocFocusOptions, // options for how to navigate to target + options: FocusViewOptions, // options for how to navigate to target finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => { Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc); @@ -293,7 +294,7 @@ export class DocumentManager { focusViewsInPath = async ( docView: DocumentView, // - options: DocFocusOptions, + options: FocusViewOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt; childDocView: Opt; focused: boolean }> ) => { let contextView: DocumentView | undefined; // view containing context that contains target @@ -313,7 +314,7 @@ export class DocumentManager { }; @action - restoreDocView(viewSpec: Opt, docView: DocumentView, options: DocFocusOptions, contextView: Opt, targetDoc: Doc) { + restoreDocView(viewSpec: Opt, docView: DocumentView, options: FocusViewOptions, contextView: Opt, targetDoc: Doc) { if (viewSpec && docView) { //if (docView.ComponentView instanceof FormattedTextBox) //viewSpec !== docView.Document && @@ -337,7 +338,7 @@ export class DocumentManager { } } } -export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { +export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 9ede18ed5..70c40c54e 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -13,6 +13,7 @@ import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; +import { DocData } from '../../fields/DocSymbols'; const { default : { contextMenuZindex } } = require('../views/global/globalCssVariables.module.scss'); // prettier-ignore export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'inSame' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove @@ -222,7 +223,7 @@ export namespace DragManager { : docDragData.dropAction === 'add' ? d : docDragData.dropAction === 'proto' - ? Doc.GetProto(d) + ? d[DocData] : docDragData.dropAction === 'copy' ? (await Doc.MakeClone(d)).clone : d @@ -250,9 +251,9 @@ export namespace DragManager { export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) { const finishDrag = (e: DragCompleteEvent) => { const bd = Docs.Create.ButtonDocument({ toolTip: title, z: 1, _width: 150, _height: 50, title, onClick: ScriptField.MakeScript(script) }); - params.map(p => Object.keys(vars).indexOf(p) !== -1 && (Doc.GetProto(bd)[p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields + params.map(p => Object.keys(vars).indexOf(p) !== -1 && (bd[DocData][p] = new PrefetchProxy(vars[p] as Doc))); // copy all "captured" arguments into document parameterfields initialize?.(bd); - Doc.GetProto(bd)['onClick-paramFieldKeys'] = new List(params); + bd[DocData]['onClick-paramFieldKeys'] = new List(params); e.docDragData && (e.docDragData.droppedDocuments = [bd]); return e; }; diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 2c371f28e..f62ec8f83 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -1,4 +1,5 @@ import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { DocData } from '../../fields/DocSymbols'; import { ObjectField } from '../../fields/ObjectField'; import { RichTextField } from '../../fields/RichTextField'; import { listSpec } from '../../fields/Schema'; @@ -12,7 +13,7 @@ import { DragManager } from './DragManager'; import { ScriptingGlobals } from './ScriptingGlobals'; export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt = undefined, templateField: string = '') { - if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated + if (templateField) doc[DocData].title = templateField; /// the title determines which field is being templated doc.isTemplateDoc = makeTemplate(doc, first, rename); return doc; } @@ -33,7 +34,7 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt = und let any = false; docs.forEach(d => { if (!StrCast(d.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)) || any; + any = Doc.MakeMetadataFieldTemplate(d, layoutDoc[DocData]) || any; } else if (d.type === DocumentType.COL || d.data instanceof RichTextField) { any = makeTemplate(d, false) || any; } @@ -41,12 +42,12 @@ function makeTemplate(doc: Doc, first: boolean = true, rename: Opt = und if (first) { if (!docs.length) { // bcz: feels hacky : if the root level document has items, it's not a field template - any = Doc.MakeMetadataFieldTemplate(doc, Doc.GetProto(layoutDoc)) || any; + any = Doc.MakeMetadataFieldTemplate(doc, layoutDoc[DocData]) || any; } } if (layoutDoc[fieldKey] instanceof RichTextField || layoutDoc[fieldKey] instanceof ImageField) { if (!StrCast(layoutDoc.title).startsWith('-')) { - any = Doc.MakeMetadataFieldTemplate(layoutDoc, Doc.GetProto(layoutDoc)); + any = Doc.MakeMetadataFieldTemplate(layoutDoc, layoutDoc[DocData]); } } rename && (doc.title = rename); diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index f46c2d431..c5f307f44 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -30,15 +30,15 @@ export namespace Hypothesis { if (currentDoc && Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the currently selected doc is the annotation's source, only use Search otherwise const results: Doc[] = []; - await SearchUtil.Search('web', true).then( - action(async (res: SearchUtil.DocSearchResult) => { - const docs = res.docs; - const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data); - filteredDocs.forEach(doc => { - uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history? - }); - }) - ); + // await SearchUtil.Search('web', true).then( + // action(async (res: SearchUtil.DocSearchResult) => { + // const docs = res.docs; + // const filteredDocs = docs.filter(doc => doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data); + // filteredDocs.forEach(doc => { + // uri === Cast(doc.data, WebField)?.url.href && results.push(doc); // TODO check visited sites history? + // }); + // }) + // ); const onScreenResults = results.filter(doc => DocumentManager.Instance.getFirstDocumentView(doc)); return onScreenResults.length ? onScreenResults[0] : results.length ? results[0] : undefined; // prioritize results that are currently on the screen diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 2df4d1ca8..20261859c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,16 +1,17 @@ -import { action, observable, runInAction } from 'mobx'; +import { action, runInAction } from 'mobx'; import { Doc, DocListCast, Field, FieldResult, Opt } from '../../fields/Doc'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; -import { DocFocusOptions, OpenWhere } from '../views/nodes/DocumentView'; +import { OpenWhere } from '../views/nodes/DocumentView'; +import { FocusViewOptions } from '../views/nodes/FieldView'; import { PresBox } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; -import { UndoManager } from './UndoManager'; import { SnappingManager } from './SnappingManager'; +import { UndoManager } from './UndoManager'; /* * link doc: * - link_anchor_1: doc @@ -72,7 +73,7 @@ export class LinkFollower { if (target) { const doFollow = (canToggle?: boolean) => { const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle); - const options: DocFocusOptions = { + const options: FocusViewOptions = { playAudio: BoolCast(srcAnchor.followLinkAudio), playMedia: BoolCast(srcAnchor.followLinkVideo), toggleTarget, diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index ccb3c6b98..353f28a92 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,7 +1,7 @@ import { action, makeObservable, observable, observe, runInAction } from 'mobx'; import { computedFn } from 'mobx-utils'; import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../fields/Doc'; -import { DirectLinks } from '../../fields/DocSymbols'; +import { DirectLinks, DocData } from '../../fields/DocSymbols'; import { FieldLoader } from '../../fields/FieldLoader'; import { List } from '../../fields/List'; import { ProxyField } from '../../fields/Proxy'; @@ -58,8 +58,8 @@ export class LinkManager { link && action(lAnchProtoProtos => { Doc.AddDocToList(Doc.UserDoc(), 'links', link); - lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].add(link); - lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].add(link); + lAnchs[0] && lAnchs[0][DocData][DirectLinks].add(link); + lAnchs[1] && lAnchs[1][DocData][DirectLinks].add(link); }) ) ) @@ -74,8 +74,8 @@ export class LinkManager { Promise.all(lAnchs.map(lAnch => PromiseValue(lAnch?.proto as Doc))).then((lAnchProtos: Opt[]) => Promise.all(lAnchProtos.map(lAnchProto => PromiseValue(lAnchProto?.proto as Doc))).then( action(lAnchProtoProtos => { - link && lAnchs[0] && Doc.GetProto(lAnchs[0])[DirectLinks].delete(link); - link && lAnchs[1] && Doc.GetProto(lAnchs[1])[DirectLinks].delete(link); + link && lAnchs[0] && lAnchs[0][DocData][DirectLinks].delete(link); + link && lAnchs[1] && lAnchs[1][DocData][DirectLinks].delete(link); }) ) ) @@ -162,7 +162,7 @@ export class LinkManager { return this.relatedLinker(anchor); } // finds all links that contain the given anchor public getAllDirectLinks(anchor?: Doc): Doc[] { - return anchor ? Array.from(Doc.GetProto(anchor)[DirectLinks]) : []; + return anchor ? Array.from(anchor[DirectLinks]) : []; } // finds all links that contain the given anchor relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index e51770c25..2cc64f415 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -1,10 +1,7 @@ -import * as rp from 'request-promise'; -import { DocServer } from '../DocServer'; import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; -import { Utils } from '../../Utils'; -import { DocumentType } from '../documents/DocumentTypes'; import { StrCast } from '../../fields/Types'; +import { DocumentType } from '../documents/DocumentTypes'; export namespace SearchUtil { export type HighlightingResult = { [id: string]: { [key: string]: string[] } }; @@ -110,154 +107,4 @@ export namespace SearchUtil { depth++; } } - export interface IdSearchResult { - ids: string[]; - lines: string[][]; - numFound: number; - highlighting: HighlightingResult | undefined; - } - - export interface DocSearchResult { - docs: Doc[]; - lines: string[][]; - numFound: number; - highlighting: HighlightingResult | undefined; - } - - export interface SearchParams { - hl?: string; - 'hl.fl'?: string; - start?: number; - rows?: number; - fq?: string; - sort?: string; - allowEmbeddings?: boolean; - onlyEmbeddings?: boolean; - facet?: string; - 'facet.field'?: string; - } - export function Search(query: string, returnDocs: true, options?: SearchParams): Promise; - export function Search(query: string, returnDocs: false, options?: SearchParams): Promise; - export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) { - query = query || '*'; //If we just have a filter query, search for * as the query - const rpquery = Utils.prepend('/dashsearch'); - let replacedQuery = query.replace(/type_t:([^ )])/g, (substring, arg) => `{!join from=id to=proto_i}*:* AND ${arg}`); - if (options.onlyEmbeddings) { - const header = query.match(/_[atnb]?:/) ? replacedQuery : 'DEFAULT:' + replacedQuery; - replacedQuery = `{!join from=id to=proto_i}* AND ${header}`; - } - //console.log("Q: " + replacedQuery + " fq: " + options.fq); - const gotten = await rp.get(rpquery, { qs: { ...options, q: replacedQuery } }); - const result: IdSearchResult = gotten.startsWith('<') ? { ids: [], docs: [], numFound: 0, lines: [] } : JSON.parse(gotten); - if (!returnDocs) { - return result; - } - - const { ids, highlighting } = result; - - const txtresult = - query !== '*' && - JSON.parse( - await rp.get(Utils.prepend('/textsearch'), { - qs: { ...options, q: query.replace(/^[ \+\?\*\|]*/, '') }, // a leading '+' leads to a server crash since findInFiles doesn't handle regex failures - }) - ); - - const fileids = txtresult ? txtresult.ids : []; - const newIds: string[] = []; - const newLines: string[][] = []; - // bcz: we stopped storing fileUpload id's, so this won't find anything - // if (fileids) { - // await Promise.all( - // fileids.map(async (tr: string, i: number) => { - // const docQuery = 'fileUpload_t:' + tr.substr(0, 7); //If we just have a filter query, search for * as the query - // const docResult = JSON.parse(await rp.get(Utils.prepend('/dashsearch'), { qs: { ...options, q: docQuery } })); - // newIds.push(...docResult.ids); - // newLines.push(...docResult.ids.map((dr: any) => txtresult.lines[i])); - // }) - // ); - // } - - const theDocs: Doc[] = []; - const theLines: string[][] = []; - const textDocMap = await DocServer.GetRefFields(newIds); - const textDocs = newIds.map((id: string) => textDocMap[id]).map(doc => doc as Doc); - for (let i = 0; i < textDocs.length; i++) { - const testDoc = textDocs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1) { - theDocs.push(Doc.GetProto(testDoc)); - theLines.push(newLines[i].map(line => line.replace(query, query.toUpperCase()))); - } - } - - const docMap = await DocServer.GetRefFields(ids); - const docs = ids.map((id: string) => docMap[id]).map(doc => doc as Doc); - for (let i = 0; i < ids.length; i++) { - const testDoc = docs[i]; - if (testDoc instanceof Doc && testDoc.type !== DocumentType.KVP && (options.allowEmbeddings || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) { - theDocs.push(testDoc); - theLines.push([]); - } else { - result.numFound--; - } - } - - return { docs: theDocs, numFound: Math.max(0, result.numFound), highlighting, lines: theLines }; - } - - export async function GetEmbeddingsOfDocument(doc: Doc): Promise; - export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs: false): Promise; - export async function GetEmbeddingsOfDocument(doc: Doc, returnDocs = true): Promise { - const proto = Doc.GetProto(doc); - const protoId = proto[Id]; - if (returnDocs) { - return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).docs; - } else { - return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).ids; - } - // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); - } - - export async function GetViewsOfDocument(doc: Doc): Promise { - const results = await Search('', true, { fq: `proto_i:"${doc[Id]}"` }); - return results.docs; - } - - export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[]; embeddingContexts: Doc[] }> { - const docContexts = (await Search('', true, { fq: `data_l:"${doc[Id]}"` })).docs; - const embeddings = await GetEmbeddingsOfDocument(doc, false); - const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', true, { fq: `data_l:"${doc}"` }))); - const contexts = { contexts: docContexts, embeddingContexts: [] as Doc[] }; - embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.docs)); - return contexts; - } - - export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[]; embeddingContexts: string[] }> { - const docContexts = (await Search('', false, { fq: `data_l:"${doc[Id]}"` })).ids; - const embeddings = await GetEmbeddingsOfDocument(doc, false); - const embeddingContexts = await Promise.all(embeddings.map(doc => Search('', false, { fq: `data_l:"${doc}"` }))); - const contexts = { contexts: docContexts, embeddingContexts: [] as string[] }; - embeddingContexts.forEach(result => contexts.embeddingContexts.push(...result.ids)); - return contexts; - } - - export async function GetAllDocs() { - const query = '*'; - const response = await rp.get(Utils.prepend('/dashsearch'), { - qs: { start: 0, rows: 10000, q: query }, - }); - const result: IdSearchResult = JSON.parse(response); - const { ids, numFound, highlighting } = result; - const docMap = await DocServer.GetRefFields(ids); - const docs: Doc[] = []; - for (const id of ids) { - const field = docMap[id]; - if (field instanceof Doc) { - docs.push(field); - } - } - return docs; - // const docs = ids.map((id: string) => docMap[id]).filter((doc: any) => doc instanceof Doc); - // return docs as Doc[]; - } } diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 0233c4051..5bf9e5b00 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -5,13 +5,13 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { BsGoogle } from 'react-icons/bs'; import { FaFillDrip, FaPalette } from 'react-icons/fa'; +import { Utils, addStyleSheet, addStyleSheetRule } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; import { DashVersion } from '../../fields/DocSymbols'; import { BoolCast, Cast, NumCast, StrCast } from '../../fields/Types'; -import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils'; -import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Networking } from '../Network'; +import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { GestureOverlay } from '../views/GestureOverlay'; import { MainViewModal } from '../views/MainViewModal'; import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox'; @@ -47,7 +47,6 @@ export class SettingsManager extends React.Component<{}> { @observable activeTab = 'Accounts'; @observable public propertiesWidth: number = 0; - @observable public headerBarHeight: number = 0; constructor(props: {}) { super(props); diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index 523721b84..472d419fc 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -5,7 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { FaPlus } from 'react-icons/fa'; import { Doc, DocListCast } from '../../fields/Doc'; -import { AclPrivate, DocAcl } from '../../fields/DocSymbols'; +import { AclPrivate, DocAcl, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; import { PrefetchProxy } from '../../fields/Proxy'; @@ -64,7 +64,7 @@ export class DashboardView extends ObservableReactComponent<{}> { getDashboards = (whichGroup: DashboardGroup) => { if (whichGroup === DashboardGroup.MyDashboards) { - return DocListCast(Doc.MyDashboards.data).filter(dashboard => Doc.GetProto(dashboard).author === Doc.CurrentUserEmail); + return DocListCast(Doc.MyDashboards.data).filter(dashboard => dashboard[DocData].author === Doc.CurrentUserEmail); } return DocListCast(Doc.MySharedDocs.data_dashboards).filter(doc => doc.dockingConfig); }; @@ -171,7 +171,7 @@ export class DashboardView extends ObservableReactComponent<{}> { } />
- (Doc.GetProto(dashboard).title = val)} /> + (dashboard[DocData].title = val)} /> {this.selectedDashboardGroup === DashboardGroup.SharedDashboards && this.isUnviewedSharedDashboard(dashboard) ?
unviewed
:
}
{ }, ], }; - if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); + if (dashboard.dockingConfig && dashboard.dockingConfig !== dashboard[DocData].dockingConfig) dashboard.dockingConfig = JSON.stringify(reset); else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true); return reset; }; @@ -391,9 +391,9 @@ export class DashboardView extends ObservableReactComponent<{}> { Doc.ActivePresentation = undefined; }; - public static SetupDashboardCalendars(dashboardDoc: Doc){ + public static SetupDashboardCalendars(dashboardDoc: Doc) { // this section is creating the button document itself === myTrails = new Button - + // create a a list of calendars (as a CalendarCollectionDocument) and store it on the new dashboard const reqdOpts: DocumentOptions = { title: 'My Calendars', diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 6aba4a042..0e5a4f013 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -2,22 +2,62 @@ import { action, computed, makeObservable, observable } from 'mobx'; import * as React from 'react'; import { returnFalse } from '../../Utils'; import { DateField } from '../../fields/DateField'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, DocData } from '../../fields/DocSymbols'; import { List } from '../../fields/List'; import { GetEffectiveAcl, inheritParentAcls } from '../../fields/util'; import { DocumentType } from '../documents/DocumentTypes'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; -import { Transform } from '../util/Transform'; import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; -import { DocumentView } from './nodes/DocumentView'; +import { FieldViewProps, FocusViewOptions } from './nodes/FieldView'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { PinProps } from './nodes/trails'; +import { RefField } from '../../fields/RefField'; /** - * DocComponent returns a generic React base class used by Doc views (not the 'Box' views that render the contents of Doc views) - * (e.g.,CollectionFreeFormDocumentView, DocumentViewInternal) - * + * Shared interface among all viewBox'es (ie, react classes that render the contents of a Doc) + * Many of these methods only make sense for specific viewBox'es, but they should be written to + * be as general as possible + */ +export interface ViewBoxInterface { + fieldKey?: string; + annotationKey?: string; + updateIcon?: () => void; // updates the icon representation of the document + getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) + restoreView?: (viewSpec: Doc) => boolean; + scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt; // returns the duration of the focus + brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) + getView?: (doc: Doc, options: FocusViewOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined + addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) + select?: (ctrlKey: boolean, shiftKey: boolean) => void; + focus?: (textAnchor: Doc, options: FocusViewOptions) => Opt; + isAnyChildContentActive?: () => boolean; // is any child content of the document active + onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected + 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; + Pause?: () => void; // pause a media document (eg, audio/video) + IsPlaying?: () => boolean; // is a media document playing + TogglePause?: (keep?: boolean) => void; // toggle media document playing state + setFocus?: () => void; // sets input focus to the componentView + setData?: (data: Field | Promise) => boolean; + componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; + dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; + incrementalRendering?: () => void; + infoUI?: () => JSX.Element | null; + screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; + ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; + ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; + snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; + search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; +} +/** + * DocComponent returns a React base class used by Doc views with accessors for unpacking he Document,layoutDoc, and dataDoc's + * (note: this should not be used for the 'Box' views that render the contents of Doc views) + * Example derived views: CollectionFreeFormDocumentView, DocumentView, DocumentViewInternal) * */ export interface DocComponentProps { Document: Doc; @@ -26,7 +66,7 @@ export interface DocComponentProps { } export function DocComponent

() { class Component extends ObservableReactComponent> { - constructor(props: any) { + constructor(props: P) { super(props); makeObservable(this); } @@ -41,28 +81,25 @@ export function DocComponent

() { } // This is the data part of a document -- ie, the data that is constant across all views of the document @computed get dataDoc() { - return this._props.Document[DocData]; + return this.Document[DocData]; } } return Component; } /** - * ViewBoxBaseComponent - base class for non-annotatable views that render the interior contents of a DocumentView - * (e.g. InkingStroke, ColorBox) + * base class for non-annotatable views that render the interior contents of a DocumentView. + * this unpacks the Document/layout/data docs as well as the fieldKey being rendered, + * and provides accessors for DocumentView and ScreenToLocalBoxXf + * Example views include: InkingStroke, FontIconBox, EquationBox, etc */ -export interface ViewBoxBaseProps { - Document: Doc; - TemplateDataDocument?: Doc; - DocumentView?: () => DocumentView; - fieldKey: string; - isSelected: () => boolean; - isContentActive: () => boolean | undefined; - ScreenToLocalTransform: () => Transform; - renderDepth: number; -} -export function ViewBoxBaseComponent

() { +export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { + constructor(props: P) { + super(props); + makeObservable(this); + } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); get DocumentView() { @@ -89,36 +126,27 @@ export function ViewBoxBaseComponent

() { } /** - * DocAnnotatableComponent - base class for annotatable views that render the interior contents of a DocumentView - * (e.g., PdfBox, ImageBox) - * These views should be interactive (respond to pointerEvents) when their conatainer DocumentView is selected + * base class for annotatable views that render the interior contents of a DocumentView + * This does what ViewBoxBaseComponent does and additionally provides accessor for the + * field key where annotations are stored as well as add/move/remove methods for handing + * annotations. + * This also provides methods to determine when the contents should be interactive + * (respond to pointerEvents) such as when the DocumentView container is selected or a + * peer child of the container is selected + * Example views include: PDFBox, ImageBox, MapBox, etc */ -export interface ViewBoxAnnotatableProps { - Document: Doc; - TemplateDataDocument?: Doc; - DocumentView?: () => DocumentView; - fieldKey: string; - filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) - isContentActive: () => boolean | undefined; - select: (isCtrlPressed: boolean) => void; - whenChildContentsActiveChanged: (isActive: boolean) => void; - ScreenToLocalTransform: () => Transform; - isSelected: () => boolean; - renderDepth: number; - isAnnotationOverlay?: boolean; -} -export function ViewBoxAnnotatableComponent

() { +export function ViewBoxAnnotatableComponent

() { class Component extends ObservableReactComponent> { - constructor(props: any) { + @observable _annotationKeySuffix = () => 'annotations'; + @observable _isAnyChildContentActive = false; + + constructor(props: P) { super(props); makeObservable(this); } ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); - @observable _annotationKeySuffix = () => 'annotations'; - @observable _isAnyChildContentActive = false; - get DocumentView() { return this._props.DocumentView; } @@ -139,9 +167,6 @@ export function ViewBoxAnnotatableComponent

() @computed get fieldKey() { return this._props.fieldKey; } - - isAnyChildContentActive = () => this._isAnyChildContentActive; - @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? '_' + this._annotationKeySuffix() : ''); } @@ -162,7 +187,7 @@ export function ViewBoxAnnotatableComponent

() toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc); - Doc.RemoveDocFromList(Doc.GetProto(doc), 'proto_embeddings', doc); + Doc.RemoveDocFromList(doc[DocData], 'proto_embeddings', doc); doc.embedContainer = undefined; if (recent) { doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); @@ -210,8 +235,8 @@ export function ViewBoxAnnotatableComponent

() if ([AclAugment, AclEdit, AclAdmin].includes(effectiveAcl)) { added.forEach(doc => { doc._dragOnlyWithinContainer = undefined; - if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.Document; - else Doc.GetProto(doc).annotationOn = undefined; + if (annotationKey ?? this._annotationKeySuffix()) doc[DocData].annotationOn = this.Document; + else doc[DocData].annotationOn = undefined; Doc.SetContainer(doc, this.Document); inheritParentAcls(targetDataDoc, doc, true); }); @@ -225,6 +250,8 @@ export function ViewBoxAnnotatableComponent

() return true; }; + isAnyChildContentActive = () => this._isAnyChildContentActive; + whenChildContentsActiveChanged = action((isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive))); } return Component; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 8db972ef0..5ef62b2c5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -8,7 +8,7 @@ import { FaUndo } from 'react-icons/fa'; import { Utils, emptyFunction, lightOrDark, numberValue, returnFalse, setupMoveUpEvents } from '../../Utils'; import { DateField } from '../../fields/DateField'; import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; -import { AclAdmin, AclAugment, AclEdit } from '../../fields/DocSymbols'; +import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; @@ -101,7 +101,7 @@ export class DocumentDecorations extends ObservableReactComponent dv._props.renderDepth > 0) - .map(dv => dv.getBounds()) + .map(dv => dv.getBounds) .reduce((bounds, rect) => !rect ? bounds : { x: Math.min(rect.left, bounds.x), y: Math.min(rect.top, bounds.y), @@ -203,7 +203,7 @@ export class DocumentDecorations extends ObservableReactComponent(); SelectionManager.Views.forEach(v => containers.add(DocCast(v.Document.embedContainer))); if (containers.size > 1) return false; - const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 }; + const { left, top } = dragDocView.getBounds || { left: 0, top: 0 }; const dragData = new DragManager.DocumentDragData( SelectionManager.Views.map(dv => dv.Document), dragDocView._props.dropAction @@ -541,17 +541,17 @@ export class DocumentDecorations extends ObservableReactComponent ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => { - Doc.GetProto(doc).data = new InkField(inkPts.map( + doc[DocData].data = new InkField(inkPts.map( (ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth) X: NumCast(doc.x) - x + (NumCast(doc.width) * ipt.X) / width, Y: NumCast(doc.y) - y + (NumCast(doc.height) * ipt.Y) / height, diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 11b05352d..92644d3c5 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -34,21 +34,19 @@ import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from './DocComponent'; +import { ViewBoxBaseComponent, ViewBoxInterface } from './DocComponent'; import { Colors } from './global/globalEnums'; import { InkControlPtHandles, InkEndPtHandles } from './InkControlPtHandles'; import './InkStroke.scss'; import { InkStrokeProperties } from './InkStrokeProperties'; import { InkTangentHandles } from './InkTangentHandles'; -import { DocComponentView } from './nodes/DocumentView'; import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; -import { Transform } from '../util/Transform'; const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer -export class InkingStroke extends ViewBoxBaseComponent() { +export class InkingStroke extends ViewBoxBaseComponent() implements ViewBoxInterface { static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big) public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); @@ -64,7 +62,7 @@ export class InkingStroke extends ViewBoxBaseComponent this._props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) @@ -332,8 +330,8 @@ export class InkingStroke extends ViewBoxBaseComponent (this._subContentView = doc); + _subContentView: ViewBoxInterface | undefined; + setSubContentView = (doc: ViewBoxInterface) => (this._subContentView = doc); @computed get fillColor() { const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; @@ -462,7 +460,7 @@ export class InkingStroke extends ViewBoxBaseComponent { addDocTab={this.AddDocTab} pinToPres={TabDocView.PinDoc} bringToFront={emptyFunction} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index d700ea020..9061e98d4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -15,6 +15,7 @@ import { DocServer } from '../DocServer'; import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { Docs } from '../documents/Documents'; +import { CalendarManager } from '../util/CalendarManager'; import { CaptureManager } from '../util/CaptureManager'; import { DocumentManager } from '../util/DocumentManager'; import { DragManager } from '../util/DragManager'; @@ -31,7 +32,6 @@ import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { ReportManager } from '../util/reportManager/ReportManager'; import { ComponentDecorations } from './ComponentDecorations'; -import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { ContextMenu } from './ContextMenu'; import { DashboardView } from './DashboardView'; import { DictationOverlay } from './DictationOverlay'; @@ -55,11 +55,13 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; import { AudioBox } from './nodes/AudioBox'; +import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { DocButtonState } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from './nodes/DocumentView'; import { ImageBox } from './nodes/ImageBox'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview, LinkInfo } from './nodes/LinkDocPreview'; +import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu'; import { MapAnchorMenu } from './nodes/MapBox/MapAnchorMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; @@ -70,9 +72,8 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +import { DocData } from '../../fields/DocSymbols'; const { default: { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore -import { DirectionsAnchorMenu } from './nodes/MapBox/DirectionsAnchorMenu'; -import { CalendarManager } from '../util/CalendarManager'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -130,9 +131,19 @@ export class MainView extends ObservableReactComponent<{}> { @computed public get mainFreeform(): Opt { return (docs => (docs?.length > 1 ? docs[1] : undefined))(DocListCast(this.mainContainer!.data)); } + @observable public headerBarHeight: number = 0; + headerBarHeightFunc = () => this.headerBarHeight; + @action + toggleTopBar = () => { + if (this.headerBarHeight > 0) { + this.headerBarHeight = 0; + } else { + this.headerBarHeight = 60; + } + }; headerBarDocWidth = () => this.mainDocViewWidth(); - headerBarDocHeight = () => (this._hideUI ? 0 : SettingsManager.Instance?.headerBarHeight ?? 0); + headerBarDocHeight = () => (this._hideUI ? 0 : this.headerBarHeight ?? 0); topMenuHeight = () => (this._hideUI ? 0 : 35); topMenuWidth = returnZero; // value is ignored ... leftMenuWidth = () => (this._hideUI ? 0 : Number(LEFT_MENU_WIDTH.replace('px', ''))); @@ -630,9 +641,11 @@ export class MainView extends ObservableReactComponent<{}> { ); } @computed get mainDocView() { + const headerBar = this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView; + console.log('Header = ' + this._hideUI + ' ' + this.headerBarDocHeight?.() + ' ' + headerBar); return ( <> - {this._hideUI || !this.headerBarDocHeight?.() ? null : this.headerBarDocView} + {headerBar} { @action selectMenu = (button: Doc) => { - const title = StrCast(Doc.GetProto(button).title); + const title = StrCast(button[DocData].title); const willOpen = !this._leftMenuFlyoutWidth || this._panelContent !== title; this.closeFlyout(); if (willOpen) { @@ -998,7 +1011,7 @@ export class MainView extends ObservableReactComponent<{}> { {this._hideUI ? null : } - {LinkDescriptionPopup.descriptionPopup ? : null} + {DocButtonState.Instance.LinkEditorDocView ? (DocButtonState.Instance.LinkEditorDocView = undefined))} docView={DocButtonState.Instance.LinkEditorDocView} /> : null} {LinkInfo.Instance?.LinkInfo ? : null} @@ -1008,7 +1021,7 @@ export class MainView extends ObservableReactComponent<{}> { default: case 'dashboard': return (<>

- +
{this.mainDashboardArea} ); diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index d0516336c..a4303c3aa 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -118,7 +118,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { if (!e.aborted && e.linkDocument) { - Doc.GetProto(e.linkDocument).link_relationship = 'cropped image'; - Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.Document.title; - Doc.GetProto(e.linkDocument).link_displayLine = false; + const linkDocData = e.linkDocument[DocData]; + linkDocData.link_relationship = 'cropped image'; + linkDocData.title = 'crop: ' + this.props.Document.title; + linkDocData.link_displayLine = false; } }, }); diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 13057ffbf..952c8f0b4 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -37,7 +37,8 @@ import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import { PropertiesSection } from './PropertiesSection'; import './PropertiesView.scss'; import { DefaultStyleProvider } from './StyleProvider'; -import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; +import { StyleProviderFuncType } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; const _global = (window /* browser */ || global) /* node */ as any; @@ -45,7 +46,7 @@ const _global = (window /* browser */ || global) /* node */ as any; interface PropertiesViewProps { width: number; height: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; addDocTab: (doc: Doc, where: OpenWhere) => boolean; } diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 086f40e96..623201ed1 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -11,6 +11,7 @@ import { EditableView } from './EditableView'; import { DocumentIconContainer } from './nodes/DocumentIcon'; import { OverlayView } from './OverlayView'; import './ScriptBox.scss'; +import { DocData } from '../../fields/DocSymbols'; export interface ScriptBoxProps { onSave: (text: string, onError: (error: string) => void) => void; @@ -102,7 +103,7 @@ export class ScriptBox extends React.Component { onCancel={overlayDisposer} onSave={(text, onError) => { if (!text) { - Doc.GetProto(doc)[fieldKey] = undefined; + doc[DocData][fieldKey] = undefined; } else { const script = CompileScript(text, { params: { this: Doc.name, ...contextParams }, @@ -125,7 +126,7 @@ export class ScriptBox extends React.Component { div.innerHTML = 'button'; params.length && DragManager.StartButtonDrag([div], text, doc.title + '-instance', {}, params, (button: Doc) => {}, clientX, clientY); - Doc.GetProto(doc)[fieldKey] = new ScriptField(script); + doc[DocData][fieldKey] = new ScriptField(script); overlayDisposer(); } }} diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 0f4a4260c..1e9272e93 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -18,6 +18,7 @@ import { StyleProp } from './StyleProvider'; import { CollectionStackingView } from './collections/CollectionStackingView'; import { FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { DocData } from '../../fields/DocSymbols'; interface ExtraProps { fieldKey: string; @@ -90,7 +91,7 @@ export class SidebarAnnos extends ObservableReactComponent { const key = data.split(':')[0]; const val = Field.Copy(this.allMetadata.get(key)); - Doc.GetProto(target)[key] = val; + target[DocData][key] = val; return { type: 'dashField', attrs: { fieldKey: key, docId: '', hideKey: false, editable: true }, @@ -98,7 +99,7 @@ export class SidebarAnnos extends ObservableReactComponent , props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isNonTransparent = property.includes(':nonTransparent'); const isNonTransparentLevel = isNonTransparent ? Number(property.replace(/.*:nonTransparent([0-9]+).*/, '$1')) : 0; // property.includes(':nonTransparent'); - const isContent = property.includes(':content'); const isAnnotated = property.includes(':annotated'); const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString; const isOpen = property.includes(':open'); @@ -125,7 +125,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily))); case StyleProp.FontWeight: return StrCast(doc?.[fieldKey + 'fontWeight'], StrCast(doc?._text_fontWeight, StrCast(Doc.UserDoc().fontWeight))); case StyleProp.FillColor: return StrCast(doc?._fillColor, StrCast(doc?.fillColor, 'transparent')); - case StyleProp.ShowCaption:return doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); + case StyleProp.ShowCaption:return props?.hideCaptions || doc?._type_collection === CollectionViewType.Carousel ? undefined: StrCast(doc?._layout_showCaption); case StyleProp.TitleHeight:return (props?.ScreenToLocalTransform().Scale ?? 1) * NumCast(Doc.UserDoc().headerHeight,30); case StyleProp.ShowTitle: return ( @@ -244,7 +244,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, ? `gray ${StrCast(doc.layout_boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (props?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent : lockedPosition() ? undefined // if it's a background & has a cluster color, make the shadow spread really big - : StrCast(doc.layout_fieldKey).includes('_inline') // if doc is an inline document in a text box + : fieldKey.includes('_inline') // if doc is an inline document in a text box ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0vw 0vw 0.1vw')}` : DocCast(doc.embedContainer)?.type=== DocumentType.RTF // if doc is embedded in a text document (but not an inline) ? `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}` @@ -316,11 +316,11 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, }; const audio = () => { const audioAnnoState = (doc: Doc) => StrCast(doc.audioAnnoState, 'stopped'); - const audioAnnosCount = (doc: Doc) => StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations']).length; + const audioAnnosCount = (doc: Doc) => StrListCast(doc[fieldKey + 'audioAnnotations']).length; if (!doc || props?.renderDepth === -1 || !audioAnnosCount(doc)) return null; const audioIconColors: { [key: string]: string } = { recording: 'red', playing: 'green', stopped: 'blue' }; return ( - {StrListCast(doc[Doc.LayoutFieldKey(doc) + '_audioAnnotations_text']).lastElement()}
}> + {StrListCast(doc[fieldKey + 'audioAnnotations_text']).lastElement()}
}>
DocumentManager.Instance.getFirstDocumentView(doc)?.playAnnotation()}>
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e5154efcb..ba7120b93 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -11,9 +11,10 @@ import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; import { undoBatch } from '../util/UndoManager'; import { CollectionTreeView } from './collections/CollectionTreeView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, returnEmptyDocViewList } from './nodes/DocumentView'; import { DefaultStyleProvider } from './StyleProvider'; import './TemplateMenu.scss'; +import { DocData } from '../../fields/DocSymbols'; @observer class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent, template: string) => void }> { @@ -79,7 +80,7 @@ export class TemplateMenu extends React.Component { }; componentDidMount() { !this._addedKeys && (this._addedKeys = new ObservableSet()); - [...Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].Document))), ...Array.from(Object.keys(this.props.docViews[0].Document))] + [...Array.from(Object.keys(this.props.docViews[0].Document[DocData])), ...Array.from(Object.keys(this.props.docViews[0].Document))] .filter(key => key.startsWith('layout_')) .map(key => runInAction(() => this._addedKeys.add(key.replace('layout_', '')))); } @@ -113,6 +114,7 @@ export class TemplateMenu extends React.Component { {templateMenu} this._props .ScreenToLocalTransform() - .translate(Doc.NativeWidth(this._props.Document), 0) + .translate(Doc.NativeWidth(this.Document), 0) .scale(this._props.NativeDimScaling?.() || 1); get calendarsKey() { @@ -74,7 +74,7 @@ export class CollectionCalendarView extends CollectionSubView() {
{ + focus = (anchor: Doc, options: FocusViewOptions) => { const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]); if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return; options.didMove = true; @@ -70,7 +71,7 @@ export class CollectionCarousel3DView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - onDoubleClick={this.onChildDoubleClick} + onDoubleClickScript={this.onChildDoubleClick} renderDepth={this._props.renderDepth + 1} LayoutTemplate={this._props.childLayoutTemplate} LayoutTemplateString={this._props.childLayoutString} diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 208fc45b5..79f5baabe 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -66,9 +66,9 @@ export class CollectionCarouselView extends CollectionSubView() { NativeWidth={returnZero} NativeHeight={returnZero} layout_fitWidth={undefined} - setContentView={undefined} - onDoubleClick={this.onContentDoubleClick} - onClick={this.onContentClick} + setContentViewBox={undefined} + onDoubleClickScript={this.onContentDoubleClick} + onClickScript={this.onContentClick} isDocumentActive={this._props.childDocumentsActive?.() ? this._props.isDocumentActive : this._props.isContentActive} isContentActive={this._props.childContentsActive ?? this._props.isContentActive() === false ? returnFalse : emptyFunction} hideCaptions={!!carouselShowsCaptions} // hide captions if the carousel is configured to show the captions diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1f867fc44..87973fd81 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import * as GoldenLayout from '../../../client/goldenLayout'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; -import { AclAdmin, AclEdit } from '../../../fields/DocSymbols'; +import { AclAdmin, AclEdit, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -277,8 +277,8 @@ export class CollectionDockingView extends CollectionSubView() { } setupGoldenLayout = async () => { if (this._unmounting) return; - //const config = StrCast(this._props.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this._props.Document))); - const config = StrCast(this._props.Document.dockingConfig); + //const config = StrCast(this.Document.dockingConfig, JSON.stringify(DashboardView.resetDashboard(this.Document))); + const config = StrCast(this.Document.dockingConfig); if (config) { const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g); const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? []; @@ -322,7 +322,7 @@ export class CollectionDockingView extends CollectionSubView() { ); new _global.ResizeObserver(this.onResize).observe(this._containerRef.current); this._reactionDisposer = reaction( - () => StrCast(this._props.Document.dockingConfig), + () => StrCast(this.Document.dockingConfig), config => { if (!this._goldenLayout || this._ignoreStateChange !== config) { // bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one. @@ -381,7 +381,7 @@ export class CollectionDockingView extends CollectionSubView() { .map(id => DocServer.GetCachedRefField(id)) .filter(f => f) .map(f => f as Doc); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; if (changesMade) { if (![AclAdmin, AclEdit].includes(GetEffectiveAcl(this.dataDoc))) { this.layoutDoc.dockingConfig = json; @@ -449,7 +449,7 @@ export class CollectionDockingView extends CollectionSubView() { if (clone) { const cloned = await Doc.MakeClone(doc); Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id]))); - Doc.GetProto(cloned.clone).dockingConfig = json; + cloned.clone[DocData].dockingConfig = json; return DashboardView.openDashboard(cloned.clone); } const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g); @@ -463,7 +463,7 @@ export class CollectionDockingView extends CollectionSubView() { const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeEmbedding(origtab); const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeEmbedding(origtabdoc)); if (newtabdocs.length) { - Doc.GetProto(newtab).data = new List(newtabdocs); + newtab[DocData].data = new List(newtabdocs); newtabdocs.forEach(ntab => Doc.SetContainer(ntab, newtab)); } json = json.replace(origtab[Id], newtab[Id]); @@ -479,7 +479,7 @@ export class CollectionDockingView extends CollectionSubView() { stateChanged = () => { this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig()); const json = JSON.stringify(this._goldenLayout.toConfig()); - const changesMade = this._props.Document.dockingConfig !== json; + const changesMade = this.Document.dockingConfig !== json; return changesMade; }; @@ -490,7 +490,7 @@ export class CollectionDockingView extends CollectionSubView() { // if you close a tab that is not embedded somewhere else (an embedded Doc can be opened simultaneously in a tab), then add the tab to recently closed if (tab.DashDoc.embedContainer === this.Document) tab.DashDoc.embedContainer = undefined; if (!tab.DashDoc.embedContainer) Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true); - Doc.RemoveDocFromList(Doc.GetProto(tab.DashDoc), 'proto_embeddings', tab.DashDoc); + Doc.RemoveDocFromList(tab.DashDoc[DocData], 'proto_embeddings', tab.DashDoc); } if (CollectionDockingView.Instance) { const dview = CollectionDockingView.Instance.Document; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a54a5ec81..2dad377e0 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -19,14 +19,17 @@ import { undoBatch } from '../../util/UndoManager'; import { AntimodeMenu } from '../AntimodeMenu'; import { EditableView } from '../EditableView'; import { MainView } from '../MainView'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, returnEmptyDocViewList } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import { CollectionLinearView } from './collectionLinear'; import './CollectionMenu.scss'; +import { DocData } from '../../../fields/DocSymbols'; interface CollectionMenuProps { panelHeight: () => number; panelWidth: () => number; + toggleTopBar: () => void; + topBarHeight: () => number; } @observer @@ -65,15 +68,6 @@ export class CollectionMenu extends AntimodeMenu { } }; - @action - toggleTopBar = () => { - if (SettingsManager.Instance.headerBarHeight > 0) { - SettingsManager.Instance.headerBarHeight = 0; - } else { - SettingsManager.Instance.headerBarHeight = 60; - } - }; - @action toggleProperties = () => { if (MainView.Instance.propertiesWidth() > 0) { @@ -95,6 +89,7 @@ export class CollectionMenu extends AntimodeMenu {
{ } render() { - const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down'; - const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar'; + const headerIcon = this.props.topBarHeight() > 0 ? 'angle-double-up' : 'angle-double-down'; + const headerTitle = this.props.topBarHeight() > 0 ? 'Close Header Bar' : 'Open Header Bar'; const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left'; const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties'; @@ -134,8 +129,8 @@ export class CollectionMenu extends AntimodeMenu { toggleType={ToggleType.BUTTON} type={Type.PRIM} color={SettingsManager.userColor} - onClick={this.toggleTopBar} - toggleStatus={SettingsManager.Instance.headerBarHeight > 0} + onClick={this.props.toggleTopBar} + toggleStatus={this.props.topBarHeight() > 0} icon={} tooltip={headerTitle} /> @@ -219,7 +214,7 @@ export class CollectionViewBaseChrome extends React.Component (Doc.GetProto(this.target).data = new List(source))), + immediate: undoBatch((source: Doc[]) => (this.target[DocData].data = new List(source))), initialize: emptyFunction, }; _onClickCommand = { diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 363db8850..e6ce5baab 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { Copy, Id } from '../../../fields/FieldSymbols'; @@ -18,8 +18,8 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; import './CollectionNoteTakingView.scss'; @@ -51,7 +51,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } @computed get chromeHidden() { - return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClick?.() ? true : false; + return BoolCast(this.layoutDoc.chromeHidden) || this._props.onBrowseClickScript?.() ? true : false; } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns @computed get colHeaderData() { @@ -189,7 +189,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { }; // let's dive in and get the actual document we want to drag/move around - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { @@ -254,9 +254,9 @@ export class CollectionNoteTakingView extends CollectionSubView() { rootSelected={this.rootSelected} layout_showTitle={this._props.childlayout_showTitle} dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onBrowseClick={this._props.onBrowseClick} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onBrowseClickScript={this._props.onBrowseClickScript} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={noteTakingDocTransform} focus={this.focusDocument} childFilters={this.childDocFilters} @@ -410,7 +410,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if ((e.ctrlKey || fieldProps.Document._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); const newDoc = Doc.MakeCopy(fieldProps.Document, true); - Doc.GetProto(newDoc).text = undefined; + newDoc[DocData].text = undefined; FormattedTextBox.SetSelectOnLoad(newDoc); return this.addDocument?.(newDoc); } @@ -442,7 +442,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } return true; } - } else if (de.complete.linkDragData?.dragDocument.embedContainer === this._props.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.Document && de.complete.linkDragData?.linkDragView?.CollectionFreeFormDocumentView) { const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); if (!this._props.addDocument?.(source)) e.preventDefault(); de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 1239a038a..1394e62ba 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -3,6 +3,7 @@ import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { Doc, Opt } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -23,17 +24,17 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; +import { FocusFuncType, FocusViewOptions, StyleProviderFuncType } from '../nodes/FieldView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; -import { FieldViewProps } from '../nodes/FieldView'; export type CollectionStackedTimelineProps = { Play: () => void; Pause: () => void; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; playFrom: (seekTimeInSeconds: number, endTime?: number) => void; playing: () => boolean; thumbnails?: () => string[]; @@ -162,7 +163,7 @@ export class CollectionStackedTimeline extends CollectionSubView this.childDocList?.some(item => item === doc); - getView = async (doc: Doc, options: DocFocusOptions): Promise> => + getView = async (doc: Doc, options: FocusViewOptions): Promise> => new Promise>(res => { if (doc.hidden) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); @@ -427,8 +428,8 @@ export class CollectionStackedTimeline extends CollectionSubView number; - styleProvider?: StyleProviderFunc; - playLink: (linkDoc: Doc, options: DocFocusOptions) => void; + styleProvider?: StyleProviderFuncType; + playLink: (linkDoc: Doc, options: FocusViewOptions) => void; setTime: (time: number) => void; startTag: string; endTag: string; @@ -701,7 +702,7 @@ interface StackedTimelineAnchorProps { isDocumentActive?: () => boolean | undefined; ScreenToLocalTransform: () => Transform; _timeline: HTMLDivElement | null; - focus: DocFocusFunc; + focus: FocusFuncType; currentTimecode: () => number; isSelected: () => boolean; stackedTimeline: CollectionStackedTimeline; @@ -810,7 +811,7 @@ class StackedTimelineAnchor extends ObservableReactComponent ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) { const anchor = observable({ view: undefined as Opt | null }); - const focusFunc = (doc: Doc, options: DocFocusOptions): number | undefined => { + const focusFunc = (doc: Doc, options: FocusViewOptions): number | undefined => { this._props.playLink(mark, options); return undefined; }; @@ -842,8 +843,8 @@ class StackedTimelineAnchor extends ObservableReactComponent { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); @@ -288,7 +288,7 @@ export class CollectionStackingView extends CollectionSubView this.refList.splice(this.refList.indexOf(ref), 1)} @@ -670,7 +670,7 @@ export class CollectionStackingView extends CollectionSubView this.isContentActive() && e.stopPropagation()}> {this.renderedSections} {!this.showAddAGroup ? null : ( -
+
)} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index d7c42a975..0aa74aaba 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -21,18 +21,17 @@ import { ImageUtils } from '../../util/Import & Export/ImageUtils'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; import { UndoManager, undoBatch } from '../../util/UndoManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { LoadingBox } from '../nodes/LoadingBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { CollectionView, CollectionViewProps } from './CollectionView'; -import { returnEmptyDocViewList } from '../nodes/DocumentView'; export interface SubCollectionViewProps extends CollectionViewProps { isAnyChildContentActive: () => boolean; } export function CollectionSubView(moreProps?: X) { - class CollectionSubView extends ViewBoxBaseComponent() { + class CollectionSubView extends ViewBoxBaseComponent() { private dropDisposer?: DragManager.DragDropDisposer; private gestureDisposer?: GestureUtils.GestureEventDisposer; protected _mainCont?: HTMLDivElement; @@ -63,20 +62,16 @@ export function CollectionSubView(moreProps?: X) { } get dataDoc() { - return this._props.TemplateDataDocument instanceof Doc && this._props.Document.isTemplateForField - ? Doc.GetProto(this._props.TemplateDataDocument) - : this._props.Document.resolvedDataDoc - ? this._props.Document - : Doc.GetProto(this._props.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + return this._props.TemplateDataDocument instanceof Doc && this.Document.isTemplateForField ? Doc.GetProto(this._props.TemplateDataDocument) : this.Document.resolvedDataDoc ? this.Document : Doc.GetProto(this.Document); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template } get childContainerViewPath() { - return this.DocumentView?.().docViewPath ?? returnEmptyDocViewList; + return this.DocumentView?.().docViewPath; } // this returns whether either the collection is selected, or the template that it is part of is selected rootSelected = () => this._props.isSelected() || BoolCast(this._props.TemplateDataDocument && this._props.rootSelected?.()); - // The data field for rendering this collection will be on the this._props.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. + // The data field for rendering this collection will be on the this.Document unless we're rendering a template in which case we try to use props.TemplateDataDocument. // When a document has a TemplateDataDoc but it's not a template, then it contains its own rendering data, but needs to pass the TemplateDataDoc through // to its children which may be templates. // If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey' @@ -97,14 +92,14 @@ export function CollectionSubView(moreProps?: X) { @computed get childDocList() { return Cast(this.dataField, listSpec(Doc)); } - collectionFilters = () => this._focusFilters ?? StrListCast(this._props.Document._childFilters); - collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this._props.Document._childFiltersByRanges, listSpec('string'), []); + collectionFilters = () => this._focusFilters ?? StrListCast(this.Document._childFilters); + collectionRangeDocFilters = () => this._focusRangeFilters ?? Cast(this.Document._childFiltersByRanges, listSpec('string'), []); // child filters apply to the descendants of the documents in this collection childDocFilters = () => [...(this._props.childFilters?.().filter(f => Utils.IsRecursiveFilter(f)) || []), ...this.collectionFilters()]; // unrecursive filters apply to the documents in the collection, but no their children. See Utils.noRecursionHack unrecursiveDocFilters = () => [...(this._props.childFilters?.().filter(f => !Utils.IsRecursiveFilter(f)) || [])]; childDocRangeFilters = () => [...(this._props.childFiltersByRanges?.() || []), ...this.collectionRangeDocFilters()]; - searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this._props.Document._searchFilterDocs); + searchFilterDocs = () => this._props.searchFilterDocs?.() ?? DocListCast(this.Document._searchFilterDocs); @computed.struct get childDocs() { TraceMobx(); let rawdocs: (Doc | Promise)[] = []; @@ -127,7 +122,7 @@ export function CollectionSubView(moreProps?: X) { const childDocFilters = this.childDocFilters(); const childFiltersByRanges = this.childDocRangeFilters(); const searchDocs = this.searchFilterDocs(); - if (this._props.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { + if (this.Document.dontRegisterView || (!childDocFilters.length && !this.unrecursiveDocFilters().length && !childFiltersByRanges.length && !searchDocs.length)) { return childDocs.filter(cd => !cd.cookies); // remove any documents that require a cookie if there are no filters to provide one } @@ -136,9 +131,9 @@ export function CollectionSubView(moreProps?: X) { // dragging facets const dragged = this._props.childFilters?.().some(f => f.includes(Utils.noDragDocsFilter)); if (dragged && SnappingManager.CanEmbed && DragManager.docsBeingDragged.includes(d)) return false; - let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this._props.Document).length > 0; + let notFiltered = d.z || Doc.IsSystem(d) || DocUtils.FilterDocs([d], this.unrecursiveDocFilters(), childFiltersByRanges, this.Document).length > 0; if (notFiltered) { - notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this._props.Document).length > 0; + notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, childFiltersByRanges, this.Document).length > 0; const fieldKey = Doc.LayoutFieldKey(d); const annos = !Field.toString(Doc.LayoutField(d) as Field).includes(CollectionView.name); const data = d[annos ? fieldKey + '_annotations' : fieldKey]; @@ -171,7 +166,7 @@ export function CollectionSubView(moreProps?: X) { @action protected async setCursorPosition(position: [number, number]) { let ind; - const doc = this._props.Document; + const doc = this.Document; const id = Doc.UserDoc()[Id]; const email = Doc.CurrentUserEmail; const pos = { x: position[0], y: position[1] }; @@ -207,7 +202,7 @@ export function CollectionSubView(moreProps?: X) { const dropAction = this.layoutDoc.dropAction as dropActionType; // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding. // so we check if our collection has a dropAction set on it and if so, we use that instead. - if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this._props.Document && this.childDocs.includes(d))) { + if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.Document && this.childDocs.includes(d))) { de.complete.docDragData.dropAction = dropAction; } e.stopPropagation(); @@ -471,7 +466,7 @@ export function CollectionSubView(moreProps?: X) { } if (generatedDocuments.length) { // Creating a dash document - const isFreeformView = this._props.Document._type_collection === CollectionViewType.Freeform; + const isFreeformView = this.Document._type_collection === CollectionViewType.Freeform; const set = !isFreeformView ? generatedDocuments : generatedDocuments.length > 1 diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 7036ec41c..ee5147428 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -16,7 +16,8 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; -import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; +import { DocumentView } from '../nodes/DocumentView'; +import { FocusViewOptions } from '../nodes/FieldView'; import { PresBox } from '../nodes/trails'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; @@ -38,7 +39,7 @@ export class CollectionTimeView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(this)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); @@ -68,7 +69,7 @@ export class CollectionTimeView extends CollectionSubView() { }; @action - scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: DocFocusOptions) => { + scrollPreview = (docView: DocumentView, anchor: Doc, focusSpeed: number, options: FocusViewOptions) => { // if in preview, then override document's fields with view spec this._focusFilters = StrListCast(anchor.config_docFilters); this._focusRangeFilters = StrListCast(anchor.config_docRangeFilters); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 76b934802..4696d7948 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -447,7 +447,7 @@ export class CollectionTreeView extends CollectionSubView { isAnnotationOverlay?: boolean; // is the collection an annotation overlay (eg an overlay on an image/video/etc) isAnnotationOverlayScrollable?: boolean; // whether the annotation overlay can be vertically scrolled (just for tree views, currently) layoutEngine?: () => string; @@ -63,9 +63,8 @@ interface CollectionViewProps_ extends FieldViewProps { RemFromMap?: (treeViewDoc: Doc, index: number[]) => void; hierarchyIndex?: number[]; // hierarchical index of a document up to the rendering root (primarily used for tree views) } -export interface CollectionViewProps extends React.PropsWithChildren {} @observer -export class CollectionView extends ViewBoxAnnotatableComponent() { +export class CollectionView extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); } diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index f00e42360..da15f8dc5 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,8 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod, returnEmptyDocViewList } from '../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -37,7 +38,6 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; -import { FieldViewProps } from '../nodes/FieldView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -118,7 +118,7 @@ export class TabDocView extends ObservableReactComponent { titleEle.onchange = (e: any) => { undoable(() => { titleEle.size = e.currentTarget.value.length + 3; - Doc.GetProto(doc).title = e.currentTarget.value; + doc[DocData].title = e.currentTarget.value; }, 'edit tab title')(); }; @@ -416,7 +416,7 @@ export class TabDocView extends ObservableReactComponent { return tab !== undefined; }; @action - focusFunc = (doc: Doc, options: DocFocusOptions) => { + focusFunc = (doc: Doc, options: FocusViewOptions) => { if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) { this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost) } @@ -452,7 +452,7 @@ export class TabDocView extends ObservableReactComponent { hideTitle={this._props.keyValue} Document={this._document} TemplateDataDocument={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} waitForDoubleClickToClick={this.waitForDoubleClick} isContentActive={this.isContentActive} isDocumentActive={returnFalse} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 9f40edee1..38a2fe978 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -27,8 +27,8 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; +import { FieldViewProps, StyleProviderFuncType } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; @@ -62,7 +62,7 @@ export interface TreeViewProps { ScreenToLocalTransform: () => Transform; contextMenuItems?: { script: ScriptField; filter: ScriptField; icon: string; label: string }[]; dontRegisterView?: boolean; - styleProvider?: StyleProviderFunc | undefined; + styleProvider?: StyleProviderFuncType | undefined; treeViewHideHeaderFields: () => boolean; renderedIds: string[]; // list of document ids rendered used to avoid unending expansion of items in a cycle onCheckedClick?: () => ScriptField; @@ -367,8 +367,9 @@ export class TreeView extends ObservableReactComponent { _width: 1000, _height: 10, }); - Doc.GetProto(bullet).title = ComputedField.MakeFunction('this.text?.Text'); - Doc.GetProto(bullet).data = new List([]); + const bulletData = bullet[DocData]; + bulletData.title = ComputedField.MakeFunction('this.text?.Text'); + bulletData.data = new List([]); DocumentManager.Instance.AddViewRenderedCb(bullet, dv => dv.ComponentView?.setFocus?.()); return bullet; @@ -982,8 +983,8 @@ export class TreeView extends ObservableReactComponent { addDocument={undefined} addDocTab={this._props.addDocTab} pinToPres={this.treeView._props.pinToPres} - onClick={this.onChildClick} - onDoubleClick={this.onChildDoubleClick} + onClickScript={this.onChildClick} + onDoubleClickScript={this.onChildDoubleClick} dragAction={this._props.dragAction} moveDocument={this.move} removeDocument={this._props.removeDoc} @@ -1076,7 +1077,7 @@ export class TreeView extends ObservableReactComponent { fitContentsToBox={returnTrue} hideDecorationTitle={this.treeView.outlineMode} hideResizeHandles={this.treeView.outlineMode} - onClick={this.onChildClick} + onClickScript={this.onChildClick} focus={this.refocus} onKey={this.onKeyDown} hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)} @@ -1209,7 +1210,7 @@ export class TreeView extends ObservableReactComponent { move: DragManager.MoveFunction, dragAction: dropActionType, addDocTab: (doc: Doc, where: OpenWhere) => boolean, - styleProvider: undefined | StyleProviderFunc, + styleProvider: undefined | StyleProviderFuncType, screenToLocalXf: () => Transform, isContentActive: (outsideReaction?: boolean) => boolean, panelWidth: () => number, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 5204633ea..f0a31a8c6 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -130,7 +130,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent { })} // />, { x: 300, y: 300 }); }) @@ -204,8 +204,8 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent number; NativeHeight?: () => number; originTopLeft?: boolean; @@ -65,12 +65,12 @@ export type collectionFreeformViewProps = { noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale) engineProps?: any; getScrollHeight?: () => number | undefined; -}; +} @observer export class CollectionFreeFormView extends CollectionSubView>() { public get displayName() { - return 'CollectionFreeFormView(' + this._props.Document.title?.toString() + ')'; + return 'CollectionFreeFormView(' + this.Document.title?.toString() + ')'; } // this makes mobx trace() statements more descriptive constructor(props: any) { @@ -180,12 +180,10 @@ export class CollectionFreeFormView extends CollectionSubView { CollectionFreeFormDocumentView.animFields.forEach(val => { @@ -223,7 +221,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._keyframeEditing = set); getKeyFrameEditing = () => this._keyframeEditing; - onBrowseClickHandler = () => this._props.onBrowseClick?.() || ScriptCast(this.layoutDoc.onBrowseClick); + onBrowseClickHandler = () => this._props.onBrowseClickScript?.() || ScriptCast(this.layoutDoc.onBrowseClick); onChildClickHandler = () => this._props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this._props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); elementFunc = () => this._layoutElements; @@ -288,14 +286,14 @@ export class CollectionFreeFormView extends CollectionSubView= -1e-4 && curTime <= endTime); } - groupFocus = (anchor: Doc, options: DocFocusOptions) => { + groupFocus = (anchor: Doc, options: FocusViewOptions) => { options.docTransform = new Transform(-NumCast(this.layoutDoc[this.panXFieldKey]) + NumCast(anchor.x), -NumCast(this.layoutDoc[this.panYFieldKey]) + NumCast(anchor.y), 1); const res = this._props.focus(this.Document, options); options.docTransform = undefined; return res; }; - focus = (anchor: Doc, options: DocFocusOptions) => { + focus = (anchor: Doc, options: FocusViewOptions) => { if (this._lightboxDoc) return; if (anchor === this.Document) { if (options.willZoomCentered && options.zoomScale) { @@ -321,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView> => + getView = async (doc: Doc, options: FocusViewOptions): Promise> => new Promise>(res => { if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); @@ -467,7 +465,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout) .reduce((cluster, cd) => { - const grouping = this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); + const grouping = this.Document._freeform_useClusters ? NumCast(cd.layout_cluster, -1) : NumCast(cd.group, -1); if (grouping !== -1) { const layoutDoc = Doc.Layout(cd); const cx = NumCast(cd.x) - this._clusterDistance / 2; @@ -484,9 +482,9 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === cluster); const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.DocumentView?.())!); - const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; + const { left, top } = clusterDocs[0].getBounds || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); de.moveDocument = this._props.moveDocument; de.offset = this.screenToFreeformContentsXf.transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); @@ -506,7 +504,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).map(c => this.updateCluster(c)); } @@ -514,7 +512,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { const docFirst = docs[0]; docs.map(doc => this._clusterSets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1))); const preferredInd = NumCast(docFirst.layout_cluster); @@ -557,7 +555,7 @@ export class CollectionFreeFormView extends CollectionSubView { const childLayouts = this.childLayoutPairs.map(pair => pair.layout); - if (this._props.Document._freeform_useClusters) { + if (this.Document._freeform_useClusters) { this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); const preferredInd = NumCast(doc.layout_cluster); doc.layout_cluster = -1; @@ -616,7 +614,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this._hitCluster !== -1) { !addToSel && SelectionManager.DeselectAll(); - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this._props.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.Document._freeform_useClusters ? NumCast(cd.layout_cluster) : NumCast(cd.group, -1)) === this._hitCluster); this.selectDocuments(eles); return true; } @@ -810,7 +808,7 @@ export class CollectionFreeFormView extends CollectionSubView DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) - .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) + .map(inkView => ({ inkViewBounds: inkView!.getBounds, inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) .filter( ({ inkViewBounds }) => inkViewBounds && // bounding box of eraser segment and ink stroke overlap @@ -959,8 +957,8 @@ export class CollectionFreeFormView extends CollectionSubView= 0.05 || localTransform.Scale > this.zoomScaling()) { const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20); - this._props.Document[this.scaleFieldKey] = Math.abs(safeScale); - this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this._props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); + this.Document[this.scaleFieldKey] = Math.abs(safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this._props.originTopLeft ? undefined : NumCast(this.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @@ -968,7 +966,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.Document.isGroup || !this.isContentActive()) return; // group style collections neither pan nor zoom PresBox.Instance?.pauseAutoPres(); - if (this.layoutDoc._Transform || this._props.Document.treeView_OutlineMode === TreeViewType.outline) return; + if (this.layoutDoc._Transform || this.Document.treeView_OutlineMode === TreeViewType.outline) return; e.stopPropagation(); const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = this.isAnnotationOverlay && NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling + 1e-4; @@ -989,7 +987,7 @@ export class CollectionFreeFormView extends CollectionSubView { - (this._props.viewDefDivClick || ScriptCast(this._props.Document.onViewDefDivClick))?.script.run({ this: this._props.Document, payload }); + (this._props.viewDefDivClick || ScriptCast(this.Document.onViewDefDivClick))?.script.run({ this: this.Document, payload }); e.stopPropagation(); }; @@ -1377,7 +1375,7 @@ export class CollectionFreeFormView extends CollectionSubView, engine: (poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) => ViewDefResult[] ) { - return engine(poolData, this._props.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); + return engine(poolData, this.Document, this.childLayoutPairs, [this._props.PanelWidth(), this._props.PanelHeight()], this.viewDefsToJSX, this._props.engineProps); } doFreeformLayout(poolData: Map) { @@ -1437,7 +1435,7 @@ export class CollectionFreeFormView extends CollectionSubView (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : ); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); super.componentDidMount?.(); setTimeout( action(() => { @@ -1639,15 +1637,15 @@ export class CollectionFreeFormView extends CollectionSubView (this.layoutDoc._autoArrange = !this.layoutDoc._autoArrange), icon: 'compress-arrows-alt', }); - if (this._props.setContentView === emptyFunction) { + if (this._props.setContentViewBox === emptyFunction) { !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' }); return; } @@ -1656,7 +1654,7 @@ export class CollectionFreeFormView extends CollectionSubView this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; @@ -1680,8 +1678,8 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this._props.Document.isGroup && this._props.Document.transcription) { - const text = StrCast(this._props.Document.transcription); + if (this.Document.isGroup && this.Document.transcription) { + const text = StrCast(this.Document.transcription); const lines = text.split('\n'); const height = 30 + 15 * lines.length; @@ -1742,7 +1740,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this._props.Document.annotationOn ? '' : this._props.Document.title?.toString()} + {this.Document.annotationOn ? '' : this.Document.title?.toString()}
); } @@ -1882,10 +1880,10 @@ export class CollectionFreeFormView extends CollectionSubView { - Doc.GetProto(doc).data = new List(selected); - Doc.GetProto(doc).isGroup = makeGroup; - Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; + const docData = doc[DocData]; + docData.data = new List(selected); + docData.isGroup = makeGroup; + docData.title = makeGroup ? 'grouping' : 'nested freeform'; doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 113ffedb3..f25872c2b 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -192,7 +192,7 @@ export class CollectionGridView extends CollectionSubView() { {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} - setContentView={emptyFunction} + setContentViewBox={emptyFunction} Document={layout} TemplateDataDocument={layout.resolvedDataDoc as Doc} isContentActive={this.isChildContentActive} @@ -200,7 +200,7 @@ export class CollectionGridView extends CollectionSubView() { PanelHeight={height} ScreenToLocalTransform={dxf} whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged} - onClick={this.onChildClickHandler} + onClickScript={this.onChildClickHandler} renderDepth={this._props.renderDepth + 1} dontCenter={StrCast(this.layoutDoc.layout_dontCenter) as any} // 'y', 'x', 'xy' /> @@ -340,7 +340,7 @@ export class CollectionGridView extends CollectionSubView() { * Handles text document creation on double click. */ onPointerDown = (e: React.PointerEvent) => { - if (this._props.isContentActive(true)) { + if (this._props.isContentActive()) { setupMoveUpEvents( this, e, diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 40b4151fe..1fa106b45 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -267,8 +267,8 @@ export class CollectionMulticolumnView extends CollectionSubView() { PanelHeight={height} rootSelected={this.rootSelected} dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} suppressSetHeight={true} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 04a4042f1..97a444b8c 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -262,8 +262,8 @@ export class CollectionMultirowView extends CollectionSubView() { PanelHeight={height} rootSelected={this.rootSelected} dragAction={StrCast(this.Document.childDragAction, this._props.childDragAction) as dropActionType} - onClick={this.onChildClickHandler} - onDoubleClick={this.onChildDoubleClickHandler} + onClickScript={this.onChildClickHandler} + onDoubleClickScript={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} isContentActive={this.isChildContentActive} isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index c38c6dc4e..d580d9c52 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toLeft?: Doc; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 6f1b3b425..73d08d5ef 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,16 +1,16 @@ -import { action, observable } from 'mobx'; +import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { StyleProviderFuncType } from '../../nodes/FieldView'; import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; isContentActive?: () => boolean | undefined; columnUnitLength(): number | undefined; toTop?: Doc; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 227274a53..ec91b25f8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,8 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../../nodes/DocumentView'; +import { DocumentView } from '../../nodes/DocumentView'; +import { FocusViewOptions, FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -24,7 +25,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; -import { FieldViewProps } from '../../nodes/FieldView'; export enum ColumnType { Number, @@ -147,7 +147,7 @@ export class CollectionSchemaView extends CollectionSubView() { } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); document.addEventListener('keydown', this.onKeyDown); Object.entries(this._documentOptions).forEach((pair: [string, FInfo]) => this.fieldInfos.set(pair[0], pair[1])); @@ -498,13 +498,13 @@ export class CollectionSchemaView extends CollectionSubView() { ContextMenu.Instance.displayMenu(x, y, undefined, true); }; - focusDocument = (doc: Doc, options: DocFocusOptions) => { + focusDocument = (doc: Doc, options: FocusViewOptions) => { Doc.BrushDoc(doc); this.scrollToDoc(doc, options); return undefined; }; - scrollToDoc = (doc: Doc, options: DocFocusOptions) => { + scrollToDoc = (doc: Doc, options: FocusViewOptions) => { const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 3f94e7fc1..f2fe0dde7 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -12,7 +12,7 @@ import { DragManager } from '../../../util/DragManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoable } from '../../../util/UndoManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../../DocComponent'; +import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { OpenWhere } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; @@ -20,17 +20,17 @@ import { CollectionSchemaView } from './CollectionSchemaView'; import './CollectionSchemaView.scss'; import { SchemaTableCell } from './SchemaTableCell'; -interface SchemaRowBoxProps { +interface SchemaRowBoxProps extends FieldViewProps { rowIndex: number; } @observer -export class SchemaRowBox extends ViewBoxBaseComponent() { +export class SchemaRowBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string, rowIndex: number) { return FieldView.LayoutString(SchemaRowBox, fieldKey).replace('fieldKey', `rowIndex={${rowIndex}} fieldKey`); } private _ref: HTMLDivElement | null = null; - constructor(props: any) { + constructor(props: SchemaRowBoxProps) { super(props); makeObservable(this); } @@ -50,7 +50,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent { diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 422c4155d..fda5764dd 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -18,7 +18,7 @@ import { EditableView } from '../../EditableView'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider } from '../../StyleProvider'; import { Colors } from '../../global/globalEnums'; -import { OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere, returnEmptyDocViewList } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -49,7 +49,7 @@ export interface SchemaTableCellProps { @observer export class SchemaTableCell extends ObservableReactComponent { - constructor(props: any) { + constructor(props: SchemaTableCellProps) { super(props); makeObservable(this); } @@ -75,6 +75,7 @@ export class SchemaTableCell extends ObservableReactComponent { render() { const sourceDoc = this.props.docView.Document; const sourceAnchor = this.props.docView.anchorViewDoc ?? sourceDoc; - const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds()); + const style = this.props.style ?? (dv => ({ left: dv?.left || 0, top: this.props.docView.topMost ? undefined : (dv?.bottom || 0) + 15, bottom: this.props.docView.topMost ? 20 : undefined, maxWidth: 200 }))(this.props.docView.getBounds); return (
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index 91142b90b..028d3da53 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -47,18 +47,18 @@ export class LinkMenuGroup extends React.Component { const sourceDoc = this.props.docView.anchorViewDoc ?? (this.props.docView.Document.type === DocumentType.LINK // - ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1') + ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(linkDoc.link_anchor_1) : DocCast(linkDoc.link_anchor_2) : this.props.sourceDoc); const destDoc = !sourceDoc ? undefined : this.props.docView.Document.type === DocumentType.LINK - ? this.props.docView.props.LayoutTemplateString?.includes('link_anchor_1') - ? DocCast(linkDoc.link_anchor_2) - : DocCast(linkDoc.link_anchor_1) - : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || - LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); + ? this.props.docView._props.LayoutTemplateString?.includes('link_anchor_1') + ? DocCast(linkDoc.link_anchor_2) + : DocCast(linkDoc.link_anchor_1) + : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || + LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.link_anchor_2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.link_anchor_2, Doc, null) : Cast(linkDoc.link_anchor_1, Doc, null)); return !destDoc || !sourceDoc ? null : ( { addDocTab={this.addDocTab} pinToPres={TabDocView.PinDoc} bringToFront={emptyFunction} - onBrowseClick={DocumentView.exploreMode} + onBrowseClickScript={DocumentView.exploreMode} focus={emptyFunction} /> diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1729af191..2b71fd156 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -5,6 +5,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, DateCast, NumCast } from '../../../fields/Types'; import { AudioField, nullAudio } from '../../../fields/URLField'; @@ -19,8 +20,7 @@ import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import './AudioBox.scss'; -import { DocFocusOptions } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; /** @@ -121,7 +121,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @action componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (this.path) { this.mediaState = media_state.Paused; this.setPlayheadTime(NumCast(this.layoutDoc.clipStart)); @@ -374,9 +374,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { action(() => { const newDoc = DocUtils.GetNewTextDoc('', NumCast(this.Document.x), NumCast(this.Document.y) + NumCast(this.layoutDoc._height) + 10, NumCast(this.layoutDoc._width), 2 * NumCast(this.layoutDoc._height)); const textField = Doc.LayoutFieldKey(newDoc); - Doc.GetProto(newDoc)[`${textField}_recordingSource`] = this.dataDoc; - Doc.GetProto(newDoc)[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`); - Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`); + const newDocData = newDoc[DocData]; + newDocData[`${textField}_recordingSource`] = this.dataDoc; + newDocData[`${textField}_recordingStart`] = ComputedField.MakeFunction(`this.${textField}_recordingSource.${this.fieldKey}_recordingStart`); + newDocData.mediaState = ComputedField.MakeFunction(`this.${textField}_recordingSource.mediaState`); if (Doc.IsInMyOverlay(this.Document)) { newDoc.overlayX = this.Document.x; newDoc.overlayY = NumCast(this.Document.y) + NumCast(this.layoutDoc._height); @@ -432,7 +433,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { }; // plays link - playLink = (link: Doc, options: DocFocusOptions) => { + playLink = (link: Doc, options: FocusViewOptions) => { if (link.annotationOn === this.Document) { if (!this.layoutDoc.dontAutoPlayFollowedLinks) { this.playFrom(this.timeline?.anchorStart(link) || 0, this.timeline?.anchorEnd(link)); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 73709c17e..0ae4ed62c 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -38,8 +38,8 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView CollectionFreeFormView: CollectionFreeFormView; } @observer -export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent implements CollectionFreeFormDocumentViewProps { - constructor(props: any) { +export class CollectionFreeFormDocumentViewWrapper extends ObservableReactComponent { + constructor(props: CollectionFreeFormDocumentViewWrapperProps) { super(props); makeObservable(this); } @@ -104,7 +104,7 @@ export class CollectionFreeFormDocumentViewWrapper extends ObservableReactCompon ); } } -export interface CollectionFreeFormDocumentViewProps { +export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { w_X: () => number; w_Y: () => number; w_Z: () => number; @@ -125,8 +125,8 @@ export interface CollectionFreeFormDocumentViewProps { } @observer -export class CollectionFreeFormDocumentView extends DocComponent() { - constructor(props: any) { +export class CollectionFreeFormDocumentView extends DocComponent() { + constructor(props: CollectionFreeFormDocumentViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 500eb52ac..116dc48a6 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -8,20 +8,20 @@ import { DocCast, NumCast, StrCast } from '../../../fields/Types'; import { DocUtils, Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, returnEmptyDocViewList } from './DocumentView'; +import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @observer -export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class ComparisonBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ComparisonBox, fieldKey); } private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -35,7 +35,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { this._disposers[disposerId]?.(); @@ -152,9 +152,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (doc: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); remDoc1 = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((res, doc) => res && this.remDoc(doc, this.fieldKey + '_1'), true); @@ -181,7 +178,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() { +export class DataVizBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { private _mainCont: React.RefObject = React.createRef(); private _marqueeref = React.createRef(); private _annotationLayer: React.RefObject = React.createRef(); @@ -46,10 +46,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent(); - constructor(props: ViewBoxAnnotatableProps & FieldViewProps) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } @computed get annotationLayer() { @@ -233,7 +233,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar') ); }; - getView = async (doc: Doc, options: DocFocusOptions) => { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { options.didMove = true; this.toggleSidebar(); @@ -254,7 +254,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent this.removeDocument(doc, sidebarKey); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 55859b92b..9538cebb2 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,7 +24,6 @@ import { YoutubeBox } from './../../apis/youtube/YoutubeBox'; import { AudioBox } from './AudioBox'; import { ComparisonBox } from './ComparisonBox'; import { DataVizBox } from './DataVizBox/DataVizBox'; -import { DocumentViewProps } from './DocumentView'; import './DocumentView.scss'; import { EquationBox } from './EquationBox'; import { FieldView, FieldViewProps } from './FieldView'; @@ -114,13 +113,11 @@ export class HTMLtag extends React.Component { } } +export interface DocumentContentsViewProps extends FieldViewProps { + layoutFieldKey: string; +} @observer -export class DocumentContentsView extends ObservableReactComponent< - FieldViewProps & { - onClick?: () => ScriptField; - LayoutTemplate?: () => Opt; - } -> { +export class DocumentContentsView extends ObservableReactComponent { constructor(props: any) { super(props); makeObservable(this); @@ -130,8 +127,8 @@ export class DocumentContentsView extends ObservableReactComponent< TraceMobx(); if (this._props.LayoutTemplateString) return this._props.LayoutTemplateString; if (!this.layoutDoc) return '

awaiting layout

'; - if (this._props.fieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.fieldKey ? this._props.fieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); + if (this._props.layoutFieldKey === 'layout_keyValue') return StrCast(this._props.Document.layout_keyValue, KeyValueBox.LayoutString()); + const layout = Cast(this.layoutDoc[this.layoutDoc === this._props.Document && this._props.layoutFieldKey ? this._props.layoutFieldKey : StrCast(this.layoutDoc.layout_fieldKey, 'layout')], 'string'); if (layout === undefined) return this._props.Document.data ? "" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '

Loading layout

'; @@ -143,26 +140,26 @@ export class DocumentContentsView extends ObservableReactComponent< const template: Doc = this._props.LayoutTemplate?.() || (this._props.LayoutTemplateString && this._props.Document) || - (this._props.fieldKey && StrCast(this._props.Document[this._props.fieldKey]) && this._props.Document) || - Doc.Layout(this._props.Document, this._props.fieldKey ? Cast(this._props.Document[this._props.fieldKey], Doc, null) : undefined); + (this._props.layoutFieldKey && StrCast(this._props.Document[this._props.layoutFieldKey]) && this._props.Document) || + Doc.Layout(this._props.Document, this._props.layoutFieldKey ? Cast(this._props.Document[this._props.layoutFieldKey], Doc, null) : undefined); return Doc.expandTemplateLayout(template, this._props.Document); } CreateBindings(onClick: Opt, onInput: Opt): JsxBindings { const docOnlyProps = [ - // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews + // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews 'hideResizeHandles', 'hideTitle', 'contentPointerEvents', - 'radialMenu', 'LayoutTemplateString', 'LayoutTemplate', + 'layoutFieldKey', 'dontCenter', 'contextMenuItems', //'onClick', // don't need to omit this since it will be set - 'onDoubleClick', - 'onPointerDown', - 'onPointerUp', + 'onDoubleClickScript', + 'onPointerDownScript', + 'onPointerUpScript', ]; const templateDataDoc = this._props.TemplateDataDocument ?? (this.layoutDoc !== this._props.Document ? this._props.Document[DocData] : undefined); const list: BindingProps & React.DetailedHTMLProps, HTMLDivElement> = { diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index 5ce08cdc3..4a22766cc 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -29,7 +29,7 @@ export class DocumentIcon extends ObservableReactComponent { } render() { const view = this._props.view; - const { left, top, right, bottom } = view.getBounds() || { left: 0, top: 0, right: 0, bottom: 0 }; + const { left, top, right, bottom } = view.getBounds || { left: 0, top: 0, right: 0, bottom: 0 }; return (
rect.width) { - LinkDescriptionPopup.popupX -= 190; + if (LinkDescriptionPopup.Instance.popupX + 200 > rect.width) { + LinkDescriptionPopup.Instance.popupX -= 190; TaskCompletionBox.popupX -= 40; } - if (LinkDescriptionPopup.popupY + 100 > rect.height) { - LinkDescriptionPopup.popupY -= 40; + if (LinkDescriptionPopup.Instance.popupY + 100 > rect.height) { + LinkDescriptionPopup.Instance.popupY -= 40; TaskCompletionBox.popupY -= 40; } setTimeout( - action(() => { - TaskCompletionBox.taskCompleted = false; - }), + action(() => (TaskCompletionBox.taskCompleted = false)), 2500 ); } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 444c300f3..3e5e43b47 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -3,19 +3,17 @@ import { Dropdown, DropdownType, Type } from 'browndash-components'; import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { computedFn } from 'mobx-utils'; import * as React from 'react'; import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; +import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; -import { RefField } from '../../../fields/RefField'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; -import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { DocServer } from '../../DocServer'; @@ -33,34 +31,27 @@ import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; -import { Transform } from '../../util/Transform'; -import { UndoManager, undoBatch } from '../../util/UndoManager'; +import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocComponent } from '../DocComponent'; +import { DocComponent, ViewBoxInterface } from '../DocComponent'; import { EditableView } from '../EditableView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; -import { FieldViewProps } from './FieldView'; +import { FieldViewProps, FieldViewSharedProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; -import { PinProps, PresBox } from './trails/PresBox'; - interface Window { MediaRecorder: MediaRecorder; } - declare class MediaRecorder { - // whatever MediaRecorder has - constructor(e: any); + constructor(e: any); // whatever MediaRecorder has } export enum OpenWhereMod { @@ -92,114 +83,7 @@ export enum OpenWhere { export function returnEmptyDocViewList() { return [] as DocumentView[]; } -export interface DocFocusOptions { - willPan?: boolean; // determines whether to pan to target document - willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document - zoomScale?: number; // percent of containing frame to zoom into document - zoomTime?: number; - didMove?: boolean; // whether a document was changed during the showDocument process - docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy - instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) - preview?: boolean; // whether changes should be previewed by the componentView or written to the document - effect?: Doc; // animation effect for focus - noSelect?: boolean; // whether target should be selected after focusing - playAudio?: boolean; // whether to play audio annotation on focus - playMedia?: boolean; // whether to play start target videos - openLocation?: OpenWhere; // where to open a missing document - zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections - toggleTarget?: boolean; // whether to toggle target on and off - anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc - easeFunc?: 'linear' | 'ease'; // transition method for scrolling -} -export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => Opt; -export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; -export interface DocComponentView { - fieldKey?: string; - annotationKey?: string; - updateIcon?: () => void; // updates the icon representation of the document - getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) - restoreView?: (viewSpec: Doc) => boolean; - scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus - brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) - getView?: (doc: Doc, options: DocFocusOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined - addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox - addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) - select?: (ctrlKey: boolean, shiftKey: boolean) => void; - focus?: (textAnchor: Doc, options: DocFocusOptions) => Opt; - isAnyChildContentActive?: () => boolean; // is any child content of the document active - onClickScriptDisable?: () => 'never' | 'always'; // disable click scripts : never, always, or undefined = only when selected - 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; - Pause?: () => void; // pause a media document (eg, audio/video) - IsPlaying?: () => boolean; // is a media document playing - TogglePause?: (keep?: boolean) => void; // toggle media document playing state - setFocus?: () => void; // sets input focus to the componentView - setData?: (data: Field | Promise) => boolean; - componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; - dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; - incrementalRendering?: () => void; - infoUI?: () => JSX.Element | null; - screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; - ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; - ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; - snapPt?: (pt: { X: number; Y: number }, excludeSegs?: number[]) => { nearestPt: { X: number; Y: number }; distance: number }; - search?: (str: string, bwd?: boolean, clear?: boolean) => boolean; -} -/** - * props that DocumentViews, DocumentInternalViews and FieldViews all can use - * */ -export interface DocumentViewSharedProps { - Document: Doc; - LayoutTemplateString?: string; - TemplateDataDocument?: Doc; - renderDepth: number; - scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document - treeViewDoc?: Doc; - xPadding?: number; - yPadding?: number; - dontRegisterView?: boolean; - dropAction?: dropActionType; - dragAction?: dropActionType; - forceAutoHeight?: boolean; - ignoreAutoHeight?: boolean; - disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. - CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; - containerViewPath?: () => DocumentView[]; - fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document - isGroupActive?: () => string | undefined; // is this document part of a group that is active - setContentView?: (view: DocComponentView) => any; - PanelWidth: () => number; - PanelHeight: () => number; - isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events - isContentActive: () => boolean | undefined; // whether document contents should handle pointer events - childFilters: () => string[]; - childFiltersByRanges: () => string[]; - styleProvider: Opt; - setTitleFocus?: () => void; - focus: DocFocusFunc; - layout_fitWidth?: (doc: Doc) => boolean | undefined; - searchFilterDocs: () => Doc[]; - layout_showTitle?: () => string; - whenChildContentsActiveChanged: (isActive: boolean) => void; - rootSelected?: () => boolean; // whether the root of a template has been selected - addDocTab: (doc: Doc, where: OpenWhere) => boolean; - filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) - addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; - removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; - moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean; - pinToPres: (document: Doc, pinProps: PinProps) => void; - ScreenToLocalTransform: () => Transform; - bringToFront: (doc: Doc, sendToBack?: boolean) => void; - waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; - defaultDoubleClick?: () => 'default' | 'ignore' | undefined; - pointerEvents?: () => Opt; -} - -/** - * props that are used by DocumentViews and DocumentInternalViews but not by the contents of those views (FieldViews). - */ -export interface DocumentViewProps extends DocumentViewSharedProps { +export interface DocumentViewProps extends FieldViewSharedProps { hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings @@ -221,35 +105,22 @@ export interface DocumentViewProps extends DocumentViewSharedProps { onClickScriptDisable?: 'never' | 'always'; // undefined = only when selected NativeWidth?: () => number; NativeHeight?: () => number; - LayoutTemplate?: () => Opt; contextMenuItems?: () => { script: ScriptField; filter?: ScriptField; label: string; icon: string }[]; - onClick?: () => ScriptField; - onDoubleClick?: () => ScriptField; - onPointerDown?: () => ScriptField; - onPointerUp?: () => ScriptField; - onBrowseClick?: () => ScriptField | undefined; - onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; dragStarting?: () => void; dragEnding?: () => void; } - -/** - * props used by DocInternalViews and FieldViews but not DocumentViews - * these props correspond to things that the DocumentView creates and thus doesn't need to receive as a prop - */ -export interface DocumentViewInternalSharedProps { - select: (ctrlPressed: boolean, shiftPress?: boolean) => void; - isSelected: () => boolean; - docViewPath: () => DocumentView[]; - NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal -} -export interface DocumentViewInternalProps extends DocumentViewProps, DocumentViewInternalSharedProps { - docViewPublic: () => DocumentView; -} - @observer -export class DocumentViewInternal extends DocComponent() { +export class DocumentViewInternal extends DocComponent() { + // this makes mobx trace() statements more descriptive + public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. + + /** + * This function is filled in by MainView to allow non-viewBox views to add Docs as tabs without + * needing to know about/reference MainView + */ + public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse; + private _disposers: { [name: string]: IReactionDisposer } = {}; private _doubleClickTimeout: NodeJS.Timeout | undefined; private _singleClickFunc: undefined | (() => any); @@ -262,79 +133,51 @@ export class DocumentViewInternal extends DocComponent(); private _titleRef = React.createRef(); private _dropDisposer?: DragManager.DragDropDisposer; - constructor(props: any) { + constructor(props: FieldViewProps & DocumentViewProps) { super(props); makeObservable(this); } - @observable _componentView: Opt = undefined; // needs to be accessed from DocumentView wrapper class + @observable _changingTitleField = false; + @observable _titleDropDownInnerWidth = 0; // width of menu dropdown when setting doc title + @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI ) + @observable _isContentActive: boolean | undefined = undefined; + @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; + @observable _componentView: Opt = undefined; // needs to be accessed from DocumentView wrapper class @observable _animateScaleTime: Opt = undefined; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; - public get animateScaleTime() { - return this._animateScaleTime ?? 100; - } - public get displayName() { - return 'DocumentViewInternal(' + this.Document.title + ')'; - } // this makes mobx trace() statements more descriptive - - public get DocumentView() { - return this._props.docViewPublic; - } + get _contentDiv() { return this._mainCont.current; } // prettier-ignore + get _docView() { return this._props.DocumentView?.(); } // prettier-ignore + + animateScaleTime = () => this._animateScaleTime ?? 100; + style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); + @computed get layout_showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt; } // prettier-ignore + @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore + @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore + @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore + @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore + @computed get backgroundBoxColor() { return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':box'); } // prettier-ignore + @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore + @computed get layout_showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore + @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore + @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore + @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore + @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore - public get ContentDiv() { - return this._mainCont.current; - } - public get LayoutFieldKey() { - return Doc.LayoutFieldKey(this.layoutDoc); - } - @computed get styleProps(): FieldViewProps { - return { ...this._props, fieldKey: '' }; - } - @computed get layout_showTitle() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowTitle) as Opt; - } - @computed get NativeDimScaling() { - return this._props.NativeDimScaling?.() || 1; - } - @computed get thumb() { - return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png'); - } - @computed get opacity() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Opacity); - } - @computed get boxShadow() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BoxShadow); - } - @computed get borderRounding() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BorderRounding); - } - @computed get widgetDecorations() { - TraceMobx(); - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.Decorations); - } - @computed get backgroundBoxColor() { - return this._props.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.BackgroundColor + ':box'); - } - @computed get docContents() { - return this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.DocContents); - } - @computed get headerMargin() { - return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.HeaderMargin) || 0; - } - @computed get layout_showCaption() { - return this._props?.hideCaptions ? undefined : this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.ShowCaption) || 0; + @computed get onClickHandler() { + return this._props.onClickScript?.() ?? this._props.onBrowseClickScript?.() ?? ScriptCast(this.Document.onClick, ScriptCast(this.layoutDoc.onClick)); } - @computed get titleHeight() { - return this._props?.styleProvider?.(this.layoutDoc, this.styleProps, StyleProp.TitleHeight) || 0; + @computed get onDoubleClickHandler() { + return this._props.onDoubleClickScript?.() ?? ScriptCast(this.layoutDoc.onDoubleClick, ScriptCast(this.Document.onDoubleClick)); } - @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; - @computed get pointerEvents(): 'none' | 'all' | 'visiblePainted' | undefined { - return this._pointerEvents; + @computed get onPointerDownHandler() { + return this._props.onPointerDownScript?.() ?? ScriptCast(this.layoutDoc.onPointerDown, ScriptCast(this.Document.onPointerDown)); } - @computed get finalLayoutKey() { - return StrCast(this.Document.layout_fieldKey, 'layout'); + @computed get onPointerUpHandler() { + return this._props.onPointerUpScript?.() ?? ScriptCast(this.layoutDoc.onPointerUp, ScriptCast(this.Document.onPointerUp)); } + @computed get disableClickScriptFunc() { const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable; // prettier-ignore @@ -344,23 +187,50 @@ export class DocumentViewInternal extends DocComponent + (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || + (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || + ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || + ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) + ); } - @computed get onPointerUpHandler() { - return this._props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); + @computed get _allLinks() { + TraceMobx(); + return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); + } + + @computed get filteredLinks() { + return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); } componentWillUnmount() { this.cleanupHandlers(true); } - @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI ) componentDidMount() { runInAction(() => (this._mounted = true)); @@ -380,7 +250,7 @@ export class DocumentViewInternal extends DocComponent this._props.styleProvider?.(this.Document, this.styleProps, StyleProp.PointerEvents), + () => this.style(this.Document, StyleProp.PointerEvents), pointerevents => (this._pointerEvents = pointerevents), { fireImmediately: true } ); @@ -406,18 +276,19 @@ export class DocumentViewInternal extends DocComponent dv.ContentDiv); - const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this.DocumentView()]; + const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [docView]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const screenXf = this.DocumentView().screenToViewTransform(); + const screenXf = docView.screenToViewTransform(); const [left, top] = screenXf.inverse().transformPoint(0, 0); dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; dragData.moveDocument = this._props.moveDocument; - dragData.draggedViews = [this.DocumentView()]; + dragData.draggedViews = [docView]; dragData.canEmbed = this.Document.dragAction ?? this._props.dragAction ? true : false; DragManager.StartDocumentDrag( selected.map(dv => dv.ContentDiv!), @@ -434,12 +305,10 @@ export class DocumentViewInternal extends DocComponent this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined }; - - public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse; - onClick = action((e: React.MouseEvent | React.PointerEvent) => { if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; - if (!this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { + const documentView = this._docView; + if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; !this.layoutDoc._keepZWhenDragged && this._props.bringToFront(this.Document); @@ -451,7 +320,7 @@ export class DocumentViewInternal extends DocComponent this.onDoubleClickHandler.script.run( { this: this.Document, scriptContext: this._props.scriptContext, - documentView: this.DocumentView(), + documentView, clientX, clientY, altKey, shiftKey, ctrlKey, value: undefined, }, console.log ); @@ -482,7 +351,7 @@ export class DocumentViewInternal extends DocComponent (sendToBack ? this.DocumentView()._props.bringToFront(this.Document, true) : + clickFunc ?? (() => (sendToBack ? documentView._props.bringToFront(this.Document, true) : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this._props.select(e.ctrlKey||e.shiftKey, e.metaKey))); const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; @@ -525,12 +394,8 @@ export class DocumentViewInternal extends DocComponent { if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; - this._longPressSelector = setTimeout(() => { - if (DocumentView.LongPress) { - this._props.select(false); - } - }, 1000); - if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this.DocumentView(); + this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000); + if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._docView; this._downX = e.clientX; this._downY = e.clientY; @@ -541,7 +406,7 @@ export class DocumentViewInternal extends DocComponent { + toggleFollowLink = undoable((zoom?: boolean, setTargetToggle?: boolean): void => { const hadOnClick = this.Document.onClick; this.noOnClick(); this.Document.onClick = hadOnClick ? undefined : FollowLinkScript(); this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never'; - }; - @undoBatch - followLinkOnClick = () => { + }, 'toggle follow link'); + + followLinkOnClick = undoable(() => { this.Document.ignoreClick = false; this.Document.onClick = FollowLinkScript(); this.Document.followLinkToggle = false; this.Document.followLinkZoom = false; this.Document.followLinkLocation = undefined; - }; - @undoBatch - noOnClick = () => { - this.Document.ignoreClick = false; - this.Document.onClick = Doc.GetProto(this.Document).onClick = undefined; - }; - - @undoBatch deleteClicked = () => this._props.removeDocument?.(this.Document); - @undoBatch setToggleDetail = () => - (this.Document.onClick = ScriptField.MakeScript( - `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) - .replace('layout_', '') - .replace(/^layout$/, 'detail')}")`, - { documentView: 'any' } - )); + }, 'follow link on click'); - @undoBatch - drop = (e: Event, de: DragManager.DropEvent) => { + noOnClick = undoable(() => { + this.Document.ignoreClick = false; + this.Document.onClick = this.Document[DocData].onClick = undefined; + }, 'default on click'); + + deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc'); + setToggleDetail = undoable( + () => + (this.Document.onClick = ScriptField.MakeScript( + `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) + .replace('layout_', '') + .replace(/^layout$/, 'detail')}")`, + { documentView: 'any' } + )), + 'set toggle detail' + ); + + drop = undoable((e: Event, de: DragManager.DropEvent) => { if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); @@ -642,7 +508,7 @@ export class DocumentViewInternal extends DocComponent { - const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); + makeIntoPortal = undoable(() => { + const portalLink = this._allLinks.find(d => d.link_anchor_1 === this.Document && d.link_relationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( this.Document, @@ -670,7 +535,7 @@ export class DocumentViewInternal extends DocComponent { const input = document.createElement('input'); @@ -716,7 +581,7 @@ export class DocumentViewInternal extends DocComponent { - if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && !this._props.isSelected() && SelectionManager.SelectView(this.DocumentView(), false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. + if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); }; if (navigator.userAgent.includes('Macintosh')) { @@ -811,7 +676,7 @@ export class DocumentViewInternal extends DocComponent Doc.Zip(this.Document) }); - (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this.DocumentView()), icon: 'users' }); + (this.Document._type_collection !== CollectionViewType.Docking || !Doc.noviceMode) && constantItems.push({ description: 'Share', event: () => SharingManager.Instance.open(this._docView), icon: 'users' }); if (this._props.removeDocument && Doc.ActiveDashboard !== this.Document) { // need option to gray out menu items ... preferably with a '?' that explains why they're grayed out (eg., no permissions) constantItems.push({ description: 'Close', event: this.deleteClicked, icon: 'times' }); @@ -877,63 +742,16 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); - onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); + onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler; setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); - setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); - @observable _isContentActive: boolean | undefined = undefined; - + setContentView = action((view: ViewBoxInterface) => (this._componentView = view)); isContentActive = (): boolean | undefined => this._isContentActive; childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; - /// disable pointer events on content when there's an enabled onClick script (but not the browse script) and the contents aren't forced active, or if contents are marked inactive - @computed get _contentPointerEvents() { - TraceMobx(); - return this._props.contentPointerEvents ?? - ((!this.disableClickScriptFunc && // - this.onClickHandler && - !this._props.onBrowseClick?.() && - this.isContentActive() !== true) || - this.isContentActive() === false) - ? 'none' - : this.pointerEvents; - } contentPointerEvents = () => this._contentPointerEvents; - @computed get contents() { - TraceMobx(); - const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; - const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); - return ( -
- - {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints} -
- ); - } anchorPanelWidth = () => this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; @@ -950,33 +768,12 @@ export class DocumentViewInternal extends DocComponent - (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || - (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || - ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.Document)) || - ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.Document)) - ); - } - @computed get allLinks() { - TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.Document); - } - hideLink = computedFn((link: Doc) => () => (link.link_displayLine = false)); - @computed get allLinkEndpoints() { + + removeLinkByHiding = (link: Doc) => () => (link.link_displayLine = false); + allLinkEndpoints = () => { // the small blue dots that mark the endpoints of links - TraceMobx(); if (this._componentView instanceof KeyValueBox || this._props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this._props.dontRegisterView || this.layoutDoc.layout_unrendered) return null; - const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); - return filtered.map(link => ( + return this.filteredLinks.map(link => (
)); - } - - static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { - let gumStream: any; - let recorder: any; - navigator.mediaDevices - .getUserMedia({ - audio: true, - }) - .then(function (stream) { - let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); - if (audioTextAnnos) audioTextAnnos.push(''); - else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List(['']); - DictationManager.Controls.listen({ - interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value), - continuous: { indefinite: false }, - }).then(results => { - if (results && [DictationManager.Controls.Infringed].includes(results)) { - DictationManager.Controls.stop(); - } - onEnd?.(); - }); + }; - gumStream = stream; - recorder = new MediaRecorder(stream); - recorder.ondataavailable = async (e: any) => { - const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); - if (!(result instanceof Error)) { - const audioField = new AudioField(result.accessPaths.agnostic.client); - const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); - if (audioAnnos === undefined) { - dataDoc[field + '_audioAnnotations'] = new List([audioField]); - } else { - audioAnnos.push(audioField); - } - } - }; - //runInAction(() => (dataDoc.audioAnnoState = 'recording')); - recorder.start(); - const stopFunc = () => { - recorder.stop(); - DictationManager.Controls.stop(false); - runInAction(() => (dataDoc.audioAnnoState = 'stopped')); - gumStream.getAudioTracks()[0].stop(); - }; - if (onRecording) onRecording(stopFunc); - else setTimeout(stopFunc, 5000); - }); - } - playAnnotation = () => { - const self = this; - const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped'; - const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); - const anno = audioAnnos?.lastElement(); - if (anno instanceof AudioField) { - switch (audioAnnoState) { - case 'stopped': - this.dataDoc[AudioPlay] = new Howl({ - src: [anno.url.href], - format: ['mp3'], - autoplay: true, - loop: false, - volume: 0.5, - onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')), - }); - this.dataDoc.audioAnnoState = 'playing'; - break; - case 'playing': - this.dataDoc[AudioPlay]?.stop(); - this.dataDoc.audioAnnoState = 'stopped'; - break; - } - } + viewBoxContents = () => { + TraceMobx(); + const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; + const noBackground = this.Document.isGroup && !this._props.LayoutTemplateString?.includes(KeyValueBox.name) && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); + return ( +
+ + {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints()} +
+ ); }; captionStyleProvider = (doc: Opt, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); - @observable _changingTitleField = false; - @observable _dropDownInnerWidth = 0; - fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { - const filteredOptions = new Set(inputOptions); - const scaling = this.titleHeight / 30; /* height of Dropdown */ - Object.entries(DocOptions) - .filter(opts => opts[1].filterable) - .forEach((pair: [string, FInfo]) => filteredOptions.add(pair[0])); - filteredOptions.add(StrCast(this.layoutDoc.layout_showTitle)); - const options = Array.from(filteredOptions) - .filter(f => f) - .map(facet => ({ val: facet, text: facet })); + fieldsDropdown = (reqdFields: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { + const filteredFields = Object.entries(DocOptions).reduce((set, [field, opts]) => (opts.filterable ? set.add(field) : set), new Set(reqdFields)); return (
r && (this._dropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))} + ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))} onPointerDown={action(e => (this._changingTitleField = true))} - style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${scaling})` }}> + style={{ width: 'max-content', transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> !isOpen && (this._changingTitleField = false))} selectedVal={placeholder} @@ -1100,7 +844,7 @@ export class DocumentViewInternal extends DocComponent ({ val: facet, text: facet }))} width={100} fillWidth /> @@ -1108,43 +852,24 @@ export class DocumentViewInternal extends DocComponent ); }; - @computed get innards() { - TraceMobx(); + /** + * displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by + * setting layout_showTitle using the format: field1[;field2[...][:hover]] + * from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover] + **/ + titleView = () => { const showTitle = this.layout_showTitle?.split(':')[0]; const showTitleHover = this.layout_showTitle?.includes(':hover'); - const captionView = !this.layout_showCaption ? null : ( -
- -
- ); - const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document; - const background = StrCast( - this.layoutDoc.layout_headingColor, - StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)) - ); - const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._dropDownInnerWidth * this.titleHeight) / 30) : 0; - const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); - // displays a 'title' at the top of a document. The title contents default to the 'title' field, but can be changed to one or more fields by - // setting layout_showTitle using the format: field1[;field2[...][:hover]] - // from the UI, this is done by clicking the title field and prefixin the format with '#'. eg., #field1[;field2;...][:hover] - const titleView = !showTitle ? null : ( + + const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.Document; + const background = StrCast( + this.layoutDoc.layout_headingColor, + StrCast(SharingManager.Instance.users.find(u => u.user.email === this.dataDoc.author)?.sharingDoc.headingColor, StrCast(Doc.SharingDoc().headingColor, SettingsManager.userBackgroundColor)) + ); + const dropdownWidth = this._titleRef.current?._editing || this._changingTitleField ? Math.max(10, (this._titleDropDownInnerWidth * this.titleHeight) / 30) : 0; + const sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); + + return !showTitle ? null : (
{ @@ -1206,19 +931,36 @@ export class DocumentViewInternal extends DocComponent
); - return this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? ( - this.contents - ) : ( -
- {titleView} - {this.contents} - {captionView} + }; + + captionView = () => { + return !this.layout_showCaption ? null : ( +
+
); - } + }; renderDoc = (style: object) => { TraceMobx(); + const showTitle = this.layout_showTitle?.split(':')[0]; return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null : this.docContents ?? ( @@ -1234,49 +976,22 @@ export class DocumentViewInternal extends DocComponent - {this.innards} + {this._props.hideTitle || (!showTitle && !this.layout_showCaption) ? ( + this.viewBoxContents() + ) : ( +
+ {this.titleView()} + {this.viewBoxContents()} + {this.captionView()} +
+ )} {this.widgetDecorations ?? null}
); }; - /** - * returns an entrance animation effect function to wrap a JSX element - * @param presEffectDoc presentation effects document that specifies the animation effect parameters - * @returns a function that will wrap a JSX animation element wrapping any JSX element - */ - public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt, root: Doc) { - const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; - const effectProps = { - left: dir === PresEffectDirection.Left, - right: dir === PresEffectDirection.Right, - top: dir === PresEffectDirection.Top, - bottom: dir === PresEffectDirection.Bottom, - opposite: true, - delay: 0, - duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)), - }; - //prettier-ignore - switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { - default: - case PresEffect.None: return renderDoc; - case PresEffect.Zoom: return {renderDoc}; - case PresEffect.Fade: return {renderDoc}; - case PresEffect.Flip: return {renderDoc}; - case PresEffect.Rotate: return {renderDoc}; - case PresEffect.Bounce: return {renderDoc}; - case PresEffect.Roll: return {renderDoc}; - case PresEffect.Lightspeed: return {renderDoc}; - } - } - @computed get highlighting() { - return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.Highlighting); - } - @computed get borderPath() { - return this._props.styleProvider?.(this.Document, { ...this._props, fieldKey: '' }, StyleProp.BorderPath); - } render() { TraceMobx(); const highlighting = this.highlighting; @@ -1304,10 +1019,10 @@ export class DocumentViewInternal extends DocComponent (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerOver={e => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} - onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} + onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} style={{ borderRadius: this.borderRounding, - pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) + pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) }}> <> {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} @@ -1316,176 +1031,124 @@ export class DocumentViewInternal extends DocComponent ); } -} -@observer -export class DocumentView extends ObservableReactComponent { - public static ROOT_DIV = 'documentView-effectsWrapper'; - - constructor(props: any) { - super(props); - makeObservable(this); + /** + * returns an entrance animation effect function to wrap a JSX element + * @param presEffectDoc presentation effects document that specifies the animation effect parameters + * @returns a function that will wrap a JSX animation element wrapping any JSX element + */ + public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt, root: Doc) { + const dir = presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection; + const effectProps = { + left: dir === PresEffectDirection.Left, + right: dir === PresEffectDirection.Right, + top: dir === PresEffectDirection.Top, + bottom: dir === PresEffectDirection.Bottom, + opposite: true, + delay: 0, + duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)), + }; + //prettier-ignore + switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { + default: + case PresEffect.None: return renderDoc; + case PresEffect.Zoom: return {renderDoc}; + case PresEffect.Fade: return {renderDoc}; + case PresEffect.Flip: return {renderDoc}; + case PresEffect.Rotate: return {renderDoc}; + case PresEffect.Bounce: return {renderDoc}; + case PresEffect.Roll: return {renderDoc}; + case PresEffect.Lightspeed: return {renderDoc}; + } } + public static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { + let gumStream: any; + let recorder: any; + navigator.mediaDevices + .getUserMedia({ + audio: true, + }) + .then(function (stream) { + let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); + if (audioTextAnnos) audioTextAnnos.push(''); + else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List(['']); + DictationManager.Controls.listen({ + interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value), + continuous: { indefinite: false }, + }).then(results => { + if (results && [DictationManager.Controls.Infringed].includes(results)) { + DictationManager.Controls.stop(); + } + onEnd?.(); + }); - @observable _selected = false; - public get IsSelected() { - return this._selected; - } - public set IsSelected(val) { - runInAction(() => (this._selected = val)); - } - @observable public static LongPress = false; - @computed public static get exploreMode() { - return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); + gumStream = stream; + recorder = new MediaRecorder(stream); + recorder.ondataavailable = async (e: any) => { + const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); + if (!(result instanceof Error)) { + const audioField = new AudioField(result.accessPaths.agnostic.client); + const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); + if (audioAnnos === undefined) { + dataDoc[field + '_audioAnnotations'] = new List([audioField]); + } else { + audioAnnos.push(audioField); + } + } + }; + //runInAction(() => (dataDoc.audioAnnoState = 'recording')); + recorder.start(); + const stopFunc = () => { + recorder.stop(); + DictationManager.Controls.stop(false); + runInAction(() => (dataDoc.audioAnnoState = 'stopped')); + gumStream.getAudioTracks()[0].stop(); + }; + if (onRecording) onRecording(stopFunc); + else setTimeout(stopFunc, 5000); + }); } - @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; - @observable private _htmlOverlayText: Opt = undefined; - @observable private _isHovering = false; - private _htmlOverlayEffect: Opt; +} - public get displayName() { - return 'DocumentView(' + this.Document?.title + ')'; - } // this makes mobx trace() statements more descriptive +@observer +export class DocumentView extends DocComponent() { + public static ROOT_DIV = 'documentView-effectsWrapper'; + public get displayName() { return 'DocumentView(' + this.Document?.title + ')'; } // prettier-ignore public ContentRef = React.createRef(); - public ViewTimer: NodeJS.Timeout | undefined; // timer for res - public AnimEffectTimer: NodeJS.Timeout | undefined; // timer for res + private _htmlOverlayEffect: Opt; private _disposers: { [name: string]: IReactionDisposer } = {}; - public clearViewTransition = () => { - this.ViewTimer && clearTimeout(this.ViewTimer); - this.layoutDoc._viewTransition = undefined; - }; - playAnnotation = () => this._docViewInternal?.playAnnotation(); - noOnClick = () => this._docViewInternal?.noOnClick(); - makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); - setToggleDetail = () => this._docViewInternal?.setToggleDetail(); - onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); - cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + private _viewTimer: NodeJS.Timeout | undefined; + private _animEffectTimer: NodeJS.Timeout | undefined; - public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); - - public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { - this._htmlOverlayText = text; - this._htmlOverlayEffect = effect; - }); - public setAnimateScaling = action((scale: number, time?: number) => { - if (this._docViewInternal) { - this._docViewInternal._animateScalingTo = scale; - this._docViewInternal._animateScaleTime = time; - } - }); - public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { - this.AnimEffectTimer && clearTimeout(this.AnimEffectTimer); - this.Document[Animation] = presEffect; - this.AnimEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); - }; - public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this.layoutDoc._viewTransition = `${transProp} ${timeInMs}ms`; - if (dataTrans) this.Document._dataTransition = `${transProp} ${timeInMs}ms`; - this.ViewTimer && clearTimeout(this.ViewTimer); - return (this.ViewTimer = setTimeout(() => { - this.layoutDoc._viewTransition = undefined; - this.Document._dataTransition = 'inherit'; - afterTrans?.(); - }, timeInMs + 10)); - }; - public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) { - docs.forEach(doc => { - doc._viewTransition = `${transProp} ${timeInMs}ms`; - dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); - }); - return setTimeout( - () => - docs.forEach(doc => { - doc._viewTransition = undefined; - dataTrans && (doc.dataTransition = 'inherit'); - afterTrans?.(); - }), - timeInMs + 10 - ); + @computed public static get exploreMode() { + return () => (SnappingManager.ExploreMode ? ScriptField.MakeScript('CollectionBrowseClick(documentView, clientX, clientY)', { documentView: 'any', clientX: 'number', clientY: 'number' })! : undefined); } - // shows a stacking view collection (by default, but the user can change) of all documents linked to the source - public static showBackLinks(linkAnchor: Doc) { - const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish'; - // prettier-ignore - DocServer.GetRefField(docId).then(docx => - LightboxView.Instance.SetLightboxDoc( - (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection - Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) - ) - ); + constructor(props: DocumentViewProps) { + super(props); + makeObservable(this); } - toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); - get Document() { - return this._props.Document; - } - get topMost() { - return this._props.renderDepth === 0; - } - get dataDoc() { - return this._docViewInternal?.dataDoc ?? this.Document; - } - get ContentDiv() { - return this._docViewInternal?.ContentDiv; - } - get ComponentView() { - return this._docViewInternal?._componentView; - } - get allLinks() { - return (this._docViewInternal?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); - } - get LayoutFieldKey() { - return this._docViewInternal?.LayoutFieldKey || 'layout'; - } - @computed get layout_fitWidth() { - return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; - } - @computed get anchorViewDoc() { - return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; - } - @computed get hideLinkButton() { - return ( - this._props.hideLinkButton || - this._props.renderDepth === -1 || // - (this.IsSelected && this._props.renderDepth) || - !this._isHovering || - (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || - SnappingManager.IsDragging || - SnappingManager.IsResizing - ); - } - hideLinkCount = () => (this.hideLinkButton ? true : false); + // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. + // unfortunately, CSS can't transition animate any properties for something that is display 'none'. + // so we need to first activate the div, then, after a render timeout, start the opacity transition. + @observable private _enableHtmlOverlayTransitions: boolean = false; + @observable private _docViewInternal: DocumentViewInternal | undefined | null = undefined; + @observable private _htmlOverlayText: Opt = undefined; + @observable private _isHovering = false; + @observable private _selected = false; + @observable public static LongPress = false; - @computed get linkCountView() { - return ; - } - /** - * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg) - */ - @computed get containerViewPath() { - return this._props.containerViewPath; - } - @computed get layoutDoc() { - return Doc.Layout(this.Document, this._props.LayoutTemplate?.()); - } - @computed get nativeWidth() { - return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); - } - @computed get nativeHeight() { - return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); - } - @computed get shouldNotScale() { + @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this._props.LayoutTemplateString?.includes(KeyValueBox.name) || [CollectionViewType.Docking].includes(this.Document._type_collection as any); } - @computed get effectiveNativeWidth() { + @computed private get effectiveNativeWidth() { return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width); } - @computed get effectiveNativeHeight() { + @computed private get effectiveNativeHeight() { return this.shouldNotScale ? 0 : this.nativeHeight || NumCast(this.layoutDoc.height); } - @computed get nativeScaling() { + @computed private get nativeScaling() { if (this.shouldNotScale) return 1; const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; if (this.layout_fitWidth || this._props.PanelHeight() / (this.effectiveNativeHeight || 1) > this._props.PanelWidth() / (this.effectiveNativeWidth || 1)) { @@ -1493,19 +1156,19 @@ export class DocumentView extends ObservableReactComponent { } return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled } - @computed get panelWidth() { + @computed private get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth(); } - @computed get panelHeight() { + @computed private get panelHeight() { if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) { return Math.min(this._props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this._props.PanelHeight(); } - @computed get Xshift() { + @computed private get Xshift() { return this.effectiveNativeWidth ? Math.max(0, (this._props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0; } - @computed get Yshift() { + @computed private get Yshift() { return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && @@ -1513,41 +1176,99 @@ export class DocumentView extends ObservableReactComponent { ? Math.max(0, (this._props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2) : 0; } - @computed get centeringX() { - return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; + @computed private get hideLinkButton() { + return ( + this._props.hideLinkButton || + this._props.renderDepth === -1 || // + (this.IsSelected && this._props.renderDepth) || + !this._isHovering || + (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || + SnappingManager.IsDragging || + SnappingManager.IsResizing + ); + } + + componentDidMount() { + runInAction(() => this.Document[DocViews].add(this)); + this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); + } + + componentWillUnmount() { + runInAction(() => this.Document[DocViews].delete(this)); + Object.values(this._disposers).forEach(disposer => disposer?.()); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } - @computed get centeringY() { - return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; + + public set IsSelected(val) { runInAction(() => (this._selected = val)); } // prettier-ignore + public get IsSelected() { return this._selected; } // prettier-ignore + public get topMost() { return this._props.renderDepth === 0; } // prettier-ignore + public get ContentDiv() { return this._docViewInternal?._contentDiv; } // prettier-ignore + public get ComponentView() { return this._docViewInternal?._componentView; } // prettier-ignore + public get allLinks() { return this._docViewInternal?._allLinks ?? []; } // prettier-ignore + + get LayoutFieldKey() { + return Doc.LayoutFieldKey(this.Document, this._props.LayoutTemplateString); } - @computed get CollectionFreeFormView() { - return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; + @computed get layout_fitWidth() { + return this._props.layout_fitWidth?.(this.layoutDoc) ?? this.layoutDoc?.layout_fitWidth; } - @computed get CollectionFreeFormDocumentView() { - return this._props.CollectionFreeFormDocumentView?.(); + @computed get anchorViewDoc() { + return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } - public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this._docViewInternal.NativeDimScaling, this._props.PanelWidth(), this._props.PanelHeight()); - public getBounds = () => { - if (!this._docViewInternal?.ContentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { + @computed get getBounds() { + if (!this._docViewInternal?._contentDiv || this._props.treeViewDoc || Doc.AreProtosEqual(this.Document, Doc.UserDoc())) { return undefined; } if (this._docViewInternal._componentView?.screenBounds?.()) { return this._docViewInternal._componentView.screenBounds(); } - const xf = this._docViewInternal._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); + const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this._docViewInternal._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const docuBox = this._docViewInternal.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); + if (this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { + const docuBox = this._docViewInternal._contentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } return { left, top, right, bottom }; + } + + @computed get nativeWidth() { + return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); + } + @computed get nativeHeight() { + return this._props.LayoutTemplateString?.includes(KeyValueBox.name) ? 0 : returnVal(this._props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this._props.TemplateDataDocument, !this.layout_fitWidth)); + } + @computed public get centeringX() { return this._props.dontCenter?.includes('x') ? 0 : this.Xshift; } // prettier-ignore + @computed public get centeringY() { return this._props.dontCenter?.includes('y') ? 0 : this.Yshift; } // prettier-ignore + + /** + * path of DocumentViews hat contains this DocumentView (does not includes this DocumentView thouhg) + */ + public get containerViewPath() { return this._props.containerViewPath; } // prettier-ignore + public get CollectionFreeFormView() { return this.CollectionFreeFormDocumentView?.CollectionFreeFormView; } // prettier-ignore + public get CollectionFreeFormDocumentView() { return this._props.CollectionFreeFormDocumentView?.(); } // prettier-ignore + + public clearViewTransition = () => { + this._viewTimer && clearTimeout(this._viewTimer); + this.layoutDoc._viewTransition = undefined; }; + public noOnClick = () => this._docViewInternal?.noOnClick(); + public makeIntoPortal = () => this._docViewInternal?.makeIntoPortal(); + public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle); + public setToggleDetail = () => this._docViewInternal?.setToggleDetail(); + public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); + public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); + public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); + + public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); public iconify(finished?: () => void, animateTime?: number) { this.ComponentView?.updateIcon?.(); - const animTime = this._docViewInternal?._animateScaleTime; + const animTime = this._docViewInternal?.animateScaleTime(); runInAction(() => this._docViewInternal && animateTime !== undefined && (this._docViewInternal._animateScaleTime = animateTime)); const finalFinished = action(() => { finished?.(); @@ -1564,13 +1285,58 @@ export class DocumentView extends ObservableReactComponent { this._props.bringToFront(this.Document); } } - @undoBatch - setCustomView = (custom: boolean, layout: string): void => { + + public playAnnotation = () => { + const self = this; + const audioAnnoState = this.dataDoc.audioAnnoState ?? 'stopped'; + const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); + const anno = audioAnnos?.lastElement(); + if (anno instanceof AudioField) { + switch (audioAnnoState) { + case 'stopped': + this.dataDoc[AudioPlay] = new Howl({ + src: [anno.url.href], + format: ['mp3'], + autoplay: true, + loop: false, + volume: 0.5, + onend: action(() => (self.dataDoc.audioAnnoState = 'stopped')), + }); + this.dataDoc.audioAnnoState = 'playing'; + break; + case 'playing': + this.dataDoc[AudioPlay]?.stop(); + this.dataDoc.audioAnnoState = 'stopped'; + break; + } + } + }; + + public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { + this._htmlOverlayText = text; + this._htmlOverlayEffect = effect; + }); + public setAnimateScaling = action((scale: number, time?: number) => { + if (this._docViewInternal) { + this._docViewInternal._animateScalingTo = scale; + this._docViewInternal._animateScaleTime = time; + } + }); + public setAnimEffect = (presEffect: Doc, timeInMs: number, afterTrans?: () => void) => { + this._animEffectTimer && clearTimeout(this._animEffectTimer); + this.Document[Animation] = presEffect; + this._animEffectTimer = setTimeout(() => (this.Document[Animation] = undefined), timeInMs); + }; + public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { + this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans); + }; + + public setCustomView = undoable((custom: boolean, layout: string): void => { Doc.setNativeView(this.Document); custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined); - }; + }, 'set custom view'); - switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { + public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => { runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc setTimeout( action(() => { @@ -1585,16 +1351,19 @@ export class DocumentView extends ObservableReactComponent { this._docViewInternal && (this._docViewInternal._animateScalingTo = 0); finished?.(); }), - this._docViewInternal ? Math.max(0, this._docViewInternal.animateScaleTime - 10) : 0 + Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10) ); }), - this._docViewInternal ? Math.max(0, this._docViewInternal?.animateScaleTime - 10) : 0 + Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10) ); }; + /** + * @returns a hierarchy path through the nested DocumentViews that display this view. The last element of the path is this view. + */ + public docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; - docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); @@ -1615,6 +1384,7 @@ export class DocumentView extends ObservableReactComponent { PanelWidth = () => this.panelWidth; PanelHeight = () => this.panelHeight; NativeDimScaling = () => this.nativeScaling; + hideLinkCount = () => (this.hideLinkButton ? true : false); selfView = () => this; /** * @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView) @@ -1629,34 +1399,19 @@ export class DocumentView extends ObservableReactComponent { .translate(-this.centeringX, -this.centeringY) .scale(1 / this.nativeScaling); - componentDidMount() { - runInAction(() => this.Document[DocViews].add(this)); - this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); - } - - componentWillUnmount() { - runInAction(() => this.Document[DocViews].delete(this)); - Object.values(this._disposers).forEach(disposer => disposer?.()); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); - } - // want the htmloverlay to be able to fade in but we also want it to be display 'none' until it is needed. - // unfortunately, CSS can't transition animate any properties for something that is display 'none'. - // so we need to first activate the div, then, after a render timeout, start the opacity transition. - @observable enableHtmlOverlayTransitions: boolean = false; - @computed get htmlOverlay() { + htmlOverlay = () => { const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect)); return (
{ const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition - if (r && val !== this.enableHtmlOverlayTransitions) { - setTimeout(action(() => (this.enableHtmlOverlayTransitions = val))); + if (r && val !== this._enableHtmlOverlayTransitions) { + setTimeout(action(() => (this._enableHtmlOverlayTransitions = val))); } }} style={{ display: !this._htmlOverlayText ? 'none' : undefined }}> -
+
{DocumentViewInternal.AnimationEffect(
console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> @@ -1667,11 +1422,7 @@ export class DocumentView extends ObservableReactComponent {
); - } - - @computed get infoUI() { - return this.ComponentView?.infoUI?.(); - } + }; render() { TraceMobx(); @@ -1685,14 +1436,14 @@ export class DocumentView extends ObservableReactComponent { className="contentFittingDocumentView-previewDoc" ref={this.ContentRef} style={{ - transition: 'inherit', // this._props.dataTransition, transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`), }}> { focus={this._props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this._docViewInternal = r))} /> - {this.htmlOverlay} - {this.infoUI} + {this.htmlOverlay()} + {this.ComponentView?.infoUI?.()}
)} - - {this.linkCountView} + {/* display link count button */} +
); } + + public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) { + docs.forEach(doc => { + doc._viewTransition = `${transProp} ${timeInMs}ms`; + dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); + }); + timer && clearTimeout(timer); + return setTimeout( + () => + docs.forEach(doc => { + doc._viewTransition = undefined; + dataTrans && (doc.dataTransition = 'inherit'); + afterTrans?.(); + }), + timeInMs + 10 + ); + } + + // shows a stacking view collection (by default, but the user can change) of all documents linked to the source + public static showBackLinks(linkAnchor: Doc) { + const docId = Doc.CurrentUserEmail + Doc.GetProto(linkAnchor)[Id] + '-pivotish'; + // prettier-ignore + DocServer.GetRefField(docId).then(docx => + LightboxView.Instance.SetLightboxDoc( + (docx as Doc) ?? // reuse existing pivot view of documents, or else create a new collection + Docs.Create.StackingDocument([], { title: linkAnchor.title + '-pivot', _width: 500, _height: 500, target: linkAnchor, onViewMounted: ScriptField.MakeScript('updateLinkCollection(this, this.target)') }, docId) + ) + ); + } } ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index cad76ddf7..2e03a766a 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -20,13 +20,13 @@ export class EquationBox extends ViewBoxBaseComponent() { public static SelectOnLoad: string = ''; _ref: React.RefObject = React.createRef(); - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); if (EquationBox.SelectOnLoad === this.Document[Id] && (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.()))) { this._props.select(false); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index b456807d7..5bb295565 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,26 +1,108 @@ -import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { DateField } from '../../../fields/DateField'; -import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; +import { Doc, Field, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ScriptField } from '../../../fields/ScriptField'; import { WebField } from '../../../fields/URLField'; -import { DocumentView, DocumentViewInternalSharedProps, DocumentViewSharedProps } from './DocumentView'; +import { dropActionType } from '../../util/DragManager'; +import { Transform } from '../../util/Transform'; +import { ViewBoxInterface } from '../DocComponent'; +import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; +import { DocumentView, OpenWhere } from './DocumentView'; +import { PinProps } from './trails'; +export interface FocusViewOptions { + willPan?: boolean; // determines whether to pan to target document + willZoomCentered?: boolean; // determines whether to zoom in on target document. if zoomScale is 0, this just centers the document + zoomScale?: number; // percent of containing frame to zoom into document + zoomTime?: number; + didMove?: boolean; // whether a document was changed during the showDocument process + docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy + instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) + preview?: boolean; // whether changes should be previewed by the componentView or written to the document + effect?: Doc; // animation effect for focus + noSelect?: boolean; // whether target should be selected after focusing + playAudio?: boolean; // whether to play audio annotation on focus + playMedia?: boolean; // whether to play start target videos + openLocation?: OpenWhere; // where to open a missing document + zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections + toggleTarget?: boolean; // whether to toggle target on and off + anchorDoc?: Doc; // doc containing anchor info to apply at end of focus to target doc + easeFunc?: 'linear' | 'ease'; // transition method for scrolling +} +export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt; +export type StyleProviderFuncType = (doc: Opt, props: Opt, property: string) => any; // // these properties get assigned through the render() method of the DocumentView when it creates this node. // However, that only happens because the properties are "defined" in the markup for the field view. // See the LayoutString method on each field view : ImageBox, FormattedTextBox, etc. // -export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInternalSharedProps { - // FieldView specific props that are not part of DocumentView props - fieldKey: string; - - setHeight?: (height: number) => void; - onBrowseClick?: () => ScriptField | undefined; +export interface FieldViewSharedProps { + Document: Doc; + LayoutTemplateString?: string; + LayoutTemplate?: () => Opt; + TemplateDataDocument?: Doc; + renderDepth: number; + scriptContext?: any; // can be assigned anything and will be passed as 'scriptContext' to any OnClick script that executes on this document + treeViewDoc?: Doc; + xPadding?: number; + yPadding?: number; + dontRegisterView?: boolean; + dropAction?: dropActionType; + dragAction?: dropActionType; + forceAutoHeight?: boolean; + ignoreAutoHeight?: boolean; + disableBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over. + CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; + containerViewPath?: () => DocumentView[]; + fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document + isGroupActive?: () => string | undefined; // is this document part of a group that is active + setContentViewBox?: (view: ViewBoxInterface) => any; // called by rendered field's viewBox so that DocumentView can make direct calls to the viewBox + PanelWidth: () => number; + PanelHeight: () => number; + isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events + isContentActive: () => boolean | undefined; // whether document contents should handle pointer events + childFilters: () => string[]; + childFiltersByRanges: () => string[]; + styleProvider: Opt; + setTitleFocus?: () => void; + focus: FocusFuncType; + onClickScript?: () => ScriptField; + onDoubleClickScript?: () => ScriptField; + onPointerDownScript?: () => ScriptField; + onPointerUpScript?: () => ScriptField; + onBrowseClickScript?: () => ScriptField | undefined; onKey?: (e: React.KeyboardEvent, fieldProps: FieldViewProps) => boolean | undefined; + layout_fitWidth?: (doc: Doc) => boolean | undefined; + searchFilterDocs: () => Doc[]; + layout_showTitle?: () => string; + whenChildContentsActiveChanged: (isActive: boolean) => void; + rootSelected?: () => boolean; // whether the root of a template has been selected + addDocTab: (doc: Doc, where: OpenWhere) => boolean; + filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) + addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + removeDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; + moveDocument?: (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => boolean; + pinToPres: (document: Doc, pinProps: PinProps) => void; + ScreenToLocalTransform: () => Transform; + bringToFront: (doc: Doc, sendToBack?: boolean) => void; + waitForDoubleClickToClick?: () => 'never' | 'always' | undefined; + defaultDoubleClick?: () => 'default' | 'ignore' | undefined; pointerEvents?: () => Opt; +} + +/** + * FieldView specific props that are not shared with DocumentView props + * */ +export interface FieldViewProps extends FieldViewSharedProps { + DocumentView?: () => DocumentView; + fieldKey: string; + isSelected: () => boolean; + select: (ctrlPressed: boolean, shiftPress?: boolean) => void; + docViewPath: () => DocumentView[]; + setHeight?: (height: number) => void; + NativeDimScaling?: () => number; // scaling the DocumentView does to transform its contents into its panel & needed by ScreenToLocal // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React) // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields @@ -30,9 +112,9 @@ export interface FieldViewProps extends DocumentViewSharedProps, DocumentViewInt color?: string; height?: number; width?: number; + dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field) noSidebar?: boolean; dontScale?: boolean; - dontSelectOnLoad?: boolean; // suppress selecting (e.g.,. text box) when loaded (and mark as not being associated with scrollTop document field) } @observer @@ -41,13 +123,8 @@ export class FieldView extends React.Component { return `<${fieldType.name} {...props} fieldKey={'${fieldStr}'}/>`; //e.g., "" } - @computed - get field(): FieldResult { - const { Document, fieldKey: fieldKey } = this.props; - return Document[fieldKey]; - } render() { - const field = this.field; + const field = this.props.Document[this.props.fieldKey]; // prettier-ignore if (field instanceof Doc) return

{field.title?.toString()}

; if (field === undefined) return

{''}

; diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index 5a8665aaf..cf07d98be 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -46,7 +46,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(FontIconBox, fieldKey); } - constructor(props: any) { + constructor(props: ButtonProps) { super(props); makeObservable(this); } diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index c26579e66..2e7a2120e 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -31,7 +31,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); reaction( () => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange], () => this.createGraph() diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4483d12ce..2a10bd766 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -21,17 +21,17 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../../views/ContextMenu'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, OpenWhere } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { OpenWhere } from './DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import { PinProps, PresBox } from './trails'; @observer -export class ImageBox extends ViewBoxAnnotatableComponent() { +export class ImageBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } @@ -55,10 +55,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent(); @observable _curSuffix = ''; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } protected createDropTarget = (ele: HTMLDivElement) => { @@ -186,9 +186,10 @@ export class ImageBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; this.addDocument(region); const anchx = NumCast(cropping.x); const anchy = NumCast(cropping.y); @@ -201,7 +202,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); + focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); _ffref = React.createRef(); savedAnnotations = () => this._savedAnnotations; @@ -421,7 +422,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { private _valInput = React.createRef(); componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); } isKeyValueBox = returnTrue; able = returnAlways; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index b2aab2422..7c532f33f 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -12,8 +12,7 @@ import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; -import { OpenWhere } from './DocumentView'; -import { FieldViewProps } from './FieldView'; +import { OpenWhere, returnEmptyDocViewList } from './DocumentView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; @@ -110,6 +109,7 @@ export class KeyValuePair extends ObservableReactComponent { childFiltersByRanges: returnEmptyFilter, searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, + docViewPath: returnEmptyDocViewList, fieldKey: this._props.keyName, isSelected: returnFalse, setHeight: returnFalse, diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index cc7c15a10..10eeff08d 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -14,13 +14,15 @@ import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; +import { PinProps, PresBox } from './trails'; +import { Docs } from '../../documents/Documents'; -export interface LabelBoxProps { +export interface LabelBoxProps extends FieldViewProps { label?: string; } @observer -export class LabelBox extends ViewBoxBaseComponent() { +export class LabelBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } @@ -30,13 +32,13 @@ export class LabelBox extends ViewBoxBaseComponent { + if (!pinProps) return this.Document; + const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document }); + + if (anchor) { + if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; + // addAsAnnotation && this.addDocument(anchor); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}) } }, this.Document); + return anchor; + } + return anchor; + }; + fitTextToBox = ( r: any ): diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 362a7def1..00e1f04c5 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,4 +1,5 @@ import { action, computed, makeObservable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; @@ -7,13 +8,14 @@ import { TraceMobx } from '../../../fields/util'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { SelectionManager } from '../../util/SelectionManager'; -import { ViewBoxBaseComponent, ViewBoxBaseProps } from '../DocComponent'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkInfo } from './LinkDocPreview'; const { default: { MEDIUM_GRAY }, } = require('../global/globalCssVariables.module.scss'); // prettier-ignore -export class LinkAnchorBox extends ViewBoxBaseComponent() { +@observer +export class LinkAnchorBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkAnchorBox, fieldKey); } @@ -23,13 +25,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(LinkBox, fieldKey); } - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -59,7 +59,7 @@ export class LinkBox extends ViewBoxBaseComponent() { }; disposer: IReactionDisposer | undefined; componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this.disposer = reaction( () => { if (this.layoutDoc._layout_isSvg && (this.anchor1 || this.anchor2)?.CollectionFreeFormView) { @@ -100,6 +100,9 @@ export class LinkBox extends ViewBoxBaseComponent() { this.layoutDoc._width = params.rx - params?.lx; this.layoutDoc._height = params?.by - params?.ty; } + } else { + this.layoutDoc._width = Math.max(50, NumCast(this.layoutDoc._width)); + this.layoutDoc._height = Math.max(50, NumCast(this.layoutDoc._height)); } }, { fireImmediately: true } diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 8ad0b7dde..13f0ac4fc 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,20 +1,27 @@ -import { action, observable } from 'mobx'; +import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { LinkManager } from '../../util/LinkManager'; import './LinkDescriptionPopup.scss'; import { TaskCompletionBox } from './TaskCompletedBox'; @observer export class LinkDescriptionPopup extends React.Component<{}> { - @observable public static descriptionPopup: boolean = false; - @observable public static showDescriptions: string = 'ON'; - @observable public static popupX: number = 700; - @observable public static popupY: number = 350; + public static Instance: LinkDescriptionPopup; + @observable public display: boolean = false; + @observable public showDescriptions: string = 'ON'; + @observable public popupX: number = 700; + @observable public popupY: number = 350; @observable description: string = ''; @observable popupRef = React.createRef(); + constructor(props: any) { + super(props); + makeObservable(this); + LinkDescriptionPopup.Instance = this; + } + @action descriptionChanged = (e: React.ChangeEvent) => { this.description = e.currentTarget.value; @@ -22,16 +29,16 @@ export class LinkDescriptionPopup extends React.Component<{}> { @action onDismiss = (add: boolean) => { - LinkDescriptionPopup.descriptionPopup = false; + this.display = false; if (add) { - LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description); + LinkManager.currentLink && (LinkManager.currentLink[DocData].link_description = this.description); } }; @action onClick = (e: PointerEvent) => { if (this.popupRef && !!!this.popupRef.current?.contains(e.target as any)) { - LinkDescriptionPopup.descriptionPopup = false; + this.display = false; TaskCompletionBox.taskCompleted = false; } }; @@ -46,13 +53,13 @@ export class LinkDescriptionPopup extends React.Component<{}> { } render() { - return ( + return !this.display ? null : (
; @@ -45,7 +45,7 @@ interface LinkDocPreviewProps { linkDoc?: Doc; linkSrc?: Doc; DocumentView?: () => DocumentView; - styleProvider?: StyleProviderFunc; + styleProvider?: StyleProviderFuncType; location: number[]; hrefs?: string[]; showHeader?: boolean; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 56fb157da..c185c66fc 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -23,12 +23,12 @@ import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../../DocComponent'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; @@ -96,7 +96,7 @@ type MapMarker = { // }); @observer -export class MapBox extends ViewBoxAnnotatableComponent() { +export class MapBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBox, fieldKey); } @@ -107,7 +107,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => void); - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } @@ -248,7 +248,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -504,7 +504,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { this.toggleSidebar(); options.didMove = true; diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 9734d9db1..9825824bd 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -12,7 +12,7 @@ // import { SnappingManager } from '../../../util/SnappingManager'; // import { UndoManager } from '../../../util/UndoManager'; // import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; -// import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +// import { ViewBoxAnnotatableComponent } from '../../DocComponent'; // import { Colors } from '../../global/globalEnums'; // import { AnchorMenu } from '../../pdf/AnchorMenu'; // import { Annotation } from '../../pdf/Annotation'; @@ -83,7 +83,7 @@ // } as google.maps.places.AutocompleteOptions; // @observer -// export class MapBox2 extends ViewBoxAnnotatableComponent>() { +// export class MapBox2 extends ViewBoxAnnotatableComponent>() { // private _dropDisposer?: DragManager.DragDropDisposer; // private _disposers: { [name: string]: IReactionDisposer } = {}; // private _annotationLayer: React.RefObject = React.createRef(); @@ -137,7 +137,7 @@ // // iterate allMarkers to size, center, and zoom map to contain all markers // private fitBounds = (map: google.maps.Map) => { -// const curBounds = map.getBounds() ?? new window.google.maps.LatLngBounds(); +// const curBounds = map.getBounds ?? new window.google.maps.LatLngBounds(); // const isFitting = this.allMapMarkers.reduce((fits, place) => fits && curBounds?.contains({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), true as boolean); // !isFitting && map.fitBounds(this.allMapMarkers.reduce((bounds, place) => bounds.extend({ lat: NumCast(place.lat), lng: NumCast(place.lng) }), new window.google.maps.LatLngBounds())); // }; @@ -257,7 +257,7 @@ // map.setZoom(NumCast(this.dataDoc.map_zoom, 2.5)); // map.setCenter(new google.maps.LatLng(NumCast(this.dataDoc.mapLat), NumCast(this.dataDoc.mapLng))); // setTimeout(() => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } @@ -272,7 +272,7 @@ // @action // centered = () => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } @@ -282,7 +282,7 @@ // @action // zoomChanged = () => { -// if (this._loadPending && this._map.getBounds()) { +// if (this._loadPending && this._map.getBounds) { // this._loadPending = false; // this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); // } diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx index a9c6ba22c..6ccbbbe1c 100644 --- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx +++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx @@ -9,19 +9,18 @@ // import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; // import { CollectionNoteTakingView } from '../../collections/CollectionNoteTakingView'; // import { CollectionStackingView } from '../../collections/CollectionStackingView'; -// import { ViewBoxAnnotatableProps } from '../../DocComponent'; // import { FieldViewProps } from '../FieldView'; // import { FormattedTextBox } from '../formattedText/FormattedTextBox'; // import './MapBox.scss'; -// interface MapBoxInfoWindowProps { +// interface MapBoxInfoWindowProps extends FieldViewProps { // place: Doc; // renderDepth: number; // markerMap: { [id: string]: google.maps.Marker }; // isAnyChildContentActive: () => boolean; // } // @observer -// export class MapBoxInfoWindow extends React.Component { +// export class MapBoxInfoWindow extends React.Component { // @action // private handleInfoWindowClose = () => { // if (this.props.place.infoWindowOpen) { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index e079f7457..8a5bd7ce6 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { MapProvider, Map as MapboxMap } from 'react-map-gl'; @@ -16,18 +16,17 @@ import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoable } from '../../../util/UndoManager'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import './MapBox.scss'; -// amongus /** * MapBox architecture: * Main component: MapBox.tsx @@ -61,7 +60,7 @@ const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing // }); @observer -export class MapBoxContainer extends ViewBoxAnnotatableComponent() { +export class MapBoxContainer extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MapBoxContainer, fieldKey); } @@ -71,6 +70,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent) => void); + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + @observable private _savedAnnotations = new ObservableMap(); @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); @@ -97,7 +101,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -374,7 +378,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { this.toggleSidebar(); options.didMove = true; @@ -787,8 +791,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent() { +export class PDFBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PDFBox, fieldKey); } @@ -58,7 +59,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; this.addDocument(region); const docViewContent = this.DocumentView?.().ContentDiv!; @@ -120,7 +122,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent disposer?.()); } componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this._disposers.select = reaction( () => this._props.isSelected(), () => { @@ -219,12 +221,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent { + focus = (anchor: Doc, options: FocusViewOptions) => { this._initialScrollTarget = anchor; return this._pdfViewer?.scrollFocus(anchor, NumCast(anchor.y, NumCast(anchor.config_scrollTop)), options); }; - getView = async (doc: Doc, options: DocFocusOptions) => { + getView = async (doc: Doc, options: FocusViewOptions) => { if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { options.didMove = true; this.toggleSidebar(false); @@ -528,7 +530,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.DocumentView?.()!, false), true)}> () { @@ -30,8 +31,13 @@ export class RecordingBox extends ViewBoxBaseComponent() { private _ref: React.RefObject = React.createRef(); + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + componentDidMount() { - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); Doc.SetNativeWidth(this.dataDoc, 1280); Doc.SetNativeHeight(this.dataDoc, 720); } @@ -100,7 +106,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { }); screengrabber.overlayX = 70; //was -400 screengrabber.overlayY = 590; //was 0 - Doc.GetProto(screengrabber)[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true; + screengrabber[DocData][Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true; Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => { RecordingBox.screengrabber = docView.ComponentView as RecordingBox; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index f74e6fb2b..1e3933ac3 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -21,12 +21,13 @@ import { TrackMovements } from '../../util/TrackMovements'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { media_state } from './AudioBox'; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import './ScreenshotBox.scss'; import { VideoBox } from './VideoBox'; +import { DocData } from '../../../fields/DocSymbols'; declare class MediaRecorder { constructor(e: any, options?: any); // whatever MediaRecorder has @@ -109,7 +110,7 @@ declare class MediaRecorder { // } @observer -export class ScreenshotBox extends ViewBoxAnnotatableComponent() { +export class ScreenshotBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); } @@ -121,7 +122,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }), // ({ width, height }) => { // if (this._camera) { @@ -281,7 +282,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent () { +export class ScriptingBox extends ViewBoxAnnotatableComponent() { private dropDisposer?: DragManager.DragDropDisposer; public static LayoutString(fieldStr: string) { return FieldView.LayoutString(ScriptingBox, fieldStr); @@ -56,7 +56,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1913ab032..a6c524881 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -4,10 +4,11 @@ import { observer } from 'mobx-react'; import { basename } from 'path'; import * as React from 'react'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; +import { DocData } from '../../../fields/DocSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; @@ -21,12 +22,12 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent, ViewBoxInterface } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView } from './DocumentView'; -import { FieldView, FieldViewProps } from './FieldView'; +import { DocumentView } from './DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import { PinProps, PresBox } from './trails'; import './VideoBox.scss'; @@ -44,7 +45,7 @@ import './VideoBox.scss'; */ @observer -export class VideoBox extends ViewBoxAnnotatableComponent() { +export class VideoBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } @@ -61,10 +62,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true)); }; @@ -368,7 +369,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { + getView = (doc: Doc, options: FocusViewOptions) => { if (this._stackedTimeline?.makeDocUnfiltered(doc)) { if (this.heightPercent === 100) { this.layoutDoc._layout_timelineHeightPercent = VideoBox.heightPercent; @@ -738,7 +739,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.timeline?.setZoom(zoom); // plays link - playLink = (doc: Doc, options: DocFocusOptions) => { + playLink = (doc: Doc, options: FocusViewOptions) => { const startTime = Math.max(0, NumCast(doc.config_clipStart, this._stackedTimeline?.anchorStart(doc) || 0)); const endTime = this.timeline?.anchorEnd(doc); if (startTime !== undefined) { @@ -885,10 +886,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent { if (!region) return; const cropping = Doc.MakeCopy(region, true); - Doc.GetProto(region).backgroundColor = 'transparent'; - Doc.GetProto(region).lockedPosition = true; - Doc.GetProto(region).title = 'region:' + this.Document.title; - Doc.GetProto(region).followLinkToggle = true; + const regionData = region[DocData]; + regionData.backgroundColor = 'transparent'; + regionData.lockedPosition = true; + regionData.title = 'region:' + this.Document.title; + regionData.followLinkToggle = true; region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001; this.addDocument(region); const anchx = NumCast(cropping.x); @@ -904,7 +906,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent () { +export class WebBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } @@ -98,7 +98,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { this._annotationKeySuffix = () => (this._urlHash ? this._urlHash + '_' : '') + 'annotations'; @@ -280,7 +280,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + focus = (anchor: Doc, options: FocusViewOptions) => { if (anchor !== this.Document && this._outerRef.current) { const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); const scrollTo = Utils.scrollIntoView(NumCast(anchor.y), NumCast(anchor._height), NumCast(this.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(anchor.y) + NumCast(anchor._height), this._scrollHeight)); @@ -297,7 +297,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + getView = (doc: Doc, options: FocusViewOptions) => { if (Doc.AreProtosEqual(doc, this.Document)) return new Promise>(res => res(this.DocumentView?.())); if (this.Document.layout_fieldKey === 'layout_icon') this.DocumentView?.().iconify(); const webUrl = WebCast(doc.config_data)?.url; @@ -924,7 +924,7 @@ export class WebBox extends ViewBoxAnnotatableComponent this._innerCollectionView?.zoomScaling() ?? 1; - setInnerContent = (component: DocComponentView) => (this._innerCollectionView = component as CollectionFreeFormView); + setInnerContent = (component: ViewBoxInterface) => (this._innerCollectionView = component as CollectionFreeFormView); @computed get content() { const interactive = this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && Doc.ActiveTool === InkTool.None; @@ -966,7 +966,7 @@ export class WebBox extends ViewBoxAnnotatableComponent string[]) => ( () { return FieldView.LayoutString(CalendarBox, fieldKey); } + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } + componentDidMount(): void {} componentWillUnmount(): void {} @@ -105,11 +110,6 @@ export class CalendarBox extends ViewBoxBaseComponent() { }); } - constructor(props: any) { - super(props); - makeObservable(this); - } - render() { return (
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 4ae12505e..bc49ed23d 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -6,12 +6,13 @@ import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnFalse, Utils } from '../../../../Utils'; +import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { DocFocusOptions, DocumentView, returnEmptyDocViewList } from '../DocumentView'; +import { DocumentView } from '../DocumentView'; +import { FocusViewOptions } from '../FieldView'; import { FormattedTextBox } from './FormattedTextBox'; var horizPadding = 3; // horizontal padding to container to allow cursor to show up on either side. @@ -159,7 +160,7 @@ export class DashDocViewInternal extends ObservableReactComponent this._textBox.focus(target, options); // ideally, this would scroll to show the focus target + outerFocus = (target: Doc, options: FocusViewOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target onKeyDown = (e: any) => { e.stopPropagation(); @@ -178,9 +179,6 @@ export class DashDocViewInternal extends ObservableReactComponent Object.values(this._disposers).forEach(disposer => disposer?.()); isContentActive = () => this._props.tbox._props.isContentActive() || this._props.tbox.isAnyChildContentActive?.(); @@ -210,7 +208,7 @@ export class DashDocViewInternal extends ObservableReactComponent() { +export class FormattedTextBox extends ViewBoxAnnotatableComponent() implements ViewBoxInterface { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } @@ -202,7 +200,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (stopFunc = stop)); + const targetData = target[DocData]; + targetData.mediaState = media_state.Recording; + targetData.audioAnnoState = 'recording'; + DocumentViewInternal.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => (stopFunc = stop)); let reactionDisposer = reaction( () => target.mediaState, action(dictation => { if (!dictation) { - Doc.GetProto(target).audioAnnoState = 'stopped'; + targetData.audioAnnoState = 'stopped'; stopFunc(); reactionDisposer(); } @@ -433,7 +432,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const newAutoLinks = new Set(); - const oldAutoLinks = LinkManager.Links(this._props.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords); + const oldAutoLinks = LinkManager.Links(this.Document).filter(link => link.link_relationship === LinkManager.AutoKeywords); if (this._editorView?.state.doc.textContent) { const isNodeSel = this._editorView.state.selection instanceof NodeSelection; const f = this._editorView.state.selection.from; @@ -451,7 +450,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const title = StrCast(this.dataDoc.title, Cast(this.dataDoc.title, RichTextField, null)?.Text); if ( - !this._props.dontRegisterView && // (this._props.Document.isTemplateForField === "text" || !this._props.Document.isTemplateForField) && // only update the title if the data document's data field is changing + !this._props.dontRegisterView && // (this.Document.isTemplateForField === "text" || !this.Document.isTemplateForField) && // only update the title if the data document's data field is changing (title.startsWith('-') || title.startsWith('@')) && this._editorView && !this.dataDoc.title_custom && @@ -494,7 +493,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.autoLinkAnchor.name)?.attrs.allAnchors ?? [])); const link = editorView.state.schema.marks.autoLinkAnchor.create({ allAnchors, title: 'auto term' }); tr = tr.addMark(pos, pos + node.nodeSize, link); @@ -578,7 +577,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { + getView = async (doc: Doc, options: FocusViewOptions) => { if (DocListCast(this.dataDoc[this.SidebarKey]).find(anno => Doc.AreProtosEqual(doc.layout_unrendered ? DocCast(doc.annotationOn) : doc, anno))) { if (!this.SidebarShown) { this.toggleSidebar(false); @@ -1066,7 +1065,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; - focus = (textAnchor: Doc, options: DocFocusOptions) => { + focus = (textAnchor: Doc, options: FocusViewOptions) => { const focusSpeed = options.zoomTime ?? 500; const textAnchorId = textAnchor[Id]; const findAnchorFrag = (frag: Fragment, editor: EditorView) => { @@ -1141,7 +1140,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent Doc.RecordingEvent, this.breakupDictation); this._disposers.layout_autoHeight = reaction( @@ -1777,7 +1776,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent BoolCast(this._props.Document._freeform_fitContentsToBox); + fitContentsToBox = () => BoolCast(this.Document._freeform_fitContentsToBox); sidebarContentScaling = () => (this._props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1); sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); @@ -2011,7 +2010,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImportElementBox, fieldKey); } + constructor(props: FieldViewProps) { + super(props); + makeObservable(this); + } screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 645ac08e1..9e5ea9524 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, makeObservable, observable, Observ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; -import { Animation } from '../../../../fields/DocSymbols'; +import { Animation, DocData } from '../../../../fields/DocSymbols'; import { Copy, Id } from '../../../../fields/FieldSymbols'; import { InkField } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; @@ -31,8 +31,8 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; -import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView'; -import { FieldView, FieldViewProps } from '../FieldView'; +import { DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView'; +import { FocusViewOptions, FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; @@ -70,7 +70,7 @@ export class PresBox extends ViewBoxBaseComponent() { } static navigateToDocScript: ScriptField; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); if (!PresBox.navigateToDocScript) { @@ -184,7 +184,7 @@ export class PresBox extends ViewBoxBaseComponent() { }, { fireImmediately: true } ); - this._props.setContentView?.(this); + this._props.setContentViewBox?.(this); this._unmounting = false; this.turnOffEdit(true); this._disposers.selection = reaction( @@ -438,9 +438,10 @@ export class PresBox extends ViewBoxBaseComponent() { const setData = bestTargetView?.ComponentView?.setData; if (setData) setData(activeItem.config_data); else { - const current = Doc.GetProto(bestTarget)[fkey]; - Doc.GetProto(bestTarget)[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current; - Doc.GetProto(bestTarget)[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; + const bestTargetData = bestTarget[DocData]; + const current = bestTargetData[fkey]; + bestTargetData[fkey + '_' + Date.now()] = current instanceof ObjectField ? current[Copy]() : current; + bestTargetData[fkey] = activeItem.config_data instanceof ObjectField ? activeItem.config_data[Copy]() : activeItem.config_data; } bestTarget[fkey + '_usePath'] = activeItem.config_usePath; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); @@ -498,11 +499,11 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.config_fillColor !== undefined || activeItem.color !== undefined))) { if (bestTarget.fillColor !== activeItem.config_fillColor) { - Doc.GetProto(bestTarget).fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); + bestTarget[DocData].fillColor = StrCast(activeItem.config_fillColor, StrCast(bestTarget.fillColor)); changed = true; } if (bestTarget.color !== activeItem.config_color) { - Doc.GetProto(bestTarget).color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); + bestTarget[DocData].color = StrCast(activeItem.config_color, StrCast(bestTarget.color)); changed = true; } if (bestTarget.width !== activeItem.width) { @@ -559,7 +560,7 @@ export class PresBox extends ViewBoxBaseComponent() { return doc; }); const newList = new List([...oldItems, ...hiddenItems, ...newItems]); - Doc.GetProto(bestTarget)[fkey + '_annotations'] = newList; + bestTarget[DocData][fkey + '_annotations'] = newList; } if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.config_pinLayoutData !== undefined)) { changed = true; @@ -580,9 +581,9 @@ export class PresBox extends ViewBoxBaseComponent() { data.fill && (doc._fillColor = data.fill); doc._width = data.w; doc._height = data.h; - data.data && (Doc.GetProto(doc).data = field); - data.text && (Doc.GetProto(doc).text = tfield); - Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc); + data.data && (doc[DocData].data = field); + data.text && (doc[DocData].text = tfield); + Doc.AddDocToList(bestTarget[DocData], layoutField, doc); } }); setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); @@ -648,7 +649,7 @@ export class PresBox extends ViewBoxBaseComponent() { } if (pinProps.pinData.dataannos) { const fkey = Doc.LayoutFieldKey(targetDoc); - pinDoc.config_annotations = new List(DocListCast(Doc.GetProto(targetDoc)[fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); + pinDoc.config_annotations = new List(DocListCast(targetDoc[DocData][fkey + '_annotations']).filter(doc => !doc.layout_unrendered)); } if (pinProps.pinData.inkable) { pinDoc.config_fillColor = targetDoc.fillColor; @@ -763,7 +764,7 @@ export class PresBox extends ViewBoxBaseComponent() { } const effect = activeItem.presentation_effect && activeItem.presentation_effect !== PresEffect.None ? activeItem.presentation_effect : undefined; const presTime = NumCast(activeItem.presentation_transition, effect ? 750 : 500); - const options: DocFocusOptions = { + const options: FocusViewOptions = { willPan: activeItem.presentation_movement !== PresMovement.None, willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center, zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.config_zoom, 1), @@ -1115,7 +1116,7 @@ export class PresBox extends ViewBoxBaseComponent() { presDocView && SelectionManager.SelectView(presDocView, false); }; - focusElement = (doc: Doc, options: DocFocusOptions) => { + focusElement = (doc: Doc, options: FocusViewOptions) => { this.selectElement(doc); return undefined; }; @@ -2605,7 +2606,7 @@ export class PresBox extends ViewBoxBaseComponent() { moveDocument={returnFalse} ignoreUnrendered={true} childDragAction="move" - setContentView={emptyFunction} + setContentViewBox={emptyFunction} //childLayoutFitWidth={returnTrue} childOpacity={returnOne} childClickScript={PresBox.navigateToDocScript} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 4bc79176e..7e68711fa 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -41,7 +41,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { readonly expandViewHeight = 100; readonly collapsedHeight = 35; - constructor(props: any) { + constructor(props: FieldViewProps) { super(props); makeObservable(this); } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 01590749e..ba7286111 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -17,16 +17,15 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; +import { FocusViewOptions, FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; +import { PDFBox } from '../nodes/PDFBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import { PDFBox } from '../nodes/PDFBox'; const _global = (window /* browser */ || global) /* node */ as any; //pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`; @@ -172,7 +171,7 @@ export class PDFViewer extends ObservableReactComponent { // scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location, // otherwise it will scroll smoothly. - scrollFocus = (doc: Doc, scrollTop: number, options: DocFocusOptions) => { + scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => { const mainCont = this._mainCont.current; let focusSpeed: Opt; if (doc !== this._props.Document && mainCont) { @@ -521,7 +520,7 @@ export class PDFViewer extends ObservableReactComponent { {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} - setContentView={emptyFunction} // override setContentView to do nothing + setContentViewBox={emptyFunction} // override setContentView to do nothing pointerEvents={this._props.isContentActive() && (SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? returnAll : returnNone} // freeform view doesn't get events unless something is being dragged onto it. childPointerEvents={this.childPointerEvents} // but freeform children need to get events to allow text editing, etc renderDepth={this._props.renderDepth + 1} diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 4d29573d4..5dc4f5550 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCastAsync, Field } from '../../../fields/Doc'; -import { DirectLinks } from '../../../fields/DocSymbols'; +import { DirectLinks, DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; @@ -58,7 +58,7 @@ export class SearchBox extends ViewBoxBaseComponent() { /** * This is the constructor for the SearchBox class. */ - constructor(props: any) { + constructor(props: SearchBoxProps) { super(props); makeObservable(this); SearchBox.Instance = this; @@ -207,7 +207,7 @@ export class SearchBox extends ViewBoxBaseComponent() { this._results.forEach((_, doc) => { this._pageRanks.set(doc, 1.0 / this._results.size); - if (Doc.GetProto(doc)[DirectLinks].size === 0) { + if (doc[DocData][DirectLinks].size === 0) { this._linkedDocsOut.set(doc, new Set(this._results.keys())); this._results.forEach((_, linkedDoc) => { @@ -216,7 +216,7 @@ export class SearchBox extends ViewBoxBaseComponent() { } else { const linkedDocSet = new Set(); - Doc.GetProto(doc)[DirectLinks].forEach(link => { + doc[DocData][DirectLinks].forEach(link => { const d1 = link?.link_anchor_1 as Doc; const d2 = link?.link_anchor_2 as Doc; if (doc === d1 && this._results.has(d2)) { diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 39e778b76..c9c01189e 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { DocFocusOptions } from '../nodes/DocumentView'; -import { emptyFunction } from '../../../Utils'; import { SettingsManager } from '../../util/SettingsManager'; +import { FocusViewOptions } from '../nodes/FieldView'; export interface SelectedDocViewProps { selectedDocs: Doc[]; @@ -25,7 +25,7 @@ export class SelectedDocView extends React.Component {
{ - const options: DocFocusOptions = { + const options: FocusViewOptions = { playAudio: false, playMedia: false, willPan: true, diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 94458563e..4e984f3d6 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -8,7 +8,6 @@ import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { SnappingManager } from '../../util/SnappingManager'; import '../../views/nodes/WebBox.scss'; -import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; @@ -17,14 +16,12 @@ import { hangup, initialize, refreshVideos } from './WebCamLogic'; * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. */ @observer -export class DashWebRTCVideo extends React.Component { +export class DashWebRTCVideo extends React.Component { private roomText: HTMLInputElement | undefined; @observable remoteVideoAdded: boolean = false; @action - changeUILook = () => { - this.remoteVideoAdded = true; - }; + changeUILook = () => (this.remoteVideoAdded = true); /** * Function that submits the title entered by user on enter press. @@ -42,14 +39,9 @@ export class DashWebRTCVideo extends React.Component { - refreshVideos(); - }; + onClickRefresh = () => refreshVideos(); - onClickHangUp = () => { - hangup(); - }; + onClickHangUp = () => hangup(); render() { const content = ( diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9c2350bd0..ff416bbe7 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -31,6 +31,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, StrCast, ToConstructor } import { AudioField, CsvField, ImageField, PdfField, VideoField, WebField } from './URLField'; import { containedFieldChangedHandler, deleteProperty, GetEffectiveAcl, getField, getter, makeEditable, makeReadOnly, setter, SharingPermissions } from './util'; import * as JSZip from 'jszip'; +import { FieldViewProps } from '../client/views/nodes/FieldView'; export const LinkedTo = '-linkedTo'; export namespace Field { export function toKeyValueString(doc: Doc, key: string): string { @@ -423,7 +424,7 @@ export namespace Doc { // export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { if (key.startsWith('_')) key = key.substring(1); - const hasProto = Doc.GetProto(doc) !== doc ? Doc.GetProto(doc) : undefined; + const hasProto = doc[DocData] !== doc ? doc[DocData] : undefined; const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; const onProto = hasProto && Object.getOwnPropertyNames(hasProto).indexOf(key) !== -1; if (onDeleg || !hasProto || (!onProto && !defaultProto)) { @@ -510,7 +511,7 @@ export namespace Doc { export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc) { const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); + listDoc[DocData][key] = new List(); } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { @@ -530,7 +531,7 @@ export namespace Doc { export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); + listDoc[DocData][key] = new List(); } const list = Cast(listDoc[key], listSpec(Doc)); if (list) { @@ -564,7 +565,7 @@ export namespace Doc { Doc.SetLayout(embedding, Doc.MakeEmbedding(layout)); } embedding.createdFrom = doc; - embedding.proto_embeddingId = Doc.GetProto(doc).proto_embeddingId = DocListCast(Doc.GetProto(doc).proto_embeddings).length - 1; + embedding.proto_embeddingId = doc[DocData].proto_embeddingId = DocListCast(doc[DocData].proto_embeddings).length - 1; !Doc.GetT(embedding, 'title', 'string', true) && (embedding.title = ComputedField.MakeFunction(`renameEmbedding(this)`)); embedding.author = Doc.CurrentUserEmail; @@ -1084,8 +1085,8 @@ export namespace Doc { export function LayoutField(doc: Doc) { return doc[StrCast(doc.layout_fieldKey, 'layout')]; } - export function LayoutFieldKey(doc: Doc): string { - return StrCast(Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey + export function LayoutFieldKey(doc: Doc, templateLayoutString?: string): string { + return StrCast(templateLayoutString || Doc.Layout(doc).layout).split("'")[1]; // bcz: TODO check on this . used to always reference 'layout', now it uses the layout speicfied by the current layout_fieldKey } export function NativeAspect(doc: Doc, dataDoc?: Doc, useDim?: boolean) { return Doc.NativeWidth(doc, dataDoc, useDim) / (Doc.NativeHeight(doc, dataDoc, useDim) || 1); @@ -1100,10 +1101,10 @@ export namespace Doc { return NumCast(doc._nativeHeight, nheight || dheight); } export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { - doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width; + doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeWidth'] = width; } export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) { - doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height; + doc[(fieldKey || Doc.LayoutFieldKey(doc)) + '_nativeHeight'] = height; } const manager = new UserDocData(); @@ -1127,22 +1128,22 @@ export namespace Doc { } const isSearchMatchCache = computedFn(function IsSearchMatch(doc: Doc) { - return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined; + return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined; }); export function IsSearchMatch(doc: Doc) { return isSearchMatchCache(doc); } export function IsSearchMatchUnmemoized(doc: Doc) { - return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(Doc.GetProto(doc)) ? brushManager.SearchMatchDoc.get(Doc.GetProto(doc)) : undefined; + return brushManager.SearchMatchDoc.has(doc) ? brushManager.SearchMatchDoc.get(doc) : brushManager.SearchMatchDoc.has(doc[DocData]) ? brushManager.SearchMatchDoc.get(doc[DocData]) : undefined; } export function SetSearchMatch(doc: Doc, results: { searchMatch: number }) { - if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) { brushManager.SearchMatchDoc.set(doc, results); } return doc; } export function SearchMatchNext(doc: Doc, backward: boolean) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate) return doc; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate) return doc; const result = brushManager.SearchMatchDoc.get(doc); const num = Math.abs(result?.searchMatch || 0) + 1; runInAction(() => result && brushManager.SearchMatchDoc.set(doc, { searchMatch: backward ? -num : num })); @@ -1160,13 +1161,13 @@ export namespace Doc { } // returns 'how' a Doc has been brushed over - whether the document itself was brushed, it's prototype, or neither export function GetBrushStatus(doc: Doc) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed; - return doc[Brushed] ? DocBrushStatus.selfBrushed : Doc.GetProto(doc)[Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return DocBrushStatus.unbrushed; + return doc[Brushed] ? DocBrushStatus.selfBrushed : doc[DocData][Brushed] ? DocBrushStatus.protoBrushed : DocBrushStatus.unbrushed; } export function BrushDoc(doc: Doc, unbrush = false) { - if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(Doc.GetProto(doc)) !== AclPrivate) { + if (doc && GetEffectiveAcl(doc) !== AclPrivate && GetEffectiveAcl(doc[DocData]) !== AclPrivate) { brushManager.brushDoc(doc, unbrush); - brushManager.brushDoc(Doc.GetProto(doc), unbrush); + brushManager.brushDoc(doc[DocData], unbrush); } return doc; } @@ -1186,6 +1187,7 @@ export namespace Doc { } export function linkFollowUnhighlight() { clearTimeout(UnhighlightTimer); + UnhighlightTimer = 0; UnhighlightWatchers.forEach(watcher => watcher()); UnhighlightWatchers.length = 0; highlightedDocs.forEach(doc => Doc.UnHighlightDoc(doc)); @@ -1205,8 +1207,8 @@ export namespace Doc { export var highlightedDocs = new ObservableSet(); export function IsHighlighted(doc: Doc) { - if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(Doc.GetProto(doc)) === AclPrivate || doc.opacity === 0) return false; - return doc[Highlight] || Doc.GetProto(doc)[Highlight]; + if (!doc || GetEffectiveAcl(doc) === AclPrivate || GetEffectiveAcl(doc[DocData]) === AclPrivate || doc.opacity === 0) return false; + return doc[Highlight] || doc[DocData][Highlight]; } export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true, presentation_effect?: Doc) { runInAction(() => { @@ -1214,8 +1216,8 @@ export namespace Doc { doc[Highlight] = true; doc[Animation] = presentation_effect; if (dataAndDisplayDocs) { - highlightedDocs.add(Doc.GetProto(doc)); - Doc.GetProto(doc)[Highlight] = true; + highlightedDocs.add(doc[DocData]); + doc[DocData][Highlight] = true; } }); } @@ -1224,8 +1226,8 @@ export namespace Doc { runInAction(() => { (doc ? [doc] : Array.from(highlightedDocs)).forEach(doc => { highlightedDocs.delete(doc); - highlightedDocs.delete(Doc.GetProto(doc)); - doc[Highlight] = Doc.GetProto(doc)[Highlight] = false; + highlightedDocs.delete(doc[DocData]); + doc[Highlight] = doc[DocData][Highlight] = false; doc[Animation] = undefined; }); }); @@ -1346,7 +1348,7 @@ export namespace Doc { }); } - export function styleFromLayoutString(doc: Doc, props: any, scale: number) { + export function styleFromLayoutString(doc: Doc, props: FieldViewProps, scale: number) { const style: { [key: string]: any } = {}; const divKeys = ['width', 'height', 'fontSize', 'transform', 'left', 'backgroundColor', 'left', 'right', 'top', 'bottom', 'pointerEvents', 'position']; const replacer = (match: any, expr: string, offset: any, string: any) => { @@ -1354,7 +1356,7 @@ export namespace Doc { return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: 'number' })?.script.run({ this: doc, self: doc, scale }).result?.toString() ?? ''; }; divKeys.map((prop: string) => { - const p = props[prop]; + const p = (props as any)[prop]; typeof p === 'string' && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer)); }); return style; @@ -1593,7 +1595,7 @@ ScriptingGlobals.add(function idToDoc(id: string): any { return IdToDoc(id); }); ScriptingGlobals.add(function renameEmbedding(doc: any) { - return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`; + return StrCast(doc[DocData].title).replace(/\([0-9]*\)/, '') + `(${doc.proto_embeddingId})`; }); ScriptingGlobals.add(function getProto(doc: any) { return Doc.GetProto(doc); -- cgit v1.2.3-70-g09d2