From fe98c7d46df1852a74cd84dbe9ad010bfb3d5550 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 4 Nov 2022 12:43:59 -0400 Subject: more fixes to pdf and text to allow dashfieldview nodes to be link anchors and make sidebar annotations work better. --- src/client/views/nodes/LinkDocPreview.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 27e79a83b..0e66214d1 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -26,6 +26,7 @@ interface LinkDocPreviewProps { location: number[]; hrefs?: string[]; showHeader?: boolean; + noPreview?: boolean; } @observer export class LinkDocPreview extends React.Component { @@ -111,6 +112,7 @@ export class LinkDocPreview extends React.Component { this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; } this._toolTipText = ''; + if (LinkDocPreview.LinkInfo?.noPreview) this.followLink(); } }) ); -- cgit v1.2.3-70-g09d2 From bbc993dd70d105c3de078208763e6415eedb1ff7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 10 Nov 2022 11:18:46 -0500 Subject: partial fix for previewing multiple links to different sidebar notes. fixed opening sidebar to create an annotation the first time. fixed honoring dashFieldView's non-editable flag. moved isLinkButton setter to expert and make isLinkButton default for Buttons. fixed following Links with Zoom to reset view. fixed view for editing onClick for documents --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 2 +- src/client/util/LinkFollower.ts | 5 +++-- src/client/views/DocumentButtonBar.tsx | 4 ++-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 12 +++++++----- src/client/views/nodes/formattedText/DashFieldView.tsx | 3 +++ src/client/views/nodes/formattedText/FormattedTextBox.tsx | 13 ++++++++----- src/fields/Proxy.ts | 2 +- 10 files changed, 28 insertions(+), 19 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d789d4ee3..f1b8c3034 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1607,7 +1607,7 @@ export namespace DocUtils { const iconViews = DocListCast(Cast(Doc.UserDoc()['template-icons'], Doc, null)?.data); const templBtns = DocListCast(Cast(Doc.UserDoc()['template-buttons'], Doc, null)?.data); const noteTypes = DocListCast(Cast(Doc.UserDoc()['template-notes'], Doc, null)?.data); - const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data); + const clickFuncs = DocListCast(Cast(Doc.UserDoc()['template-clickFuncs'], Doc, null)?.data); const allTemplates = iconViews .concat(templBtns) .concat(noteTypes) diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f2d851a40..d13209c4f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -267,7 +267,7 @@ export class CurrentUserUtils { {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _showSidebar: 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, system: true, cloneFieldFilter: new List(["system"]) }}, - {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, }}, + {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, _isLinkButton: true }}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, // {key: "DataViz", creator: opts => Docs.Create.DataVizDocument(opts), opts: { _width: 300, _height: 300 }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true,}}, diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index ea0531fa2..43b2caf88 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -48,9 +48,10 @@ export class LinkFollower { }, }); } else { - res(where !== 'inPlace' ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target + finished?.(); + res(where !== 'inPlace' || BoolCast(sourceDoc.followLinkZoom) ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target } - }); + }, 100); }); if (!sourceDoc.followLinkZoom) { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ce77b7446..3f12c7c9d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -356,7 +356,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {'Click to record 5 second annotation'}}>
{ this._isRecording = true; @@ -463,7 +463,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV {this.metadataButton}
*/ } - {!SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
} + {Doc.noviceMode || !SelectionManager.Views()?.some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
{!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null :
{this.shareButton}
} {!Doc.UserDoc()['documentLinksButton-fullMenu'] ? null : ( diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cec03c991..3fac137fe 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -767,7 +767,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight)); const useLock = bounds.r - bounds.x > 135 && seldocview.props.CollectionFreeFormDocumentView; - const useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION; // when do we want an object to not rotate? + const useRotation = seldocview.rootDoc.type !== DocumentType.EQUATION && seldocview.props.CollectionFreeFormDocumentView; // when do we want an object to not rotate? const rotation = NumCast(seldocview.rootDoc._rotation); const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4ee871ba2..973363f78 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -618,7 +618,7 @@ export class DocumentViewInternal extends DocComponent { _linkDocRef = React.createRef(); @observable public static LinkInfo: Opt; @observable _targetDoc: Opt; + @observable _markerTargetDoc: Opt; @observable _linkDoc: Opt; @observable _linkSrc: Opt; @observable _toolTipText = ''; @@ -57,9 +58,9 @@ export class LinkDocPreview extends React.Component { } if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { // want to show annotation context document if annotation is not text - linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._targetDoc = anno))); + linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno))); } else { - this._targetDoc = linkTarget; + this._markerTargetDoc = this._targetDoc = linkTarget; } this._toolTipText = ''; } @@ -105,10 +106,11 @@ export class LinkDocPreview extends React.Component { // automatic links specify the target in the link info, not the source const linkTarget = anchor; this._linkSrc = LinkManager.getOppositeAnchor(this._linkDoc, linkTarget); - this._targetDoc = linkTarget; + this._markerTargetDoc = this._targetDoc = linkTarget; } else { this._linkSrc = anchor; const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); + this._markerTargetDoc = linkTarget; this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; } this._toolTipText = ''; @@ -175,10 +177,10 @@ export class LinkDocPreview extends React.Component { return Math.min(225, NumCast(this._targetDoc?.[HeightSym](), 225)); }; @computed get previewHeader() { - return !this._linkDoc || !this._targetDoc || !this._linkSrc ? null : ( + return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : (
- {StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + '...' : StrCast(this._targetDoc.title)} + {StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)}

{StrCast(this._linkDoc.description)}

diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 39b38add2..41b92a3c7 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -171,6 +171,9 @@ export class DashFieldViewInternal extends React.Component this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection'); + getAnchor = () => this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', false); @action setupAnchorMenu = () => { @@ -239,7 +239,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { !this.layoutDoc.showSidebar && this.toggleSidebar(); - this._sidebarRef.current?.anchorMenuClick(this.getAnchor()); + setTimeout(() => this._sidebarRef.current?.anchorMenuClick(this.makeLinkAnchor(undefined, 'add:right', undefined, 'Anchored Selection', true))); // give time for sidebarRef to be created }; AnchorMenu.Instance.OnAudio = (e: PointerEvent) => { !this.layoutDoc.showSidebar && this.toggleSidebar(); @@ -891,9 +891,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent m.type.name === schema.marks.splitter.name)) { const allAnchors = [{ href, title, anchorId: anchor[Id] }]; allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.linkAnchor.name)?.attrs.allAnchors ?? [])); - const link = state.schema.marks.linkAnchor.create({ allAnchors, title, location }); + const link = state.schema.marks.linkAnchor.create({ allAnchors, title, location, noPreview }); tr = tr.addMark(pos, pos + node.nodeSize, link); + selectedText += (node as Node).textContent; } }); this.dataDoc[ForceServerWrite] = this.dataDoc[UpdatingFromServer] = true; // need to allow permissions for adding links to readonly/augment only documents this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter)); this.dataDoc[UpdatingFromServer] = this.dataDoc[ForceServerWrite] = false; + anchor.text = selectedText; return anchor; } return anchorDoc ?? this.rootDoc; @@ -1471,7 +1474,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink while (target && !target.dataset?.targethrefs) target = target.parentElement; - FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview); + FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true'); } if (e.button === 0 && this.props.isSelected(true) && !e.altKey) { diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index e924ef7a3..72ae13035 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -66,7 +66,7 @@ export class ProxyField extends ObjectField { const cached = DocServer.GetCachedRefField(this.fieldId) as T; if (cached !== undefined) { - this.cache = cached; + setTimeout(action(() => (this.cache = cached))); } else if (!this.promise) { this.promise = DocServer.GetRefField(this.fieldId).then( action((field: any) => { -- cgit v1.2.3-70-g09d2 From b7d4f932d826d48aca4c7c058e05ceaea9c43057 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 17 Nov 2022 14:35:13 -0500 Subject: mostly changing strings to enums --- src/client/util/DictationManager.ts | 6 +- src/client/util/LinkFollower.ts | 4 +- src/client/views/LightboxView.tsx | 16 +- src/client/views/MainView.tsx | 28 +- .../views/PropertiesDocBacklinksSelector.tsx | 45 ++- src/client/views/PropertiesDocContextSelector.tsx | 6 +- src/client/views/PropertiesView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 26 +- .../views/collections/CollectionNoteTakingView.tsx | 12 +- .../views/collections/CollectionPileView.tsx | 22 +- .../views/collections/CollectionStackingView.tsx | 4 +- .../views/collections/CollectionTimeView.tsx | 351 +++++++++------- src/client/views/collections/CollectionView.tsx | 11 +- src/client/views/collections/TabDocView.tsx | 34 +- src/client/views/collections/TreeView.tsx | 8 +- .../CollectionFreeFormLayoutEngines.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +- .../CollectionMulticolumnView.tsx | 9 +- .../collectionSchema/CollectionSchemaCells.tsx | 447 +++++++++++---------- .../CollectionSchemaMovableRow.tsx | 3 +- .../collections/collectionSchema/SchemaTable.tsx | 6 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 35 +- src/client/views/nodes/KeyValueBox.tsx | 5 +- src/client/views/nodes/KeyValuePair.tsx | 65 +-- src/client/views/nodes/LinkAnchorBox.tsx | 5 +- src/client/views/nodes/LinkDocPreview.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 3 +- src/client/views/nodes/button/FontIconBox.tsx | 3 +- .../views/nodes/formattedText/DashFieldView.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../formattedText/ProsemirrorExampleTransfer.ts | 3 +- src/client/views/nodes/trails/PresBox.tsx | 13 +- src/mobile/MobileInterface.tsx | 2 +- 34 files changed, 668 insertions(+), 550 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 0a61f3478..203d4ad62 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -11,7 +11,7 @@ import { Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DictationOverlay } from '../views/DictationOverlay'; -import { DocumentView } from '../views/nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; @@ -328,7 +328,7 @@ export namespace DictationManager { { action: (target: DocumentView) => { const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 }); - target.props.addDocTab(kvp, 'add:right'); + target.props.addDocTab(kvp, OpenWhere.addRight); }, }, ], @@ -345,7 +345,7 @@ export namespace DictationManager { const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`; proto.data = new RichTextField(proseMirrorState); proto.backgroundColor = '#eeffff'; - target.props.addDocTab(newBox, 'add:right'); + target.props.addDocTab(newBox, OpenWhere.addRight); }, }, ], diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 68716a207..a3eb7ed7a 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -4,7 +4,7 @@ import { BoolCast, Cast, DocCast, StrCast } from '../../fields/Types'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; -import { DocumentViewSharedProps, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocumentViewSharedProps, OpenWhere, ViewAdjustment } from '../views/nodes/DocumentView'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; import { UndoManager } from './UndoManager'; @@ -32,7 +32,7 @@ export class LinkFollower { const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { const createTabForTarget = (didFocus: boolean) => new Promise(res => { - const where = LightboxView.LightboxDoc ? 'inPlace' : StrCast(sourceDoc.followLinkLocation, followLoc); + const where = LightboxView.LightboxDoc ? OpenWhere.inPlace : (StrCast(sourceDoc.followLinkLocation, followLoc) as OpenWhere); docViewProps.addDocTab(doc, where); setTimeout(() => { const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 5660a34e9..1f58763d1 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -18,7 +18,7 @@ import { TabDocView } from './collections/TabDocView'; import { GestureOverlay } from './GestureOverlay'; import './LightboxView.scss'; import { MainView } from './MainView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider'; interface LightboxViewProps { @@ -141,11 +141,13 @@ export class LightboxView extends React.Component { this._docFilters = (f => (this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f]))(`cookies:${cookie}:provide`); } } - public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc, openInTabFunc?: any) => { - const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; - if (inPlaceView) { - inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); - return true; + public static AddDocTab = (doc: Doc, location: OpenWhere, layoutTemplate?: Doc, openInTabFunc?: any) => { + if (location !== OpenWhere.lightbox) { + const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + if (inPlaceView) { + inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); + return true; + } } LightboxView.openInTabFunc = openInTabFunc; SelectionManager.DeselectAll(); @@ -360,7 +362,7 @@ export class LightboxView extends React.Component { title={'open in tab'} onClick={e => { e.stopPropagation(); - CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, ''); + CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, OpenWhereMod.none); //LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace"); SelectionManager.DeselectAll(); LightboxView.SetLightboxDoc(undefined); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 392b4eeeb..c151aebcd 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -49,7 +49,7 @@ import { LinkMenu } from './linking/LinkMenu'; import './MainView.scss'; import { AudioBox } from './nodes/AudioBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import { DashFieldViewMenu } from './nodes/formattedText/DashFieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from './nodes/formattedText/RichTextMenu'; @@ -538,7 +538,7 @@ export class MainView extends React.Component { @action createNewPresentation = () => { const pres = Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true); - CollectionDockingView.AddSplit(pres, 'right'); + CollectionDockingView.AddSplit(pres, OpenWhereMod.right); Doc.MyTrails && Doc.AddDocToList(Doc.MyTrails, 'data', pres); // Doc.MyTrails should be created in createDashboard Doc.ActivePresentation = pres; }; @@ -546,7 +546,7 @@ export class MainView extends React.Component { @action openPresentation = (pres: Doc) => { if (pres.type === DocumentType.PRES) { - CollectionDockingView.AddSplit(pres, 'right'); + CollectionDockingView.AddSplit(pres, OpenWhereMod.right); Doc.MyTrails && (Doc.ActivePresentation = pres); Doc.AddDocToList(Doc.MyTrails, 'data', pres); this.closeFlyout(); @@ -683,20 +683,20 @@ export class MainView extends React.Component { sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); - addDocTabFunc = (doc: Doc, location: string): boolean => { - const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':'); - const locationParams = locationFields.length > 1 ? locationFields[1] : ''; + addDocTabFunc = (doc: Doc, location: OpenWhere): boolean => { + const whereFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); + const whereMods = whereFields.length > 1 ? whereFields[1] : ''; if (doc.dockingConfig) return DashboardView.openDashboard(doc); // prettier-ignore - switch (locationFields[0]) { + switch (whereFields[0]) { default: - case 'inPlace': - case 'lightbox': return LightboxView.AddDocTab(doc, location); - case 'add': return CollectionDockingView.AddSplit(doc, locationParams); - case 'dashboard': return DashboardView.openDashboard(doc); - case 'close': return CollectionDockingView.CloseSplit(doc, locationParams); - case 'fullScreen': return CollectionDockingView.OpenFullScreen(doc); - case 'toggle': return CollectionDockingView.ToggleSplit(doc, locationParams); + case OpenWhere.inPlace: + case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location); + case OpenWhere.add: return CollectionDockingView.AddSplit(doc, whereMods as OpenWhereMod); + case OpenWhere.dashboard: return DashboardView.openDashboard(doc); + case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, whereMods); + case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, whereMods as OpenWhereMod); } }; diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 4ead8eaf0..25ac44078 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -1,20 +1,21 @@ -import { computed } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { Doc, DocListCast } from "../../fields/Doc"; -import { Cast } from "../../fields/Types"; -import { emptyFunction } from "../../Utils"; -import { DocumentType } from "../documents/DocumentTypes"; -import { LinkManager } from "../util/LinkManager"; -import { SelectionManager } from "../util/SelectionManager"; -import { LinkMenu } from "./linking/LinkMenu"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast } from '../../fields/Doc'; +import { Cast } from '../../fields/Types'; +import { emptyFunction } from '../../Utils'; +import { DocumentType } from '../documents/DocumentTypes'; +import { LinkManager } from '../util/LinkManager'; +import { SelectionManager } from '../util/SelectionManager'; +import { LinkMenu } from './linking/LinkMenu'; +import { OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import './PropertiesDocBacklinksSelector.scss'; type PropertiesDocBacklinksSelectorProps = { - Document: Doc, - Stack?: any, - hideTitle?: boolean, - addDocTab(doc: Doc, location: string): void + Document: Doc; + Stack?: any; + hideTitle?: boolean; + addDocTab(doc: Doc, location: OpenWhere): void; }; @observer @@ -40,14 +41,16 @@ export class PropertiesDocBacklinksSelector extends React.Component - {this.props.hideTitle ? (null) :

Contexts:

} - -
; + return !SelectionManager.Views().length ? null : ( +
+ {this.props.hideTitle ? null :

Contexts:

} + +
+ ); } -} \ No newline at end of file +} diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 9d89ee036..2c7da5931 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -7,14 +7,14 @@ import { Cast, NumCast, StrCast } from '../../fields/Types'; import { CollectionViewType } from '../documents/DocumentTypes'; import { DocFocusOrOpen } from '../util/DocumentManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; -import { DocumentView } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; import './PropertiesDocContextSelector.scss'; type PropertiesDocContextSelectorProps = { DocView?: DocumentView; Stack?: any; hideTitle?: boolean; - addDocTab(doc: Doc, location: string): void; + addDocTab(doc: Doc, location: OpenWhere): void; }; @observer @@ -53,7 +53,7 @@ export class PropertiesDocContextSelector extends React.Component DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100); }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index e5ff9e267..93a3fd253 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -24,7 +24,7 @@ import { Transform } from '../util/Transform'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { EditableView } from './EditableView'; import { InkStrokeProperties } from './InkStrokeProperties'; -import { DocumentView, StyleProviderFunc } from './nodes/DocumentView'; +import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; import { FilterBox } from './nodes/FilterBox'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PresBox } from './nodes/trails'; @@ -42,7 +42,7 @@ interface PropertiesViewProps { width: number; height: number; styleProvider?: StyleProviderFunc; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; } @observer diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 434466505..8cbe548c7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -25,6 +25,7 @@ import { CollectionFreeFormView } from './collectionFreeForm'; import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import { TabDocView } from './TabDocView'; import React = require('react'); +import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -142,7 +143,7 @@ export class CollectionDockingView extends CollectionSubView() { @undoBatch @action - public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean { + public static ReplaceTab(document: Doc, panelName: OpenWhereMod, stack: any, addToSplit?: boolean): boolean { const instance = CollectionDockingView.Instance; if (!instance) return false; const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName); @@ -164,7 +165,7 @@ export class CollectionDockingView extends CollectionSubView() { } @undoBatch - public static ToggleSplit(doc: Doc, location: string, stack?: any, panelName?: string) { + public static ToggleSplit(doc: Doc, location: OpenWhereMod, stack?: any, panelName?: string) { return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1 ? CollectionDockingView.CloseSplit(doc) : CollectionDockingView.AddSplit(doc, location, stack, panelName); @@ -175,7 +176,7 @@ export class CollectionDockingView extends CollectionSubView() { // @undoBatch @action - public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) { + public static AddSplit(document: Doc, pullSide: OpenWhereMod, stack?: any, panelName?: string) { if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document); if (!CollectionDockingView.Instance) return false; const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document); @@ -208,14 +209,15 @@ export class CollectionDockingView extends CollectionSubView() { // if row switch (pullSide) { default: - case 'right': + case OpenWhereMod.none: + case OpenWhereMod.right: glayRoot.contentItems[0].addChild(newContentItem()); break; - case 'left': + case OpenWhereMod.left: glayRoot.contentItems[0].addChild(newContentItem(), 0); break; - case 'top': - case 'bottom': + case OpenWhereMod.top: + case OpenWhereMod.bottom: // if not going in a row layout, must add already existing content into column const rowlayout = glayRoot.contentItems[0]; const newColumn = rowlayout.layoutManager.createContentItem({ type: 'column' }, instance._goldenLayout); @@ -496,7 +498,7 @@ export class CollectionDockingView extends CollectionSubView() { title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, '', stack); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }); @@ -539,7 +541,7 @@ export class CollectionDockingView extends CollectionSubView() { title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`, }); this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd); - CollectionDockingView.AddSplit(docToAdd, '', stack); + CollectionDockingView.AddSplit(docToAdd, OpenWhereMod.none, stack); } }) ); @@ -568,14 +570,14 @@ export class CollectionDockingView extends CollectionSubView() { ScriptingGlobals.add( function openInLightbox(doc: any) { - LightboxView.AddDocTab(doc, 'lightbox'); + LightboxView.AddDocTab(doc, OpenWhere.lightbox); }, 'opens up document in a lightbox', '(doc: any)' ); ScriptingGlobals.add( function openOnRight(doc: any) { - return CollectionDockingView.AddSplit(doc, 'right'); + return CollectionDockingView.AddSplit(doc, OpenWhereMod.right); }, 'opens up document in tab on right side of the screen', '(doc: any)' @@ -588,5 +590,5 @@ ScriptingGlobals.add( '(doc: any)' ); ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) { - CollectionDockingView.ReplaceTab(doc, 'right', undefined, shiftKey); + CollectionDockingView.ReplaceTab(doc, OpenWhereMod.right, undefined, shiftKey); }); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index b0f64ed60..29670a1a7 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -19,7 +19,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -180,14 +180,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { return () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } - addDocTab = (doc: Doc, where: string) => { - if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List([doc]); - return true; - } - return this.props.addDocTab(doc, where); - }; - scrollToBottom = () => { smoothScroll(500, this._mainCont!, this._mainCont!.scrollHeight); }; @@ -274,7 +266,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { removeDocument={this.props.removeDocument} contentPointerEvents={StrCast(this.layoutDoc.contentPointerEvents)} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.addDocTab} + addDocTab={this.props.addDocTab} bringToFront={returnFalse} scriptContext={this.props.scriptContext} pinToPres={this.props.pinToPres} diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 38e240ac6..e95622630 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -12,6 +12,8 @@ import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; import React = require('react'); import { ScriptField } from '../../../fields/ScriptField'; +import { OpenWhere } from '../nodes/DocumentView'; +import { computePassLayout, computeStarburstLayout } from './collectionFreeForm'; @observer export class CollectionPileView extends CollectionSubView() { @@ -19,8 +21,8 @@ export class CollectionPileView extends CollectionSubView() { _disposers: { [name: string]: IReactionDisposer } = {}; componentDidMount() { - if (this.layoutEngine() !== 'pass' && this.layoutEngine() !== 'starburst') { - this.Document._pileLayoutEngine = 'pass'; + if (this.layoutEngine() !== computePassLayout.name && this.layoutEngine() !== computeStarburstLayout.name) { + this.Document._pileLayoutEngine = computePassLayout.name; } this._originalChrome = this.layoutDoc._chromeHidden; this.layoutDoc._chromeHidden = true; @@ -56,7 +58,7 @@ export class CollectionPileView extends CollectionSubView() { // returns the contents of the pileup in a CollectionFreeFormView @computed get contents() { - const isStarburst = this.layoutEngine() === 'starburst'; + const isStarburst = this.layoutEngine() === computeStarburstLayout.name; return (
{ - if (this.layoutEngine() === 'starburst') { + if (this.layoutEngine() === computeStarburstLayout.name) { const defaultSize = 110; this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; @@ -83,12 +85,12 @@ export class CollectionPileView extends CollectionSubView() { DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); this.layoutDoc._panX = 0; this.layoutDoc._panY = -10; - this.props.Document._pileLayoutEngine = 'pass'; + this.props.Document._pileLayoutEngine = computePassLayout.name; } else { const defaultSize = 25; !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 250); !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); - if (this.layoutEngine() === 'pass') { + if (this.layoutEngine() === computePassLayout.name) { this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2; this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym](); @@ -96,7 +98,7 @@ export class CollectionPileView extends CollectionSubView() { } this.layoutDoc._panX = this.layoutDoc._panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; - this.props.Document._pileLayoutEngine = 'starburst'; + this.props.Document._pileLayoutEngine = computeStarburstLayout.name; } }); @@ -118,7 +120,7 @@ export class CollectionPileView extends CollectionSubView() { const doc = this.childDocs[0]; doc.x = e.clientX; doc.y = e.clientY; - this.props.addDocTab(doc, 'inParent') && (this.props.removeDocument?.(doc) || false); + this.props.addDocTab(doc, OpenWhere.inParent) && (this.props.removeDocument?.(doc) || false); dist = 0; } } @@ -130,8 +132,8 @@ export class CollectionPileView extends CollectionSubView() { SnappingManager.SetIsDragging(false); }, emptyFunction, - e.shiftKey && this.layoutEngine() === 'pass', - this.layoutEngine() === 'pass' && e.shiftKey + e.shiftKey && this.layoutEngine() === computePassLayout.name, + this.layoutEngine() === computePassLayout.name && e.shiftKey ); // this sets _doubleTap }; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 175051d5c..aa4583af6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -22,7 +22,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { LightboxView } from '../LightboxView'; import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -241,7 +241,7 @@ export class CollectionStackingView extends CollectionSubView this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); } - addDocTab = (doc: Doc, where: string) => { + addDocTab = (doc: Doc, where: OpenWhere) => { if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { this.dataDoc[this.props.fieldKey] = new List([doc]); return true; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 3dd9d2d84..ac896a8fd 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,32 +1,32 @@ -import { toUpper } from "lodash"; -import { action, computed, observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, Opt, StrListCast } from "../../../fields/Doc"; -import { List } from "../../../fields/List"; -import { ObjectField } from "../../../fields/ObjectField"; -import { RichTextField } from "../../../fields/RichTextField"; -import { listSpec } from "../../../fields/Schema"; -import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils"; -import { Docs } from "../../documents/Documents"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { DocumentManager } from "../../util/DocumentManager"; -import { ScriptingGlobals } from "../../util/ScriptingGlobals"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { EditableView } from "../EditableView"; -import { ViewSpecPrefix } from "../nodes/DocumentView"; -import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import { CollectionSubView } from "./CollectionSubView"; -import "./CollectionTimeView.scss"; -import React = require("react"); +import { toUpper } from 'lodash'; +import { action, computed, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; +import { RichTextField } from '../../../fields/RichTextField'; +import { listSpec } from '../../../fields/Schema'; +import { ComputedField, ScriptField } from '../../../fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { DocumentType } from '../../documents/DocumentTypes'; +import { DocumentManager } from '../../util/DocumentManager'; +import { ScriptingGlobals } from '../../util/ScriptingGlobals'; +import { ContextMenu } from '../ContextMenu'; +import { ContextMenuProps } from '../ContextMenuItem'; +import { EditableView } from '../EditableView'; +import { ViewSpecPrefix } from '../nodes/DocumentView'; +import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { CollectionSubView } from './CollectionSubView'; +import './CollectionTimeView.scss'; +import React = require('react'); @observer export class CollectionTimeView extends CollectionSubView() { _changing = false; - @observable _layoutEngine = "pivot"; + @observable _layoutEngine = computePivotLayout.name; @observable _collapsed: boolean = false; @observable _childClickedScript: Opt; @observable _viewDefDivClick: Opt; @@ -35,7 +35,7 @@ export class CollectionTimeView extends CollectionSubView() { getAnchor = () => { const anchor = Docs.Create.HTMLAnchorDocument([], { title: ComputedField.MakeFunction(`"${this.pivotField}"])`) as any, - annotationOn: this.rootDoc + annotationOn: this.rootDoc, }); // save view spec information for anchor @@ -43,81 +43,103 @@ export class CollectionTimeView extends CollectionSubView() { proto.pivotField = this.pivotField; proto.docFilters = ObjectField.MakeCopy(this.layoutDoc._docFilters as ObjectField) || new List([]); proto.docRangeFilters = ObjectField.MakeCopy(this.layoutDoc._docRangeFilters as ObjectField) || new List([]); - proto[ViewSpecPrefix + "_viewType"] = this.layoutDoc._viewType; + proto[ViewSpecPrefix + '_viewType'] = this.layoutDoc._viewType; // store anchor in annotations list of document (not technically needed since these anchors are never drawn) - if (Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), null) !== undefined) { - Cast(this.dataDoc[this.props.fieldKey + "-annotations"], listSpec(Doc), []).push(anchor); + if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) { + Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor); } else { - this.dataDoc[this.props.fieldKey + "-annotations"] = new List([anchor]); + this.dataDoc[this.props.fieldKey + '-annotations'] = new List([anchor]); } return anchor; - } + }; async componentDidMount() { this.props.setContentView?.(this); //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; runInAction(() => { - this._childClickedScript = ScriptField.MakeScript("openInLightbox(self)", { this: Doc.name }); - this._viewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }); + this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name }); + this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); }); } - get pivotField() { return this._focusPivotField || StrCast(this.layoutDoc._pivotField); } + get pivotField() { + return this._focusPivotField || StrCast(this.layoutDoc._pivotField); + } @action setViewSpec = (anchor: Doc, preview: boolean) => { - if (preview) { // if in preview, then override document's fields with view spec + if (preview) { + // if in preview, then override document's fields with view spec this._focusFilters = StrListCast(Doc.GetProto(anchor).docFilters); this._focusRangeFilters = StrListCast(Doc.GetProto(anchor).docRangeFilters); this._focusPivotField = StrCast(anchor.pivotField); - } else if (anchor.pivotField !== undefined) { // otherwise set document's fields based on anchor view spec + } else if (anchor.pivotField !== undefined) { + // otherwise set document's fields based on anchor view spec this.layoutDoc._prevFilterIndex = 1; this.layoutDoc._pivotField = StrCast(anchor.pivotField); this.layoutDoc._docFilters = new List(StrListCast(anchor.docFilters)); this.layoutDoc._docRangeFilters = new List(StrListCast(anchor.docRangeFilters)); } return 0; - } + }; layoutEngine = () => this._layoutEngine; - toggleVisibility = action(() => this._collapsed = !this._collapsed); + toggleVisibility = action(() => (this._collapsed = !this._collapsed)); onMinDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + "-timelineSpan"] = undefined; - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + this.props.Document[this.props.fieldKey + '-timelineSpan'] = undefined; + return false; + }), + returnFalse, + emptyFunction + ); + }; onMaxDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq + (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq + ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + return false; + }), + returnFalse, + emptyFunction + ); + }; onMidDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - const minReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMinReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMin"], 0)); - const maxReq = NumCast(this.props.Document[this.props.fieldKey + "-timelineMaxReq"], NumCast(this.props.Document[this.props.fieldKey + "-timelineMax"], 10)); - this.props.Document[this.props.fieldKey + "-timelineMinReq"] = minReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - this.props.Document[this.props.fieldKey + "-timelineMaxReq"] = maxReq - (maxReq - minReq) * delta[0] / this.props.PanelWidth(); - return false; - }), returnFalse, emptyFunction); - } + setupMoveUpEvents( + this, + e, + action((e: PointerEvent, down: number[], delta: number[]) => { + const minReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMinReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMin'], 0)); + const maxReq = NumCast(this.props.Document[this.props.fieldKey + '-timelineMaxReq'], NumCast(this.props.Document[this.props.fieldKey + '-timelineMax'], 10)); + this.props.Document[this.props.fieldKey + '-timelineMinReq'] = minReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + this.props.Document[this.props.fieldKey + '-timelineMaxReq'] = maxReq - ((maxReq - minReq) * delta[0]) / this.props.PanelWidth(); + return false; + }), + returnFalse, + emptyFunction + ); + }; goTo = (prevFilterIndex: number) => { - this.layoutDoc._pivotField = this.layoutDoc["_prevPivotFields" + prevFilterIndex]; - this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocFilter" + prevFilterIndex] as ObjectField); - this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc["_prevDocRangeFilters" + prevFilterIndex] as ObjectField); + this.layoutDoc._pivotField = this.layoutDoc['_prevPivotFields' + prevFilterIndex]; + this.layoutDoc._docFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocFilter' + prevFilterIndex] as ObjectField); + this.layoutDoc._docRangeFilters = ObjectField.MakeCopy(this.layoutDoc['_prevDocRangeFilters' + prevFilterIndex] as ObjectField); this.layoutDoc._prevFilterIndex = prevFilterIndex; - } + }; @action contentsDown = (e: React.MouseEvent) => { @@ -127,37 +149,58 @@ export class CollectionTimeView extends CollectionSubView() { } else { this.layoutDoc._docFilters = new List([]); } - } + }; dontScaleFilter = (doc: Doc) => doc.type === DocumentType.RTF; @computed get contents() { - return
- -
; + return ( +
+ +
+ ); } public static SyncTimelineToPresentation(doc: Doc) { const fieldKey = Doc.LayoutFieldKey(doc); - doc[fieldKey + "-timelineCur"] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)"); + doc[fieldKey + '-timelineCur'] = ComputedField.MakeFunction("(activePresentationItem()[this._pivotField || 'year'] || 0)"); } specificMenu = (e: React.MouseEvent) => { const layoutItems: ContextMenuProps[] = []; const doc = this.layoutDoc; - layoutItems.push({ description: "Force Timeline", event: () => { doc._forceRenderEngine = "timeline"; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Force Pivot", event: () => { doc._forceRenderEngine = "pivot"; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { doc._forceRenderEngine = undefined; }, icon: "compress-arrows-alt" }); - layoutItems.push({ description: "Sync with presentation", event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: "compress-arrows-alt" }); + layoutItems.push({ + description: 'Force Timeline', + event: () => { + doc._forceRenderEngine = computeTimelineLayout.name; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ + description: 'Force Pivot', + event: () => { + doc._forceRenderEngine = computePivotLayout.name; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ + description: 'Auto Time/Pivot layout', + event: () => { + doc._forceRenderEngine = undefined; + }, + icon: 'compress-arrows-alt', + }); + layoutItems.push({ description: 'Sync with presentation', event: () => CollectionTimeView.SyncTimelineToPresentation(doc), icon: 'compress-arrows-alt' }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); - } + ContextMenu.Instance.addItem({ description: 'Options...', subitems: layoutItems, icon: 'eye' }); + }; @computed get _allFacets() { const facets = new Set(); this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); @@ -169,37 +212,40 @@ export class CollectionTimeView extends CollectionSubView() { const docItems: ContextMenuProps[] = []; const keySet: Set = new Set(); - this.childLayoutPairs.map(pair => this._allFacets.filter(fieldKey => - pair.layout[fieldKey] instanceof RichTextField || - typeof (pair.layout[fieldKey]) === "number" || - typeof (pair.layout[fieldKey]) === "boolean" || - typeof (pair.layout[fieldKey]) === "string").filter(fieldKey => fieldKey[0] !== "_" && (fieldKey[0] !== "#" || fieldKey === "#") && (fieldKey === "tags" || fieldKey[0] === toUpper(fieldKey)[0])).map(fieldKey => keySet.add(fieldKey))); - 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" }); + this.childLayoutPairs.map(pair => + this._allFacets + .filter(fieldKey => pair.layout[fieldKey] instanceof RichTextField || typeof pair.layout[fieldKey] === 'number' || typeof pair.layout[fieldKey] === 'boolean' || typeof pair.layout[fieldKey] === 'string') + .filter(fieldKey => fieldKey[0] !== '_' && (fieldKey[0] !== '#' || fieldKey === '#') && (fieldKey === 'tags' || fieldKey[0] === toUpper(fieldKey)[0])) + .map(fieldKey => keySet.add(fieldKey)) + ); + 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, ":"); - } + ContextMenu.Instance.displayMenu(x, y, ':'); + }; @computed get pivotKeyUI() { - return
- { - if (value?.length) { - this.layoutDoc._pivotField = value; - return true; - } - return false; - }} - toggle={this.toggleVisibility} - background={"#f1efeb"} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; - contents={":" + StrCast(this.layoutDoc._pivotField)} - showMenuOnLoad={true} - display={"inline"} - menuCallback={this.menuCallback} /> -
; + return ( +
+ { + if (value?.length) { + this.layoutDoc._pivotField = value; + return true; + } + return false; + }} + toggle={this.toggleVisibility} + background={'#f1efeb'} // this.props.headingObject ? this.props.headingObject.color : "#f1efeb"; + contents={':' + StrCast(this.layoutDoc._pivotField)} + showMenuOnLoad={true} + display={'inline'} + menuCallback={this.menuCallback} + /> +
+ ); } render() { @@ -211,55 +257,62 @@ export class CollectionTimeView extends CollectionSubView() { } }); const forceLayout = StrCast(this.layoutDoc._forceRenderEngine); - const doTimeline = forceLayout ? (forceLayout === "timeline") : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; - if (doTimeline !== (this._layoutEngine === "timeline")) { + const doTimeline = forceLayout ? forceLayout === computeTimelineLayout.name : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; + if (doTimeline !== (this._layoutEngine === computeTimelineLayout.name)) { if (!this._changing) { this._changing = true; - setTimeout(action(() => { - this._layoutEngine = doTimeline ? "timeline" : "pivot"; - this._changing = false; - }), 0); + setTimeout( + action(() => { + this._layoutEngine = doTimeline ? computeTimelineLayout.name : computePivotLayout.name; + this._changing = false; + }), + 0 + ); } } - return
- {this.pivotKeyUI} - {this.contents} - {!this.props.isSelected() || !doTimeline ? (null) : <> -
-
-
- } -
; + return ( +
+ {this.pivotKeyUI} + {this.contents} + {!this.props.isSelected() || !doTimeline ? null : ( + <> +
+
+
+ + )} +
+ ); } } ScriptingGlobals.add(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { - const pivotField = StrCast(pivotDoc._pivotField) || "author"; + const pivotField = StrCast(pivotDoc._pivotField) || 'author'; let prevFilterIndex = NumCast(pivotDoc._prevFilterIndex); const originalFilter = StrListCast(ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField)); - pivotDoc["_prevDocFilter" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField); - pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField); - pivotDoc["_prevPivotFields" + prevFilterIndex] = pivotField; + pivotDoc['_prevDocFilter' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilters as ObjectField); + pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = ObjectField.MakeCopy(pivotDoc._docRangeFilters as ObjectField); + pivotDoc['_prevPivotFields' + prevFilterIndex] = pivotField; pivotDoc._prevFilterIndex = ++prevFilterIndex; pivotDoc._docFilters = new List(); - setTimeout(action(() => { - const filterVals = (bounds.payload as string[]); - filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, "check")); - const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc); - if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { - if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { - pivotDoc._pivotField = filterVals[0]; + setTimeout( + action(() => { + const filterVals = bounds.payload as string[]; + filterVals.map(filterVal => Doc.setDocFilter(pivotDoc, pivotField, filterVal, 'check')); + const pivotView = DocumentManager.Instance.getDocumentView(pivotDoc); + if (pivotDoc && pivotView?.ComponentView instanceof CollectionTimeView && filterVals.length === 1) { + if (pivotView?.ComponentView.childDocs.length && pivotView.ComponentView.childDocs[0][filterVals[0]]) { + pivotDoc._pivotField = filterVals[0]; + } } - } - const newFilters = StrListCast(pivotDoc._docFilters); - if (newFilters.length && originalFilter.length && - newFilters.lastElement() === originalFilter.lastElement()) { - pivotDoc._prevFilterIndex = --prevFilterIndex; - pivotDoc["_prevDocFilter" + prevFilterIndex] = undefined; - pivotDoc["_prevDocRangeFilters" + prevFilterIndex] = undefined; - pivotDoc["_prevPivotFields" + prevFilterIndex] = undefined; - } - })); -}); \ No newline at end of file + const newFilters = StrListCast(pivotDoc._docFilters); + if (newFilters.length && originalFilter.length && newFilters.lastElement() === originalFilter.lastElement()) { + pivotDoc._prevFilterIndex = --prevFilterIndex; + pivotDoc['_prevDocFilter' + prevFilterIndex] = undefined; + pivotDoc['_prevDocRangeFilters' + prevFilterIndex] = undefined; + pivotDoc['_prevPivotFields' + prevFilterIndex] = undefined; + } + }) + ); +}); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 625d4e9e5..917d7618c 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -16,6 +16,7 @@ import { InteractionUtils } from '../../util/InteractionUtils'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; @@ -174,7 +175,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { const newRendition = Doc.MakeAlias(this.rootDoc); newRendition._viewType = vtype; - this.props.addDocTab(newRendition, 'add:right'); + this.props.addDocTab(newRendition, OpenWhere.addRight); return newRendition; }, false @@ -184,17 +185,17 @@ 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, 'add:right'), icon: 'project-diagram' }); + optionItems.push({ description: 'View Child Layout', event: () => this.props.addDocTab(this.rootDoc.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, 'add:right'), icon: 'project-diagram' }); + optionItems.push({ description: 'View Child Detailed Layout', event: () => this.props.addDocTab(this.rootDoc.childClickedOpenTemplateView as Doc, OpenWhere.addRight), icon: 'project-diagram' }); } !Doc.noviceMode && optionItems.push({ description: `${this.rootDoc.isInPlaceContainer ? 'Unset' : 'Set'} inPlace Container`, event: () => (this.rootDoc.isInPlaceContainer = !this.rootDoc.isInPlaceContainer), icon: 'project-diagram' }); if (!Doc.noviceMode && false) { optionItems.push({ description: 'Create Branch', - event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), 'add:right'), + event: async () => this.props.addDocTab(await BranchCreate(this.rootDoc), OpenWhere.addRight), icon: 'project-diagram', }); optionItems.push({ @@ -225,7 +226,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { const alias = Doc.MakeAlias(this.rootDoc); DocUtils.makeCustomViewClicked(alias, undefined, func.key); - this.props.addDocTab(alias, 'add:right'); + this.props.addDocTab(alias, OpenWhere.addRight); }, }) ); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index e21649648..2cc588b78 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -26,7 +26,7 @@ import { DashboardView } from '../DashboardView'; import { Colors, Shadows } from '../global/globalEnums'; import { LightboxView } from '../LightboxView'; import { MainView } from '../MainView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; @@ -296,7 +296,7 @@ export class TabDocView extends React.Component { ) { const docs = Cast(Doc.MyOverlayDocs.data, listSpec(Doc), []); if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1); - CollectionDockingView.AddSplit(curPres, 'right'); + CollectionDockingView.AddSplit(curPres, OpenWhereMod.right); setTimeout(() => DocumentManager.Instance.jumpToDocument(docList.lastElement(), false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things } setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs @@ -343,34 +343,30 @@ export class TabDocView extends React.Component { // "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, // "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right // inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack - addDocTab = (doc: Doc, location: string) => { + addDocTab = (doc: Doc, location: OpenWhere) => { SelectionManager.DeselectAll(); - const locationFields = doc._viewType === CollectionViewType.Docking ? ['dashboard'] : location.split(':'); - const locationParams = locationFields.length > 1 ? locationFields[1] : ''; + const locationFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); + const locationParams: OpenWhereMod = locationFields.length > 1 ? (locationFields[1] as OpenWhereMod) : OpenWhereMod.none; switch (locationFields[0]) { - case 'dashboard': + case OpenWhere.dashboard: return DashboardView.openDashboard(doc); - case 'close': + case OpenWhere.close: return CollectionDockingView.CloseSplit(doc, locationParams); - case 'fullScreen': + case OpenWhere.fullScreen: return CollectionDockingView.OpenFullScreen(doc); - case 'replace': + case OpenWhere.replace: return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack); - // case "lightbox": { - // // TabDocView.PinDoc(doc, { hidePresBox: true }); - // return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); - // } - case 'inPlace': + case OpenWhere.inPlace: const inPlaceView = DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; if (inPlaceView) { inPlaceView.dataDoc[Doc.LayoutFieldKey(inPlaceView.rootDoc)] = new List([doc]); return true; - } - case 'lightbox': + } // fall through to lightbox + case OpenWhere.lightbox: return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab); - case 'toggle': + case OpenWhere.toggle: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack); - case 'add': + case OpenWhere.add: default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack); } @@ -509,7 +505,7 @@ interface TabMinimapViewProps { document: Doc; hideMinimap: () => boolean; tabView: () => DocumentView | undefined; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; PanelWidth: () => number; PanelHeight: () => number; background: () => string; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 13cf64558..bd326f917 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -22,7 +22,7 @@ import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { TREE_BULLET_WIDTH } from '../global/globalCssVariables.scss'; -import { DocumentView, DocumentViewInternal, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; @@ -44,7 +44,7 @@ export interface TreeViewProps { containerCollection: Doc; renderDepth: number; dropAction: dropActionType; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; panelWidth: () => number; panelHeight: () => number; addDocument: (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => boolean; @@ -236,7 +236,7 @@ export class TreeView extends React.Component { const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail); - this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), 'lightbox'); + this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), OpenWhere.lightbox); } }; @@ -1109,7 +1109,7 @@ export class TreeView extends React.Component { remove: undefined | ((doc: Doc | Doc[]) => boolean), move: DragManager.MoveFunction, dropAction: dropActionType, - addDocTab: (doc: Doc, where: string) => boolean, + addDocTab: (doc: Doc, where: OpenWhere) => boolean, styleProvider: undefined | StyleProviderFunc, screenToLocalXf: () => Transform, isContentActive: (outsideReaction?: boolean) => boolean, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 54be6ba0f..7dd9cdb8b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -82,7 +82,7 @@ interface PivotColumn { filters: string[]; } -export function computerPassLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { +export function computePassLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { const docMap = new Map(); childPairs.forEach(({ layout, data }, i) => { docMap.set(layout[Id], { @@ -97,7 +97,7 @@ export function computerPassLayout(poolData: Map, pivotDoc: Do return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []); } -export function computerStarburstLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { +export function computeStarburstLayout(poolData: Map, pivotDoc: Doc, childPairs: { layout: Doc; data?: Doc }[], panelDim: number[], viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], engineProps: any) { const mustFit = pivotDoc[WidthSym]() !== panelDim[0]; // if a panel size is set that's not the same as the pivot doc's size, then assume this is in a panel for a content fitting view (like a grid) in which case everything must be scaled to stay within the panel const docMap = new Map(); const docSize = mustFit ? panelDim[0] * 0.33 : 75; // assume an icon sized at 75 diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 57cccec4a..8cabf060d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,7 +37,7 @@ import { GestureOverlay } from '../../GestureOverlay'; import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView'; -import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PresBox } from '../../nodes/trails/PresBox'; @@ -47,7 +47,7 @@ import { StyleProp } from '../../StyleProvider'; import { CollectionSubView } from '../CollectionSubView'; import { TreeViewType } from '../CollectionTreeView'; import { TabDocView } from '../TabDocView'; -import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; +import { computePivotLayout, computePassLayout as computePassLayout, computeStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from './CollectionFreeFormLayoutEngines'; import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; @@ -1272,7 +1272,8 @@ export class CollectionFreeFormView extends CollectionSubView { const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine); - const pointerEvents = this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === 'pass' && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); + const pointerEvents = + this.props.isContentActive() === false ? 'none' : this.props.childPointerEvents ?? (this.props.viewDefDivClick || (engine === computePassLayout.name && !this.props.isSelected(true)) ? 'none' : this.props.pointerEvents?.()); return pointerEvents; }; getChildDocView(entry: PoolData) { @@ -1328,8 +1329,8 @@ export class CollectionFreeFormView extends CollectionSubView ); } - addDocTab = action((doc: Doc, where: string) => { - if (where === 'inParent') { + addDocTab = action((doc: Doc, where: OpenWhere) => { + if (where === OpenWhere.inParent) { (doc instanceof Doc ? [doc] : doc).forEach(doc => { const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; @@ -1337,7 +1338,7 @@ export class CollectionFreeFormView extends CollectionSubView(doc as any as Doc[]); return true; } @@ -1457,10 +1458,10 @@ export class CollectionFreeFormView extends CollectionSubView(); // prettier-ignore switch (this.layoutEngine) { - case 'pass': return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) }; - case 'timeline': return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; - case 'pivot': return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; - case 'starburst': return { newPool, computedElementData: this.doEngineLayout(newPool, computerStarburstLayout) }; + case computePassLayout.name : return { newPool, computedElementData: this.doEngineLayout(newPool, computePassLayout) }; + case computeTimelineLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) }; + case computePivotLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computePivotLayout) }; + case computeStarburstLayout.name: return { newPool, computedElementData: this.doEngineLayout(newPool, computeStarburstLayout) }; } return { newPool, computedElementData: this.doFreeformLayout(newPool) }; } @@ -1724,7 +1725,7 @@ export class CollectionFreeFormView extends CollectionSubView ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => ScriptCast(this.Document.onChildDoubleClick); - addDocTab = (doc: Doc, where: string) => { - if (where === 'inPlace' && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List([doc]); - return true; - } - return this.props.addDocTab(doc, where); - }; focusDocument = (doc: Doc, options: DocFocusOptions) => this.props.focus(this.rootDoc, options); isContentActive = () => this.props.isSelected() || this.props.isContentActive() || this.props.isAnyChildContentActive(); isChildContentActive = () => (((this.props.childDocumentsActive?.() || this.Document._childDocumentsActive) && this.props.isDocumentActive?.() && SnappingManager.GetIsDragging()) || this.isContentActive() ? true : false); @@ -278,7 +271,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { moveDocument={this.props.moveDocument} removeDocument={this.props.removeDocument} whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged} - addDocTab={this.addDocTab} + addDocTab={this.props.addDocTab} pinToPres={this.props.pinToPres} bringToFront={returnFalse} /> diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index adcd9e1e3..ef75fb159 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -1,35 +1,36 @@ -import React = require("react"); -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, observable } from "mobx"; -import { observer } from "mobx-react"; -import { extname } from "path"; -import DatePicker from "react-datepicker"; -import { CellInfo } from "react-table"; -import { DateField } from "../../../../fields/DateField"; -import { Doc, DocListCast, Field, Opt } from "../../../../fields/Doc"; -import { Id } from "../../../../fields/FieldSymbols"; -import { List } from "../../../../fields/List"; -import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; -import { ComputedField } from "../../../../fields/ScriptField"; -import { BoolCast, Cast, DateCast, FieldValue, StrCast } from "../../../../fields/Types"; -import { ImageField } from "../../../../fields/URLField"; -import { emptyFunction, Utils } from "../../../../Utils"; -import { Docs } from "../../../documents/Documents"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { DragManager } from "../../../util/DragManager"; -import { KeyCodes } from "../../../util/KeyCodes"; -import { CompileScript } from "../../../util/Scripting"; -import { SearchUtil } from "../../../util/SearchUtil"; -import { SnappingManager } from "../../../util/SnappingManager"; -import { undoBatch } from "../../../util/UndoManager"; +import React = require('react'); +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import { extname } from 'path'; +import DatePicker from 'react-datepicker'; +import { CellInfo } from 'react-table'; +import { DateField } from '../../../../fields/DateField'; +import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; +import { Id } from '../../../../fields/FieldSymbols'; +import { List } from '../../../../fields/List'; +import { SchemaHeaderField } from '../../../../fields/SchemaHeaderField'; +import { ComputedField } from '../../../../fields/ScriptField'; +import { BoolCast, Cast, DateCast, FieldValue, StrCast } from '../../../../fields/Types'; +import { ImageField } from '../../../../fields/URLField'; +import { emptyFunction, Utils } from '../../../../Utils'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocumentManager } from '../../../util/DocumentManager'; +import { DragManager } from '../../../util/DragManager'; +import { KeyCodes } from '../../../util/KeyCodes'; +import { CompileScript } from '../../../util/Scripting'; +import { SearchUtil } from '../../../util/SearchUtil'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { undoBatch } from '../../../util/UndoManager'; import '../../../views/DocumentDecorations.scss'; -import { EditableView } from "../../EditableView"; +import { EditableView } from '../../EditableView'; import { MAX_ROW_HEIGHT } from '../../global/globalCssVariables.scss'; -import { DocumentIconContainer } from "../../nodes/DocumentIcon"; -import { OverlayView } from "../../OverlayView"; -import { CollectionView } from "../CollectionView"; -import "./CollectionSchemaView.scss"; +import { DocumentIconContainer } from '../../nodes/DocumentIcon'; +import { OverlayView } from '../../OverlayView'; +import { CollectionView } from '../CollectionView'; +import './CollectionSchemaView.scss'; +import { OpenWhere } from '../../nodes/DocumentView'; // intialize cell properties export interface CellProps { @@ -46,10 +47,9 @@ export interface CellProps { // currently unused renderDepth: number; // called when a button is pressed on the node itself - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: OpenWhere) => boolean; pinToPres: (document: Doc) => void; - moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, - addDocument: (document: Doc | Doc[]) => boolean) => boolean; + moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; // set whether the cell is in the isEditing mode @@ -67,7 +67,7 @@ export class CollectionSchemaCell extends React.Component { // return a field key that is corrected for whether it COMMENT public static resolvedFieldKey(column: string, rowDoc: Doc) { const fieldKey = column; - if (fieldKey.startsWith("*")) { + if (fieldKey.startsWith('*')) { const rootKey = fieldKey.substring(1); const allKeys = [...Array.from(Object.keys(rowDoc)), ...Array.from(Object.keys(Doc.GetProto(rowDoc)))]; const matchedKeys = allKeys.filter(key => key.includes(rootKey)); @@ -82,33 +82,37 @@ export class CollectionSchemaCell extends React.Component { protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original); // methods for dragging and dropping protected _dropDisposer?: DragManager.DragDropDisposer; - @observable contents: string = ""; + @observable contents: string = ''; - componentDidMount() { document.addEventListener("keydown", this.onKeyDown); } - componentWillUnmount() { document.removeEventListener("keydown", this.onKeyDown); } + componentDidMount() { + document.addEventListener('keydown', this.onKeyDown); + } + componentWillUnmount() { + document.removeEventListener('keydown', this.onKeyDown); + } @action onKeyDown = (e: KeyboardEvent): void => { // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) { - document.removeEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); this._isEditing = true; this.props.setIsEditing(true); } - } + }; @action isEditingCallback = (isEditing: boolean): void => { // a general method that takes a boolean that determines whether the cell should be in // is-editing mode // remove the event listener if it's there - document.removeEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); // it's not already in is-editing mode, re-add the event listener - isEditing && document.addEventListener("keydown", this.onKeyDown); + isEditing && document.addEventListener('keydown', this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } + }; @action onPointerDown = async (e: React.PointerEvent): Promise => { @@ -119,19 +123,19 @@ export class CollectionSchemaCell extends React.Component { this.props.setPreviewDoc(this.props.rowProps.original); let url: string; - if (url = StrCast(this.props.rowProps.row.href)) { + if ((url = StrCast(this.props.rowProps.row.href))) { // opens up the the doc in a new window, blurring the old one try { new URL(url); const temp = window.open(url)!; temp.blur(); window.focus(); - } catch { } + } catch {} } const doc = Cast(this._rowDoc[this.renderFieldKey], Doc, null); doc && this.props.setPreviewDoc(doc); - } + }; @undoBatch applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => { @@ -142,7 +146,7 @@ export class CollectionSchemaCell extends React.Component { doc[this.renderFieldKey] = res.result; return true; // return whether the change was successful - } + }; private drop = (e: Event, de: DragManager.DropEvent) => { // if the drag has data at its completion @@ -151,41 +155,51 @@ export class CollectionSchemaCell extends React.Component { if (de.complete.docDragData.draggedDocuments.length === 1) { // update the renderFieldKey this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0]; - } - else { + } else { // create schema document reflecting the new column arrangement - const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {}); + const coll = Docs.Create.SchemaDocument([new SchemaHeaderField('title', '#f1efeb')], de.complete.docDragData.draggedDocuments, {}); this._rowDataDoc[this.renderFieldKey] = coll; } e.stopPropagation(); } - } + }; protected dropRef = (ele: HTMLElement | null) => { // if the drop disposer is not undefined, run its function this._dropDisposer?.(); // if ele is not null, give ele a non-undefined drop disposer ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); - } + }; returnHighlights(contents: string, positions?: number[]) { if (positions) { const results = []; StrCast(this.props.Document._searchString); const length = StrCast(this.props.Document._searchString).length; - const color = contents ? "black" : "grey"; + const color = contents ? 'black' : 'grey'; - results.push({contents?.slice(0, positions[0])}); + results.push( + + {contents?.slice(0, positions[0])} + + ); positions.forEach((num, cur) => { - results.push({contents?.slice(num, num + length)}); + results.push( + + {contents?.slice(num, num + length)} + + ); let end = 0; - cur === positions.length - 1 ? end = contents.length : end = positions[cur + 1]; - results.push({contents?.slice(num + length, end)}); - } - ); + cur === positions.length - 1 ? (end = contents.length) : (end = positions[cur + 1]); + results.push( + + {contents?.slice(num + length, end)} + + ); + }); return results; } - return {contents ? contents?.valueOf() : "undefined"}; + return {contents ? contents?.valueOf() : 'undefined'}; } @computed get renderFieldKey() { @@ -199,10 +213,9 @@ export class CollectionSchemaCell extends React.Component { const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc); const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null); // Jump to the this document - DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], - undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); + DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [], undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); } - } + }; renderCellWithType(type: string | undefined) { const dragRef: React.RefObject = React.createRef(); @@ -214,29 +227,29 @@ export class CollectionSchemaCell extends React.Component { const onPointerEnter = (e: React.PointerEvent): void => { // e.buttons === 1 means the left moue pointer is down - if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { - dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; + if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === 'document' || type === undefined)) { + dragRef.current!.className = 'collectionSchemaView-cellContainer doc-drag-over'; } }; const onPointerLeave = (e: React.PointerEvent): void => { // change the class name to indicate that the cell is no longer being dragged - dragRef.current!.className = "collectionSchemaView-cellContainer"; + dragRef.current!.className = 'collectionSchemaView-cellContainer'; }; let contents = Field.toString(field as Field); // display 2 hyphens instead of a blank box for empty cells - contents = contents === "" ? "--" : contents; + contents = contents === '' ? '--' : contents; // classname reflects the tatus of the cell - let className = "collectionSchemaView-cellWrapper"; - if (this._isEditing) className += " editing"; - if (this.props.isFocused && this.props.isEditable) className += " focused"; - if (this.props.isFocused && !this.props.isEditable) className += " inactive"; + let className = 'collectionSchemaView-cellWrapper'; + if (this._isEditing) className += ' editing'; + if (this.props.isFocused && this.props.isEditable) className += ' focused'; + if (this.props.isFocused && !this.props.isEditable) className += ' inactive'; const positions = []; - if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { + if (StrCast(this.props.Document._searchString).toLowerCase() !== '') { // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents - let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase(); + let term = field instanceof Promise ? '...promise pending...' : contents.toLowerCase(); const search = StrCast(this.props.Document._searchString).toLowerCase(); let start = term.indexOf(search); let tally = 0; @@ -256,56 +269,60 @@ export class CollectionSchemaCell extends React.Component { positions.pop(); } } - const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined"; + const placeholder = type === 'number' ? '0' : contents === '' ? '--' : 'undefined'; return ( -
this._isEditing = true)} onPointerEnter={onPointerEnter} onPointerLeave={onPointerLeave}> +
(this._isEditing = true))} + onPointerEnter={onPointerEnter} + onPointerLeave={onPointerLeave}>
-
- {!this.props.Document._searchDoc ? +
+ {!this.props.Document._searchDoc ? ( { const cfield = ComputedField.WithoutComputed(() => FieldValue(field)); const cscript = cfield instanceof ComputedField ? cfield.script.originalScript : undefined; - const cfinalScript = cscript?.split("return")[cscript.split("return").length - 1]; - return cscript ? (cfinalScript?.endsWith(";") ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : - Field.IsField(cfield) ? Field.toScriptString(cfield) : ""; + const cfinalScript = cscript?.split('return')[cscript.split('return').length - 1]; + return cscript ? (cfinalScript?.endsWith(';') ? `:=${cfinalScript?.substring(0, cfinalScript.length - 2)}` : cfinalScript) : Field.IsField(cfield) ? Field.toScriptString(cfield) : ''; }} SetValue={action((value: string) => { // sets what is displayed after the user makes an input let retVal = false; - if (value.startsWith(":=") || value.startsWith("=:=")) { + if (value.startsWith(':=') || value.startsWith('=:=')) { // decides how to compute a value when given either of the above strings - const script = value.substring(value.startsWith("=:=") ? 3 : 2); - retVal = this.props.setComputed(script, value.startsWith(":=") ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col); + const script = value.substring(value.startsWith('=:=') ? 3 : 2); + retVal = this.props.setComputed(script, value.startsWith(':=') ? this._rowDataDoc : this._rowDoc, this.renderFieldKey, this.props.row, this.props.col); } else { // check if the input is a number let inputIsNum = true; for (const s of value) { - if (isNaN(parseInt(s)) && !(s === ".") && !(s === ",")) { + if (isNaN(parseInt(s)) && !(s === '.') && !(s === ',')) { inputIsNum = false; } } // check if the input is a boolean - const inputIsBool: boolean = value === "false" || value === "true"; - // what to do in the case - if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { + const inputIsBool: boolean = value === 'false' || value === 'true'; + // what to do in the case + if (!inputIsNum && !inputIsBool && !value.startsWith('=')) { // if it's not a number, it's a string, and should be processed as such - // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically + // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically // after each edit let valueSansQuotes = value; if (this._isEditing) { const vsqLength = valueSansQuotes.length; // get rid of outer quotes - valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, - valueSansQuotes.charAt(vsqLength - 1) === "\"" ? vsqLength - 1 : vsqLength); + valueSansQuotes = valueSansQuotes.substring(value.startsWith('"') ? 1 : 0, valueSansQuotes.charAt(vsqLength - 1) === '"' ? vsqLength - 1 : vsqLength); } let inputAsString = '"'; // escape any quotes in the string @@ -319,27 +336,27 @@ export class CollectionSchemaCell extends React.Component { // add a closing quote inputAsString += '"'; //two options here: we can strip off outer quotes or we can figure out what's going on with the script - const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length; // change it if a change is made, otherwise, just compile using the old cell conetnts script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle numbers and expressions - } else if (inputIsNum || value.startsWith("=")) { + } else if (inputIsNum || value.startsWith('=')) { //TODO: make accept numbers - const inputscript = value.substring(value.startsWith("=") ? 1 : 0); + const inputscript = value.substring(value.startsWith('=') ? 1 : 0); // if commas are not stripped, the parser only considers the numbers after the last comma - let inputSansCommas = ""; + let inputSansCommas = ''; for (const s of inputscript) { - if (!(s === ",")) { + if (!(s === ',')) { inputSansCommas += s; } } - const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); // handle booleans } else if (inputIsBool) { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); const changeMade = value.length - 2 !== value.length; script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); } @@ -352,33 +369,47 @@ export class CollectionSchemaCell extends React.Component { })} OnFillDown={async (value: string) => { // computes all of the value preceded by := - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - script.compiled && DocListCast(this.props.Document[this.props.fieldKey]). - forEach((doc, i) => value.startsWith(":=") ? - this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : - this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run)); + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: 'number', $c: 'number', $: 'any' } }); + script.compiled && + DocListCast(this.props.Document[this.props.fieldKey]).forEach((doc, i) => + value.startsWith(':=') ? this.props.setComputed(value.substring(2), Doc.GetProto(doc), this.renderFieldKey, i, this.props.col) : this.applyToDoc(Doc.GetProto(doc), i, this.props.col, script.run) + ); }} /> - : + ) : ( this.returnHighlights(contents, positions) - } -
+ )} +
); } - render() { return this.renderCellWithType(undefined); } + render() { + return this.renderCellWithType(undefined); + } } @observer -export class CollectionSchemaNumberCell extends CollectionSchemaCell { render() { return this.renderCellWithType("number"); } } +export class CollectionSchemaNumberCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('number'); + } +} @observer -export class CollectionSchemaBooleanCell extends CollectionSchemaCell { render() { return this.renderCellWithType("boolean"); } } +export class CollectionSchemaBooleanCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('boolean'); + } +} @observer -export class CollectionSchemaStringCell extends CollectionSchemaCell { render() { return this.renderCellWithType("string"); } } +export class CollectionSchemaStringCell extends CollectionSchemaCell { + render() { + return this.renderCellWithType('string'); + } +} @observer export class CollectionSchemaDateCell extends CollectionSchemaCell { @@ -396,24 +427,24 @@ export class CollectionSchemaDateCell extends CollectionSchemaCell { // ^ DateCast is always undefined for some reason, but that is what the field should be set to this._rowDoc[this.renderFieldKey] = new DateField(date as Date); //} - } + }; render() { - return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : - this.handleChange(date)} - onChange={date => this.handleChange(date)} - />; + return !this.props.isFocused ? ( + {this._date ? Field.toString(this._date as Field) : '--'} + ) : ( + this.handleChange(date)} onChange={date => this.handleChange(date)} /> + ); } } @observer export class CollectionSchemaDocCell extends CollectionSchemaCell { - _overlayDisposer?: () => void; - @computed get _doc() { return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); } + @computed get _doc() { + return FieldValue(Cast(this._rowDoc[this.renderFieldKey], Doc)); + } @action onSetValue = (value: string) => { @@ -422,7 +453,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { const script = CompileScript(value, { addReturn: true, typecheck: true, - transformer: DocumentIconContainer.getTransformer() + transformer: DocumentIconContainer.getTransformer(), }); // compile the script const results = script.compiled && script.run(); @@ -432,44 +463,43 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { return true; } return false; - } + }; - componentWillUnmount() { this.onBlur(); } + componentWillUnmount() { + this.onBlur(); + } - onBlur = () => { this._overlayDisposer?.(); }; + onBlur = () => { + this._overlayDisposer?.(); + }; onFocus = () => { this.onBlur(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } + }; @action isEditingCallback = (isEditing: boolean): void => { // the isEditingCallback from a general CollectionSchemaCell - document.removeEventListener("keydown", this.onKeyDown); - isEditing && document.addEventListener("keydown", this.onKeyDown); + document.removeEventListener('keydown', this.onKeyDown); + isEditing && document.addEventListener('keydown', this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); this.props.changeFocusedCellByIndex(this.props.row, this.props.col); - } + }; render() { // if there's a doc, render it - return !this._doc ? this.renderCellWithType("document") : -
-
+ return !this._doc ? ( + this.renderCellWithType('document') + ) : ( +
+
StrCast(this._doc?.title)} SetValue={action((value: string) => { @@ -477,33 +507,36 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { return true; })} /> -
-
this._doc && this.props.addDocTab(this._doc, "add:right")} className="collectionSchemaView-cellContents-docButton"> +
+
this._doc && this.props.addDocTab(this._doc, OpenWhere.addRight)} className="collectionSchemaView-cellContents-docButton">
-
; +
+ ); } } @observer export class CollectionSchemaImageCell extends CollectionSchemaCell { - choosePath(url: URL) { - if (url.protocol === "data") return url.href; // if the url ises the data protocol, just return the href + 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 - if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href;//Why is this here — good question + if (!/\.(png|jpg|jpeg|gif|webp)$/.test(url.href.toLowerCase())) return url.href; //Why is this here — good question const ext = extname(url.href); - return url.href.replace(ext, "_o" + ext); + return url.href.replace(ext, '_o' + ext); } render() { const field = Cast(this._rowDoc[this.renderFieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc - const alts = DocListCast(this._rowDoc[this.renderFieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images - const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents + const alts = DocListCast(this._rowDoc[this.renderFieldKey + '-alternates']); // retrieve alternate documents that may be rendered as alternate images + const altpaths = alts + .map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url) + .filter(url => url) + .map(url => this.choosePath(url)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; // If there is a path, follow it; otherwise, follow a link to a default image icon - const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; + const url = paths.length ? paths : [Utils.CorsProxy('http://www.cs.brown.edu/~bcz/noImage.png')]; const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px @@ -511,25 +544,28 @@ export class CollectionSchemaImageCell extends CollectionSchemaCell { width = height * aspect; // increase the width of the image if necessary to maintain proportionality const reference = React.createRef(); - return
-
- -
-
; + return ( +
+
+ +
+
+ ); } } - @observer export class CollectionSchemaListCell extends CollectionSchemaCell { _overlayDisposer?: () => void; - @computed get _field() { return this._rowDoc[this.renderFieldKey]; } - @computed get _optionsList() { return this._field as List; } + @computed get _field() { + return this._rowDoc[this.renderFieldKey]; + } + @computed get _optionsList() { + return this._field as List; + } @observable private _opened = false; // whether the list is opened - @observable private _text = "select an item"; + @observable private _text = 'select an item'; @observable private _selectedNum = 0; // the index of the list item selected @action @@ -538,102 +574,109 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { this._optionsList[this._selectedNum] = this._text = value; (this._field as List).splice(this._selectedNum, 1, value); - } + }; @action onSelected = (element: string, index: number) => { // if an item is selected, the private variables should update to reflect this this._text = element; this._selectedNum = index; - } + }; onFocus = () => { this._overlayDisposer?.(); this._overlayDisposer = OverlayView.Instance.addElement(, { x: 0, y: 0 }); - } + }; render() { const link = false; const reference = React.createRef(); - // if the list is not opened, don't display it; otherwise, do. + // if the list is not opened, don't display it; otherwise, do. if (this._optionsList?.length) { - const options = !this._opened ? (null) : + const options = !this._opened ? null : (
{this._optionsList.map((element, index) => { const val = Field.toString(element); - return
this.onSelected(StrCast(element), index)} > - {val} -
; + return ( +
this.onSelected(StrCast(element), index)}> + {val} +
+ ); })} -
; - - const plainText =
{this._text}
; - const textarea =
- this._text} - SetValue={action((value: string) => { - // add special for params - this.onSetValue(value); - return true; - })} - /> -
; +
+ ); + + const plainText =
{this._text}
; + const textarea = ( +
+ this._text} + SetValue={action((value: string) => { + // add special for params + this.onSetValue(value); + return true; + })} + /> +
+ ); //☰ return (
-
{link ? plainText : textarea}
{options} -
+
); } - return this.renderCellWithType("list"); + return this.renderCellWithType('list'); } } - @observer export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { - @computed get _isChecked() { return BoolCast(this._rowDoc[this.renderFieldKey]); } + @computed get _isChecked() { + return BoolCast(this._rowDoc[this.renderFieldKey]); + } render() { const reference = React.createRef(); return (
- this._rowDoc[this.renderFieldKey] = e.target.checked} /> + (this._rowDoc[this.renderFieldKey] = e.target.checked)} />
); } } - @observer export class CollectionSchemaButtons extends CollectionSchemaCell { // the navigation buttons for schema view when it is used for search. render() { - return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <> : -
+ return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? ( + <> + ) : ( +
- -
; +
+ ); } } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx index f872637e5..3cb2df7d3 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaMovableRow.tsx @@ -10,6 +10,7 @@ import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; +import { OpenWhere } from '../../nodes/DocumentView'; import './CollectionSchemaView.scss'; export interface MovableRowProps { @@ -138,7 +139,7 @@ export class MovableRow extends React.Component
-
this.props.addDocTab(this.props.rowInfo.original, 'add:right')}> +
this.props.addDocTab(this.props.rowInfo.original, OpenWhere.addRight)}>
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index fafea5ce3..45ad4f86b 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -23,7 +23,7 @@ import { undoBatch } from '../../../util/UndoManager'; import '../../../views/DocumentDecorations.scss'; import { ContextMenu } from '../../ContextMenu'; import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; -import { DocumentView } from '../../nodes/DocumentView'; +import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; import { DefaultStyleProvider } from '../../StyleProvider'; import { CollectionView } from '../CollectionView'; import { @@ -86,7 +86,7 @@ export interface SchemaTableProps { ScreenToLocalTransform: () => Transform; active: (outsideReaction: boolean | undefined) => boolean | undefined; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; - addDocTab: (document: Doc, where: string) => boolean; + addDocTab: (document: Doc, where: OpenWhere) => boolean; pinToPres: (document: Doc) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc, outsideReaction: boolean) => boolean; @@ -625,7 +625,7 @@ export class SchemaTable extends React.Component { }; onOpenClick = () => { - this._showDoc && this.props.addDocTab(this._showDoc, 'add:right'); + this._showDoc && this.props.addDocTab(this._showDoc, OpenWhere.addRight); }; getPreviewTransform = (): Transform => { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 570039550..868822fbf 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -16,7 +16,7 @@ import { CollectionFreeFormView } from '../collections/collectionFreeForm/Collec import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewProps } from './DocumentView'; +import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; import React = require('react'); export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { @@ -199,7 +199,7 @@ export class CollectionFreeFormDocumentView extends DocComponent string; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected - addDocTab: (doc: Doc, where: string) => boolean; + 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[]) => boolean; removeDocument?: (doc: Doc | Doc[]) => boolean; @@ -474,7 +495,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "add:right"), icon: "map-pin", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: "map-pin", selected: -1 }); const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]); (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) && RadialMenu.Instance.addItem({ @@ -485,7 +506,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(this.props.Document, "add:right"), icon: "trash", selected: -1 }); + // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, OpenWhere.addRight), icon: "trash", selected: -1 }); RadialMenu.Instance.addItem({ description: 'Pin', event: () => this.props.pinToPres(this.props.Document, {}), icon: 'map-pin', selected: -1 }); RadialMenu.Instance.addItem({ description: 'Open', event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: 'trash', selected: -1 }); @@ -586,7 +607,7 @@ export class DocumentViewInternal extends DocComponent (func().result?.select === true ? this.props.select(false) : ''), 'on double click'); } else if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isLinkButton) { - UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, 'lightbox', this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap'); + UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, OpenWhere.lightbox, this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap'); SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } @@ -857,7 +878,7 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, 'add:right'), icon: 'eye' }); + !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !Doc.noviceMode && appearanceItems.push({ description: 'Add a Field', @@ -957,8 +978,8 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), 'add:right'), icon: 'layer-group' }); - !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), 'add:right'), icon: 'keyboard' }); + helpItems.push({ description: 'Show Metadata', event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'layer-group' }); + !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this.props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.props.Document), icon: 'hand-point-right' }); !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.props.Document[DataSym]), icon: 'hand-point-right' }); diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 7d04c4b64..18c5b81ec 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -20,6 +20,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import e = require('express'); import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { ImageBox } from './ImageBox'; +import { OpenWhere } from './DocumentView'; export type KVPScript = { script: CompiledScript; @@ -259,8 +260,8 @@ export class KeyValueBox extends React.Component { openItems.push({ description: 'Default Perspective', event: () => { - this.props.addDocTab(this.props.Document, 'close'); - this.props.addDocTab(this.fieldDocToLayout, 'add:right'); + this.props.addDocTab(this.props.Document, OpenWhere.close); + this.props.addDocTab(this.fieldDocToLayout, OpenWhere.addRight); }, icon: 'image', }); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 80def3025..e74ef4a39 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,18 +1,19 @@ import { action, observable } from 'mobx'; -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; import { Doc, Field, Opt } from '../../../fields/Doc'; import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist, emptyPath } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; -import { EditableView } from "../EditableView"; +import { EditableView } from '../EditableView'; import { FieldView, FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; -import "./KeyValueBox.scss"; -import "./KeyValuePair.scss"; -import React = require("react"); +import './KeyValueBox.scss'; +import './KeyValuePair.scss'; +import React = require('react'); import { DefaultStyleProvider } from '../StyleProvider'; +import { OpenWhere } from './DocumentView'; // Represents one row in a key value plane @@ -23,7 +24,7 @@ export interface KeyValuePairProps { keyWidth: number; PanelHeight: () => number; PanelWidth: () => number; - addDocTab: (doc: Doc, where: string) => boolean; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; } @observer export class KeyValuePair extends React.Component { @@ -34,23 +35,23 @@ export class KeyValuePair extends React.Component { @action handleCheck = (e: React.ChangeEvent) => { this.isChecked = e.currentTarget.checked; - } + }; @action uncheck = () => { this.checkbox.current!.checked = false; this.isChecked = false; - } + }; onContextMenu = (e: React.MouseEvent) => { const value = this.props.doc[this.props.keyName]; if (value instanceof Doc) { e.stopPropagation(); e.preventDefault(); - ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "add:right"), icon: "layer-group" }); + ContextMenu.Instance.addItem({ description: 'Open Fields', event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'layer-group' }); ContextMenu.Instance.displayMenu(e.clientX, e.clientY); } - } + }; render() { const props: FieldViewProps = { @@ -68,7 +69,7 @@ export class KeyValuePair extends React.Component { isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, - dropAction: "alias", + dropAction: 'alias', bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, @@ -92,30 +93,30 @@ export class KeyValuePair extends React.Component { doc = doc.proto; } const parenCount = Math.max(0, protoCount - 1); - const keyStyle = protoCount === 0 ? "black" : "blue"; + const keyStyle = protoCount === 0 ? 'black' : 'blue'; - const hover = { transition: "0.3s ease opacity", opacity: this.isPointerOver || this.isChecked ? 1 : 0 }; + const hover = { transition: '0.3s ease opacity', opacity: this.isPointerOver || this.isChecked ? 1 : 0 }; return ( - this.isPointerOver = true)} onPointerLeave={action(() => this.isPointerOver = false)}> + (this.isPointerOver = true))} onPointerLeave={action(() => (this.isPointerOver = false))}>
- - -
{"(".repeat(parenCount)}{props.fieldKey}{")".repeat(parenCount)}
+ +
+ {'('.repeat(parenCount)} + {props.fieldKey} + {')'.repeat(parenCount)} +
@@ -123,13 +124,13 @@ export class KeyValuePair extends React.Component { Field.toKeyValueString(props.Document, props.fieldKey)} - SetValue={(value: string) => - KeyValueBox.SetField(props.Document, props.fieldKey, value)} /> + SetValue={(value: string) => KeyValueBox.SetField(props.Document, props.fieldKey, value)} + />
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index d6cf79f87..be9565452 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -17,6 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import './LinkAnchorBox.scss'; import { LinkDocPreview } from './LinkDocPreview'; import React = require('react'); +import { OpenWhere } from './DocumentView'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -88,13 +89,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { }; openLinkDocOnRight = (e: React.MouseEvent) => { - this.props.addDocTab(this.rootDoc, 'add:right'); + this.props.addDocTab(this.rootDoc, OpenWhere.addRight); }; openLinkTargetOnRight = (e: React.MouseEvent) => { const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null)); alias._isLinkButton = undefined; alias.layoutKey = 'layout'; - this.props.addDocTab(alias, 'add:right'); + this.props.addDocTab(alias, OpenWhere.addRight); }; @action openLinkEditor = action((e: React.MouseEvent) => { diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index a47577701..135fbca31 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -14,7 +14,7 @@ import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; -import { DocumentView, DocumentViewSharedProps } from './DocumentView'; +import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); import { LinkEditor } from '../linking/LinkEditor'; @@ -156,7 +156,7 @@ export class LinkDocPreview extends React.Component { LinkDocPreview.Clear(); LinkFollower.FollowLink(this._linkDoc, this._linkSrc, this.props.docProps, false); } else if (this.props.hrefs?.length) { - this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), 'add:right'); + this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }), OpenWhere.addRight); } }; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 70ac84fa4..82d5b00f9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -31,6 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import './VideoBox.scss'; import { ObjectField } from '../../../fields/ObjectField'; +import { OpenWhere } from './DocumentView'; const path = require('path'); /** @@ -273,7 +274,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { } showTemplate = (): void => { const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null); - dragFactory && this.props.addDocTab(dragFactory, 'add:right'); + dragFactory && this.props.addDocTab(dragFactory, OpenWhere.addRight); }; dragAsTemplate = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 1e7cb6ea5..63347015b 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -17,6 +17,7 @@ import { Tooltip } from '@material-ui/core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CollectionViewType } from '../../../documents/DocumentTypes'; import { NodeSelection } from 'prosemirror-state'; +import { OpenWhere } from '../DocumentView'; export class DashFieldView { dom: HTMLDivElement; // container for label and value @@ -227,7 +228,7 @@ export class DashFieldViewInternal extends React.Component c.heading).indexOf(this._fieldKey) === -1 && list.push(new SchemaHeaderField(this._fieldKey, '#f1efeb')); list.map(c => c.heading).indexOf('text') === -1 && list.push(new SchemaHeaderField('text', '#f1efeb')); alias._pivotField = this._fieldKey.startsWith('#') ? '#' : this._fieldKey; - this.props.tbox.props.addDocTab(alias, 'add:right'); + this.props.tbox.props.addDocTab(alias, OpenWhere.addRight); } }; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fdd61463d..ce4639b76 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -45,7 +45,7 @@ import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { SidebarAnnos } from '../../SidebarAnnos'; import { StyleProp } from '../../StyleProvider'; -import { DocumentViewInternal } from '../DocumentView'; +import { DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { LinkDocPreview } from '../LinkDocPreview'; import { DashDocCommentView } from './DashDocCommentView'; @@ -1428,7 +1428,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const docView = DocumentManager.Instance.getDocumentView(audiodoc); if (!docView) { - this.props.addDocTab(audiodoc, 'add:bottom'); + this.props.addDocTab(audiodoc, OpenWhere.addBottom); setTimeout(func); } else docView.ComponentView?.playFrom?.(timecode, Cast(anchor.timecodeToHide, 'number', null)); // bcz: would be nice to find the next audio tag in the doc and play until that }; diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 3d9bd6add..68b0488a2 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -9,6 +9,7 @@ import { GetEffectiveAcl } from '../../../../fields/util'; import { Utils } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; +import { OpenWhere } from '../DocumentView'; import { liftListItem, sinkListItem } from './prosemirrorPatches.js'; const mac = typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false; @@ -135,7 +136,7 @@ export function buildKeymap>(schema: S, props: any, mapKey //Command to create a new Tab with a PDF of all the command shortcuts bind('Mod-/', (state: EditorState, dispatch: (tx: Transaction) => void) => { const newDoc = Docs.Create.PdfDocument(Utils.prepend('/assets/cheat-sheet.pdf'), { _width: 300, _height: 300 }); - props.addDocTab(newDoc, 'add:right'); + props.addDocTab(newDoc, OpenWhere.addRight); }); //Commands to modify BlockType diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e19b53f50..adfd2fda1 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -23,7 +23,7 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionView } from '../../collections/CollectionView'; import { TabDocView } from '../../collections/TabDocView'; import { ViewBoxBaseComponent } from '../../DocComponent'; @@ -35,6 +35,7 @@ import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresMovement, PresStatus } from './PresEnums'; import { map } from 'bluebird'; +import { OpenWhere, OpenWhereMod } from '../DocumentView'; const { Howl } = require('howler'); export interface PinProps { @@ -196,7 +197,7 @@ export class PresBox extends ViewBoxBaseComponent() { ); this.props.setContentView?.(this); this._unmounting = false; - this.rootDoc._forceRenderEngine = 'timeline'; + this.rootDoc._forceRenderEngine = computeTimelineLayout.name; this.layoutDoc.presStatus = PresStatus.Edit; this.layoutDoc._gridGap = 0; this.layoutDoc._yMargin = 0; @@ -563,7 +564,7 @@ export class PresBox extends ViewBoxBaseComponent() { self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); const openInTab = (doc: Doc, finished?: () => void) => { - (collectionDocView ?? this).props.addDocTab(doc, ''); + (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.add); this.layoutDoc.presCollection = targetDoc; // this still needs some fixing setTimeout(resetSelection, 500); @@ -725,7 +726,7 @@ export class PresBox extends ViewBoxBaseComponent() { if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); - CollectionDockingView.AddSplit(this.rootDoc, 'right'); + CollectionDockingView.AddSplit(this.rootDoc, OpenWhereMod.right); } else { this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); @@ -1760,7 +1761,7 @@ export class PresBox extends ViewBoxBaseComponent() { TabDocView.PinDoc(doc, {}); this.gotoDocument(this.childDocs.length, this.activeItem); } else { - this.props.addDocTab(doc, 'add:right'); + this.props.addDocTab(doc, OpenWhere.addRight); } } }; @@ -2322,7 +2323,7 @@ export class PresBox extends ViewBoxBaseComponent() { static NavigateToDoc(bestTarget: Doc, activeItem: Doc) { const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null); const openInTab = (doc: Doc, finished?: () => void) => { - CollectionDockingView.AddSplit(doc, 'right'); + CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); }; PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 8265de445..2ae597b0b 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -700,7 +700,7 @@ export class MobileInterface extends React.Component { className="docButton" title={Doc.isDocPinned(this._activeDoc) ? 'Unpin from presentation' : 'Pin to presentation'} style={{ backgroundColor: isPinned ? 'black' : 'white', color: isPinned ? 'white' : 'black' }} - onClick={e => TabDocView.PinDoc(this._activeDoc)}> + onClick={e => TabDocView.PinDoc(this._activeDoc, {})}>
); -- cgit v1.2.3-70-g09d2 From cdd1dd95c67fcb95914913bb5346c5117c0abc27 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 18 Nov 2022 17:26:17 -0500 Subject: migration of link properties to propertiesView --- src/client/util/LinkFollower.ts | 14 +- src/client/util/LinkManager.ts | 3 +- src/client/util/SelectionManager.ts | 4 + src/client/views/DocumentButtonBar.tsx | 4 +- src/client/views/PropertiesView.scss | 8 +- src/client/views/PropertiesView.tsx | 307 +++++++++++++++------ .../CollectionFreeFormLinkView.tsx | 27 +- src/client/views/linking/LinkEditor.tsx | 16 +- src/client/views/linking/LinkMenu.scss | 8 +- src/client/views/linking/LinkMenuItem.scss | 24 +- src/client/views/linking/LinkMenuItem.tsx | 42 ++- src/client/views/nodes/LinkDocPreview.tsx | 2 + src/client/views/nodes/trails/PresBox.tsx | 30 +- src/client/views/nodes/trails/PresEnums.ts | 3 + src/fields/Doc.ts | 2 +- src/fields/documentSchemas.ts | 2 +- 16 files changed, 327 insertions(+), 169 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index a3eb7ed7a..52885e428 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -111,7 +111,19 @@ export class LinkFollower { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished); + DocumentManager.Instance.jumpToDocument( + target, + zoom, + (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, 'inPlace'), finished), + targetContexts, + linkDoc, + undefined, + sourceDoc, + allFinished, + undefined, + undefined, + Cast(target.presZoom, 'number', null) + ); } } else { allFinished(); diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 7a12a8580..49cc3218d 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -19,7 +19,8 @@ import { Cast, StrCast } from '../../fields/Types'; export class LinkManager { @observable static _instance: LinkManager; @observable static userLinkDBs: Doc[] = []; - public static currentLink: Opt; + @observable public static currentLink: Opt; + @observable public static currentLinkAnchor: Opt; public static get Instance() { return LinkManager._instance; } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index a3d6f5227..1a2dda953 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -4,6 +4,7 @@ import { Doc, Opt } from '../../fields/Doc'; import { DocCast } from '../../fields/Types'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from '../views/nodes/DocumentView'; +import { LinkManager } from './LinkManager'; import { ScriptingGlobals } from './ScriptingGlobals'; export namespace SelectionManager { @@ -15,6 +16,7 @@ export namespace SelectionManager { @action SelectSchemaViewDoc(doc: Opt) { manager.SelectedSchemaDocument = doc; + if (doc?.type === DocumentType.LINK) LinkManager.currentLink = doc; } @action SelectView(docView: DocumentView, ctrlPressed: boolean): void { @@ -32,6 +34,7 @@ export namespace SelectionManager { manager.SelectedViews.clear(); manager.SelectedViews.set(docView, docView.rootDoc); } + if (docView.rootDoc.type === DocumentType.LINK) LinkManager.currentLink = docView.rootDoc; } @action DeselectView(docView: DocumentView): void { @@ -42,6 +45,7 @@ export namespace SelectionManager { } @action DeselectAll(): void { + LinkManager.currentLink = undefined; manager.SelectedSchemaDocument = undefined; Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); manager.SelectedViews.clear(); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ecf330792..5969d55e9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -21,7 +21,7 @@ import './DocumentButtonBar.scss'; import { Colors } from './global/globalEnums'; import { MetadataEntryMenu } from './MetadataEntryMenu'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; -import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhereMod } from './nodes/DocumentView'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; import { GoogleRef } from './nodes/formattedText/FormattedTextBox'; import { TemplateMenu } from './TemplateMenu'; @@ -180,7 +180,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } - CollectionDockingView.AddSplit(googleDoc, 'right'); + CollectionDockingView.AddSplit(googleDoc, OpenWhereMod.right); } else if (e.altKey) { e.preventDefault(); window.open(googleDocUrl); diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index 437df4739..30806f718 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -1,9 +1,9 @@ -@import "./global/globalCssVariables.scss"; +@import './global/globalCssVariables.scss'; .propertiesView { height: 100%; width: 250; - font-family: "Roboto"; + font-family: 'Roboto'; cursor: auto; overflow-x: hidden; @@ -843,7 +843,7 @@ } .propertiesView-section { - padding: 10px 0; + padding-left: 20px; } .propertiesView-input { @@ -877,4 +877,4 @@ color: white; padding-left: 8px; background-color: rgb(51, 51, 51); -} \ No newline at end of file +} diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 93a3fd253..076dc8261 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -4,7 +4,7 @@ import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@material-ui/core'; import { intersection } from 'lodash'; -import { action, autorun, computed, Lambda, observable } from 'mobx'; +import { action, autorun, computed, Lambda, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, AclSelfEdit, AclSym, AclUnset, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc'; @@ -27,12 +27,13 @@ import { InkStrokeProperties } from './InkStrokeProperties'; import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; import { FilterBox } from './nodes/FilterBox'; import { KeyValueBox } from './nodes/KeyValueBox'; -import { PresBox } from './nodes/trails'; +import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; import { PropertiesButtons } from './PropertiesButtons'; import { PropertiesDocBacklinksSelector } from './PropertiesDocBacklinksSelector'; import { PropertiesDocContextSelector } from './PropertiesDocContextSelector'; import './PropertiesView.scss'; import { DefaultStyleProvider } from './StyleProvider'; +import { Colors } from './global/globalEnums'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -54,7 +55,7 @@ export class PropertiesView extends React.Component { } @computed get selectedDoc() { - return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; + return LinkManager.currentLink || SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc || Doc.ActiveDashboard; } @computed get selectedDocumentView() { if (SelectionManager.Views().length) return SelectionManager.Views()[0]; @@ -405,7 +406,7 @@ export class PropertiesView extends React.Component { */ @computed get expansionIcon() { return ( - {'Show more permissions'}
}> + Show more permissions
}>
{ @@ -1406,6 +1407,37 @@ export class PropertiesView extends React.Component { } }); + @undoBatch + changeAnimationBehavior = action((behavior: string) => { + const lanch = this.destinationAnchor; + if (lanch) { + lanch.presEffect = behavior; + } + }); + @undoBatch + @action + updateEffectDirection = (effect: PresEffectDirection) => { + const lanch = this.destinationAnchor; + if (lanch) { + lanch.presEffectDirection = effect; + } + }; + + @undoBatch + animationDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const lanch = this.destinationAnchor; + const color = lanch?.presEffectDirection === direction || (direction === PresEffectDirection.Center && !lanch?.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + return ( + {direction}
}> +
this.updateEffectDirection(direction)}> + {icon ? : null} +
+ + ); + }; + @undoBatch changeFollowBehavior = action((follow: string) => { if (LinkManager.currentLink && this.selectedDoc) { @@ -1438,19 +1470,23 @@ export class PropertiesView extends React.Component { } }; - toggleAnchor = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.linkAutoMove = !this.selectedDoc.linkAutoMove)))); + toggleProp = (e: React.PointerEvent, prop: string) => { + setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc[prop] = !this.selectedDoc[prop])))); }; - toggleArrow = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (this.selectedDoc.displayArrow = !this.selectedDoc.displayArrow)))); - }; + @computed get destinationAnchor() { + const ldoc = LinkManager.currentLink; + const lanch = LinkManager.currentLinkAnchor; + if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch; + return ldoc ? DocCast(ldoc.anchor2) : ldoc; + } - toggleZoomToTarget1 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor1).followLinkZoom = !DocCast(this.selectedDoc.anchor1).followLinkZoom)))); - }; - toggleZoomToTarget2 = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (DocCast(this.selectedDoc.anchor2).followLinkZoom = !DocCast(this.selectedDoc.anchor2).followLinkZoom)))); + @computed get sourceAnchor() { + return LinkManager.currentLinkAnchor ?? (LinkManager.currentLink && this.destinationAnchor ? LinkManager.getOppositeAnchor(LinkManager.currentLink, this.destinationAnchor) : LinkManager.currentLink); + } + + toggleAnchorProp = (e: React.PointerEvent, prop: string, anchor?: Doc) => { + anchor && setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => this.selectedDoc && (anchor[prop] = !anchor[prop])))); }; @computed @@ -1485,6 +1521,23 @@ export class PropertiesView extends React.Component { ); } + // Converts seconds to ms and updates presTransition + setZoom = (number: String, change?: number) => { + let scale = Number(number) / 100; + if (change) scale += change; + if (scale < 0.01) scale = 0.01; + if (scale > 1) scale = 1; + this.destinationAnchor && (this.destinationAnchor.presZoom = scale); + }; + // Converts seconds to ms and updates presTransition + setZoomSrc = (number: String, change?: number) => { + let scale = Number(number) / 100; + if (change) scale += change; + if (scale < 0.01) scale = 0.01; + if (scale > 1) scale = 1; + this.sourceAnchor && (this.sourceAnchor.presZoom = scale); + }; + /** * Handles adding and removing members from the sharing panel */ @@ -1498,6 +1551,10 @@ export class PropertiesView extends React.Component { render() { const isNovice = Doc.noviceMode; + const zoom = Number((NumCast(this.destinationAnchor?.presZoom) * 100).toPrecision(3)); + const zoomSrc = Number((NumCast(this.sourceAnchor?.presZoom) * 100).toPrecision(3)); + const targZoom = this.destinationAnchor?.followLinkZoom; + const srcZooom = this.sourceAnchor?.followLinkZoom; if (!this.selectedDoc && !this.isPres) { return (
@@ -1507,81 +1564,6 @@ export class PropertiesView extends React.Component {
); } else { - if (this.selectedDoc && this.isLink) { - return ( -
-
Linking
-
-

Information

-
-

Link Relationship

- {this.editRelationship} -
-
-

Description

- {this.editDescription} -
-
-
-

Behavior

-
-

Follow

- -
-
-

Auto-move anchor

- -
-
-

Display arrow

- -
-
-

Zoom to target

- -
-
-

Zoom to source

- -
-
-
- ); - } if (this.selectedDoc && !this.isPres) { return (
{ {this.contextsSubMenu} {this.linksSubMenu} + {!this.selectedDoc || !LinkManager.currentLink ? null : ( + <> +
+
+

Link Relationship

+ {this.editRelationship} +
+
+

Description

+ {this.editDescription} +
+
+
+
+

Follow Behavior

+ +
+
+

Target Effect

+ +
+ {this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {this.animationDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} +
+
+ {PresBox.inputter('0.1', '0.1', '10', NumCast(this.destinationAnchor?.presTransition) / 1000, true, (val: string) => + PresBox.SetTransitionTime(val, (timeInMS: number) => this.destinationAnchor && (this.destinationAnchor.presTransition = timeInMS)) + )}{' '} +
+
Fast
+
Medium
+
Slow
+
{' '} +
+

Play Target Audio

+ +
+
+

Auto-move anchor

+ +
+
+

Show link

+ +
+
+

Display arrow

+ +
+
+

Zoom to target (% screen filled)

+
+ +
+
this.setZoom(String(zoom), 0.1))}> + +
+
this.setZoom(String(zoom), -0.1))}> + +
+
+
+ +
+ {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom)} +
+

Zoom to source (% screen filled)

+
+ +
+
this.setZoomSrc(String(zoomSrc), 0.1))}> + +
+
this.setZoomSrc(String(zoomSrc), -0.1))}> + +
+
+
+ +
+ {!srcZooom ? null : PresBox.inputter('0', '1', '100', zoomSrc, true, this.setZoomSrc)} +
+ + )} {this.inkSubMenu} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index bf9de6760..a4131d7c0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -44,7 +44,7 @@ export class CollectionFreeFormLinkView extends React.Component { - if (SettingsManager.propertiesWidth > 0) { - SettingsManager.propertiesWidth = 0; - } else { + if ((SettingsManager.propertiesWidth ?? 0) < 100) { SettingsManager.propertiesWidth = 250; } }; @@ -217,14 +215,25 @@ export class CollectionFreeFormLinkView extends React.Component (LinkManager.currentLink = this.props.LinkDocs[0]))); if (!this.renderData) return null; const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; - LinkManager.currentLink = this.props.LinkDocs[0]; const linkRelationship = Field.toString(LinkManager.currentLink?.linkRelationship as any as Field); //get string representing relationship const linkRelationshipList = Doc.UserDoc().linkRelationshipList as List; const linkColorList = Doc.UserDoc().linkColorList as List; @@ -241,8 +250,8 @@ export class CollectionFreeFormLinkView extends React.Component {textX === undefined ? null : ( diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 8c4d756d2..07c20dae4 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -327,21 +327,7 @@ export class LinkEditor extends React.Component {
- {[ - PresEffect.None, - PresEffect.Zoom, - PresEffect.Lightspeed, - PresEffect.Fade, - PresEffect.Flip, - PresEffect.Rotate, - PresEffect.Bounce, - PresEffect.Roll, - PresEffect.Left, - PresEffect.Right, - PresEffect.Center, - PresEffect.Top, - PresEffect.Bottom, - ].map(effect => ( + {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => (
this.changeEffect(effect.toString())}> {effect.toString()}
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss index 77c16a28f..80cf93ed8 100644 --- a/src/client/views/linking/LinkMenu.scss +++ b/src/client/views/linking/LinkMenu.scss @@ -1,4 +1,4 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .linkMenu { width: auto; @@ -13,7 +13,6 @@ border: 1px solid #e4e4e4; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); background: white; - min-width: 170px; max-height: 230px; overflow-y: scroll; z-index: 10; @@ -22,7 +21,7 @@ .linkMenu-list { white-space: nowrap; overflow-x: hidden; - width: 240px; + width: 100%; scrollbar-color: white; &:last-child { @@ -39,7 +38,6 @@ border-bottom: 0.5px solid lightgray; //@extend: 5px 0; - &:last-child { border-bottom: none; } @@ -76,4 +74,4 @@ display: none; } } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index 8333aa374..2ca97a27d 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -1,7 +1,7 @@ -@import "../global/globalCssVariables"; +@import '../global/globalCssVariables'; .linkMenu-item { - // border-top: 0.5px solid $medium-gray; + // border-top: 0.5px solid $medium-gray; position: relative; display: flex; border-top: 0.5px solid #cdcdcd; @@ -14,7 +14,6 @@ background-color: white; - .linkMenu-name { position: relative; width: auto; @@ -22,9 +21,7 @@ display: flex; .linkMenu-text { - - // padding: 4px 2px; - //display: inline; + width: 100%; .linkMenu-source-title { text-decoration: none; @@ -35,9 +32,7 @@ margin-left: 20px; } - .linkMenu-title-wrapper { - display: flex; align-items: center; min-height: 20px; @@ -59,7 +54,7 @@ .linkMenu-destination-title { text-decoration: none; - color: #4476F7; + color: #4476f7; font-size: 13px; line-height: 0.9; padding-bottom: 2px; @@ -96,9 +91,7 @@ //overflow-wrap: break-word; user-select: none; } - } - } .linkMenu-item-content { @@ -114,7 +107,6 @@ } &:hover { - background-color: rgb(201, 239, 252); .linkMenu-item-buttons { @@ -122,7 +114,6 @@ } .linkMenu-item-content { - .linkMenu-destination-title { text-decoration: underline; color: rgb(60, 90, 156); @@ -135,10 +126,7 @@ .linkMenu-item-buttons { //@extend: right; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); + position: relative; display: none; .button { @@ -172,4 +160,4 @@ cursor: pointer; } } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 387e0e3d5..c3b5fa997 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,12 +1,12 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; -import { action, observable } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, StrCast } from '../../../fields/Types'; +import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; -import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; +import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; @@ -16,6 +16,9 @@ import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require('react'); +import { SettingsManager } from '../../util/SettingsManager'; +import { SelectionManager } from '../../util/SelectionManager'; +import { undoBatch } from '../../util/UndoManager'; interface LinkMenuItemProps { groupType: string; @@ -76,8 +79,19 @@ export class LinkMenuItem extends React.Component { this._showMore = !this._showMore; } - onEdit = (e: React.PointerEvent): void => { - LinkManager.currentLink = this.props.linkDoc; + @computed get sourceAnchor() { + const ldoc = this.props.linkDoc; + if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + } + return this.props.sourceDoc; + } + @action + onEdit = (e: React.PointerEvent) => { + const sel = SelectionManager.Views(); + LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc; + LinkManager.currentLinkAnchor = this.sourceAnchor; setupMoveUpEvents( this, e, @@ -88,7 +102,12 @@ export class LinkMenuItem extends React.Component { return true; }, emptyFunction, - () => this.props.showEditor(this.props.linkDoc) + action(() => { + if ((SettingsManager.propertiesWidth ?? 0) < 100) { + SettingsManager.propertiesWidth = 250; + } + //this.props.showEditor(this.props.linkDoc); + }) ); }; @@ -123,6 +142,8 @@ export class LinkMenuItem extends React.Component { ); }; + deleteLink = (e: React.PointerEvent): void => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => LinkManager.Instance.deleteLink(this.props.linkDoc)))); + render() { const destinationIcon = Doc.toIcon(this.props.destinationDoc) as any as IconProp; @@ -141,7 +162,7 @@ export class LinkMenuItem extends React.Component { : undefined; return ( -
+
{
Edit Link
}>
e.stopPropagation()}> - + +
+ + Delete Link
}> +
e.stopPropagation()}> +
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 135fbca31..b326865b3 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -124,6 +124,8 @@ export class LinkDocPreview extends React.Component { return undefined; } @observable _showEditor = false; + + @action editLink = (e: React.PointerEvent): void => { LinkManager.currentLink = this.props.linkDoc; setupMoveUpEvents( diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index adfd2fda1..1cb6bc3a2 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -33,7 +33,7 @@ import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentVie import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; -import { PresEffect, PresMovement, PresStatus } from './PresEnums'; +import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import { map } from 'bluebird'; import { OpenWhere, OpenWhereMod } from '../DocumentView'; const { Howl } = require('howler'); @@ -71,10 +71,10 @@ export class PresBox extends ViewBoxBaseComponent() { */ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc, root: Doc) { const effectProps = { - left: presEffectDoc?.presEffectDirection === PresEffect.Left, - right: presEffectDoc?.presEffectDirection === PresEffect.Right, - top: presEffectDoc?.presEffectDirection === PresEffect.Top, - bottom: presEffectDoc?.presEffectDirection === PresEffect.Bottom, + left: presEffectDoc?.presEffectDirection === PresEffectDirection.Left, + right: presEffectDoc?.presEffectDirection === PresEffectDirection.Right, + top: presEffectDoc?.presEffectDirection === PresEffectDirection.Top, + bottom: presEffectDoc?.presEffectDirection === PresEffectDirection.Bottom, opposite: true, delay: 0, duration: Cast(presEffectDoc?.presTransition, 'number', null), @@ -1191,7 +1191,7 @@ export class PresBox extends ViewBoxBaseComponent() { @undoBatch @action - updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); + updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); @undoBatch @action @@ -1236,12 +1236,12 @@ export class PresBox extends ViewBoxBaseComponent() { {movement}
); - const presDirection = (direction: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const color = this.activeItem.presEffectDirection === direction || (direction === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === direction || (direction === PresEffectDirection.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
}>
this.updateEffectDirection(direction)}> {icon ? : null}
@@ -1405,11 +1405,11 @@ export class PresBox extends ViewBoxBaseComponent() {
{StrCast(this.activeItem.presEffectDirection)}
- {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})} - {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})} - {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})} - {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})} - {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} + {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
)} @@ -1428,7 +1428,7 @@ export class PresBox extends ViewBoxBaseComponent() { applyTo = (array: Doc[]) => { this.updateMovement(this.activeItem.presMovement as PresMovement, true); this.updateEffect(this.activeItem.presEffect as PresEffect, true); - this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true); + this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; array.forEach(curDoc => { curDoc.presTransition = presTransition; diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts index c6a222c3a..034f7588b 100644 --- a/src/client/views/nodes/trails/PresEnums.ts +++ b/src/client/views/nodes/trails/PresEnums.ts @@ -14,6 +14,9 @@ export enum PresEffect { Bounce = 'Bounce', Roll = 'Roll', None = 'None', +} + +export enum PresEffectDirection { Left = 'Enter from left', Right = 'Enter from right', Center = 'Enter from center', diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 75801b68c..c10751698 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1268,7 +1268,7 @@ export namespace Doc { let _lastDate = 0; export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) { - linkFollowUnhighlight(); + //linkFollowUnhighlight(); // runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = undefined)); // setTimeout(() => runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect))); runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect)); diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index 24b5a359d..10324449f 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -93,7 +93,7 @@ export const documentSchema = createSchema({ layers: listSpec('string'), // which layers the document is part of _lockedPosition: 'boolean', // whether the document can be moved (dragged) _lockedTransform: 'boolean', // whether a freeformview can pan/zoom - displayArrow: 'boolean', // toggles directed arrows + linkDisplayArrow: 'boolean', // toggles directed arrows // drag drop properties _stayInCollection: 'boolean', // whether document can be dropped into a different collection -- cgit v1.2.3-70-g09d2 From 1f5db9cfc594dbf337d752ec94dab5fca7d8b6f7 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 21 Nov 2022 14:50:25 -0500 Subject: working cleaned up version of link editor properties in propertiesView --- src/client/util/DocumentManager.ts | 6 +- src/client/util/LinkFollower.ts | 2 +- src/client/util/SelectionManager.ts | 3 - .../views/PropertiesDocBacklinksSelector.tsx | 5 +- src/client/views/PropertiesView.tsx | 161 ++++++++++----------- .../CollectionFreeFormLinkView.tsx | 1 - .../collectionSchema/CollectionSchemaCells.tsx | 3 +- .../collections/collectionSchema/SchemaTable.tsx | 3 +- src/client/views/linking/LinkEditor.tsx | 22 +-- src/client/views/linking/LinkMenu.tsx | 31 ++-- src/client/views/linking/LinkMenuGroup.tsx | 65 +++++---- src/client/views/linking/LinkMenuItem.scss | 6 +- src/client/views/linking/LinkMenuItem.tsx | 57 ++++---- src/client/views/nodes/LinkDocPreview.tsx | 33 +++-- src/client/views/nodes/LoadingBox.scss | 15 +- src/client/views/nodes/trails/PresBox.tsx | 3 +- 16 files changed, 205 insertions(+), 211 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 00f6bc40a..7120eeb88 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -5,7 +5,7 @@ import { Cast } from '../../fields/Types'; import { returnFalse } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { LightboxView } from '../views/LightboxView'; -import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocumentView, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionFreeFormView } from '../views/collections/collectionFreeForm'; @@ -167,7 +167,7 @@ export class DocumentManager { } static addView = (doc: Doc, finished?: () => void) => { - CollectionDockingView.AddSplit(doc, 'right'); + CollectionDockingView.AddSplit(doc, OpenWhereMod.right); finished?.(); }; public jumpToDocument = ( @@ -347,7 +347,7 @@ export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) { } else { const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null); const showDoc = context || doc; - CollectionDockingView.AddSplit(Doc.BestAlias(showDoc), 'right') && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); + CollectionDockingView.AddSplit(Doc.BestAlias(showDoc), OpenWhereMod.right) && context && setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc, {})); } } ScriptingGlobals.add(DocFocusOrOpen); diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 52885e428..5374bf44b 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -122,7 +122,7 @@ export class LinkFollower { allFinished, undefined, undefined, - Cast(target.presZoom, 'number', null) + Cast(sourceDoc.presZoom, 'number', null) ); } } else { diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1a2dda953..02d672a65 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -16,7 +16,6 @@ export namespace SelectionManager { @action SelectSchemaViewDoc(doc: Opt) { manager.SelectedSchemaDocument = doc; - if (doc?.type === DocumentType.LINK) LinkManager.currentLink = doc; } @action SelectView(docView: DocumentView, ctrlPressed: boolean): void { @@ -34,7 +33,6 @@ export namespace SelectionManager { manager.SelectedViews.clear(); manager.SelectedViews.set(docView, docView.rootDoc); } - if (docView.rootDoc.type === DocumentType.LINK) LinkManager.currentLink = docView.rootDoc; } @action DeselectView(docView: DocumentView): void { @@ -45,7 +43,6 @@ export namespace SelectionManager { } @action DeselectAll(): void { - LinkManager.currentLink = undefined; manager.SelectedSchemaDocument = undefined; Array.from(manager.SelectedViews.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false)); manager.SelectedViews.clear(); diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 25ac44078..f7173a593 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -3,7 +3,6 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { Cast } from '../../fields/Types'; -import { emptyFunction } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; @@ -47,9 +46,9 @@ export class PropertiesDocBacklinksSelector extends React.Component +
{this.props.hideTitle ? null :

Contexts:

} - +
); } diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 076dc8261..ad3f62990 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1409,7 +1409,7 @@ export class PropertiesView extends React.Component { @undoBatch changeAnimationBehavior = action((behavior: string) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; if (lanch) { lanch.presEffect = behavior; } @@ -1417,7 +1417,7 @@ export class PropertiesView extends React.Component { @undoBatch @action updateEffectDirection = (effect: PresEffectDirection) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; if (lanch) { lanch.presEffectDirection = effect; } @@ -1425,7 +1425,7 @@ export class PropertiesView extends React.Component { @undoBatch animationDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => { - const lanch = this.destinationAnchor; + const lanch = this.sourceAnchor; const color = lanch?.presEffectDirection === direction || (direction === PresEffectDirection.Center && !lanch?.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; return ( {direction}
}> @@ -1451,7 +1451,7 @@ export class PropertiesView extends React.Component { document.getElementById('link_description_input')?.blur(); }; - onDescriptionKey = (e: React.KeyboardEvent) => { + onDescriptionKey = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { this.setDescripValue(this.description); document.getElementById('link_description_input')?.blur(); @@ -1508,29 +1508,21 @@ export class PropertiesView extends React.Component { @computed get editDescription() { return ( - this.handleDescriptionChange(e.currentTarget.value)} className="text" - type="text" /> ); } // Converts seconds to ms and updates presTransition setZoom = (number: String, change?: number) => { - let scale = Number(number) / 100; - if (change) scale += change; - if (scale < 0.01) scale = 0.01; - if (scale > 1) scale = 1; - this.destinationAnchor && (this.destinationAnchor.presZoom = scale); - }; - // Converts seconds to ms and updates presTransition - setZoomSrc = (number: String, change?: number) => { let scale = Number(number) / 100; if (change) scale += change; if (scale < 0.01) scale = 0.01; @@ -1551,11 +1543,11 @@ export class PropertiesView extends React.Component { render() { const isNovice = Doc.noviceMode; - const zoom = Number((NumCast(this.destinationAnchor?.presZoom) * 100).toPrecision(3)); - const zoomSrc = Number((NumCast(this.sourceAnchor?.presZoom) * 100).toPrecision(3)); - const targZoom = this.destinationAnchor?.followLinkZoom; - const srcZooom = this.sourceAnchor?.followLinkZoom; - if (!this.selectedDoc && !this.isPres) { + const zoom = Number((NumCast(this.sourceAnchor?.presZoom, 1) * 100).toPrecision(3)); + const targZoom = this.sourceAnchor?.followLinkZoom; + const selectedDoc = this.selectedDoc; + const indent = 30; + if (!selectedDoc && !this.isPres) { return (
@@ -1564,7 +1556,7 @@ export class PropertiesView extends React.Component {
); } else { - if (this.selectedDoc && !this.isPres) { + if (selectedDoc && !this.isPres) { return (
{ {this.contextsSubMenu} {this.linksSubMenu} - {!this.selectedDoc || !LinkManager.currentLink ? null : ( + {!selectedDoc || !LinkManager.currentLink || !SelectionManager.Views().some(dv => DocListCast(dv.rootDoc.links).includes(LinkManager.currentLink!)) ? null : ( <>
-
-

Link Relationship

+
+

Relationship

{this.editRelationship}
-
+

Description

{this.editDescription}
-
-

Follow Behavior

- this.changeFollowBehavior(e.currentTarget.value)} value={StrCast(selectedDoc.followLinkLocation, 'default')}> - - - - - - - - - {this.selectedDoc.linksToAnnotation ? : null} + + + + + + + + + {selectedDoc.linksToAnnotation ? : null}
-
-

Target Effect

- this.changeAnimationBehavior(e.currentTarget.value)} value={StrCast(this.sourceAnchor?.presEffect, 'default')}> {[PresEffect.None, PresEffect.Zoom, PresEffect.Lightspeed, PresEffect.Fade, PresEffect.Flip, PresEffect.Rotate, PresEffect.Bounce, PresEffect.Roll].map(effect => ( ))} -
+
{this.animationDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})} {this.animationDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})} {this.animationDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})} @@ -1625,20 +1617,27 @@ export class PropertiesView extends React.Component { {this.animationDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
- {PresBox.inputter('0.1', '0.1', '10', NumCast(this.destinationAnchor?.presTransition) / 1000, true, (val: string) => - PresBox.SetTransitionTime(val, (timeInMS: number) => this.destinationAnchor && (this.destinationAnchor.presTransition = timeInMS)) + {PresBox.inputter( + '0.1', + '0.1', + '10', + NumCast(this.sourceAnchor?.presTransition) / 1000, + true, + (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => this.sourceAnchor && (this.sourceAnchor.presTransition = timeInMS)), + indent )}{' '}
Fast
-
Medium
Slow
{' '}
@@ -1652,39 +1651,35 @@ export class PropertiesView extends React.Component {
+

Show link

+ +
+

Auto-move anchor

-
-

Show link

- -
-
+

Display arrow

-
-

Zoom to target (% screen filled)

-
- +
+

Zoom % screen

+
+
this.setZoom(String(zoom), 0.1))}> @@ -1695,36 +1690,28 @@ export class PropertiesView extends React.Component {
-
- {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom)} -
-

Zoom to source (% screen filled)

-
- -
-
this.setZoomSrc(String(zoomSrc), 0.1))}> - -
-
this.setZoomSrc(String(zoomSrc), -0.1))}> - -
-
-
-
- {!srcZooom ? null : PresBox.inputter('0', '1', '100', zoomSrc, true, this.setZoomSrc)} + {!targZoom ? null : PresBox.inputter('0', '1', '100', zoom, true, this.setZoom, 30)} +
+
0%
+
100%
+
{' '}
)} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index a4131d7c0..b39fcbd48 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -230,7 +230,6 @@ export class CollectionFreeFormLinkView extends React.Component (LinkManager.currentLink = this.props.LinkDocs[0]))); if (!this.renderData) return null; const { a, b, pt1norm, pt2norm, aActive, bActive, textX, textY, pt1, pt2 } = this.renderData; diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index ef75fb159..a22999f52 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -31,6 +31,7 @@ import { OverlayView } from '../../OverlayView'; import { CollectionView } from '../CollectionView'; import './CollectionSchemaView.scss'; import { OpenWhere } from '../../nodes/DocumentView'; +import { PinProps } from '../../nodes/trails'; // intialize cell properties export interface CellProps { @@ -48,7 +49,7 @@ export interface CellProps { renderDepth: number; // called when a button is pressed on the node itself addDocTab: (document: Doc, where: OpenWhere) => boolean; - pinToPres: (document: Doc) => void; + pinToPres: (document: Doc, pinProps: PinProps) => void; moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx index 45ad4f86b..16910cc83 100644 --- a/src/client/views/collections/collectionSchema/SchemaTable.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx @@ -24,6 +24,7 @@ import '../../../views/DocumentDecorations.scss'; import { ContextMenu } from '../../ContextMenu'; import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../global/globalCssVariables.scss'; import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { PinProps } from '../../nodes/trails'; import { DefaultStyleProvider } from '../../StyleProvider'; import { CollectionView } from '../CollectionView'; import { @@ -87,7 +88,7 @@ export interface SchemaTableProps { active: (outsideReaction: boolean | undefined) => boolean | undefined; onDrop: (e: React.DragEvent, options: DocumentOptions, completed?: (() => void) | undefined) => void; addDocTab: (document: Doc, where: OpenWhere) => boolean; - pinToPres: (document: Doc) => void; + pinToPres: (document: Doc, pinProps: PinProps) => void; isSelected: (outsideReaction?: boolean) => boolean; isFocused: (document: Doc, outsideReaction: boolean) => boolean; setFocused: (document: Doc) => void; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 07c20dae4..01e33708a 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -252,7 +252,7 @@ export class LinkEditor extends React.Component { get followingDropdown() { return (
-
Follow Behavior:
+
Follow by:
{StrCast(this.props.linkDoc.followLinkLocation, 'default')} @@ -263,28 +263,28 @@ export class LinkEditor extends React.Component { Default
this.changeFollowBehavior('add:left')}> - Always open in new left pane + Always opening in new left pane
this.changeFollowBehavior('add:right')}> - Always open in new right pane + Always opening in new right pane
this.changeFollowBehavior('replace:right')}> - Always replace right tab + Always replacing right tab
this.changeFollowBehavior('replace:left')}> - Always replace left tab + Always replacing left tab
this.changeFollowBehavior('fullScreen')}> - Always open full screen + Always opening full screen
this.changeFollowBehavior('add')}> - Always open in a new tab + Always opening in a new tab
this.changeFollowBehavior('replace')}> - Replace Tab + Replacing Tab
this.changeFollowBehavior('inPlace')}> - In Place + Opening in Place
{this.props.linkDoc.linksToAnnotation ? (
this.changeFollowBehavior('openExternal')}> @@ -320,7 +320,7 @@ export class LinkEditor extends React.Component { get effectDropdown() { return (
-
Transition Effect:
+
Animation:
{StrCast(this.destinationAnchor.presEffect, 'default')} @@ -437,6 +437,8 @@ export class LinkEditor extends React.Component {
void; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; } /** @@ -25,26 +26,24 @@ export class LinkMenu extends React.Component { @observable _editingLink?: Doc; @observable _linkMenuRef = React.createRef(); - @computed get position() { - return this.props.position ?? (dv => ({ x: dv?.left || 0, y: (dv?.bottom || 0) + 15 }))(this.props.docView.getBounds()); - } - - clear = action(() => { - this.props.clearLinkEditor(); - this._editingLink = undefined; - }); + clear = !this.props.clearLinkEditor + ? undefined + : action(() => { + this.props.clearLinkEditor?.(); + this._editingLink = undefined; + }); componentDidMount() { - document.addEventListener('pointerdown', this.onPointerDown, true); + this.props.clearLinkEditor && document.addEventListener('pointerdown', this.onPointerDown, true); } componentWillUnmount() { - document.removeEventListener('pointerdown', this.onPointerDown, true); + this.props.clearLinkEditor && document.removeEventListener('pointerdown', this.onPointerDown, true); } onPointerDown = action((e: PointerEvent) => { LinkDocPreview.Clear(); if (!this._linkMenuRef.current?.contains(e.target as any) && !this._editorRef.current?.contains(e.target as any)) { - this.clear(); + this.clear?.(); } }); @@ -67,13 +66,15 @@ export class LinkMenu extends React.Component { /> )); - return linkItems.length ? linkItems : this.props.position ? [<>] : [

No links have been created yet. Drag the linking button onto another document to create a link.

]; + return linkItems.length ? linkItems : this.props.style ? [<>] : [

No links have been created yet. Drag the linking button onto another document to create a link.

]; }; render() { const sourceDoc = this.props.docView.props.Document; + 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 ( -
+
{this._editingLink ? (
(this._editingLink = undefined))} /> diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index fa6a2f506..9d2082e21 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -1,19 +1,19 @@ -import { observer } from "mobx-react"; -import { observable, action } from "mobx"; -import { Doc, StrListCast } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { Cast } from "../../../fields/Types"; -import { LinkManager } from "../../util/LinkManager"; -import { DocumentView } from "../nodes/DocumentView"; +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; +import { Doc, StrListCast } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { Cast } from '../../../fields/Types'; +import { LinkManager } from '../../util/LinkManager'; +import { DocumentView } from '../nodes/DocumentView'; import './LinkMenu.scss'; -import { LinkMenuItem } from "./LinkMenuItem"; -import React = require("react"); +import { LinkMenuItem } from './LinkMenuItem'; +import React = require('react'); interface LinkMenuGroupProps { sourceDoc: Doc; group: Doc[]; groupType: string; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; showEditor: (linkDoc: Doc) => void; docView: DocumentView; itemHandler?: (doc: Doc) => void; @@ -26,49 +26,52 @@ export class LinkMenuGroup extends React.Component { getBackgroundColor = (): string => { const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); - let color = "white"; + let color = 'white'; // if this link's relationship property is not default "link", set its color if (linkRelationshipList) { const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType); const RGBcolor: string = linkColorList[relationshipIndex]; if (RGBcolor) { //set opacity to 0.25 by modifiying the rgb string - color = RGBcolor.slice(0, RGBcolor.length - 1) + ", 0.25)"; + color = RGBcolor.slice(0, RGBcolor.length - 1) + ', 0.25)'; } } return color; - } + }; @observable _collapsed = false; render() { const set = new Set(this.props.group); const groupItems = Array.from(set.keys()).map(linkDoc => { - const destination = LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) || + const destination = + LinkManager.getOppositeAnchor(linkDoc, this.props.sourceDoc) || LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === this.props.sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, Doc, null)); if (destination && this.props.sourceDoc) { - return ; + return ( + + ); } }); return (
-
this._collapsed = !this._collapsed)} style={{ background: this.getBackgroundColor() }}> -

{this.props.groupType}:

+
(this._collapsed = !this._collapsed))} style={{ background: this.getBackgroundColor() }}> +

{this.props.groupType}:

- {this._collapsed ? (null) :
- {groupItems} -
} -
+ {this._collapsed ? null :
{groupItems}
} +
); } -} \ No newline at end of file +} diff --git a/src/client/views/linking/LinkMenuItem.scss b/src/client/views/linking/LinkMenuItem.scss index 2ca97a27d..806a2c381 100644 --- a/src/client/views/linking/LinkMenuItem.scss +++ b/src/client/views/linking/LinkMenuItem.scss @@ -79,7 +79,6 @@ font-size: 9px; line-height: 0.9; margin-left: 20px; - max-width: 125px; height: auto; white-space: break-spaces; } @@ -110,7 +109,7 @@ background-color: rgb(201, 239, 252); .linkMenu-item-buttons { - display: flex; + opacity: 1; } .linkMenu-item-content { @@ -127,7 +126,8 @@ .linkMenu-item-buttons { //@extend: right; position: relative; - display: none; + display: flex; + opacity: 0; .button { width: 20px; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index c3b5fa997..c3705b0e1 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -12,13 +12,12 @@ import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; +import { undoBatch } from '../../util/UndoManager'; import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require('react'); -import { SettingsManager } from '../../util/SettingsManager'; -import { SelectionManager } from '../../util/SelectionManager'; -import { undoBatch } from '../../util/UndoManager'; interface LinkMenuItemProps { groupType: string; @@ -26,7 +25,7 @@ interface LinkMenuItemProps { docView: DocumentView; sourceDoc: Doc; destinationDoc: Doc; - clearLinkEditor: () => void; + clearLinkEditor?: () => void; showEditor: (linkDoc: Doc) => void; menuRef: React.Ref; itemHandler?: (doc: Doc) => void; @@ -71,7 +70,6 @@ export class LinkMenuItem extends React.Component { private _drag = React.createRef(); _editRef = React.createRef(); - _buttonRef = React.createRef(); @observable private _showMore: boolean = false; @action toggleShowMore(e: React.PointerEvent) { @@ -89,7 +87,6 @@ export class LinkMenuItem extends React.Component { } @action onEdit = (e: React.PointerEvent) => { - const sel = SelectionManager.Views(); LinkManager.currentLink = this.props.linkDoc === LinkManager.currentLink ? undefined : this.props.linkDoc; LinkManager.currentLinkAnchor = this.sourceAnchor; setupMoveUpEvents( @@ -119,12 +116,12 @@ export class LinkMenuItem extends React.Component { const eleClone: any = this._drag.current!.cloneNode(true); eleClone.style.transform = `translate(${e.x}px, ${e.y}px)`; StartLinkTargetsDrag(eleClone, this.props.docView, e.x, e.y, this.props.sourceDoc, [this.props.linkDoc]); - this.props.clearLinkEditor(); + this.props.clearLinkEditor?.(); return true; }, emptyFunction, () => { - this.props.clearLinkEditor(); + this.props.clearLinkEditor?.(); if (this.props.itemHandler) { this.props.itemHandler?.(this.props.linkDoc); } else { @@ -167,20 +164,29 @@ export class LinkMenuItem extends React.Component {
- this.props.linkDoc && - LinkDocPreview.SetLinkInfo({ - docProps: this.props.docView.props, - linkSrc: this.props.sourceDoc, - linkDoc: this.props.linkDoc, - showHeader: false, - location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY], - noPreview: false, - }) - } onPointerDown={this.onLinkButtonDown}> -
+
+ Edit Link
}> +
e.stopPropagation()}> + +
+ +
+
+ this.props.linkDoc && + this.props.clearLinkEditor && + LinkDocPreview.SetLinkInfo({ + docProps: this.props.docView.props, + linkSrc: this.props.sourceDoc, + linkDoc: this.props.linkDoc, + showHeader: false, + location: [this._drag.current?.getBoundingClientRect().right ?? 100, this._drag.current?.getBoundingClientRect().top ?? e.clientY], + noPreview: false, + }) + }> {source ? (

{' '} @@ -198,14 +204,9 @@ export class LinkMenuItem extends React.Component { {!this.props.linkDoc.description ? null :

{StrCast(this.props.linkDoc.description)}

}
-
- Edit Link
}> -
e.stopPropagation()}> - -
- +
Delete Link
}> -
e.stopPropagation()}> +
e.stopPropagation()}>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index b326865b3..097035661 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -12,12 +12,11 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; +import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; -import { undoBatch } from '../../util/UndoManager'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); -import { LinkEditor } from '../linking/LinkEditor'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -123,17 +122,21 @@ export class LinkDocPreview extends React.Component { } return undefined; } - @observable _showEditor = false; @action editLink = (e: React.PointerEvent): void => { - LinkManager.currentLink = this.props.linkDoc; setupMoveUpEvents( this, e, returnFalse, emptyFunction, - action(() => (this._showEditor = !this._showEditor)) + action(() => { + LinkManager.currentLink = this._linkDoc === LinkManager.currentLink ? undefined : this._linkDoc; + LinkManager.currentLinkAnchor = this._linkSrc; + if ((SettingsManager.propertiesWidth ?? 0) < 100) { + SettingsManager.propertiesWidth = 250; + } + }) ); }; nextHref = (e: React.PointerEvent) => { @@ -181,22 +184,23 @@ export class LinkDocPreview extends React.Component { @computed get previewHeader() { return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : (
+
+ Edit Link
} placement="top"> +
+ +
+ +
{StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)}

{StrCast(this._linkDoc.description)}

-
+
Next Link
} placement="top">
- - Edit Link
} placement="top"> -
- -
-
); @@ -280,9 +284,8 @@ export class LinkDocPreview extends React.Component { className="linkDocPreview" ref={this._linkDocRef} onPointerDown={this.followLinkPointerDown} - style={{ left: this.props.location[0], top: this.props.location[1], width: this._showEditor ? 'auto' : this.width() + borders, height: this._showEditor ? 'max-content' : this.height() + borders + (this.props.showHeader ? 37 : 0) }}> - {this._showEditor ? null : this.docPreview} - {!this._showEditor || !this._linkSrc || !this._linkDoc ? null : (this._showEditor = !this._showEditor))} />} + style={{ left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}> + {this.docPreview}
); } diff --git a/src/client/views/nodes/LoadingBox.scss b/src/client/views/nodes/LoadingBox.scss index d63ed2575..4c3b8dabe 100644 --- a/src/client/views/nodes/LoadingBox.scss +++ b/src/client/views/nodes/LoadingBox.scss @@ -6,6 +6,13 @@ background-color: #fdfdfd; height: 100%; align-items: center; + .textContainer, + .text { + overflow: hidden; + text-overflow: ellipsis; + max-width: 80%; + text-align: center; + } } .textContainer { @@ -17,14 +24,6 @@ align-content: center; } -.textContainer, -.text { - overflow: hidden; - text-overflow: ellipsis; - max-width: 80%; - text-align: center; -} - .headerText { text-align: center; font-weight: bold; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 1cb6bc3a2..c04b79a1e 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1199,7 +1199,7 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; - public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?:number) => { let batch: any; return ( () { min={min} max={max} value={value} + style={{marginLeft: hmargin, marginRight:hmargin, width: `calc(100% - ${2*(hmargin??0)}px)`}} className={`toolbar-slider ${active ? '' : 'none'}`} onPointerDown={e => { batch = UndoManager.StartBatch('pres slider'); -- cgit v1.2.3-70-g09d2 From ea5c60384399e29f7b34e27e2607320134bc5432 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 6 Dec 2022 14:08:12 -0500 Subject: added long press to select documents. fixed/reactivated link size/colors. fixed stackedTimelineItems so that they don't get pointer events until container content is active. --- src/client/views/PropertiesView.tsx | 14 +++++---- src/client/views/StyleProvider.tsx | 4 +-- .../collections/CollectionStackedTimeline.tsx | 33 ++++------------------ .../CollectionFreeFormLinkView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 32 ++++++++++++++++----- src/client/views/nodes/LinkDocPreview.tsx | 4 ++- 6 files changed, 45 insertions(+), 44 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index bc08e920a..905f9e2d0 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1332,8 +1332,12 @@ export class PropertiesView extends React.Component { ); } - @observable description = Field.toString(LinkManager.currentLink?.description as any as Field); - @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship); + @computed get description() { + return Field.toString(LinkManager.currentLink?.description as any as Field); + } + @computed get relationship() { + return StrCast(LinkManager.currentLink?.linkRelationship); + } @observable private relationshipButtonColor: string = ''; // @action @@ -1343,8 +1347,7 @@ export class PropertiesView extends React.Component { @undoBatch handleDescriptionChange = action((value: string) => { if (LinkManager.currentLink && this.selectedDoc) { - this.selectedDoc.description = value; - this.description = value; + this.setDescripValue(value); return true; } }); @@ -1352,8 +1355,7 @@ export class PropertiesView extends React.Component { @undoBatch handleLinkRelationshipChange = action((value: string) => { if (LinkManager.currentLink && this.selectedDoc) { - this.selectedDoc.linkRelationship = value; - this.relationship = value; + this.setLinkRelationshipValue(value); return true; } }); diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index dc7a4e047..b77f01250 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, runInAction } from 'mobx'; import { extname } from 'path'; -import { Doc, Opt } from '../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types'; import { DashColor, emptyFunction, lightOrDark } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; @@ -252,7 +252,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt void; @@ -610,7 +608,7 @@ export class CollectionStackedTimeline extends CollectionSubView boolean; + isDocumentActive?: () => boolean | undefined; ScreenToLocalTransform: () => Transform; _timeline: HTMLDivElement | null; focus: DocFocusFunc; @@ -806,25 +804,6 @@ class StackedTimelineAnchor extends React.Component return [resetTitle]; }; - innerStyleProvider = (doc: Opt, props: Opt, property: string): any => { - if (property === StyleProp.Decorations && doc && NumCast(doc.timecodeToHide) - NumCast(doc.timecodeToShow) < 0.0002) { - return ( -
- { - LinkFollower.FollowLink(undefined, doc, props as DocumentViewSharedProps, e.altKey); - e.stopPropagation(); - }} - size="lg" - /> -
- ); - } - return this.props.styleProvider?.(doc, props, property); - }; - // renders anchor LabelBox renderInner = computedFn(function (this: StackedTimelineAnchor, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), screenXf: () => Transform, width: () => number, height: () => number) { const anchor = observable({ view: undefined as any }); @@ -841,7 +820,7 @@ class StackedTimelineAnchor extends React.Component ref={action((r: DocumentView | null) => (anchor.view = r))} Document={mark} DataDoc={undefined} - styleProvider={this.innerStyleProvider} + styleProvider={this.props.styleProvider} renderDepth={this.props.renderDepth + 1} LayoutTemplate={undefined} LayoutTemplateString={LabelBox.LayoutStringWithTitle('data', this.computeTitle())} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index c57810a98..b85da2ce7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -241,7 +241,7 @@ export class CollectionFreeFormLinkView extends React.Component; const linkColorList = Doc.UserDoc().linkColorList as List; const linkRelationshipSizes = Doc.UserDoc().linkRelationshipSizes as List; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 4abfef563..778965553 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -239,9 +239,8 @@ export interface DocumentViewInternalProps extends DocumentViewProps { @observer export class DocumentViewInternal extends DocComponent() { public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. - @observable _animateScaleTime: Opt; // milliseconds for animating between views. defaults to 300 if not uset - @observable _animateScalingTo = 0; - @observable _pendingDoubleClick = false; + private _cursorTimer: NodeJS.Timeout | undefined; + private _longPress = false; private _disposers: { [name: string]: IReactionDisposer } = {}; private _downX: number = 0; private _downY: number = 0; @@ -255,7 +254,12 @@ export class DocumentViewInternal extends DocComponent; // 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; + @observable _pendingDoubleClick = false; + @observable _cursorPress = false; private get topMost() { return this.props.renderDepth === 0 && !LightboxView.LightboxDoc; @@ -623,7 +627,7 @@ export class DocumentViewInternal extends DocComponent @@ -652,12 +656,12 @@ export class DocumentViewInternal extends DocComponent 0)) { - // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part + // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template } else { runInAction(() => (this._pendingDoubleClick = true)); @@ -688,6 +692,13 @@ export class DocumentViewInternal extends DocComponent { + this._cursorPress = true; + this.props.select(false); + }), + 1000 // long press required duration + ); this._downX = e.clientX; this._downY = e.clientY; if ((Doc.ActiveTool === InkTool.None || this.props.addDocTab === returnFalse) && !(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) { @@ -713,6 +724,7 @@ export class DocumentViewInternal extends DocComponent { if (e.cancelBubble) return; if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return; @@ -722,6 +734,8 @@ export class DocumentViewInternal extends DocComponent { this.cleanupPointerEvents(); + this._longPress = this._cursorPress; + this._cursorTimer && clearTimeout(this._cursorTimer); + this._cursorPress = false; if (this.onPointerUpHandler?.script && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { this.onPointerUpHandler.script.run({ self: this.rootDoc, this: this.layoutDoc }, console.log); @@ -1395,7 +1413,7 @@ export class DocumentViewInternal extends DocComponent { returnFalse, emptyFunction, action(() => { - LinkManager.currentLink = this._linkDoc === LinkManager.currentLink ? undefined : this._linkDoc; + LinkManager.currentLink = this._linkDoc; LinkManager.currentLinkAnchor = this._linkSrc; + this.props.docProps.DocumentView?.().select(false); if ((SettingsManager.propertiesWidth ?? 0) < 100) { SettingsManager.propertiesWidth = 250; } -- cgit v1.2.3-70-g09d2 From d5f796b433d7e72130d4109a3775347ccb10c454 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 17 Jan 2023 22:34:32 -0500 Subject: fixed linkint to trail to follow trail immediately in lightbox and show trail ui in minimized mode. fixed overlay of pres box to not disappear when lightbox appears. closing /ending trail hackily restores collecftion to prior pan/zoom. --- src/client/util/LinkFollower.ts | 19 +- src/client/views/MainView.tsx | 14 +- src/client/views/OverlayView.tsx | 136 ++++++----- .../CollectionFreeFormLinkView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 3 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 1 + src/client/views/nodes/trails/PresBox.scss | 26 +- src/client/views/nodes/trails/PresBox.tsx | 267 +++++++++++++-------- src/client/views/nodes/trails/PresElementBox.tsx | 12 +- src/fields/FieldLoader.scss | 9 +- src/fields/FieldLoader.tsx | 14 +- 12 files changed, 298 insertions(+), 211 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 807b54cd5..0f216e349 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -2,11 +2,14 @@ import { action, runInAction } from 'mobx'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { DocumentDecorations } from '../views/DocumentDecorations'; import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, ViewAdjustment } from '../views/nodes/DocumentView'; +import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; +import { PresBox } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; +import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; @@ -116,6 +119,20 @@ export class LinkFollower { LightboxView.SetLightboxDoc(currentContext, undefined, tour); setTimeout(LightboxView.Next); allFinished(); + } else if (target.type === DocumentType.PRES) { + const containerAnnoDoc = Cast(sourceDoc, Doc, null); + const containerDoc = containerAnnoDoc || sourceDoc; + var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]); + while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking) { + containerDocContext = [Cast(await containerDocContext[0].context, Doc, null), ...containerDocContext]; + } + if (!DocumentManager.Instance.getDocumentView(containerDocContext[0])) { + CollectionDockingView.AddSplit(containerDocContext[0], OpenWhereMod.right); + } + SelectionManager.DeselectAll(); + DocumentManager.Instance.AddViewRenderedCb(target, dv => containerDocContext.length && (dv.ComponentView as PresBox).PlayTrail(containerDocContext[0])); + PresBox.OpenPresMinimized(target, [0, 0]); + finished?.(); } else { const containerAnnoDoc = Cast(target.annotationOn, Doc, null); const containerDoc = containerAnnoDoc || target; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 39cc9ba8e..4494166f2 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -574,7 +574,7 @@ export class MainView extends React.Component { Document={this.headerBarDoc} DataDoc={undefined} addDocument={undefined} - addDocTab={this.addDocTabFunc} + addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} styleProvider={DefaultStyleProvider} @@ -611,7 +611,7 @@ export class MainView extends React.Component { Document={this.mainContainer!} DataDoc={undefined} addDocument={undefined} - addDocTab={this.addDocTabFunc} + addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} styleProvider={this._hideUI ? DefaultStyleProvider : undefined} @@ -682,7 +682,7 @@ export class MainView extends React.Component { sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0); - addDocTabFunc = (doc: Doc, location: OpenWhere): boolean => { + static addDocTabFunc = (doc: Doc, location: OpenWhere): boolean => { const whereFields = doc._viewType === CollectionViewType.Docking ? [OpenWhere.dashboard] : location.split(':'); const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none; if (doc.dockingConfig) return DashboardView.openDashboard(doc); @@ -710,7 +710,7 @@ export class MainView extends React.Component { Document={this._sidebarContent.proto || this._sidebarContent} DataDoc={undefined} addDocument={undefined} - addDocTab={this.addDocTabFunc} + addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} docViewPath={returnEmptyDoclist} styleProvider={this._sidebarContent.proto === Doc.MyDashboards || this._sidebarContent.proto === Doc.MyFilesystem ? DashboardStyleProvider : DefaultStyleProvider} @@ -744,7 +744,7 @@ export class MainView extends React.Component { Document={Doc.MyLeftSidebarMenu} DataDoc={undefined} addDocument={undefined} - addDocTab={this.addDocTabFunc} + addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} rootSelected={returnTrue} removeDocument={returnFalse} @@ -808,7 +808,7 @@ export class MainView extends React.Component {
)}
- {this.propertiesWidth() < 10 ? null : } + {this.propertiesWidth() < 10 ? null : }
@@ -888,7 +888,7 @@ export class MainView extends React.Component { moveDocument={this.moveButtonDoc} CollectionView={undefined} addDocument={this.addButtonDoc} - addDocTab={this.addDocTabFunc} + addDocTab={MainView.addDocTabFunc} pinToPres={emptyFunction} removeDocument={this.remButtonDoc} ScreenToLocalTransform={this.buttonBarXf} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 6d7f2c037..08285ff0c 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, trace } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -8,15 +8,17 @@ import { Id } from '../../fields/FieldSymbols'; import { NumCast } from '../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../Utils'; import { DocUtils } from '../documents/Documents'; +import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; import { CollectionFreeFormLinksView } from './collections/collectionFreeForm/CollectionFreeFormLinksView'; import { LightboxView } from './LightboxView'; +import { MainView } from './MainView'; import { DocumentView } from './nodes/DocumentView'; import './OverlayView.scss'; import { ScriptingRepl } from './ScriptingRepl'; -import { DefaultStyleProvider } from './StyleProvider'; +import { DefaultStyleProvider, testDocProps } from './StyleProvider'; export type OverlayDisposer = () => void; @@ -170,74 +172,70 @@ export class OverlayView extends React.Component { ); @computed get overlayDocs() { - return LightboxView.LightboxDoc - ? null - : DocListCast(Doc.MyOverlayDocs?.data).map(d => { - let offsetx = 0, - offsety = 0; - const dref = React.createRef(); - const onPointerMove = action((e: PointerEvent, down: number[]) => { - if (e.buttons === 1) { - d.overlayX = e.clientX + offsetx; - d.overlayY = e.clientY + offsety; - } - if (e.metaKey) { - const dragData = new DragManager.DocumentDragData([d]); - dragData.offset = [-offsetx, -offsety]; - dragData.dropAction = 'move'; - dragData.removeDocument = (doc: Doc | Doc[]) => { - const docs = doc instanceof Doc ? [doc] : doc; - docs.forEach(d => Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, d)); - return true; - }; - dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { - return dragData.removeDocument!(doc) ? addDocument(doc) : false; - }; - DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]); - return true; - } - return false; - }); + return DocListCast(Doc.MyOverlayDocs?.data) + .filter(d => !LightboxView.LightboxDoc || d.type === DocumentType.PRES) + .map(d => { + let offsetx = 0, + offsety = 0; + const dref = React.createRef(); + const onPointerMove = action((e: PointerEvent, down: number[]) => { + if (e.buttons === 1) { + d.overlayX = e.clientX + offsetx; + d.overlayY = e.clientY + offsety; + } + if (e.metaKey) { + const dragData = new DragManager.DocumentDragData([d]); + dragData.offset = [-offsetx, -offsety]; + dragData.dropAction = 'move'; + dragData.removeDocument = this.removeOverlayDoc; + dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { + return dragData.removeDocument!(doc) ? addDocument(doc) : false; + }; + DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]); + return true; + } + return false; + }); - const onPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction); - offsetx = NumCast(d.overlayX) - e.clientX; - offsety = NumCast(d.overlayY) - e.clientY; - }; - return ( -
- -
- ); - }); + const onPointerDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction); + offsetx = NumCast(d.overlayX) - e.clientX; + offsety = NumCast(d.overlayY) - e.clientY; + }; + return ( +
+ +
+ ); + }); } public static ShowSpinner() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 4c8c65707..8919b1c01 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -204,10 +204,12 @@ export class CollectionFreeFormLinkView extends React.Component { toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight()); focus = (doc: Doc, options: DocFocusOptions) => this.docView?.focus(doc, options); getBounds = () => { - if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { + if (!this.docView || !this.docView.ContentDiv || this.props.Document.type === DocumentType.PRES || this.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) { return undefined; } const xf = this.docView?.props diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index b2fdd93fc..232c3459e 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -17,7 +17,6 @@ import { Transform } from '../../util/Transform'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); -import { SelectionManager } from '../../util/SelectionManager'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -114,7 +113,7 @@ export class LinkDocPreview extends React.Component { this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; } this._toolTipText = ''; - if (LinkDocPreview.LinkInfo?.noPreview) this.followLink(); + if (LinkDocPreview.LinkInfo?.noPreview || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink(); } }) ); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index b895043de..62e215521 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1476,6 +1476,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent node that wraps the hyerlink while (target && !target.dataset?.targethrefs) target = target.parentElement; FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs, target?.dataset.linkdoc, target?.dataset.nopreview === 'true'); + if (target) return; } if (e.button === 0 && this.props.isSelected(true) && !e.altKey) { diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index 4d60a02f1..fd202590e 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -938,14 +938,19 @@ min-width: 15px; max-width: 100px; left: 8px; + margin: auto; + margin-left: unset; + height: 100%; } .presBox-presentPanel { display: flex; justify-self: end; width: 100%; - max-width: 300px; - min-width: 150px; + margin: auto; + margin-right: unset; + height: 100%; + position: relative; } select { @@ -955,7 +960,7 @@ .presBox-button { cursor: pointer; - height: 25px; + //height: 100%; border-radius: 5px; display: none; justify-content: center; @@ -986,6 +991,9 @@ width: max-content; position: absolute; right: 10px; + margin: auto; + margin-right: unset; + height: 100%; .present-icon { margin-right: 7px; @@ -999,9 +1007,16 @@ position: relative; display: inline-block; left: 8px; + margin: auto; + margin-left: unset; } } +.presBox-buttons.inOverlay { + padding-top: unset; + padding-bottom: unset; +} + .presBox-backward, .presBox-forward { width: 25px; @@ -1052,6 +1067,8 @@ font-size: 30px; position: absolute; min-width: 50px; + margin: auto; + margin-left: unset; } } @@ -1087,13 +1104,12 @@ color: $white; border-radius: 5px; grid-template-rows: 100%; - height: 25; + height: 100%; width: max-content; min-width: max-content; justify-content: space-evenly; align-items: center; display: flex; - position: absolute; transition: all 0.2s; .presPanel-button-text { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index a609b46e4..855a7f171 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -12,7 +12,7 @@ import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { AudioField } from '../../../../fields/URLField'; -import { emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; +import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; @@ -136,6 +136,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action componentWillUnmount() { this._unmounting = true; + if (this._presTimer) clearTimeout(this._presTimer); document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); this.resetPresentation(); // Turn of progressivize editors @@ -143,7 +144,6 @@ export class PresBox extends ViewBoxBaseComponent() { Object.values(this._disposers).forEach(disposer => disposer?.()); } - @action componentDidMount() { this._disposers.keyboard = reaction( () => this.selectedDoc, @@ -167,10 +167,13 @@ export class PresBox extends ViewBoxBaseComponent() { ); this.props.setContentView?.(this); this._unmounting = false; - this.rootDoc._forceRenderEngine = computeTimelineLayout.name; - this.layoutDoc.presStatus = PresStatus.Edit; - this.layoutDoc._gridGap = 0; - this.layoutDoc._yMargin = 0; + if (this.props.renderDepth > 0) { + runInAction(() => { + this.rootDoc._forceRenderEngine = computeTimelineLayout.name; + this.layoutDoc._gridGap = 0; + this.layoutDoc._yMargin = 0; + }); + } this.turnOffEdit(true); this._disposers.selection = reaction( () => SelectionManager.Views(), @@ -247,9 +250,12 @@ export class PresBox extends ViewBoxBaseComponent() { const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]); const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex; this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1); - } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { - // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode - this.nextSlide(0); + } else { + if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { + // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode + this.nextSlide(0); + } + return 0; } return this.itemIndex; }; @@ -510,28 +516,28 @@ export class PresBox extends ViewBoxBaseComponent() { const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null); const presCollection = Cast(this.layoutDoc.presCollection, Doc, null); const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined; - const includesDoc: boolean = DocumentManager.Instance.getDocumentView(targetDoc) ? true : false; // DocListCast(presCollection?.data).includes(targetDoc); + const includesDoc = () => (DocumentManager.Instance.getDocumentView(targetDoc) ? true : false); // DocListCast(presCollection?.data).includes(targetDoc); const tabMap = CollectionDockingView.Instance?.tabMap; const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc === srcContext || tab.DashDoc === targetDoc); // Handles the setting of presCollection - if (includesDoc) { + if (includesDoc()) { //Case 1: Pres collection should not change as it is already the same } else if (tab !== undefined) { // Case 2: Pres collection should update this.layoutDoc.presCollection = srcContext; } - const presStatus = this.rootDoc.presStatus; const selViewCache = Array.from(this.selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); const resetSelection = action(() => { - const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc); - if (presDocView) SelectionManager.SelectView(presDocView, false); - this.rootDoc.presStatus = presStatus; - this.clearSelectedArray(); - selViewCache.forEach(doc => this.addToSelectedArray(doc)); - this._dragArray.splice(0, this._dragArray.length, ...dragViewCache); - this._eleArray.splice(0, this._eleArray.length, ...eleViewCache); + if (!includesDoc()) { + const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc); + if (presDocView) SelectionManager.SelectView(presDocView, false); + this.clearSelectedArray(); + selViewCache.forEach(doc => this.addToSelectedArray(doc)); + this._dragArray.splice(0, this._dragArray.length, ...dragViewCache); + this._eleArray.splice(0, this._eleArray.length, ...eleViewCache); + } finished(); }); const createDocView = (doc: Doc, finished?: () => void) => { @@ -539,7 +545,7 @@ export class PresBox extends ViewBoxBaseComponent() { (collectionDocView ?? this).props.addDocTab(doc, OpenWhere.lightbox); this.layoutDoc.presCollection = targetDoc; }; - PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc || tab ? finished : resetSelection); + PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, srcContext, includesDoc() || tab ? finished : resetSelection); }; static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, srcContext: Doc, finished?: () => void) { @@ -562,7 +568,6 @@ export class PresBox extends ViewBoxBaseComponent() { setTimeout(restoreLayout); } else { if (targetDoc) { - LightboxView.SetLightboxDoc(undefined); const options: DocFocusOptions = { willPan: activeItem.presMovement !== PresMovement.None, willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, @@ -579,10 +584,23 @@ export class PresBox extends ViewBoxBaseComponent() { while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } - + const testTarget = containerDocContext.length ? containerDocContext[0] : targetDoc; + if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(testTarget)) { + DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { + if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(LightboxView.LightboxDoc)) { + DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); + restoreLayout(); + } else { + LightboxView.SetLightboxDoc(undefined); + DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); + restoreLayout(); + } + }); + return; + } DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finished); - } - restoreLayout(); + restoreLayout(); + } else restoreLayout(); } } @@ -633,20 +651,19 @@ export class PresBox extends ViewBoxBaseComponent() { }); }; - //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc - @action - startAutoPres = async (startSlide: number) => { - if (!this.childDocs.length) return; - this.layoutDoc.presStatus = PresStatus.Autoplay; - this.startPresentation(startSlide); - clearTimeout(this._presTimer); - const func = (itemIndex: number) => { - this._presTimer = setTimeout(() => { - if (itemIndex === this.next()) this.layoutDoc.presStatus = PresStatus.Manual; - this.layoutDoc.presStatus !== PresStatus.Manual && func(this.itemIndex); - }, NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition)); + _exitTrail: Opt<() => void>; + PlayTrail = (doc: Doc) => { + const savedState = { c: doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) }; + this.startPresentation(0); + this._exitTrail = () => { + const { x, y, s, c } = savedState; + c._panX = x; + c._panY = y; + c._viewScale = s; + LightboxView.SetLightboxDoc(undefined); + Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); + return PresStatus.Edit; }; - func(this.itemIndex); }; // The function pauses the auto presentation @@ -695,40 +712,54 @@ export class PresBox extends ViewBoxBaseComponent() { * @param startIndex: index that the presentation will start at */ startPresentation = (startIndex: number) => { - this.childDocs.forEach(doc => { - const tagDoc = doc.presentationTargetDoc as Doc; - if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) { - tagDoc.opacity = 0; - } - if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) { - tagDoc.opacity = 0; - } - }); - this.gotoDocument(startIndex, this.activeItem); + clearTimeout(this._presTimer); + if (this.childDocs.length) { + this.layoutDoc.presStatus = PresStatus.Autoplay; + this.childDocs.forEach(doc => { + const tagDoc = doc.presentationTargetDoc as Doc; + if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) tagDoc.opacity = 0; + if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) tagDoc.opacity = 0; + // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; + }); + const func = () => { + const delay = NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition); + this._presTimer = setTimeout(() => { + if (!this.next()) this.layoutDoc.presStatus = this._exitTrail?.() ?? PresStatus.Manual; + this.layoutDoc.presStatus === PresStatus.Autoplay && func(); + }, delay); + }; + this.gotoDocument(startIndex, this.activeItem, undefined, func); + } }; /** * The method called to open the presentation as a minimized view */ @action - updateMinimize = async () => { + enterMinimize = () => { + clearTimeout(this._presTimer); + const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + this.props.removeDocument?.(this.layoutDoc); + return PresBox.OpenPresMinimized(this.rootDoc, [pt[0] + (this.props.PanelWidth() - 250), pt[1] + 10]); + }; + exitMinimize = () => { if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { - this.layoutDoc.presStatus = PresStatus.Edit; Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); CollectionDockingView.AddSplit(this.rootDoc, OpenWhereMod.right); - } else { - this.layoutDoc.presStatus = PresStatus.Edit; - clearTimeout(this._presTimer); - const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - this.rootDoc.overlayX = pt[0] + (this.props.PanelWidth() - 250); - this.rootDoc.overlayY = pt[1] + 10; - this.rootDoc._height = 30; - this.rootDoc._width = 248; - Doc.AddDocToList(Doc.MyOverlayDocs, undefined, this.rootDoc); - this.props.removeDocument?.(this.layoutDoc); } + return PresStatus.Edit; }; + public static minimizedWidth = 198; + public static OpenPresMinimized(doc: Doc, pt: number[]) { + doc.overlayX = pt[0]; + doc.overlayY = pt[1]; + doc._height = 30; + doc._width = PresBox.minimizedWidth; + Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); + return (doc.presStatus = PresStatus.Manual); + } + /** * Called when the user changes the view type * Either 'List' (stacking) or 'Slides' (carousel) @@ -940,11 +971,13 @@ export class PresBox extends ViewBoxBaseComponent() { break; case 'Escape': if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { - this.updateMinimize(); - } else if (this.layoutDoc.presStatus === 'edit') { + this.exitClicked(); + } else if (this.layoutDoc.presStatus === PresStatus.Edit) { this.clearSelectedArray(); this._eleArray.length = this._dragArray.length = 0; - } else this.layoutDoc.presStatus = 'edit'; + } else { + this.layoutDoc.presStatus = PresStatus.Edit; + } if (this._presTimer) clearTimeout(this._presTimer); handled = true; break; @@ -1797,7 +1830,7 @@ export class PresBox extends ViewBoxBaseComponent() { className="dropdown-play-button" onClick={undoBatch( action(() => { - this.updateMinimize(); + this.enterMinimize(); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }) @@ -1820,8 +1853,8 @@ export class PresBox extends ViewBoxBaseComponent() { } scrollFocus = () => { - this.gotoDocument(0); - this.startOrPause(false); + // this.gotoDocument(0); + // this.startOrPause(false); return undefined; }; @@ -1951,8 +1984,9 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get topPanel() { const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; const isMini: boolean = this.toolbarWidth <= 100; + const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); return ( -
+
{isMini ? null : ( )}
- +
{ @@ -2001,11 +2035,15 @@ export class PresBox extends ViewBoxBaseComponent() { @computed get playButtons() { const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; + const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); // Case 1: There are still other frames and should go through all frames before going to next slide return (
{'Loop'}
}> -
(this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}>
@@ -2013,42 +2051,77 @@ export class PresBox extends ViewBoxBaseComponent() {
{ - this.back(); - if (this._presTimer) { - clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; - } - e.stopPropagation(); - }}> + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + () => { + this.back(); + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } + e.stopPropagation(); + }, + false, + false + ) + }>
{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}
}> -
this.startOrPause(true)}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}>
{ - this.next(); - if (this._presTimer) { - clearTimeout(this._presTimer); - this.layoutDoc.presStatus = PresStatus.Manual; - } - e.stopPropagation(); - }}> + onPointerDown={e => + setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + () => { + this.next(); + if (this._presTimer) { + clearTimeout(this._presTimer); + this.layoutDoc.presStatus = PresStatus.Manual; + } + e.stopPropagation(); + }, + false, + false + ) + }>
{'Click to return to 1st slide'}
}> -
this.nextSlide(0)}> +
+ setupMoveUpEvents( + this, + e, + returnFalse, + emptyFunction, + () => { + this.nextSlide(0); + }, + false, + false + ) + }> 1
-
this.gotoDocument(0, this.activeItem)} style={{ display: this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> - Slide {this.itemIndex + 1} / {this.childDocs.length} +
this.gotoDocument(0, this.activeItem)} style={{ display: inOverlay || this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> + {`${inOverlay ? '' : 'Slide'} ${this.itemIndex + 1} / ${this.childDocs.length}`}
{this.props.PanelWidth() > 250 ? ( @@ -2056,14 +2129,14 @@ export class PresBox extends ViewBoxBaseComponent() { className="presPanel-button-text" onClick={undoBatch( action(() => { - this.layoutDoc.presStatus = 'edit'; + this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); }) )}> EXIT
) : ( -
(this.layoutDoc.presStatus = 'edit')))}> +
setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.exitClicked, false, false)}>
)} @@ -2074,7 +2147,7 @@ export class PresBox extends ViewBoxBaseComponent() { @action startOrPause = (makeActive = true) => { makeActive && this.updateCurrentPresentation(); - if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex); + if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startPresentation(this.itemIndex); else this.pauseAutoPres(); }; @@ -2097,9 +2170,8 @@ export class PresBox extends ViewBoxBaseComponent() { }; @undoBatch @action - exitClicked = (e: PointerEvent) => { - this.updateMinimize(); - this.layoutDoc.presStatus = PresStatus.Edit; + exitClicked = () => { + this.layoutDoc.presStatus = this._exitTrail?.() ?? this.exitMinimize(); clearTimeout(this._presTimer); }; @@ -2134,8 +2206,9 @@ export class PresBox extends ViewBoxBaseComponent() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; - const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; + const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; + const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0; + const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
() {
) : ( -
+
{this.topPanel} {this.toolbar} {this.newDocumentToolbarDropdown} diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 5e1474b89..f1c97d26a 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -50,9 +50,6 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get collapsedHeight() { return 35; } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up - @computed get presStatus() { - return this.presBox.presStatus; - } @computed get selectedArray() { return this.presBoxView?.selectedArray; } @@ -364,14 +361,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { }; @computed get recordingIsInOverlay() { - let isInOverlay = false; - DocListCast(Doc.MyOverlayDocs.data).forEach(doc => { - if (doc.slides === this.rootDoc) { - isInOverlay = true; - // return - } - }); - return isInOverlay; + return DocListCast(Doc.MyOverlayDocs.data).some(doc => doc.slides === this.rootDoc); } // a previously recorded video will have timecode defined diff --git a/src/fields/FieldLoader.scss b/src/fields/FieldLoader.scss index 123488c7d..9a23c3e4f 100644 --- a/src/fields/FieldLoader.scss +++ b/src/fields/FieldLoader.scss @@ -1,12 +1,15 @@ .fieldLoader { z-index: 10000; width: 200px; - height: 50; - background: white; + height: 30; + background: lightblue; position: absolute; left: calc(50% - 99px); - top: calc(50% + 99px); + top: calc(50% + 110px); display: flex; align-items: center; padding: 20px; + margin: auto; + display: 'block'; + box-shadow: darkslategrey 0.2vw 0.2vw 0.8vw; } diff --git a/src/fields/FieldLoader.tsx b/src/fields/FieldLoader.tsx index 36dca89f2..2a7b936f7 100644 --- a/src/fields/FieldLoader.tsx +++ b/src/fields/FieldLoader.tsx @@ -10,18 +10,6 @@ export class FieldLoader extends React.Component { public static active = false; render() { - return ( -
{`Requested: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}
- ); + return
{`Requested: ${FieldLoader.ServerLoadStatus.requested} ... ${FieldLoader.ServerLoadStatus.retrieved} `}
; } } -- cgit v1.2.3-70-g09d2 From 84f728cffb94319b86be8d6cc478ce424ec45c2f Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 20 Jan 2023 11:17:38 -0500 Subject: removed tour map from lightbox. added option to create anchors without adding thm as annotations. made zoom of text an option for pres and links --- src/client/documents/Documents.ts | 4 +- src/client/util/DragManager.ts | 4 +- src/client/util/LinkFollower.ts | 10 +--- src/client/views/DocComponent.tsx | 7 +++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/InkingStroke.tsx | 4 +- src/client/views/LightboxView.tsx | 56 +++++----------------- src/client/views/MarqueeAnnotator.tsx | 8 ++-- src/client/views/PropertiesView.tsx | 10 ++++ .../collections/CollectionStackedTimeline.tsx | 18 +++---- src/client/views/collections/CollectionSubView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 14 +++--- src/client/views/collections/TabDocView.tsx | 2 +- .../CollectionFreeFormLinkView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 12 +++-- src/client/views/nodes/AudioBox.tsx | 7 ++- src/client/views/nodes/DocumentLinksButton.tsx | 6 +-- src/client/views/nodes/DocumentView.tsx | 14 +++--- src/client/views/nodes/FunctionPlotBox.tsx | 7 +-- src/client/views/nodes/ImageBox.tsx | 8 ++-- src/client/views/nodes/LabelBox.tsx | 4 +- src/client/views/nodes/LinkDocPreview.tsx | 2 +- src/client/views/nodes/MapBox/MapBox.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 8 ++-- src/client/views/nodes/ScreenshotBox.tsx | 4 +- src/client/views/nodes/VideoBox.tsx | 11 +++-- src/client/views/nodes/WebBox.tsx | 6 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 39 +++++++-------- .../views/nodes/formattedText/RichTextRules.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 13 +++-- src/client/views/pdf/AnchorMenu.tsx | 13 ++--- src/client/views/pdf/Annotation.tsx | 8 ++-- src/client/views/pdf/PDFViewer.tsx | 4 +- 33 files changed, 157 insertions(+), 159 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b51fcb454..80b040cc0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1310,13 +1310,13 @@ export namespace DocUtils { options?.afterFocus?.(false); } - export let ActiveRecordings: { props: FieldViewProps; getAnchor: () => Doc }[] = []; + export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = []; export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) { broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1)); return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); - const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor() || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); + const link = sourceDoc && DocUtils.MakeLink({ doc: sourceDoc }, { doc: audio.getAnchor(true) || audio.props.Document }, 'recording annotation:linked recording', 'recording timeline'); link && (link.followLinkLocation = OpenWhere.addRight); return link; }); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d0690fa10..a56f87075 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -251,8 +251,8 @@ export namespace DragManager { } // drags a linker button and creates a link on drop - export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | (() => Doc), downX: number, downY: number, options?: DragOptions) { - StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.() ?? sourceView.rootDoc), downX, downY, options); + export function StartLinkDrag(ele: HTMLElement, sourceView: DocumentView, sourceDocGetAnchor: undefined | ((addAsAnnotation: boolean) => Doc), downX: number, downY: number, options?: DragOptions) { + StartDrag([ele], new DragManager.LinkDragData(sourceView, () => sourceDocGetAnchor?.(true) ?? sourceView.rootDoc), downX, downY, options); } // drags a column from a schema view diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 0f216e349..5bdfca54a 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -111,15 +111,9 @@ export class LinkFollower { easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, effect: sourceDoc, originatingDoc: sourceDoc, - zoomTextSelections: false, + zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), }; - if (target.TourMap) { - const fieldKey = Doc.LayoutFieldKey(target); - const tour = DocListCast(target[fieldKey]).reverse(); - LightboxView.SetLightboxDoc(currentContext, undefined, tour); - setTimeout(LightboxView.Next); - allFinished(); - } else if (target.type === DocumentType.PRES) { + if (target.type === DocumentType.PRES) { const containerAnnoDoc = Cast(sourceDoc, Doc, null); const containerDoc = containerAnnoDoc || sourceDoc; var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index c9c09b63b..78ab2b3d4 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -130,6 +130,13 @@ export function ViewBoxAnnotatableComponent

() isAnyChildContentActive = () => this._isAnyChildContentActive; + isContentActive = (outsideReaction?: boolean) => + this.props.isContentActive?.() === false + ? false + : Doc.ActiveTool !== InkTool.None || this.props.isContentActive?.() || this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.rootSelected(outsideReaction) || this.isAnyChildContentActive() + ? true + : undefined; + lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result; protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 90c6c040c..f06dc93e3 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -501,7 +501,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV key="popup" showPopup={this._showLinkPopup} linkCreated={link => (link.linkDisplay = !this.props.views().lastElement()?.rootDoc.isLinkButton)} - linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.()} + linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)} linkFrom={() => this.props.views().lastElement()?.rootDoc} />

diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index a6fa2f04b..319a9419e 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -78,8 +78,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { // 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 = () => { - return this._subContentView?.getAnchor?.() || this.rootDoc; + getAnchor = (addAsAnnotation: boolean) => { + return this._subContentView?.getAnchor?.(addAsAnnotation) || this.rootDoc; }; scrollFocus = (textAnchor: Doc, options: DocFocusOptions) => { diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index d79b696a3..3627aa783 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -37,7 +37,6 @@ export class LightboxView extends React.Component { @observable private static _doc: Opt; @observable private static _docTarget: Opt; @observable private static _docFilters: string[] = []; // filters - @observable private static _tourMap: Opt = []; // list of all tours available from the current target private static _savedState: Opt<{ panX: Opt; panY: Opt; scale: Opt; scrollTop: Opt }>; private static _history: Opt<{ doc: Doc; target?: Doc }[]> = []; @observable private static _future: Opt = []; @@ -90,13 +89,6 @@ export class LightboxView extends React.Component { this._doc = doc; this._layoutTemplate = layoutTemplate; this._docTarget = target || doc; - this._tourMap = DocListCast(doc?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, doc!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); return true; } @@ -164,7 +156,7 @@ export class LightboxView extends React.Component { const target = (LightboxView._docTarget = this._future?.pop()); const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target); if (targetDocView && target) { - const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.() || target).lastElement(); + const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen'); targetDocView.focus(target, { originalTarget: target, willPanZoom: true, zoomScale: 0.9 }); if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target }); @@ -189,13 +181,6 @@ export class LightboxView extends React.Component { LightboxView.SetLightboxDoc(target); } } - LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); } @action public static Previous() { @@ -214,13 +199,6 @@ export class LightboxView extends React.Component { LightboxView.SetLightboxDoc(doc, target); } if (LightboxView._future?.lastElement() !== previous.target || previous.doc) LightboxView._future?.push(previous.target || previous.doc); - LightboxView._tourMap = DocListCast(LightboxView._docTarget?.links) - .map(link => { - const opp = LinkManager.getOppositeAnchor(link, LightboxView._docTarget!); - return opp?.TourMap ? opp : undefined; - }) - .filter(m => m) - .map(m => m!); } @action stepInto = () => { @@ -231,27 +209,20 @@ export class LightboxView extends React.Component { history: LightboxView._history, saved: LightboxView._savedState, }); - const tours = LightboxView._tourMap; - if (tours && tours.length) { - const fieldKey = Doc.LayoutFieldKey(tours[0]); - LightboxView._future?.push(...DocListCast(tours[0][fieldKey]).reverse()); - } else { - const coll = LightboxView._docTarget; - if (coll) { - const fieldKey = Doc.LayoutFieldKey(coll); - const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; - const links = DocListCast(coll.links) - .map(link => LinkManager.getOppositeAnchor(link, coll)) - .filter(doc => doc) - .map(doc => doc!); - LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links); - TabDocView.PinDoc(coll, { hidePresBox: true }); - } + const coll = LightboxView._docTarget; + if (coll) { + const fieldKey = Doc.LayoutFieldKey(coll); + const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; + const links = DocListCast(coll.links) + .map(link => LinkManager.getOppositeAnchor(link, coll)) + .filter(doc => doc) + .map(doc => doc!); + LightboxView.SetLightboxDoc(coll, undefined, contents.length ? contents : links); + TabDocView.PinDoc(coll, { hidePresBox: true }); } }; future = () => LightboxView._future; - tourMap = () => LightboxView._tourMap; render() { let downx = 0, downy = 0; @@ -345,7 +316,7 @@ export class LightboxView extends React.Component { }, this.future()?.length.toString() )} - +
{ } interface LightboxTourBtnProps { navBtn: (left: Opt, bottom: Opt, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => JSX.Element; - tourMap: () => Opt; future: () => Opt; stepInto: () => void; } @@ -410,7 +380,7 @@ export class LightboxTourBtn extends React.Component { e.stopPropagation(); this.props.stepInto(); }, - StrCast(this.props.tourMap()?.lastElement()?.TourMap) + '' ); } } diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index bf1242346..b1965c5c8 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -52,8 +52,8 @@ export class MarqueeAnnotator extends React.Component { AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true)); AnchorMenu.Instance.OnAudio = unimplementedFunction; AnchorMenu.Instance.Highlight = this.highlight; - AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations); - AnchorMenu.Instance.onMakeAnchor = AnchorMenu.Instance.GetAnchor; + AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations, addAsAnnotation); + AnchorMenu.Instance.onMakeAnchor = () => AnchorMenu.Instance.GetAnchor(undefined, true); } @action @@ -194,11 +194,11 @@ export class MarqueeAnnotator extends React.Component { return textRegionAnno; }; @action - highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap) => { + highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => { // creates annotation documents for current highlights const effectiveAcl = GetEffectiveAcl(this.props.rootDoc[DataSym]); const annotationDoc = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color, isLinkButton, savedAnnotations); - !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc); + addAsAnnotation && !savedAnnotations && annotationDoc && this.props.addDocument(annotationDoc); return (annotationDoc as Doc) ?? undefined; }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 8d495d286..af50478b0 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1679,6 +1679,16 @@ export class PropertiesView extends React.Component {
+
+

Zoom Text Selections

+ +

Toggle Target (Show/Hide)

, - {'toggle pushpin behavior'}
}> -
}> + , diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 7069ff399..d8e44ae9d 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -55,9 +55,9 @@ class RegionAnnotation extends React.Component { pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); @undoBatch - makePushpin = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); + makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); - isPushpin = () => BoolCast(this.annoTextRegion.followLinkToggle); + isTargetToggler = () => BoolCast(this.annoTextRegion.followLinkToggle); @action onPointerDown = (e: React.PointerEvent) => { @@ -67,8 +67,8 @@ class RegionAnnotation extends React.Component { AnchorMenu.Instance.Pinned = false; AnchorMenu.Instance.AddTag = this.addTag.bind(this); AnchorMenu.Instance.PinToPres = this.pinToPres; - AnchorMenu.Instance.MakePushpin = this.makePushpin; - AnchorMenu.Instance.IsPushpin = this.isPushpin; + AnchorMenu.Instance.MakeTargetToggle = this.makeTargretToggle; + AnchorMenu.Instance.IsTargetToggler = this.isTargetToggler; AnchorMenu.Instance.jumpTo(e.clientX, e.clientY, true); e.stopPropagation(); } else if (e.button === 0) { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f95d5ac2e..b0b7816b8 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -135,7 +135,7 @@ export class PDFViewer extends React.Component { copy = (e: ClipboardEvent) => { if (this.props.isContentActive() && e.clipboardData) { e.clipboardData.setData('text/plain', this._selectionText); - const anchor = this._getAnchor(); + const anchor = this._getAnchor(undefined, false); if (anchor) { anchor.textCopied = true; e.clipboardData.setData('dash/pdfAnchor', anchor[Id]); @@ -317,7 +317,7 @@ export class PDFViewer extends React.Component { 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!()!, false); + DocUtils.MakeLinkToActiveAudio(() => this.props.DocumentView?.().ComponentView?.getAnchor!(true)!, false); this._scrollTimer = undefined; }, 200); } -- cgit v1.2.3-70-g09d2 From 1763ff090ea734ca275c3c28edc6c303c935b801 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 25 Jan 2023 12:59:50 -0500 Subject: added a linkFollow o[ption to choose between opening target, or highest level collection containing target. fixed adding marker annotations to pdf/web/etc. fixed following link to wikipedia pages to not create a new document each time. made searchBox's search function static so that it can be called programmatically. Fixed LinkDocPreview to not flicker when doing a nopreview link follow. changed PlayTrail to restore state of all freeform collections containing source anchor. --- src/client/util/DocumentManager.ts | 9 ++- src/client/util/LinkFollower.ts | 23 ++---- src/client/views/MainView.tsx | 6 +- src/client/views/PropertiesView.tsx | 12 ++- .../views/collections/CollectionDockingView.tsx | 9 ++- src/client/views/nodes/LinkDocPreview.tsx | 72 ++++++++++------- src/client/views/nodes/trails/PresBox.tsx | 16 ++-- src/client/views/pdf/AnchorMenu.tsx | 4 +- src/client/views/search/SearchBox.tsx | 27 ++++--- src/fields/Types.ts | 90 ++++++++++++---------- 10 files changed, 152 insertions(+), 116 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index aa09fb005..7c867d710 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -194,11 +194,16 @@ export class DocumentManager { return toReturn; } - static GetContextPath(doc: Opt) { + static GetContextPath(doc: Opt, includeExistingViews?: boolean) { if (!doc) return []; const srcContext = Cast(doc.context, Doc, null) ?? Cast(Cast(doc.annotationOn, Doc, null)?.context, Doc, null); var containerDocContext = srcContext ? [srcContext] : []; - while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && !DocumentManager.Instance.getDocumentView(containerDocContext[0])) { + while ( + containerDocContext.length && + containerDocContext[0]?.context && + DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && + (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0])) + ) { containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; } return containerDocContext; diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index 5bdfca54a..57618b53c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -100,7 +100,7 @@ export class LinkFollower { : linkDoc.anchor1 ) as Doc; if (target) { - const doFollow = async (canToggle?: boolean) => { + const doFollow = (canToggle?: boolean) => { const options: DocFocusOptions = { playAudio: BoolCast(sourceDoc.followLinkAudio), toggleTarget: canToggle && BoolCast(sourceDoc.followLinkToggle), @@ -114,27 +114,14 @@ export class LinkFollower { zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), }; if (target.type === DocumentType.PRES) { - const containerAnnoDoc = Cast(sourceDoc, Doc, null); - const containerDoc = containerAnnoDoc || sourceDoc; - var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]); - while (containerDocContext.length && containerDocContext[0]?.context && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking) { - containerDocContext = [Cast(await containerDocContext[0].context, Doc, null), ...containerDocContext]; - } - if (!DocumentManager.Instance.getDocumentView(containerDocContext[0])) { - CollectionDockingView.AddSplit(containerDocContext[0], OpenWhereMod.right); - } + const containerDocContext = DocumentManager.GetContextPath(sourceDoc, true); // gather all views that affect layout of sourceDoc so we can revert them after playing the rail SelectionManager.DeselectAll(); - DocumentManager.Instance.AddViewRenderedCb(target, dv => containerDocContext.length && (dv.ComponentView as PresBox).PlayTrail(containerDocContext[0])); + DocumentManager.Instance.AddViewRenderedCb(target, dv => containerDocContext.length && (dv.ComponentView as PresBox).PlayTrail(containerDocContext)); PresBox.OpenPresMinimized(target, [0, 0]); finished?.(); } else { - const containerAnnoDoc = Cast(target.annotationOn, Doc, null); - const containerDoc = containerAnnoDoc || target; - var containerDocContext = containerDoc?.context ? [Cast(await containerDoc?.context, Doc, null)] : ([] as Doc[]); - while (containerDocContext.length && containerDocContext[0]?.context && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking) { - containerDocContext = [Cast(await containerDocContext[0].context, Doc, null), ...containerDocContext]; - } - const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]].filter(a => a) : containerDocContext; + const containerDocContext = DocumentManager.GetContextPath(target); + const targetContexts = !sourceDoc.followLinkToOuterContext && containerDocContext.length ? [containerDocContext.lastElement()] : containerDocContext; DocumentManager.Instance.jumpToDocument(target, options, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, OpenWhere.inPlace), finished), targetContexts, allFinished); } }; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 839db5795..895ed9bda 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -948,6 +948,10 @@ export class MainView extends React.Component { ); } + @computed get linkDocPreview() { + return LinkDocPreview.LinkInfo ? : null; + } + render() { return (
} {LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.LinkEditorDocView ? (DocumentLinksButton.LinkEditorDocView = undefined))} docView={DocumentLinksButton.LinkEditorDocView} /> : null} - {LinkDocPreview.LinkInfo ? : null} + {this.linkDocPreview} {((page: string) => { // prettier-ignore diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index af50478b0..411f51d84 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -1,6 +1,6 @@ import React = require('react'); import { IconLookup } from '@fortawesome/fontawesome-svg-core'; -import { faAnchor, faArrowRight } from '@fortawesome/free-solid-svg-icons'; +import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@material-ui/core'; import { intersection } from 'lodash'; @@ -1689,6 +1689,16 @@ export class PropertiesView extends React.Component {
+
+

Toggle Follow to Outer Context

+ +

Toggle Target (Show/Hide)

); @@ -163,7 +154,7 @@ export class DashboardView extends React.Component {
-
this.selectDashboardGroup(DashboardGroup.MyDashboards)}> My Dashboards @@ -196,7 +187,7 @@ export class DashboardView extends React.Component { e.stopPropagation(); this.onContextMenu(dashboard, e); }}> - } /> +
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 9fc1487a0..a59189fd2 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -52,7 +52,6 @@ export function DocComponent

() { interface ViewBoxBaseProps { Document: Doc; DataDoc?: Doc; - ContainingCollectionDoc: Opt; DocumentView?: () => DocumentView; fieldKey: string; isSelected: (outsideReaction?: boolean) => boolean; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9ffbe083f..9a4aaf00e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -33,6 +33,7 @@ import { ImageBox } from './nodes/ImageBox'; import React = require('react'); import { RichTextField } from '../../fields/RichTextField'; import { LinkFollower } from '../util/LinkFollower'; +import _ = require('lodash'); @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -303,8 +304,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P SelectionManager.DeselectAll(); }; - onSelectorClick = () => SelectionManager.Views()?.[0]?.props.ContainingCollectionView?.props.select(false); - + onSelectorClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false); /** * Handles setting up events when user clicks on the border radius editor * @param e PointerEvent @@ -744,7 +744,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P seldocview.props.hideDeleteButton || seldocview.rootDoc.hideDeleteButton || SelectionManager.Views().some(docView => { - const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; + const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit; return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin); }); @@ -865,7 +865,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P

e.preventDefault()} />
e.preventDefault()} /> - {seldocview.props.renderDepth <= 1 || !seldocview.props.ContainingCollectionView ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')} + {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')} )} {useRounding && ( diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 0feccb742..13faae783 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -1010,14 +1010,12 @@ export class GestureOverlay extends Touchable { renderDepth={0} styleProvider={returnEmptyString} docViewPath={returnEmptyDoclist} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docRangeFilters={returnEmptyFilter} docFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} /> ); }; diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index e6df0801c..156825f41 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -373,10 +373,11 @@ 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.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + const containingDocView = inkView.props.CollectionFreeFormDocumentView?.().props.DocumentView?.(); containingCollection?.childDocs .filter(doc => doc.type === DocumentType.INK) .forEach(doc => { - const testInkView = DocumentManager.Instance.getDocumentView(doc, containingCollection?.props.CollectionView); + const testInkView = DocumentManager.Instance.getDocumentView(doc, containingDocView); const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []); if (snapped && snapped.distance < snapData.distance) { const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 976c8763e..69eec8456 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -266,8 +266,6 @@ export class LightboxView extends React.Component { docFilters={this.docFilters} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} addDocument={undefined} removeDocument={undefined} whenChildContentsActiveChanged={emptyFunction} @@ -275,7 +273,7 @@ export class LightboxView extends React.Component { pinToPres={TabDocView.PinDoc} bringToFront={emptyFunction} onBrowseClick={MainView.Instance.exploreMode} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 60459cf30..0384d925e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -595,14 +595,12 @@ export class MainView extends React.Component { PanelWidth={this.headerBarDocWidth} PanelHeight={this.headerBarDocHeight} renderDepth={0} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
); @@ -626,14 +624,12 @@ export class MainView extends React.Component { ScreenToLocalTransform={this._hideUI ? this.mainScreenToLocalXf : Transform.Identity} PanelWidth={this.mainDocViewWidth} PanelHeight={this.mainDocViewHeight} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} suppressSetHeight={true} renderDepth={this._hideUI ? 0 : -1} /> @@ -727,14 +723,12 @@ export class MainView extends React.Component { renderDepth={0} isContentActive={returnTrue} scriptContext={CollectionDockingView.Instance?.props.Document} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
{this.docButtons} @@ -758,7 +752,7 @@ export class MainView extends React.Component { PanelHeight={this.leftMenuHeight} renderDepth={0} docViewPath={returnEmptyDoclist} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} styleProvider={DefaultStyleProvider} isContentActive={returnTrue} whenChildContentsActiveChanged={emptyFunction} @@ -766,8 +760,6 @@ export class MainView extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} scriptContext={this} />
@@ -900,13 +892,11 @@ export class MainView extends React.Component { PanelWidth={this.leftMenuFlyoutWidth} PanelHeight={this.leftMenuFlyoutHeight} renderDepth={0} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} /> {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ?
{StrCast(this.userDoc?.presentationMode)}
: <>}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index ec22128d4..bdc48d03a 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable, trace } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; import * as React from 'react'; @@ -10,15 +10,13 @@ import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, retu import { DocUtils } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DragManager } from '../util/DragManager'; -import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { Transform } from '../util/Transform'; import { CollectionFreeFormLinksView } from './collections/collectionFreeForm/CollectionFreeFormLinksView'; import { LightboxView } from './LightboxView'; import { MainView } from './MainView'; import { DocumentView } from './nodes/DocumentView'; import './OverlayView.scss'; -import { ScriptingRepl } from './ScriptingRepl'; -import { DefaultStyleProvider, testDocProps } from './StyleProvider'; +import { DefaultStyleProvider } from './StyleProvider'; export type OverlayDisposer = () => void; @@ -223,7 +221,7 @@ export class OverlayView extends React.Component { isDocumentActive={returnTrue} isContentActive={returnTrue} whenChildContentsActiveChanged={emptyFunction} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} styleProvider={DefaultStyleProvider} docViewPath={returnEmptyDoclist} addDocTab={d.type === DocumentType.PRES ? MainView.addDocTabFunc : returnFalse} @@ -231,8 +229,6 @@ export class OverlayView extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
); diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx index 954529bc9..3ad28c418 100644 --- a/src/client/views/Palette.tsx +++ b/src/client/views/Palette.tsx @@ -1,12 +1,12 @@ -import { IReactionDisposer, observable, reaction } from "mobx"; -import { observer } from "mobx-react"; -import * as React from "react"; -import { Doc } from "../../fields/Doc"; -import { NumCast } from "../../fields/Types"; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from "../../Utils"; -import { Transform } from "../util/Transform"; -import { DocumentView } from "./nodes/DocumentView"; -import "./Palette.scss"; +import { IReactionDisposer, observable, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../fields/Doc'; +import { NumCast } from '../../fields/Types'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils'; +import { Transform } from '../util/Transform'; +import { DocumentView } from './nodes/DocumentView'; +import './Palette.scss'; export interface PaletteProps { x: number; @@ -23,20 +23,20 @@ export default class Palette extends React.Component { componentDidMount = () => { this._selectedDisposer = reaction( () => NumCast(this.props.thumbDoc.selectedIndex), - (i) => this._selectedIndex = i, + i => (this._selectedIndex = i), { fireImmediately: true } ); - } + }; componentWillUnmount = () => { this._selectedDisposer?.(); - } + }; render() { return (
-
+
{ docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} /> + />
); } -} \ No newline at end of file +} diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx index 2c7da5931..93eec61f3 100644 --- a/src/client/views/PropertiesDocContextSelector.tsx +++ b/src/client/views/PropertiesDocContextSelector.tsx @@ -22,9 +22,9 @@ export class PropertiesDocContextSelector extends React.Component alias.context && alias.context instanceof Doc && Cast(alias.context, Doc, null) !== targetContext).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set()); + const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set()); const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases)); const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); @@ -42,6 +42,7 @@ export class PropertiesDocContextSelector extends React.Component !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document)) .filter(doc => !Doc.IsSystem(doc)) + .filter(doc => doc !== targetContext) .map(doc => ({ col: doc, target })); } @@ -53,8 +54,21 @@ export class PropertiesDocContextSelector extends React.Component DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100); + //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere); + setTimeout( + () => + this.props.DocView && + DocFocusOrOpen( + Doc.GetProto(this.props.DocView.props.Document), + { + // + willZoomCentered: true, + openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere, + }, + col + ), + 100 + ); }; render() { diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index fbc7d7696..6582c3f2a 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -341,8 +341,6 @@ export class PropertiesView extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionDoc={undefined} - ContainingCollectionView={undefined} addDocument={returnFalse} moveDocument={undefined} removeDocument={returnFalse} diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index b950b4860..739d6d819 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -18,7 +18,7 @@ import { TreeSort } from './collections/TreeView'; import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { MainView } from './MainView'; -import { DocumentViewProps } from './nodes/DocumentView'; +import { DocumentViewProps, OpenWhere } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { SliderBox } from './nodes/SliderBox'; @@ -295,7 +295,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt { - if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) { + if (props?.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform) { return doc?.pointerEvents !== 'none' ? null : (
toggleLockedPosition(doc)}> @@ -383,10 +383,7 @@ export function DashboardStyleProvider(doc: Opt, props: Opt {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => { - doc.hidden = doc.hidden ? undefined : true; - if (!doc.hidden) { - DocFocusOrOpen(doc, props?.ContainingCollectionDoc); - } + DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc); })} ); diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 45db240a9..c5a501aa6 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -114,8 +114,6 @@ export class TemplateMenu extends React.Component { { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
); @@ -642,8 +640,8 @@ export class CollectionViewBaseChrome extends React.Component this.props.docView.props.CollectionFreeFormDocumentView?.().float())}> diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index aec0734b4..80e81bc1c 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -255,8 +255,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { hideTitle={this.props.childHideTitle?.()} docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} addDocument={this.props.addDocument} moveDocument={this.props.moveDocument} removeDocument={this.props.removeDocument} @@ -632,8 +630,6 @@ export class CollectionNoteTakingView extends CollectionSubView() { docFilters={this.props.docFilters} docRangeFilters={this.props.docRangeFilters} searchFilterDocs={this.props.searchFilterDocs} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
); diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index ba90ed8cd..fd9b0c0ce 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -30,7 +30,7 @@ export class CollectionPileView extends CollectionSubView() { // pileups are designed to go away when they are empty. this._disposers.selected = reaction( () => this.childDocs.length, - num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document) + num => !num && this.props.CollectionFreeFormDocumentView?.().props.removeDocument?.(this.props.Document) ); } componentWillUnmount() { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index bbd81d06d..22a575989 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -815,8 +815,6 @@ class StackedTimelineAnchor extends React.Component whenChildContentsActiveChanged={emptyFunction} focus={focusFunc} isContentActive={returnFalse} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} searchFilterDocs={returnEmptyDoclist} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index a85ee0e02..67f5dc9f4 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -346,8 +346,6 @@ export class CollectionStackingView extends CollectionSubView
); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4a11e8f0b..92932fb61 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView 0) { FormattedTextBox.SelectOnLoad = prev[Id]; - DocumentManager.Instance.getDocumentView(prev, this.props.CollectionView)?.select(false); + DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false); } return true; } @@ -242,8 +242,6 @@ export class CollectionTreeView extends CollectionSubView
); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index bc25ad43a..53fbcc3cc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent +
{this.showIsTagged()} {this.renderSubView(this.collectionViewType, props)}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 458712999..ef8f395c5 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -425,8 +425,6 @@ export class TabDocView extends React.Component { hideTitle={this.props.keyValue} Document={this._document} DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} onBrowseClick={MainView.Instance.exploreMode} waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick} isContentActive={returnTrue} @@ -580,8 +578,6 @@ export class TabMinimapView extends React.Component { { ScreenToLocalTransform={Transform.Identity} renderDepth={0} whenChildContentsActiveChanged={emptyFunction} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} styleProvider={TabMinimapView.miniStyleProvider} addDocTab={this.props.addDocTab} pinToPres={TabDocView.PinDoc} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 75e76019e..8b1dfc767 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -42,7 +42,7 @@ export interface TreeViewProps { prevSibling?: Doc; document: Doc; dataDoc?: Doc; - containerCollection: Doc; + treeViewParent: Doc; renderDepth: number; dropAction: dropActionType; addDocTab: (doc: Doc, where: OpenWhere) => boolean; @@ -143,7 +143,7 @@ export class TreeView extends React.Component { return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView; } @computed get MAX_EMBED_HEIGHT() { - return NumCast(this.props.containerCollection.maxEmbedHeight, 200); + return NumCast(this.props.treeViewParent.maxEmbedHeight, 200); } @computed get dataDoc() { return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym]; @@ -194,7 +194,7 @@ export class TreeView extends React.Component { const ind = this.dataDoc[key].indexOf(doc); const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true); - res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false); + res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.DocumentView?.())?.select(false); return res; }; @@ -385,7 +385,7 @@ export class TreeView extends React.Component { }; const addDoc = inside ? localAdd : parentAddDoc; const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument; - const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes('add')) || forceAdd; + const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd; if (canAdd) { this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true); const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false)); @@ -406,7 +406,7 @@ export class TreeView extends React.Component { getTransform = () => this.refTransform(this._tref.current); embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1); embeddedPanelHeight = () => { - const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; + const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc; return Math.min( layoutDoc[HeightSym](), this.MAX_EMBED_HEIGHT, @@ -416,7 +416,7 @@ export class TreeView extends React.Component { return layoutDoc._fitWidth ? !Doc.NativeHeight(layoutDoc) ? NumCast(layoutDoc._height) - : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height))) + : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height))) : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym](); })() ); @@ -452,7 +452,7 @@ export class TreeView extends React.Component { this, doc, undefined, - this.props.containerCollection, + this.props.treeViewParent, this.props.prevSibling, addDoc, remDoc, @@ -596,7 +596,7 @@ export class TreeView extends React.Component { this, this.layoutDoc, this.dataDoc, - this.props.containerCollection, + this.props.treeViewParent, this.props.prevSibling, addDoc, remDoc, @@ -656,7 +656,7 @@ export class TreeView extends React.Component { this.onCheckedClick?.script.run( { this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc, - heading: this.props.containerCollection.title, + heading: this.props.treeViewParent.title, checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check', containingTreeView: this.props.treeView.props.Document, }, @@ -724,9 +724,11 @@ export class TreeView extends React.Component { }; @observable headerEleWidth = 0; - @computed get headerElements() { + @computed get titleButtons() { + const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations); return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : ( <> + {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */} {this.doc.hideContextMenu ? null : ( { return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label })); }; - onChildClick = () => { - return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); - }; + onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!); onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null); @@ -906,7 +906,7 @@ export class TreeView extends React.Component { styleProvider={this.titleStyleProvider} enableDragWhenActive={true} onClickScriptDisable="never" // tree docViews have a script to show fields, etc. - docViewPath={returnEmptyDoclist} + docViewPath={this.props.treeView.props.docViewPath} treeViewDoc={this.props.treeView.props.Document} addDocument={undefined} addDocTab={this.props.addDocTab} @@ -937,12 +937,8 @@ export class TreeView extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={this.props.treeView.props.CollectionView} - ContainingCollectionDoc={this.props.treeView.props.Document} /> ); - - const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ':afterHeader' : '')); return ( <>
{ {view}
r && (this.headerEleWidth = r.getBoundingClientRect().width))}> - {buttons} {/* hide and lock buttons */} - {this.headerElements} + {this.titleButtons}
); @@ -1017,8 +1012,6 @@ export class TreeView extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionDoc={this.props.containerCollection} - ContainingCollectionView={undefined} addDocument={this.props.addDocument} moveDocument={this.move} removeDocument={this.props.removeDoc} @@ -1131,7 +1124,7 @@ export class TreeView extends React.Component { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - containerCollection: Doc, + treeViewParent: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -1162,19 +1155,19 @@ export class TreeView extends React.Component { hierarchyIndex?: number[], renderCount?: number ) { - const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField); + const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None)); + const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None)); const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1); const treeViewRefs = new Map(); return docs .filter(child => child instanceof Doc) .map((child, i) => { if (renderCount && i > renderCount) return null; - const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return null; } @@ -1192,10 +1185,7 @@ export class TreeView extends React.Component { } }; const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); - const outdent = - parentCollectionDoc?._viewType !== CollectionViewType.Tree - ? undefined - : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined); + const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined); const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false); const childLayout = Doc.Layout(pair.layout); const rowHeight = () => { @@ -1208,7 +1198,7 @@ export class TreeView extends React.Component { ref={r => treeViewRefs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - containerCollection={containerCollection} + treeViewParent={treeViewParent} prevSibling={docs[i]} // TODO: [AL] add these hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined} @@ -1220,7 +1210,7 @@ export class TreeView extends React.Component { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(containerCollection.freezeChildren).includes('remove') ? undefined : remove} + removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7ae7be3c8..a3f5e73fb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -262,7 +262,7 @@ export class CollectionFreeFormView extends CollectionSubView { SelectionManager.DeselectAll(); - docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true)); + docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())).map(dv => dv && SelectionManager.SelectView(dv, true)); }; addDocument = (newBox: Doc | Doc[]) => { let retVal = false; @@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView 1 ? NumCast(refDoc.y) - (NumCast(sorted[0].layout.y) + (topIndexed ? 0 : NumCast(sorted[0].layout._height))) : 0; const deltax = sorted.length > 1 ? NumCast(refDoc.x) - NumCast(sorted[0].layout.x) : 0; let lastx = NumCast(refDoc.x); let lasty = NumCast(refDoc.y) + (topIndexed ? 0 : NumCast(refDoc._height)); - setTimeout( - action(() => - sorted.slice(1).forEach((pair, i) => { - lastx = pair.layout.x = lastx + deltax; - lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height)); - }) - ) + runInAction(() => + sorted.slice(1).forEach((pair, i) => { + lastx = pair.layout.x = lastx + deltax; + lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height)); + }) ); } } @@ -464,7 +462,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster); - const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!); + const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!); const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined); de.moveDocument = this.props.moveDocument; @@ -872,7 +870,7 @@ export class CollectionFreeFormView extends CollectionSubView DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)) + .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())) .filter(inkView => inkView?.ComponentView instanceof InkingStroke) .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! })) .filter( @@ -966,7 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView doc.type === DocumentType.INK && !doc.dontIntersect) .forEach(doc => { - const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke; + const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.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)); @@ -1121,7 +1119,8 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) { + const collectionDoc = this.props.docViewPath().lastElement().rootDoc; + if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) { 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 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), @@ -1256,8 +1255,6 @@ export class CollectionFreeFormView extends CollectionSubView
@@ -251,8 +249,7 @@ export class CollectionLinearView extends CollectionSubView() { self: this.rootDoc, _readOnly_: false, scriptContext: this.props.scriptContext, - thisContainer: this.props.ContainingCollectionDoc, - documentView: this.props.docViewPath().lastElement(), + documentView: this.props.DocumentView?.(), }); this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked; })} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index b73b1d779..78d3d1b6e 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -262,8 +262,6 @@ export class CollectionMulticolumnView extends CollectionSubView() { docFilters={this.childDocFilters} docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} dontRegisterView={this.props.dontRegisterView} addDocument={this.props.addDocument} moveDocument={this.props.moveDocument} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 0cca83803..4d61dc272 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -261,8 +261,6 @@ export class CollectionMultirowView extends CollectionSubView() { docFilters={this.childDocFilters} docRangeFilters={this.childDocRangeFilters} searchFilterDocs={this.searchFilterDocs} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} dontRegisterView={this.props.dontRegisterView} addDocument={this.props.addDocument} moveDocument={this.props.moveDocument} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index fd9bcf681..6d5a73e55 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -793,7 +793,7 @@ export class CollectionSchemaView extends CollectionSubView() { fitContentsToBox={returnTrue} dontCenter={'y'} onClickScriptDisable="always" - focus={DocUtils.DefaultFocus} + focus={emptyFunction} renderDepth={this.props.renderDepth + 1} rootSelected={this.rootSelected} PanelWidth={this.previewWidthFunc} @@ -806,8 +806,6 @@ export class CollectionSchemaView extends CollectionSubView() { searchFilterDocs={this.searchFilterDocs} styleProvider={DefaultStyleProvider} docViewPath={returnEmptyDoclist} - ContainingCollectionDoc={this.props.CollectionView?.props.Document} - ContainingCollectionView={this.props.CollectionView} moveDocument={this.props.moveDocument} addDocument={this.addRow} removeDocument={this.props.removeDocument} @@ -849,8 +847,6 @@ class CollectionSchemaViewDocs extends React.Component() { } @computed get schemaDoc() { - return this.props.ContainingCollectionDoc!; + return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc; } @computed get rowIndex() { diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 13e45963e..5f8ffe8b0 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -28,8 +28,6 @@ export class SchemaTableCell extends React.Component { searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, docViewPath: returnEmptyDoclist, - ContainingCollectionView: undefined, - ContainingCollectionDoc: undefined, fieldKey: this.props.fieldKey, rootSelected: returnFalse, isSelected: returnFalse, diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 29e7cd3ad..d703c9595 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -44,25 +44,10 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume } const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs); - dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => { - docView.props.removeDocument?.(doc); - addDocument(doc); - return true; - }; - const containingView = docView.props.ContainingCollectionView; - const finishDrag = (e: DragManager.DragCompleteEvent) => - e.docDragData && - (e.docDragData.droppedDocuments = dragData.draggedDocuments.reduce((droppedDocs, d) => { - const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView); - if (dvs.length) { - dvs.forEach(dv => droppedDocs.push(dv.props.Document)); - } else { - droppedDocs.push(Doc.MakeAlias(d)); - } - return droppedDocs; - }, [] as Doc[])); + dragData.canEmbed = true; + dragData.moveDocument = (docView.props.docViewPath().lastElement()?.ComponentView as any)?.props.CollectionView?.moveDocument; // this is equal to docView.props.moveDocument, but moveDocument is not a defined prop of a DocumentView .. but maybe it should be? - DragManager.StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag); + DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined); } } diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 7bdace2b6..5f2d4a7b6 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -85,15 +85,13 @@ export class LinkPopup extends React.Component { PanelWidth={this.getPWidth} PanelHeight={this.getPHeight} renderDepth={0} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 9bdb2cee7..24b9f3b25 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -160,8 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent { - const { Document: topDoc, ContainingCollectionView: container } = this.props; - const screenXf = container?.screenToLocalTransform(); + const topDoc = this.rootDoc; + const containerDocView = this.props.docViewPath().lastElement(); + const screenXf = containerDocView?.screenToLocalTransform(); if (screenXf) { SelectionManager.DeselectAll(); if (topDoc.z) { @@ -178,7 +179,7 @@ export class CollectionFreeFormDocumentView extends DocComponent SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0); + setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, containerDocView), false), 0); } }; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index dbcfe43cf..76a5ce7b3 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -154,7 +154,6 @@ export class DocumentContentsView extends React.Component< // these are the properties in DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews 'hideResizeHandles', 'hideTitle', - 'treeViewDoc', 'contentPointerEvents', 'radialMenu', 'LayoutTemplateString', diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index df3299eef..47705d53d 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component undefined | { x: number; y: number; r: number; b: number }; fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document - ContainingCollectionView: Opt; - ContainingCollectionDoc: Opt; suppressSetHeight?: boolean; thumbShown?: () => boolean; setContentView?: (view: DocComponentView) => any; @@ -179,6 +177,7 @@ export interface DocumentViewSharedProps { ScreenToLocalTransform: () => Transform; bringToFront: (doc: Doc, sendToBack?: boolean) => void; canEmbedOnDrag?: boolean; + treeViewDoc?: Doc; xPadding?: number; yPadding?: number; dropAction?: dropActionType; @@ -210,7 +209,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps { hideOpenButton?: boolean; hideDeleteButton?: boolean; hideLinkAnchors?: boolean; - treeViewDoc?: Doc; isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events isContentActive: () => boolean | undefined; // whether document contents should handle pointer events contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents @@ -429,7 +427,6 @@ export class DocumentViewInternal extends DocComponent this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); - if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) { + if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) { const existingOnClick = cm.findByDescription('OnClick...'); const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; @@ -1446,7 +1442,7 @@ export class DocumentView extends React.Component { scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction); - select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection); + select = (extendSelection: boolean) => SelectionManager.SelectView(this, extendSelection); NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 8d3534a5c..86779e0dd 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -32,6 +32,7 @@ export interface FieldViewProps extends DocumentViewSharedProps { // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields // Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields backgroundColor?: string; + treeViewDoc?: Doc; color?: string; fontSize?: number; height?: number; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 94434dce7..7ea6d42ff 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -61,8 +61,6 @@ export class KeyValuePair extends React.Component { searchFilterDocs: returnEmptyDoclist, styleProvider: DefaultStyleProvider, docViewPath: returnEmptyDoclist, - ContainingCollectionView: undefined, - ContainingCollectionDoc: undefined, fieldKey: this.props.keyName, rootSelected: returnFalse, isSelected: returnFalse, diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index fcc5b6975..c58b5dd8c 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -271,14 +271,12 @@ export class LinkDocPreview extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionDoc={undefined} - ContainingCollectionView={undefined} renderDepth={0} suppressSetHeight={true} PanelWidth={this.width} PanelHeight={this.height} pointerEvents={returnNone} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={returnFalse} ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size. bringToFront={returnFalse} diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index db11a7776..e015024fd 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -305,8 +305,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent + renderDepth={this.props.renderDepth + 1}> <> {this.threed} {this.content} @@ -330,7 +329,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent + /> )}
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index 8eacfbc51..1a75a7e76 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -568,12 +568,12 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b if (selectedViews.length) { if (checkResult) { const selView = selectedViews.lastElement(); - const layoutFrameNumber = Cast(selView.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values const contentFrameNumber = Cast(selView.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed return CollectionFreeFormDocumentView.getStringValues(selView?.rootDoc, contentFrameNumber).backgroundColor ?? 'transparent'; } selectedViews.forEach(dv => { - const layoutFrameNumber = Cast(dv.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed if (contentFrameNumber !== undefined) { CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { backgroundColor: color }); diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index c00ab6a7e..b31fc01ff 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -9,10 +9,9 @@ import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { ColorScheme } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; import React = require('react'); -import { SelectionManager } from '../../../util/SelectionManager'; export class DashDocView { dom: HTMLSpanElement; // container for label and value @@ -151,7 +150,7 @@ export class DashDocViewInternal extends React.Component { const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current); return new Transform(-translateX, -translateY, 1).scale(1 / scale); }; - outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document, {}); // ideally, this would scroll to show the focus target + outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target onKeyDown = (e: any) => { e.stopPropagation(); @@ -212,8 +211,6 @@ export class DashDocViewInternal extends React.Component { docFilters={this.props.tbox?.props.docFilters} docRangeFilters={this.props.tbox?.props.docRangeFilters} searchFilterDocs={this.props.tbox?.props.searchFilterDocs} - ContainingCollectionView={this._textBox.props.ContainingCollectionView} - ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc} />
); diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index f23426bb3..c43206629 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -235,10 +235,7 @@ export class DashFieldViewInternal extends React.Component { - let container = this.props.tbox.props.ContainingCollectionView; - while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) { - container = container.props.ContainingCollectionView; - } + let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement(); if (container) { const alias = Doc.MakeAlias(container.props.Document); alias._viewType = CollectionViewType.Time; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 677c4662b..bc2a5d797 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -541,7 +541,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor' }); + const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor', unrendered: true }); return this.addDocument(tanch) ? tanch : undefined; }; const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement(); @@ -956,7 +957,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { const examinedNode = findAnchorNode(node, editor); - if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) { + if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) { nodes.push(examinedNode.node); !hadStart && (start = index + examinedNode.start); hadStart = true; @@ -971,9 +972,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent mark.type === editor.state.schema.marks.linkAnchor); @@ -987,7 +994,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent 2 || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) { + if ((ret.frag.size || (content?.length && content[0].type === this._editorView.state.schema.nodes.dashDoc) || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) { !options.instant && (this._focusSpeed = focusSpeed); let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start if (ret.frag.firstChild) { @@ -998,6 +1005,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent (this._focusSpeed = undefined), this._focusSpeed); setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000)); + return focusSpeed; + } else { + return this.props.focus(this.rootDoc, options); } } }; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 3589a9065..807a19771 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -2457,7 +2457,6 @@ export class PresBox extends ViewBoxBaseComponent() { {mode !== CollectionViewType.Invalid ? ( () { // Idea: this boolean will determine whether to automatically show the video when this preselement is selected. // @observable static showVideo: boolean = false; @computed get indexInPres() { - return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc); + return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements) @computed get expandViewHeight() { return 100; @@ -51,11 +51,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { return this.presBoxView?.selectedArray; } @computed get presBoxView() { - const vpath = this.props.docViewPath(); - return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined; + return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox; } @computed get presBox() { - return this.props.ContainingCollectionDoc!; + return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc; } @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; @@ -110,14 +109,12 @@ export class PresElementBox extends ViewBoxBaseComponent() { docFilters={this.props.docFilters} docRangeFilters={this.props.docRangeFilters} searchFilterDocs={this.props.searchFilterDocs} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} rootSelected={returnTrue} addDocument={returnFalse} removeDocument={returnFalse} fitContentsToBox={returnTrue} moveDocument={this.props.moveDocument!} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} @@ -195,7 +192,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); dragData.dropAction = 'move'; - dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; + dragData.treeViewDoc = this.presBox?._viewType === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; dragData.moveDocument = this.props.moveDocument; const dragItem: HTMLElement[] = []; if (dragArray.length === 1) { @@ -269,7 +266,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { @undoBatch removeItem = action((e: React.MouseEvent) => { e.stopPropagation(); - if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) { + if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) { this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1; } this.props.removeDocument?.(this.rootDoc); @@ -406,15 +403,15 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get toolbarWidth(): number { const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox); - let width: number = NumCast(this.presBox._width); + let width: number = NumCast(this.presBox?._width); if (presBoxDocView) width = presBoxDocView.props.PanelWidth(); if (width === 0) width = 300; return width; } @computed get presButtons() { - const presBox: Doc = this.presBox; //presBox - const presBoxColor: string = StrCast(presBox._backgroundColor); + const presBox = this.presBox; //presBox + const presBoxColor: string = StrCast(presBox?._backgroundColor); const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; const targetDoc: Doc = this.targetDoc; const activeItem: Doc = this.rootDoc; @@ -494,10 +491,10 @@ export class PresElementBox extends ViewBoxBaseComponent() { @computed get mainItem() { const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false; - const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres; + const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres; const miniView: boolean = this.toolbarWidth <= 110; - const presBox: Doc = this.presBox; //presBox - const presBoxColor: string = StrCast(presBox._backgroundColor); + const presBox = this.presBox; //presBox + const presBoxColor: string = StrCast(presBox?._backgroundColor); const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; const activeItem: Doc = this.rootDoc; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index f2e9be61d..d63c25dbe 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -46,7 +46,7 @@ export class TopBar extends React.Component { return (
{Doc.ActiveDashboard ? ( - } isCircle={true} hoverStyle="gray" color={this.textColor} /> + } color={this.textColor} /> ) : (
dash logo @@ -55,18 +55,7 @@ export class TopBar extends React.Component {
)} {Doc.ActiveDashboard && ( -
); @@ -94,13 +83,8 @@ export class TopBar extends React.Component {
); diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx index 64baa351c..a0b437354 100644 --- a/src/mobile/AudioUpload.tsx +++ b/src/mobile/AudioUpload.tsx @@ -13,13 +13,18 @@ import { listSpec } from '../fields/Schema'; import { Cast, FieldValue } from '../fields/Types'; import { nullAudio } from '../fields/URLField'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyPath } from '../Utils'; -import "./ImageUpload.scss"; +import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; import React = require('react'); @observer export class AudioUpload extends React.Component { - @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc; + @observable public _audioCol: Doc = FieldValue( + Cast( + Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }), + Doc + ) + ) as Doc; /** * Handles the onclick functionality for the 'Restart' button @@ -28,25 +33,36 @@ export class AudioUpload extends React.Component { @action clearUpload = () => { for (let i = 1; i < 8; i++) { - this.setOpacity(i, "0.2"); + this.setOpacity(i, '0.2'); } - this._audioCol = FieldValue(Cast( - Docs.Create.FreeformDocument( - [Cast(Docs.Create.AudioDocument(nullAudio, { - title: "mobile audio", - _width: 500, - _height: 100 - }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc; - } + this._audioCol = FieldValue( + Cast( + Docs.Create.FreeformDocument( + [ + Cast( + Docs.Create.AudioDocument(nullAudio, { + title: 'mobile audio', + _width: 500, + _height: 100, + }), + Doc + ) as Doc, + ], + { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' } + ), + Doc + ) + ) as Doc; + }; - /** + /** * Handles the onClick of the 'Close' button * Reset upload interface and toggle audio */ closeUpload = () => { this.clearUpload(); MobileInterface.Instance.toggleAudio(); - } + }; /** * Handles the on click of the 'Upload' button. @@ -57,14 +73,14 @@ export class AudioUpload extends React.Component { const audioDoc = this._audioCol; const data = Cast(audioRightSidebar.data, listSpec(Doc)); for (let i = 1; i < 8; i++) { - setTimeout(() => this.setOpacity(i, "1"), i * 200); + setTimeout(() => this.setOpacity(i, '1'), i * 200); } if (data) { data.push(audioDoc); } // Resets uploader after 3 seconds setTimeout(this.clearUpload, 3000); - } + }; // Returns the upload audio menu private get uploadInterface() { @@ -72,11 +88,13 @@ export class AudioUpload extends React.Component { <> -
+
+ +
this.closeUpload()}> - +
- +
"rgba(0,0,0,0)"} + styleProvider={() => 'rgba(0,0,0,0)'} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} bringToFront={emptyFunction} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
@@ -125,28 +141,16 @@ export class AudioUpload extends React.Component { // Handles the setting of the loading bar setOpacity = (index: number, opacity: string) => { - const slab = document.getElementById("slab0" + index); + const slab = document.getElementById('slab0' + index); if (slab) { slab.style.opacity = opacity; } - } + }; @observable private dialogueBoxOpacity = 1; @observable private overlayOpacity = 0.4; render() { - return ( - - ); + return ; } - } - - diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 2ae597b0b..a543c2f70 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -397,7 +397,7 @@ export class MobileInterface extends React.Component { renderDepth={0} isDocumentActive={returnTrue} isContentActive={emptyFunction} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} styleProvider={this.whitebackground} docViewPath={returnEmptyDoclist} whenChildContentsActiveChanged={emptyFunction} @@ -405,8 +405,6 @@ export class MobileInterface extends React.Component { docFilters={returnEmptyFilter} docRangeFilters={returnEmptyFilter} searchFilterDocs={returnEmptyDoclist} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />
); -- cgit v1.2.3-70-g09d2 From 42afc0250de658fc3e924864bfae5afb4edec335 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 14 May 2023 12:03:40 -0400 Subject: major overhaul of field naming conventions. --- .../apis/google_docs/GooglePhotosClientUtils.ts | 88 +++--- src/client/documents/DocumentTypes.ts | 2 +- src/client/documents/Documents.ts | 324 ++++++++++----------- src/client/documents/Gitlike.ts | 26 +- src/client/util/CaptureManager.tsx | 2 +- src/client/util/CurrentUserUtils.ts | 179 ++++++------ src/client/util/DictationManager.ts | 2 +- src/client/util/DocumentManager.ts | 22 +- src/client/util/DragManager.ts | 12 +- src/client/util/DropConverter.ts | 4 +- src/client/util/GroupManager.tsx | 8 +- src/client/util/HypothesisUtils.ts | 2 +- src/client/util/Import & Export/ImageUtils.ts | 32 +- src/client/util/InteractionUtils.tsx | 1 + src/client/util/LinkFollower.ts | 34 +-- src/client/util/LinkManager.ts | 32 +- src/client/util/ReplayMovements.ts | 4 +- src/client/util/SearchUtil.ts | 94 +++--- src/client/util/SettingsManager.tsx | 4 +- src/client/util/SharingManager.tsx | 4 +- src/client/util/SnappingManager.ts | 4 +- src/client/util/TrackMovements.ts | 2 +- src/client/views/AudioWaveform.tsx | 124 ++++---- src/client/views/DashboardView.tsx | 18 +- src/client/views/DocComponent.tsx | 21 +- src/client/views/DocumentButtonBar.tsx | 22 +- src/client/views/DocumentDecorations.tsx | 70 ++--- src/client/views/FilterPanel.tsx | 6 +- src/client/views/GestureOverlay.tsx | 14 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/InkStrokeProperties.ts | 14 +- src/client/views/InkTranscription.tsx | 2 +- src/client/views/InkingStroke.tsx | 30 +- src/client/views/LightboxView.tsx | 44 +-- src/client/views/MainView.tsx | 32 +- src/client/views/MarqueeAnnotator.tsx | 12 +- src/client/views/PreviewCursor.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 36 +-- .../views/PropertiesDocBacklinksSelector.tsx | 2 +- src/client/views/PropertiesDocContextSelector.tsx | 10 +- src/client/views/PropertiesView.tsx | 78 ++--- src/client/views/SidebarAnnos.tsx | 20 +- src/client/views/StyleProvider.tsx | 38 +-- src/client/views/TemplateMenu.tsx | 4 +- src/client/views/animationtimeline/Timeline.tsx | 14 +- src/client/views/animationtimeline/Track.tsx | 261 +++++++++-------- .../views/collections/CollectionCarouselView.tsx | 14 +- .../views/collections/CollectionDockingView.tsx | 22 +- .../collections/CollectionMasonryViewFieldRow.tsx | 44 +-- src/client/views/collections/CollectionMenu.tsx | 85 +++--- .../views/collections/CollectionNoteTakingView.tsx | 78 ++--- .../collections/CollectionNoteTakingViewColumn.tsx | 23 +- .../views/collections/CollectionPileView.tsx | 6 +- .../collections/CollectionStackedTimeline.tsx | 39 +-- .../views/collections/CollectionStackingView.tsx | 82 +++--- .../CollectionStackingViewFieldColumn.tsx | 30 +- src/client/views/collections/CollectionSubView.tsx | 14 +- .../views/collections/CollectionTimeView.tsx | 8 +- .../views/collections/CollectionTreeView.tsx | 28 +- src/client/views/collections/CollectionView.tsx | 16 +- src/client/views/collections/TabDocView.tsx | 34 +-- src/client/views/collections/TreeView.tsx | 64 ++-- .../CollectionFreeFormLinkView.tsx | 62 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 186 ++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 32 +- .../collectionSchema/CollectionSchemaView.tsx | 34 +-- .../collections/collectionSchema/SchemaRowBox.tsx | 2 +- .../collectionSchema/SchemaTableCell.tsx | 4 +- src/client/views/linking/LinkMenuGroup.tsx | 21 +- src/client/views/linking/LinkMenuItem.tsx | 30 +- .../views/linking/LinkRelationshipSearch.tsx | 52 ++-- src/client/views/nodes/AudioBox.tsx | 37 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 16 +- src/client/views/nodes/ColorBox.tsx | 4 +- src/client/views/nodes/ComparisonBox.tsx | 28 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 18 +- .../nodes/DataVizBox/components/LineChart.tsx | 14 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 12 +- src/client/views/nodes/DocumentContentsView.tsx | 12 +- src/client/views/nodes/DocumentLinksButton.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 145 ++++----- src/client/views/nodes/EquationBox.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FunctionPlotBox.tsx | 2 +- src/client/views/nodes/ImageBox.tsx | 90 +++--- src/client/views/nodes/KeyValueBox.tsx | 32 +- src/client/views/nodes/KeyValuePair.scss | 4 + src/client/views/nodes/KeyValuePair.tsx | 6 +- src/client/views/nodes/LabelBox.tsx | 8 +- src/client/views/nodes/LinkAnchorBox.tsx | 16 +- src/client/views/nodes/LinkBox.tsx | 4 +- src/client/views/nodes/LinkDescriptionPopup.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 20 +- src/client/views/nodes/MapBox/MapBox.tsx | 42 +-- src/client/views/nodes/MapBox/MapBox2.tsx | 42 +-- src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 72 ++--- .../views/nodes/RecordingBox/RecordingBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 10 +- src/client/views/nodes/ScriptingBox.tsx | 10 +- src/client/views/nodes/VideoBox.tsx | 102 +++---- src/client/views/nodes/WebBox.tsx | 123 ++++---- src/client/views/nodes/button/FontIconBox.tsx | 245 ++++++++-------- .../views/nodes/formattedText/DashDocView.tsx | 45 +-- .../views/nodes/formattedText/DashFieldView.tsx | 13 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 223 +++++++------- .../views/nodes/formattedText/RichTextMenu.tsx | 14 +- .../views/nodes/formattedText/RichTextRules.ts | 28 +- src/client/views/nodes/formattedText/nodes_rts.ts | 2 +- src/client/views/nodes/trails/PresBox.tsx | 101 ++++--- src/client/views/nodes/trails/PresElementBox.tsx | 8 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 56 ++-- src/client/views/search/SearchBox.tsx | 44 +-- src/fields/Doc.ts | 117 ++++---- src/fields/RichTextUtils.ts | 6 +- src/fields/Types.ts | 5 +- src/fields/documentSchemas.ts | 52 ++-- src/fields/util.ts | 4 +- src/mobile/AudioUpload.tsx | 10 +- src/server/ApiManagers/SearchManager.ts | 151 +++++----- src/server/updateProtos.ts | 24 +- src/server/websocket.ts | 4 +- 123 files changed, 2424 insertions(+), 2391 deletions(-) (limited to 'src/client/views/nodes/LinkDocPreview.tsx') diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index ff9460b62..e8fd8fb8a 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -1,27 +1,26 @@ -import { AssertionError } from "assert"; -import { EditorState } from "prosemirror-state"; -import { Doc, DocListCastAsync, Opt } from "../../../fields/Doc"; -import { Id } from "../../../fields/FieldSymbols"; -import { RichTextField } from "../../../fields/RichTextField"; -import { RichTextUtils } from "../../../fields/RichTextUtils"; -import { Cast, StrCast } from "../../../fields/Types"; -import { ImageField } from "../../../fields/URLField"; -import { MediaItem, NewMediaItemResult } from "../../../server/apis/google/SharedTypes"; -import { Utils } from "../../../Utils"; -import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; -import { Networking } from "../../Network"; -import { FormattedTextBox } from "../../views/nodes/formattedText/FormattedTextBox"; -import { GoogleAuthenticationManager } from "../GoogleAuthenticationManager"; +import { AssertionError } from 'assert'; +import { EditorState } from 'prosemirror-state'; +import { Doc, DocListCastAsync, Opt } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { RichTextField } from '../../../fields/RichTextField'; +import { RichTextUtils } from '../../../fields/RichTextUtils'; +import { Cast, StrCast } from '../../../fields/Types'; +import { ImageField } from '../../../fields/URLField'; +import { MediaItem, NewMediaItemResult } from '../../../server/apis/google/SharedTypes'; +import { Utils } from '../../../Utils'; +import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents'; +import { Networking } from '../../Network'; +import { FormattedTextBox } from '../../views/nodes/formattedText/FormattedTextBox'; +import { GoogleAuthenticationManager } from '../GoogleAuthenticationManager'; import Photos = require('googlephotos'); export namespace GooglePhotos { - const endpoint = async () => new Photos(await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken()); export enum MediaType { ALL_MEDIA = 'ALL_MEDIA', PHOTO = 'PHOTO', - VIDEO = 'VIDEO' + VIDEO = 'VIDEO', } export type AlbumReference = { id: string } | { title: string }; @@ -58,11 +57,10 @@ export namespace GooglePhotos { HOUSES: 'HOUSES', GARDENS: 'GARDENS', FLOWERS: 'FLOWERS', - HOLIDAYS: 'HOLIDAYS' + HOLIDAYS: 'HOLIDAYS', }; export namespace Export { - export interface AlbumCreationResult { albumId: string; mediaItems: MediaItem[]; @@ -82,20 +80,20 @@ export namespace GooglePhotos { if (!images || !images.length) { return undefined; } - const resolved = title ? title : (StrCast(collection.title) || `Dash Collection (${collection[Id]}`); + const resolved = title ? title : StrCast(collection.title) || `Dash Collection (${collection[Id]}`; const { id, productUrl } = await Create.Album(resolved); const response = await Transactions.UploadImages(images, { id }, descriptionKey); if (response) { const { results, failed } = response; let index: Opt; while ((index = failed.pop()) !== undefined) { - Doc.RemoveDocFromList(dataDocument, "data", images.splice(index, 1)[0]); + Doc.RemoveDocFromList(dataDocument, 'data', images.splice(index, 1)[0]); } const mediaItems: MediaItem[] = results.map(item => item.mediaItem); if (mediaItems.length !== images.length) { throw new AssertionError({ actual: mediaItems.length, expected: images.length }); } - const idMapping = new Doc; + const idMapping = new Doc(); for (let i = 0; i < images.length; i++) { const image = Doc.GetProto(images[i]); const mediaItem = mediaItems[i]; @@ -117,38 +115,30 @@ export namespace GooglePhotos { return { albumId: id, mediaItems }; } }; - } export namespace Import { - export type CollectionConstructor = (data: Array, options: DocumentOptions, ...args: any) => Doc; export const CollectionFromSearch = async (constructor: CollectionConstructor, requested: Opt>): Promise => { await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(); const response = await Query.ContentSearch(requested); const uploads = await Transactions.WriteMediaItemsToServer(response); - const children = uploads.map((upload: Transactions.UploadInformation) => { - const document = Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean)); - document.contentSize = upload.contentSize; - return document; - }); + const children = uploads.map((upload: Transactions.UploadInformation) => Docs.Create.ImageDocument(Utils.fileUrl(upload.fileNames.clean) /*, {"data_contentSize":upload.contentSize}*/)); const options = { _width: 500, _height: 500 }; return constructor(children, options); }; - } export namespace Query { - - const delimiter = ", "; - const comparator = (a: string, b: string) => (a < b) ? -1 : (a > b ? 1 : 0); + const delimiter = ', '; + const comparator = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0); export const TagChildImages = async (collection: Doc) => { await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(); const idMapping = await Cast(collection.googlePhotosIdMapping, Doc); if (!idMapping) { - throw new Error("Appending image metadata requires that the targeted collection have already been mapped to an album!"); + throw new Error('Appending image metadata requires that the targeted collection have already been mapped to an album!'); } const tagMapping = new Map(); const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto); @@ -169,7 +159,7 @@ export namespace GooglePhotos { const concatenated = tagMapping.get(image[Id])!; const tags = concatenated.split(delimiter); if (tags.length > 1) { - const cleaned = concatenated.replace(ContentCategories.NONE + delimiter, ""); + const cleaned = concatenated.replace(ContentCategories.NONE + delimiter, ''); image.googlePhotosTags = cleaned.split(delimiter).sort(comparator).join(delimiter); } else { image.googlePhotosTags = ContentCategories.NONE; @@ -253,19 +243,15 @@ export namespace GooglePhotos { export const GetImage = async (mediaItemId: string): Promise => { return (await endpoint()).mediaItems.get(mediaItemId); }; - } namespace Create { - export const Album = async (title: string) => { return (await endpoint()).albums.create(title); }; - } export namespace Transactions { - export interface UploadInformation { mediaPaths: string[]; fileNames: { [key: string]: string }; @@ -295,18 +281,20 @@ export namespace GooglePhotos { }; export const WriteMediaItemsToServer = async (body: { mediaItems: any[] }): Promise => { - const uploads = await Networking.PostToServer("/googlePhotosMediaGet", body); + const uploads = await Networking.PostToServer('/googlePhotosMediaGet', body); return uploads; }; - export const UploadThenFetch = async (sources: Doc[], album?: AlbumReference, descriptionKey = "caption") => { + export const UploadThenFetch = async (sources: Doc[], album?: AlbumReference, descriptionKey = 'caption') => { const response = await UploadImages(sources, album, descriptionKey); if (!response) { return undefined; } - const baseUrls: string[] = await Promise.all(response.results.map(item => { - return new Promise(resolve => Query.GetImage(item.mediaItem.id).then(item => resolve(item.baseUrl))); - })); + const baseUrls: string[] = await Promise.all( + response.results.map(item => { + return new Promise(resolve => Query.GetImage(item.mediaItem.id).then(item => resolve(item.baseUrl))); + }) + ); return baseUrls; }; @@ -315,9 +303,9 @@ export namespace GooglePhotos { failed: number[]; } - export const UploadImages = async (sources: Doc[], album?: AlbumReference, descriptionKey = "caption"): Promise> => { + export const UploadImages = async (sources: Doc[], album?: AlbumReference, descriptionKey = 'caption'): Promise> => { await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(); - if (album && "title" in album) { + if (album && 'title' in album) { album = await Create.Album(album.title); } const media: MediaInput[] = []; @@ -327,13 +315,13 @@ export namespace GooglePhotos { return; } const url = data.url.href; - const target = Doc.MakeAlias(source); + const target = Doc.MakeEmbedding(source); const description = parseDescription(target, descriptionKey); await DocUtils.makeCustomViewClicked(target, Docs.Create.FreeformDocument); media.push({ url, description }); } if (media.length) { - const results = await Networking.PostToServer("/googlePhotosMediaPost", { media, album }); + const results = await Networking.PostToServer('/googlePhotosMediaPost', { media, album }); return results; } }; @@ -341,14 +329,12 @@ export namespace GooglePhotos { const parseDescription = (document: Doc, descriptionKey: string) => { let description: string = Utils.prepend(`/doc/${document[Id]}?sharing=true`); const target = document[descriptionKey]; - if (typeof target === "string") { + if (typeof target === 'string') { description = target; } else if (target instanceof RichTextField) { description = RichTextUtils.ToPlainText(EditorState.fromJSON(FormattedTextBox.Instance.config, JSON.parse(target.Data))); } return description; }; - } - -} \ No newline at end of file +} diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index d99cd2dac..2da3a24fd 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -11,7 +11,7 @@ export enum DocumentType { AUDIO = 'audio', REC = 'recording', PDF = 'pdf', - INK = 'inks', + INK = 'ink', SCREENSHOT = 'screenshot', FONTICON = 'fonticonbox', FILTER = 'filter', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e28e29267..849a5d6ae 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -37,7 +37,6 @@ import { FontIconBox } from '../views/nodes/button/FontIconBox'; import { ColorBox } from '../views/nodes/ColorBox'; import { ComparisonBox } from '../views/nodes/ComparisonBox'; import { DataVizBox } from '../views/nodes/DataVizBox/DataVizBox'; -import { OpenWhereMod } from '../views/nodes/DocumentView'; import { EquationBox } from '../views/nodes/EquationBox'; import { FieldViewProps } from '../views/nodes/FieldView'; import { FormattedTextBox } from '../views/nodes/formattedText/FormattedTextBox'; @@ -120,7 +119,7 @@ class PEInfo extends FInfo { } class DAInfo extends FInfo { fieldType? = 'dropActionType'; - values? = ['alias', 'copy', 'move', 'same', 'proto', 'none']; + values? = ['embed', 'copy', 'move', 'same', 'proto', 'none']; readOnly = true; } class DateInfo extends FInfo { @@ -139,7 +138,7 @@ export class DocumentOptions { x?: NUMt = new NumInfo('x coordinate of document in a freeform view'); y?: NUMt = new NumInfo('y coordinage of document in a freeform view'); z?: NUMt = new NumInfo('whether document is in overlay (1) or not (0)', false, [1, 0]); - system?: BOOLt = new BoolInfo('is this a system created/owned doc', true); + isSystem?: BOOLt = new BoolInfo('is this a system created/owned doc', true); type?: STRt = new StrInfo('type of document', true, Array.from(Object.keys(DocumentType))); title?: string; creationDate?: DATEt = new DateInfo('date the document was created', true); @@ -150,33 +149,33 @@ export class DocumentOptions { userColor?: STRt = new StrInfo('color associated with a Dash user (seen in header fields of shared documents)'); color?: STRt = new StrInfo('foreground color data doc'); backgroundColor?: STRt = new StrInfo('background color for data doc'); - _autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); + _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents'); _headerHeight?: NUMt = new NumInfo('height of document header used for displaying title'); _headerFontSize?: NUMt = new NumInfo('font size of header of custom notes'); _headerPointerEvents?: PEVt = new PEInfo('types of events the header of a custom text document can consume'); - _panX?: NUMt = new NumInfo('horizontal pan location of a freeform view'); - _panY?: NUMt = new NumInfo('vertical pan location of a freeform view'); + _freeform_panX?: NUMt = new NumInfo('horizontal pan location of a freeform view'); + _freeform_panY?: NUMt = new NumInfo('vertical pan location of a freeform view'); _width?: NUMt = new NumInfo('displayed width of a document'); _height?: NUMt = new NumInfo('displayed height of document'); - 'data-nativeWidth'?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)'); - 'data-nativeHeight'?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)'); + data_nativeWidth?: NUMt = new NumInfo('native width of data field contents (e.g., the pixel width of an image)'); + data_nativeHeight?: NUMt = new NumInfo('native height of data field contents (e.g., the pixel height of an image)'); _nativeWidth?: NUMt = new NumInfo('native width of document contents (e.g., the pixel width of an image)'); _nativeHeight?: NUMt = new NumInfo('native height of document contents (e.g., the pixel height of an image)'); _nativeDimModifiable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers'); _nativeHeightUnfrozen?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers'); _dimMagnitude?: NUMt = new NumInfo("magnitude of collectionMulti{row,col} element's width or height"); _dimUnit?: DIMt = new DimInfo("units of collectionMulti{row,col} element's width or height - 'px' or '*' for pixels or relative units"); - _fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); - _fitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content'); + _layout_fitWidth?: BOOLt = new BoolInfo('whether document should scale its contents to fit its rendered width or not (e.g., for PDFviews)'); + _layoutFitContentsToBox?: BOOLt = new BoolInfo('whether a freeformview should zoom/scale to create a shrinkwrapped view of its content'); _contentBounds?: List; // the (forced) bounds of the document to display. format is: [left, top, right, bottom] _lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged - _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed + _lockedTransform?: boolean; // lock the freeform_panx,freeform_pany and scale parameters of the document so that it be panned/zoomed _followLinkToggle?: boolean; // whether document, when clicked, toggles display of its link target - _showTitle?: string; // field name to display in header (:hover is an optional suffix) - _showAltContentUI?: boolean; // whether to show alternate content button + _layout_showTitle?: string; // field name to display in header (:hover is an optional suffix) + _layout_altContentUI?: boolean; // whether to show alternate content button _isLightbox?: boolean; // whether a collection acts as a lightbox by opening lightbox links by hiding all other documents in collection besides link target - _showCaption?: string; // which field to display in the caption area. leave empty to have no caption - _scrollTop?: number; // scroll location for pdfs + _layout_showCaption?: string; // which field to display in the caption area. leave empty to have no caption + _layoutScrollTop?: number; // scroll location for pdfs _noAutoscroll?: boolean; // whether collections autoscroll when this item is dragged _chromeHidden?: boolean; // whether the editing chrome for a document is hidden _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view) @@ -188,15 +187,16 @@ export class DocumentOptions { _viewType?: string; // sub type of a collection viewType?: string; // sub type of a collection _gridGap?: number; // gap between items in masonry view - _viewScale?: number; // how much a freeform view has been scaled (zoomed) + _freeform_scale?: number; // how much a freeform view has been scaled (zoomed) _overflow?: string; // set overflow behavior _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts _xPadding?: number; _yPadding?: number; _itemIndex?: number; // which item index the carousel viewer is showing - _showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts - _singleLine?: boolean; // whether text document is restricted to a single line (carriage returns make new document) + _layout_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts + _singleLine?: boolean; // whether label box is restricted to one line of text + _createDocOnCR?: boolean; // whether carriage returns and tabs create new text documents _minFontSize?: number; // minimum font size for labelBoxes _maxFontSize?: number; // maximum font size for labelBoxes _columnWidth?: number; @@ -205,24 +205,24 @@ export class DocumentOptions { _fontFamily?: string; _fontWeight?: string; _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views - _curPage?: number; // current page of a PDF or other? paginated document - _currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds + _layout_curPage?: number; // current page of a PDF or other? paginated document + _layout_currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide) _timecodeToShow?: number; // the time that a document should be displayed (e.g., when an annotation shows up as a video plays) _timecodeToHide?: number; // the time that a document should be hidden _timelineLabel?: boolean; // whether the document exists on a timeline - '_carousel-caption-xMargin'?: NUMt = new NumInfo('x margin of caption inside of a carouself collection', true); - '_carousel-caption-yMargin'?: NUMt = new NumInfo('y margin of caption inside of a carouself collection', true); - 'icon-nativeWidth'?: NUMt = new NumInfo('native width of icon view', true); - 'icon-nativeHeight'?: NUMt = new NumInfo('native height of icon view', true); - 'dragFactory-count'?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true); + _caption_xMargin?: NUMt = new NumInfo('x margin of caption inside of a carousel collection', true); + _caption_yMargin?: NUMt = new NumInfo('y margin of caption inside of a carousel collection', true); + icon_nativeWidth?: NUMt = new NumInfo('native width of icon view', true); + icon_nativeHeight?: NUMt = new NumInfo('native height of icon view', true); + dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true); openFactoryLocation?: string; // an OpenWhere value to place the factory created document openFactoryAsDelegate?: boolean; // lat?: number; lng?: number; infoWindowOpen?: boolean; author?: string; - _layoutKey?: string; + _layout_fieldKey?: string; fieldValues?: List; // possible field values used by fieldInfos fieldType?: string; // type of afield used by fieldInfos unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf) @@ -249,7 +249,6 @@ export class DocumentOptions { defaultDoubleClick?: 'ignore' | 'default'; // ignore double clicks, or deafult (undefined) means open document full screen waitForDoubleClickToClick?: 'always' | 'never' | 'default'; // whether a click function wait for double click to expire. 'default' undefined = wait only if there's a click handler, "never" = never wait, "always" = alway wait dontUndo?: boolean; // whether button clicks should be undoable (this is set to true for Undo/Redo/and sidebar buttons that open the siebar panel) - description?: string; // added for links layout?: string | Doc; // default layout string for a document contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents childLimitHeight?: number; // whether to limit the height of collection children. 0 - means height can be no bigger than width @@ -263,11 +262,11 @@ export class DocumentOptions { childContextMenuLabels?: List; childContextMenuIcons?: List; followLinkZoom?: boolean; // whether to zoom to the target of a link - hideLinkButton?: boolean; // whether the blue link counter button should be hidden + layout_hideLinkButton?: boolean; // whether the blue link counter button should be hidden disableDocBrushing?: boolean; // whether to suppress border highlighting - hideDecorationTitle?: boolean; + layout_hideDecorationTitle?: boolean; hideOpenButton?: boolean; - hideResizeHandles?: boolean; + layout_hideResizeHandles?: boolean; hideDocumentButtonBar?: boolean; hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden isTemplateForField?: string; // the field key for which the containing document is a rendering template @@ -278,8 +277,8 @@ export class DocumentOptions { caption?: RichTextField; opacity?: number; defaultBackgroundColor?: string; - _linkAutoMove?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint - hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed + _layout_autoMoveAnchors?: boolean; // whether link endpoint should move around the edges of a document to make shortest path to other link endpoint + layout_hideLinkAnchors?: boolean; // suppresses link anchor dots from being displayed isFolder?: boolean; lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide) activeFrame?: number; // the active frame of a document in a frame base collection @@ -294,12 +293,11 @@ export class DocumentOptions { borderRounding?: string; boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow data?: any; - baseProto?: boolean; // is this a base prototoype + isBaseProto?: boolean; // this Doc is base level prototype for data documents as opposed to data documents which are prototypes for layout documents. base protos are not cloned during a deep dontRegisterView?: boolean; lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox. columnHeaders?: List; // headers for stacking views schemaHeaders?: List; // headers for schema view - clipWidth?: number; // percent transition from before to after in comparisonBox dockingConfig?: string; annotationOn?: Doc; followLinkToggle?: boolean; @@ -307,7 +305,7 @@ export class DocumentOptions { _removeDropProperties?: List; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document noteType?: string; // BACKGROUND GRID - _backgroundGridShow?: boolean; + _freeform_backgroundGrid?: boolean; //BUTTONS buttonText?: string; @@ -318,7 +316,6 @@ export class DocumentOptions { userColorBtn?: string; canClick?: string; script?: ScriptField; - numBtnType?: string; numBtnMax?: number; numBtnMin?: number; switchToggle?: boolean; @@ -335,12 +332,14 @@ export class DocumentOptions { layout_linkView?: Doc; // view template for a link document layout_keyValue?: string; // view tempalte for key value docs - linkRelationship?: string; // type of relatinoship a link represents - linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors - anchor1?: Doc; - anchor2?: Doc; - 'anchor1-useLinkSmallAnchor'?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection) - 'anchor2-useLinkSmallAnchor'?: boolean; // whether anchor1 of a link should use a miniature anchor dot (as when the anchor is a text selection) + link_description?: string; // added for links + link_relationship?: string; // type of relatinoship a link represents + layout_linkDisplay?: boolean; // whether a link line should be dipslayed between the two link anchors + layout_linkDisplayArrow?: boolean; // whether to display link's directional arrowhead + link_anchor_1?: Doc; + link_anchor_2?: Doc; + link_anchor_1_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection) + link_anchor_2_useLinkSmallAnchor?: boolean; // whether link_anchor_1 of a link should use a miniature anchor dot (as when the anchor is a text selection) ignoreClick?: boolean; onClick?: ScriptField; onDoubleClick?: ScriptField; @@ -354,13 +353,13 @@ export class DocumentOptions { onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop cloneFieldFilter?: List; // fields not to copy when the document is clonedclipboard?: Doc; filterBoolean?: string; - useCors?: boolean; + data_useCors?: boolean; icon?: string; target?: Doc; // available for use in scripts as the primary target document sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script searchFileTypes?: List; // file types allowed in a search query - strokeWidth?: number; + stroke_width?: number; freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view treeViewHideUnrendered?: boolean; // tells tree view not to display documents that have an 'unrendered' tag unless they also have a treeViewFieldKey tag (presBox) @@ -395,8 +394,8 @@ export class DocumentOptions { useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox border?: string; //for searchbox hoverBackgroundColor?: string; // background color of a label when hovered - linkRelationshipList?: List; // for storing different link relationships (when set by user in the link editor) - linkRelationshipSizes?: List; //stores number of links contained in each relationship + link_relationshipList?: List; // for storing different link relationships (when set by user in the link editor) + link_relationshipSizes?: List; //stores number of links contained in each relationship linkColorList?: List; // colors of links corresponding to specific link relationships } export namespace Docs { @@ -427,7 +426,7 @@ export namespace Docs { _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true, - forceReflow: true, + layout_forceReflow: true, defaultDoubleClick: 'ignore', }, }, @@ -457,35 +456,35 @@ export namespace Docs { DocumentType.WEB, { layout: { view: WebBox, dataField: defaultDataKey }, - options: { _height: 300, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always' }, + options: { _height: 300, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, waitForDoubleClickToClick: 'always' }, }, ], [ DocumentType.COL, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { _fitWidth: true, _panX: 0, _panY: 0, _viewScale: 1 }, + options: { _layout_fitWidth: true, _freeform_panX: 0, _freeform_panY: 0, _freeform_scale: 1 }, }, ], [ DocumentType.KVP, { layout: { view: KeyValueBox, dataField: defaultDataKey }, - options: { _fitWidth: true, _height: 150 }, + options: { _layout_fitWidth: true, _height: 150 }, }, ], [ DocumentType.VID, { layout: { view: VideoBox, dataField: defaultDataKey }, - options: { _currentTimecode: 0 }, + options: { _layout_currentTimecode: 0 }, }, ], [ DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 100, fitWidth: true, forceReflow: true, nativeDimModifiable: true }, + options: { _height: 100, layout_fitWidth: true, layout_forceReflow: true, nativeDimModifiable: true }, }, ], [ @@ -499,7 +498,7 @@ export namespace Docs { DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, - options: { _curPage: 1, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true }, + options: { _layout_curPage: 1, _layout_fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true }, }, ], [ @@ -519,14 +518,15 @@ export namespace Docs { [ DocumentType.LINK, { - layout: { view: LinkBox, dataField: defaultDataKey }, + layout: { view: LinkBox, dataField: 'link' }, options: { childDontRegisterViews: true, onClick: FollowLinkScript(), - hideLinkAnchors: true, + layout_hideLinkAnchors: true, _height: 150, - description: '', - showCaption: 'description', + link: '', + link_description: '', + layout_showCaption: 'link_description', backgroundColor: 'lightblue', // lightblue is default color for linking dot and link documents text comment area _removeDropProperties: new List(['onClick']), }, @@ -537,7 +537,7 @@ export namespace Docs { { data: new List(), layout: { view: EmptyBox, dataField: defaultDataKey }, - options: { childDropAction: 'alias', title: 'Global Link Database' }, + options: { childDropAction: 'embed', title: 'Global Link Database' }, }, ], [ @@ -545,7 +545,7 @@ export namespace Docs { { data: new List(), layout: { view: EmptyBox, dataField: defaultDataKey }, - options: { childDropAction: 'alias', title: 'Global Script Database' }, + options: { childDropAction: 'embed', title: 'Global Script Database' }, }, ], [ @@ -571,8 +571,8 @@ export namespace Docs { [ DocumentType.EQUATION, { - layout: { view: EquationBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true, fontSize: '14px', hideResizeHandles: true, hideDecorationTitle: true }, + layout: { view: EquationBox, dataField: 'text' }, + options: { nativeDimModifiable: true, fontSize: '14px', layout_hideResizeHandles: true, layout_hideDecorationTitle: true }, }, ], [ @@ -600,14 +600,14 @@ export namespace Docs { DocumentType.PRES, { layout: { view: PresBox, dataField: defaultDataKey }, - options: { defaultDoubleClick: 'ignore', hideLinkAnchors: true }, + options: { defaultDoubleClick: 'ignore', layout_hideLinkAnchors: true }, }, ], [ DocumentType.FONTICON, { layout: { view: FontIconBox, dataField: 'icon' }, - options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, hideLinkButton: true, _width: 40, _height: 40 }, + options: { defaultDoubleClick: 'ignore', waitForDoubleClickToClick: 'never', enableDragWhenActive: true, layout_hideLinkButton: true, _width: 40, _height: 40 }, }, ], [ @@ -621,21 +621,21 @@ export namespace Docs { DocumentType.PRESELEMENT, { layout: { view: PresElementBox, dataField: defaultDataKey }, - options: { title: 'pres element template', _fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: 'data' }, + options: { title: 'pres element template', _layout_fitWidth: true, _xMargin: 0, isTemplateDoc: true, isTemplateForField: 'data' }, }, ], [ DocumentType.MARKER, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { hideLinkButton: true, pointerEvents: 'none' }, + options: { layout_hideLinkButton: true, pointerEvents: 'none' }, }, ], [ DocumentType.INK, { // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method - layout: { view: InkingStroke, dataField: defaultDataKey }, + layout: { view: InkingStroke, dataField: 'stroke' }, options: {}, }, ], @@ -649,8 +649,9 @@ export namespace Docs { [ DocumentType.COMPARISON, { + data: '', layout: { view: ComparisonBox, dataField: defaultDataKey }, - options: { clipWidth: 50, nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'alias' }, + options: { nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'embed' }, }, ], [ @@ -658,7 +659,7 @@ export namespace Docs { { data: new List(), layout: { view: EmptyBox, dataField: defaultDataKey }, - options: { childDropAction: 'alias', title: 'Global Group Database' }, + options: { childDropAction: 'embed', title: 'Global Group Database' }, }, ], [ @@ -672,14 +673,14 @@ export namespace Docs { DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { _fitWidth: true, nativeDimModifiable: true }, + options: { _layout_fitWidth: true, nativeDimModifiable: true }, }, ], [ DocumentType.LOADING, { layout: { view: LoadingBox, dataField: '' }, - options: { _fitWidth: true, _fitHeight: true, nativeDimModifiable: true }, + options: { _layout_fitWidth: true, _fitHeight: true, nativeDimModifiable: true }, }, ], ]); @@ -773,11 +774,11 @@ export namespace Docs { // synthesize the default options, the type and title from computed values and // whatever options pertain to this specific prototype const options: DocumentOptions = { - system: true, - _layoutKey: 'layout', + isSystem: true, + _layout_fieldKey: 'layout', title, type, - baseProto: true, + isBaseProto: true, x: 0, y: 0, _width: 300, @@ -818,24 +819,24 @@ export namespace Docs { * main document. */ function InstanceFromProto(proto: Doc, data: Field | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDoc?: Doc) { - const viewKeys = ['x', 'y', 'system']; // keys that should be addded to the view document even though they don't begin with an "_" + const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_" const { omit: dataProps, extract: viewProps } = OmitKeys(options, viewKeys, '^_'); // dataProps['acl-Override'] = SharingPermissions.Unset; dataProps['acl-Public'] = options['acl-Public'] ? options['acl-Public'] : Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; - dataProps.system = viewProps.system; - dataProps.isPrototype = true; + dataProps.isSystem = viewProps.isSystem; + dataProps.isDataDoc = true; dataProps.author = Doc.CurrentUserEmail; dataProps.creationDate = new DateField(); if (fieldKey) { - dataProps[`${fieldKey}-lastModified`] = new DateField(); + dataProps[`${fieldKey}_modificationDate`] = new DateField(); dataProps[fieldKey] = data; // so that the list of annotations is already initialised, prevents issues in addonly. // without this, if a doc has no annotations but the user has AddOnly privileges, they won't be able to add an annotation because they would have needed to create the field's list which they don't have permissions to do. - dataProps[fieldKey + '-annotations'] = new List(); - dataProps[fieldKey + '-sidebar'] = new List(); + dataProps[fieldKey + '_annotations'] = new List(); + dataProps[fieldKey + '_sidebar'] = new List(); } // users placeholderDoc as proto if it exists @@ -901,7 +902,7 @@ export namespace Docs { } export function ComparisonDocument(options: DocumentOptions = { title: 'Comparison Box' }) { - return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), '', options); + return InstanceFromProto(Prototypes.get(DocumentType.COMPARISON), undefined, options); } export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) { @@ -954,11 +955,12 @@ export namespace Docs { Prototypes.get(DocumentType.LINK), undefined, { - anchor1: source, - anchor2: target, + link_anchor_1: source, + link_anchor_2: target, ...options, }, - id + id, + 'link' ); LinkManager.Instance.addLink(linkDoc); @@ -966,36 +968,24 @@ export namespace Docs { return linkDoc; } - export function InkDocument( - color: string, - tool: string, - strokeWidth: number, - strokeBezier: string, - fillColor: string, - arrowStart: string, - arrowEnd: string, - dash: string, - points: PointData[], - isInkMask: boolean, - options: DocumentOptions = {} - ) { + export function InkDocument(color: string, strokeWidth: number, stroke_bezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: PointData[], isInkMask: boolean, options: DocumentOptions = {}) { const I = new Doc(); I[Initializing] = true; - I.isInkMask = isInkMask; I.type = DocumentType.INK; - I.layout = InkingStroke.LayoutString('data'); - I.color = color; - I.hideDecorationTitle = true; // don't show title when selected + I.layout = InkingStroke.LayoutString('stroke'); + I.layout_fitWidth = true; + I.layout_hideDecorationTitle = true; // don't show title when selected // I.hideOpenButton = true; // don't show open full screen button when selected + I.color = color; I.fillColor = fillColor; - I.strokeWidth = strokeWidth; - I.strokeBezier = strokeBezier; - I.strokeStartMarker = arrowStart; - I.strokeEndMarker = arrowEnd; - I.strokeDash = dash; - I.tool = tool; - I.fitWidth = true; - I['text-align'] = 'center'; + I.stroke = new InkField(points); + I.stroke_width = strokeWidth; + I.stroke_bezier = stroke_bezier; + I.stroke_startMarker = arrowStart; + I.stroke_endMarker = arrowEnd; + I.stroke_dash = dash; + I.stroke_isInkMask = isInkMask; + I.text_align = 'center'; I.title = 'ink'; I.x = options.x as number; I.y = options.y as number; @@ -1004,7 +994,6 @@ export namespace Docs { I._fontFamily = 'cursive'; I.author = Doc.CurrentUserEmail; I.rotation = 0; - I.data = new InkField(points); I.defaultDoubleClick = 'click'; I.creationDate = new DateField(); I['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; @@ -1050,7 +1039,7 @@ export namespace Docs { export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string) { const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _viewType: CollectionViewType.Freeform }, id); - documents.map(d => (d.context = inst)); + documents.map(d => (d.embedContainer = inst)); return inst; } @@ -1136,7 +1125,7 @@ export namespace Docs { } export function EquationDocument(options?: DocumentOptions) { - return InstanceFromProto(Prototypes.get(DocumentType.EQUATION), undefined, { ...(options || {}) }); + return InstanceFromProto(Prototypes.get(DocumentType.EQUATION), undefined, { ...(options || {}) }, undefined, 'text'); } export function FunctionPlotDocument(documents: Array, options?: DocumentOptions) { @@ -1263,7 +1252,7 @@ export namespace DocUtils { ? true : matches.some(value => { if (facetKey.startsWith('*')) { - // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc + // fields starting with a '*' are used to match families of related fields. ie, *modificationDate will match text_modificationDate, data_modificationDate, etc const allKeys = Array.from(Object.keys(d)); allKeys.push(...Object.keys(Doc.GetProto(d))); const keys = allKeys.filter(key => key.includes(facetKey.substring(1))); @@ -1304,12 +1293,12 @@ export namespace DocUtils { broadcastEvent && runInAction(() => (DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1)); return DocUtils.ActiveRecordings.map(audio => { const sourceDoc = getSourceDoc(); - return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { linkDisplay: false, linkRelationship: 'recording annotation:linked recording', description: 'recording timeline' }); + return sourceDoc && DocUtils.MakeLink(sourceDoc, audio.getAnchor(true) || audio.props.Document, { layout_linkDisplay: false, link_relationship: 'recording annotation:linked recording', link_description: 'recording timeline' }); }); } - export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, showPopup?: number[]) { - if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link'; + export function MakeLink(source: Doc, target: Doc, linkSettings: { link_relationship?: string; link_description?: string; layout_linkDisplay?: boolean }, id?: string, showPopup?: number[]) { + if (!linkSettings.link_relationship) linkSettings.link_relationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link'; const sv = DocumentManager.Instance.getDocumentView(source); if (target.doc === Doc.UserDoc()) return undefined; @@ -1350,16 +1339,16 @@ export namespace DocUtils { target, { title: ComputedField.MakeFunction('generateLinkTitle(self)') as any, - 'anchor1-useLinkSmallAnchor': source.useLinkSmallAnchor ? true : undefined, - 'anchor2-useLinkSmallAnchor': target.useLinkSmallAnchor ? true : undefined, + link_anchor_1_useLinkSmallAnchor: source.useLinkSmallAnchor ? true : undefined, + link_anchor_2_useLinkSmallAnchor: target.useLinkSmallAnchor ? true : undefined, 'acl-Public': SharingPermissions.Augment, '_acl-Public': SharingPermissions.Augment, - linkDisplay: linkSettings.linkDisplay, - _linkAutoMove: true, - linkRelationship: linkSettings.linkRelationship, - _showCaption: 'description', - _showTitle: 'linkRelationship', - description: linkSettings.description, + layout_linkDisplay: linkSettings.layout_linkDisplay, + link_relationship: linkSettings.link_relationship, + link_description: linkSettings.link_description, + _layout_autoMoveAnchors: true, + _layout_showCaption: 'link_description', + _layout_showTitle: 'link_relationship', }, id ), @@ -1443,13 +1432,13 @@ export namespace DocUtils { created = Docs.Create.AudioDocument(field.url.href, resolved); created.layout = AudioBox.LayoutString(fieldKey); } else if (field instanceof InkField) { - created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved); + created = Docs.Create.InkDocument(ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved); created.layout = InkingStroke.LayoutString(fieldKey); } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); created.layout = CollectionView.LayoutString(fieldKey); } else { - created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _autoHeight: true }, ...resolved }); + created = Docs.Create.TextDocument('', { ...{ _width: 200, _height: 25, _layout_autoHeight: true }, ...resolved }); created.layout = FormattedTextBox.LayoutString(fieldKey); } if (created) { @@ -1503,12 +1492,12 @@ export namespace DocUtils { const id = s[s.length - 1]; return DocServer.GetRefField(id).then(field => { if (field instanceof Doc) { - const alias = Doc.MakeAlias(field); - alias.x = (options.x as number) || 0; - alias.y = (options.y as number) || 0; - alias._width = (options._width as number) || 300; - alias._height = (options._height as number) || (options._width as number) || 300; - return alias; + const embedding = Doc.MakeEmbedding(field); + embedding.x = (options.x as number) || 0; + embedding.y = (options.y as number) || 0; + embedding._width = (options._width as number) || 300; + embedding._height = (options._height as number) || (options._width as number) || 300; + return embedding; } return undefined; }); @@ -1531,11 +1520,11 @@ export namespace DocUtils { _width: 200, x, y, - _autoHeight: note._autoHeight !== false, - title: StrCast(note.title) + '#' + (note.aliasCount = NumCast(note.aliasCount) + 1), + _layout_autoHeight: note._layout_autoHeight !== false, + title: StrCast(note.title) + '#' + (note.embeddingCount = NumCast(note.embeddingCount) + 1), }); - textDoc.layoutKey = 'layout_' + note.title; - textDoc[textDoc.layoutKey] = note; + textDoc.layout_fieldKey = 'layout_' + note.title; + textDoc[textDoc.layout_fieldKey] = note; if (pivotField) { textDoc[pivotField] = pivotValue; } @@ -1576,7 +1565,7 @@ export namespace DocUtils { export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = 'custom', docLayoutTemplate?: Doc) { const batch = UndoManager.StartBatch('makeCustomViewClicked'); runInAction(() => { - doc.layoutKey = 'layout_' + templateSignature; + doc.layout_fieldKey = 'layout_' + templateSignature; createCustomView(doc, creator, templateSignature, docLayoutTemplate); }); batch.end(); @@ -1607,7 +1596,7 @@ export namespace DocUtils { const customName = 'layout_' + templateSignature; const _width = NumCast(doc._width); const _height = NumCast(doc._height); - const options = { title: 'data', backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: -_height / 2, _showSidebar: false }; + const options = { title: 'data', backgroundColor: StrCast(doc.backgroundColor), _layout_autoHeight: true, _width, x: -_width / 2, y: -_height / 2, _layout_showSidebar: false }; if (docLayoutTemplate) { if (docLayoutTemplate !== doc[customName]) { @@ -1638,9 +1627,9 @@ export namespace DocUtils { } } export function iconify(doc: Doc) { - const layoutKey = Cast(doc.layoutKey, 'string', null); + const layout_fieldKey = Cast(doc.layout_fieldKey, 'string', null); DocUtils.makeCustomViewClicked(doc, Docs.Create.StackingDocument, 'icon', undefined); - if (layoutKey && layoutKey !== 'layout' && layoutKey !== 'layout_icon') doc.deiconifyLayout = layoutKey.replace('layout_', ''); + if (layout_fieldKey && layout_fieldKey !== 'layout' && layout_fieldKey !== 'layout_icon') doc.deiconifyLayout = layout_fieldKey.replace('layout_', ''); } export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) { @@ -1680,8 +1669,8 @@ export namespace DocUtils { export function LeavePushpin(doc: Doc, annotationField: string) { if (doc.followLinkToggle) return undefined; - const context = Cast(doc.context, Doc, null) ?? Cast(doc.annotationOn, Doc, null); - const hasContextAnchor = LinkManager.Links(doc).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); + const context = Cast(doc.embedContainer, Doc, null) ?? Cast(doc.annotationOn, Doc, null); + const hasContextAnchor = LinkManager.Links(doc).some(l => (l.link_anchor_2 === doc && Cast(l.link_anchor_1, Doc, null)?.annotationOn === context) || (l.link_anchor_1 === doc && Cast(l.link_anchor_2, Doc, null)?.annotationOn === context)); if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) { const pushpin = Docs.Create.FontIconDocument({ title: 'pushpin', @@ -1700,7 +1689,7 @@ export namespace DocUtils { _timecodeToShow: Cast(doc._timecodeToShow, 'number', null), }); Doc.AddDocToList(context, annotationField, pushpin); - const pushpinLink = DocUtils.MakeLink(pushpin, doc, { linkRelationship: 'pushpin' }, ''); + const pushpinLink = DocUtils.MakeLink(pushpin, doc, { link_relationship: 'pushpin' }, ''); doc._timecodeToShow = undefined; return pushpin; } @@ -1745,21 +1734,17 @@ export namespace DocUtils { if (doc) { const proto = Doc.GetProto(doc); proto.text = result.rawText; - proto.fileUpload = pathname - .replace(/.*\//, '') - .replace('upload_', '') - .replace(/\.[a-z0-9]*$/, ''); if (Upload.isImageInformation(result)) { const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim); const exifRotation = StrCast((result.exifData?.data as any)?.Orientation).toLowerCase(); proto['data-nativeOrientation'] = result.exifData?.data?.image?.Orientation ?? (exifRotation.includes('rotate 90') || exifRotation.includes('rotate 270') ? 5 : undefined); - proto['data-nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; - proto['data-nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); + proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; + proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); if (NumCast(proto['data-nativeOrientation']) >= 5) { - proto['data-nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; - proto['data-nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); + proto['data_nativeHeight'] = result.nativeWidth < result.nativeHeight ? (maxNativeDim * result.nativeWidth) / result.nativeHeight : maxNativeDim; + proto['data_nativeWidth'] = result.nativeWidth < result.nativeHeight ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight); } - proto.contentSize = result.contentSize; + proto.data_contentSize = result.contentSize; // exif gps data coordinates are stored in DMS (Degrees Minutes Seconds), the following operation converts that to decimal coordinates const latitude = result.exifData?.data?.GPSLatitude; const latitudeDirection = result.exifData?.data?.GPSLatitudeRef; @@ -1771,12 +1756,12 @@ export namespace DocUtils { } } if (Upload.isVideoInformation(result)) { - proto['data-duration'] = result.duration; + proto.data_duration = result.duration; } if (overwriteDoc) { Doc.removeCurrentlyLoading(overwriteDoc); // loading doc icons are just labels. so any icon views of loading docs need to be replaced with the proper icon view. - DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layoutKey) === 'layout_icon' && dv.iconify(() => dv.iconify())); + DocumentManager.Instance.getAllDocumentViews(overwriteDoc).forEach(dv => StrCast(dv.rootDoc.layout_fieldKey) === 'layout_icon' && dv.iconify(() => dv.iconify())); } generatedDocuments.push(doc); } @@ -1793,16 +1778,16 @@ export namespace DocUtils { _height: 35, x: x, y: y, - _fitWidth: true, - _autoHeight: true, - _showAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards), + _layout_fitWidth: true, + _layout_autoHeight: true, + _layout_altContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards), title, }); const template = Doc.UserDoc().defaultTextLayout; if (template instanceof Doc) { tbox._width = NumCast(template._width); - tbox.layoutKey = 'layout_' + StrCast(template.title); - Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template; + tbox.layout_fieldKey = 'layout_' + StrCast(template.title); + Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = template; } return tbox; } @@ -1857,9 +1842,9 @@ export namespace DocUtils { if (!dragFactory) return undefined; const ndoc = dragFactory.isTemplateDoc ? Doc.ApplyTemplate(dragFactory) : Doc.MakeCopy(dragFactory, true); ndoc && Doc.AddFileOrphan(Doc.GetProto(ndoc)); - if (ndoc && dragFactory['dragFactory-count'] !== undefined) { - dragFactory['dragFactory-count'] = NumCast(dragFactory['dragFactory-count']) + 1; - Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory-count']).toString(), true); + if (ndoc && dragFactory['dragFactory_count'] !== undefined) { + dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1; + Doc.SetInPlace(ndoc, 'title', ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(), true); } if (ndoc && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, ndoc); @@ -1868,9 +1853,9 @@ export namespace DocUtils { } export function delegateDragFactory(dragFactory: Doc) { const ndoc = Doc.MakeDelegateWithProto(dragFactory); - if (ndoc && dragFactory['dragFactory-count'] !== undefined) { - dragFactory['dragFactory-count'] = NumCast(dragFactory['dragFactory-count']) + 1; - Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory['dragFactory-count']).toString(); + if (ndoc && dragFactory['dragFactory_count'] !== undefined) { + dragFactory['dragFactory_count'] = NumCast(dragFactory['dragFactory_count']) + 1; + Doc.GetProto(ndoc).title = ndoc.title + ' ' + NumCast(dragFactory['dragFactory_count']).toString(); } return ndoc; } @@ -1885,11 +1870,8 @@ ScriptingGlobals.add(function makeDelegate(proto: any) { return d; }); ScriptingGlobals.add(function generateLinkTitle(self: Doc) { - const anchor1title = self.anchor1 && self.anchor1 !== self ? Cast(self.anchor1, Doc, null)?.title : ''; - const anchor2title = self.anchor2 && self.anchor2 !== self ? Cast(self.anchor2, Doc, null)?.title : ''; - const relation = self.linkRelationship || 'to'; - return `${anchor1title} (${relation}) ${anchor2title}`; -}); -ScriptingGlobals.add(function openTabAlias(tab: Doc) { - CollectionDockingView.AddSplit(Doc.MakeAlias(tab), OpenWhereMod.right); + const link_anchor_1title = self.link_anchor_1 && self.link_anchor_1 !== self ? Cast(self.link_anchor_1, Doc, null)?.title : ''; + const link_anchor_2title = self.link_anchor_2 && self.link_anchor_2 !== self ? Cast(self.link_anchor_2, Doc, null)?.title : ''; + const relation = self.link_relationship || 'to'; + return `${link_anchor_1title} (${relation}) ${link_anchor_2title}`; }); diff --git a/src/client/documents/Gitlike.ts b/src/client/documents/Gitlike.ts index 5e2baf924..f35f33f65 100644 --- a/src/client/documents/Gitlike.ts +++ b/src/client/documents/Gitlike.ts @@ -9,24 +9,24 @@ // // we don't have individual timestamps for all fields -- this is a problematic design issue. // function GitlikeSynchDocs(bd: Doc, md: Doc) { // const fieldKey = Doc.LayoutFieldKey(md); -// const bdate = DateCast(bd[`${fieldKey}-lastModified`])?.date; -// const mdate = DateCast(md[`${fieldKey}-lastModified`])?.date; +// const bdate = DateCast(bd[`${fieldKey}_modificationDate`])?.date; +// const mdate = DateCast(md[`${fieldKey}_modificationDate`])?.date; // const bdproto = bd && Doc.GetProto(bd); // if (bdate !== mdate && bdate <= mdate) { // if (bdproto && md) { // bdproto[fieldKey] = Field.Copy(md[fieldKey]); -// bdproto[`${fieldKey}-lastModified`] = new DateField(); +// bdproto[`${fieldKey}_modificationDate`] = new DateField(); // } // } -// const bldate = DateCast(bd._lastModified)?.date; -// const mldate = DateCast(md._lastModified)?.date; +// const bldate = DateCast(bd._layout_modificationDate)?.date; +// const mldate = DateCast(md._layout_modificationDate)?.date; // if (bldate === mldate || bldate > mldate) return; // if (bdproto && md) { // bd.x = Field.Copy(md.x); // bd.y = Field.Copy(md.y); // bd.width = Field.Copy(md.width); // bd.height = Field.Copy(md.height); -// bdproto._lastModified = new DateField(); +// bdproto._layout_modificationDate = new DateField(); // } // } @@ -53,10 +53,10 @@ // const newlyBranchedDocs = await Promise.all(newDocsFromMaster?.map(async md => (await Doc.MakeClone(md, false, true, cloneMap)).clone) || []); // newlyBranchedDocs.forEach(nd => { // Doc.AddDocToList(branch, Doc.LayoutFieldKey(branch) + suffix, nd); -// nd.context = branch; +// nd.embedContainer = branch; // }); -// // if a branch doc's corresponding main branch doc doesn't have a context, then it was deleted. -// const remDocsFromMaster = branchMainDocs?.filter(bd => Cast(bd.branchOf, Doc, null) && !Cast(bd.branchOf, Doc, null)?.context); +// // if a branch doc's corresponding main branch doc doesn't have a embedContainer, then it was deleted. +// const remDocsFromMaster = branchMainDocs?.filter(bd => Cast(bd.branchOf, Doc, null) && !Cast(bd.branchOf, Doc, null)?.embedContainer); // // so then remove all the deleted main docs from this branch. // remDocsFromMaster?.forEach(rd => Doc.RemoveDocFromList(branch, Doc.LayoutFieldKey(branch) + suffix, rd)); // } @@ -87,14 +87,14 @@ // branchDocProto.branchOf = masterChild; // the branch child is now a branch of the master child // } // Doc.AddDocToList(master, Doc.LayoutFieldKey(master) + suffix, masterChild); // add the masterChild to master (if it's already there, this is a no-op) -// masterChild.context = master; +// masterChild.embedContainer = master; // GitlikeSynchDocs(masterChild, bd);//Doc.GetProto(masterChild), bd); // })); // const masterChildren = await DocListCastAsync(master[Doc.LayoutFieldKey(master) + suffix]); // masterChildren?.forEach(mc => { // see if any master children // if (!branchChildren?.find(bc => bc.branchOf === mc)) { // are not in the list of children for this branch. // Doc.RemoveDocFromList(master, Doc.LayoutFieldKey(master) + suffix, mc); // if so, delete the master child since the branch has deleted it. -// mc.context = undefined; // NOTE if we merge a branch that didn't do a pull, it will look like the branch deleted documents -- need edit timestamps that prevent merging if branch isn't up-to-date with last edit timestamp +// mc.embedContainer = undefined; // NOTE if we merge a branch that didn't do a pull, it will look like the branch deleted documents -- need edit timestamps that prevent merging if branch isn't up-to-date with last edit timestamp // } // }); // }); @@ -109,8 +109,8 @@ // export async function BranchTask(target: Doc, action: "pull" | "merge") { // const func = action === "pull" ? GitlikePullFromMaster : GitlikeMergeWithMaster; // await func(target, ""); -// await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-annotations")); -// await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "-sidebar")); +// await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_annotations")); +// await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_sidebar")); // } // export async function BranchCreate(target: Doc) { diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index c9fcc84a3..d68761ba7 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -53,7 +53,7 @@ export class CaptureManager extends React.Component<{}> { order.push(
{i}
- {StrCast(DocCast(l.anchor1)?.title)} + {StrCast(DocCast(l.link_anchor_1)?.title)}
) ); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index fbfe306a4..5cfd77937 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -20,7 +20,7 @@ import { TreeViewType } from "../views/collections/CollectionTreeView"; import { DashboardView } from "../views/DashboardView"; import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; -import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; +import { ButtonType } from "../views/nodes/button/FontIconBox"; import { OpenWhere } from "../views/nodes/DocumentView"; import { OverlayView } from "../views/OverlayView"; import { DragManager } from "./DragManager"; @@ -37,7 +37,6 @@ interface Button { toolTip?: string; icon?: string; btnType?: ButtonType; - numBtnType?: NumButtonType; numBtnMin?: number; numBtnMax?: number; switchToggle?: boolean; @@ -65,11 +64,11 @@ export class CurrentUserUtils { const requiredTypeNameFields:{btnOpts:DocumentOptions, templateOpts:DocumentOptions, template:(opts:DocumentOptions) => Doc}[] = [ { btnOpts: { title: "slide", icon: "address-card" }, - templateOpts: { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, system: true }, + templateOpts: { _width: 400, _height: 300, title: "slideView", _xMargin: 3, _yMargin: 3, isSystem: true }, template: (opts:DocumentOptions) => Docs.Create.MultirowDocument( [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, system: true }), - Docs.Create.TextDocument("", { title: "text", _fitWidth:true, _height: 100, system: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, isSystem: true }), + Docs.Create.TextDocument("", { title: "text", _layout_fitWidth:true, _height: 100, isSystem: true, _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize) }) ], opts) }, { @@ -97,9 +96,9 @@ export class CurrentUserUtils { }); const reqdOpts:DocumentOptions = { - title: "Experimental Tools", _xMargin: 0, _showTitle: "title", _chromeHidden: true, - _stayInCollection: true, _hideContextMenu: true, _forceActive: true, system: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, + title: "Experimental Tools", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true, + _stayInCollection: true, _hideContextMenu: true, _forceActive: true, isSystem: true, + _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, }; const reqdScripts = { dropConverter : "convertToButtons(dragData)" }; const reqdFuncs = { hidden: "IsNoviceMode()" }; @@ -109,7 +108,7 @@ export class CurrentUserUtils { /// Initializes templates for editing click funcs of a document static setupChildClickEditors(doc: Doc, field = "clickFuncs-child") { const tempClicks = DocCast(doc[field]); - const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, system: true}; + const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true}; const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [ { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"}, { opts: { title: "Open Detail On Right", targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}]; @@ -119,14 +118,14 @@ export class CurrentUserUtils { return DocUtils.AssignOpts(clickDoc, allOpts) ?? Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, allOpts),allOpts); }); - const reqdOpts:DocumentOptions = { title: "child click editors", _height:75, system: true}; + const reqdOpts:DocumentOptions = { title: "child click editors", _height:75, isSystem: true}; return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts)); } /// Initializes templates for editing click funcs of a document static setupClickEditorTemplates(doc: Doc, field = "template-clickFuncs") { const tempClicks = DocCast(doc[field]); - const reqdClickOpts:DocumentOptions = { _width: 300, _height:200, system: true}; + const reqdClickOpts:DocumentOptions = { _width: 300, _height:200, isSystem: true}; const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [ { opts: { title: "onClick"}, script: "console.log('click')"}, { opts: { title: "onDoubleClick"}, script: "console.log('click')"}, @@ -140,7 +139,7 @@ export class CurrentUserUtils { return DocUtils.AssignOpts(clickDoc, allOpts) ?? MakeTemplate(Docs.Create.ScriptingDocument(ScriptField.MakeScript(opts.script, {heading:Doc.name, checked:"boolean", containingTreeView:Doc.name}), allOpts), true, opts.opts.title); }); - const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, system: true}; + const reqdOpts:DocumentOptions = {title: "click editor templates", _height:75, isSystem: true}; return DocUtils.AssignOpts(tempClicks, reqdOpts, reqdClickList) ?? (doc[field] = Docs.Create.TreeDocument(reqdClickList, reqdOpts)); } @@ -152,12 +151,12 @@ export class CurrentUserUtils { { noteType: "Idea", backgroundColor: "pink", icon: "lightbulb" }, { noteType: "Topic", backgroundColor: "lightblue", icon: "book-open" }]; const reqdNoteList = reqdTempOpts.map(opts => { - const reqdOpts = {...opts, title: "text", width:200, autoHeight: true, fitWidth: true}; + const reqdOpts = {...opts, title: "text", width:200, layout_autoHeight: true, layout_fitWidth: true}; const noteType = tempNotes ? DocListCast(tempNotes.data).find(doc => doc.noteType === opts.noteType): undefined; return DocUtils.AssignOpts(noteType, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts), true, opts.noteType??"Note"); }); - const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, system: true }; + const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; return DocUtils.AssignOpts(tempNotes, reqdOpts, reqdNoteList) ?? (doc[field] = Docs.Create.TreeDocument(reqdNoteList, reqdOpts)); } @@ -169,14 +168,14 @@ export class CurrentUserUtils { CurrentUserUtils.setupClickEditorTemplates(doc) ]; CurrentUserUtils.setupChildClickEditors(doc) - const reqdOpts = { title: "template layouts", _xMargin: 0, system: true, }; + const reqdOpts = { title: "template layouts", _xMargin: 0, isSystem: true, }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; return DocUtils.AssignDocField(doc, field, (opts,items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, templates, reqdScripts); } // setup templates for different document types when they are iconified from Document Decorations static setupDefaultIconTemplates(doc: Doc, field="template-icons") { - const reqdOpts = { title: "icon templates", _height: 75, system: true }; + const reqdOpts = { title: "icon templates", _height: 75, isSystem: true }; const templateIconsDoc = DocUtils.AssignOpts(DocCast(doc[field]), reqdOpts) ?? (doc[field] = Docs.Create.TreeDocument([], reqdOpts)); const makeIconTemplate = (type: DocumentType | undefined, templateField: string, opts:DocumentOptions) => { @@ -187,7 +186,7 @@ export class CurrentUserUtils { case DocumentType.IMG : creator = imageBox; break; case DocumentType.FONTICON: creator = fontBox; break; } - const allopts = {system: true, onClickScriptDisable: "never", ...opts}; + const allopts = {isSystem: true, onClickScriptDisable: "never", ...opts}; return DocUtils.AssignScripts( (curIcon?.iconTemplate === opts.iconTemplate ? DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts), true, iconFieldName, templateField))), {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", }); @@ -195,14 +194,14 @@ export class CurrentUserUtils { const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({ textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, 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, _showTitle: "title", ...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 }); const iconTemplates = [ makeIconTemplate(undefined, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "dimgray"}), makeIconTemplate(DocumentType.AUDIO, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "lightgreen"}), makeIconTemplate(DocumentType.PDF, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "pink"}), makeIconTemplate(DocumentType.WEB, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "brown"}), - makeIconTemplate(DocumentType.RTF, "text", { iconTemplate:DocumentType.LABEL, _showTitle: "creationDate"}), + makeIconTemplate(DocumentType.RTF, "text", { iconTemplate:DocumentType.LABEL, _layout_showTitle: "creationDate"}), makeIconTemplate(DocumentType.IMG, "data", { iconTemplate:DocumentType.IMG, _height: undefined}), makeIconTemplate(DocumentType.COL, "icon", { iconTemplate:DocumentType.IMG}), makeIconTemplate(DocumentType.COL, "icon", { iconTemplate:DocumentType.IMG}), @@ -220,7 +219,7 @@ export class CurrentUserUtils { title: string, toolTip: string, icon: string, ignoreClick?: boolean, dragFactory?: Doc, backgroundColor?: string, openFactoryAsDelegate?:boolean, openFactoryLocation?:string, clickFactory?: Doc, scripts?: { onClick?: string, onDragStart?: string}, funcs?: {onDragStart?:string, hidden?: string}, }[] { - const standardOps = (key:string) => ({ title : "Untitled "+ key, _fitWidth: false, system: true, "dragFactory-count": 0, cloneFieldFilter: new List(["system"]) }); + const standardOps = (key:string) => ({ title : "Untitled "+ key, _layout_fitWidth: false, isSystem: true, "dragFactory_count": 0, cloneFieldFilter: new List(["isSystem"]) }); const json = { doc: { type: "doc", @@ -247,7 +246,7 @@ export class CurrentUserUtils { "" + ` ` + " " + - ` Metadata` + + ` Metadata` + "" }, "header"); @@ -263,27 +262,27 @@ export class CurrentUserUtils { funcs?:{[key:string]: any}, // computed fields that are rquired for the empth thing creator:(opts:DocumentOptions)=> any // how to create the empty thing if it doesn't exist }[] = [ - {key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _autoHeight: true }}, - {key: "Flashcard", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _autoHeight: true, _showAltContentUI: true}}, - {key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, _backgroundGridShow: true, }}, - {key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200, _fitWidth: true}}, - {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _fitWidth: true }}, - {key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, useCors: true, }}, + {key: "Note", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _layout_autoHeight: true }}, + {key: "Flashcard", creator: opts => Docs.Create.TextDocument("", opts), opts: { _width: 200, _layout_autoHeight: true, _layout_altContentUI: true}}, + {key: "Equation", creator: opts => Docs.Create.EquationDocument(opts), opts: { _width: 300, _height: 35, }}, + {key: "Noteboard", creator: opts => Docs.Create.NoteTakingDocument([], opts), opts: { _width: 250, _height: 200, _layout_fitWidth: true}}, + {key: "Collection", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 150, _height: 100, _layout_fitWidth: true }}, + {key: "Webpage", creator: opts => Docs.Create.WebDocument("",opts), opts: { _width: 400, _height: 512, _nativeWidth: 850, data_useCors: true, }}, {key: "Comparison", creator: Docs.Create.ComparisonDocument, opts: { _width: 300, _height: 300 }}, {key: "Audio", creator: opts => Docs.Create.AudioDocument(nullAudio, opts),opts: { _width: 200, _height: 100, }}, - {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _fitWidth: true, _showSidebar: true, }}, + {key: "Map", creator: opts => Docs.Create.MapDocument([], opts), opts: { _width: 800, _height: 600, _layout_fitWidth: true, _layout_showSidebar: 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, system: true, cloneFieldFilter: new List(["system"]) }}, + {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, onClick: FollowLinkScript()}}, {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, _autoHeight: true, treeViewHideUnrendered: true}}, - {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "alias" as any, treeViewHideTitle: true, _fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }}, - {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _fitWidth: true, _backgroundGridShow: true, }}, + {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _layout_autoHeight: true, treeViewHideUnrendered: true}}, + {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _viewType: CollectionViewType.Stacking, targetDropAction: "embed" as any, treeViewHideTitle: true, _layout_fitWidth:true, _chromeHidden: true, boxShadow: "0 0" }}, + {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _viewType: CollectionViewType.Tree, - treeViewHasOverlay: true, _fontSize: "20px", _autoHeight: true, + treeViewHasOverlay: true, _fontSize: "20px", _layout_autoHeight: true, allowOverlayDrop: true, treeViewType: TreeViewType.outline, - backgroundColor: "white", _xMargin: 0, _yMargin: 0, _singleLine: true + backgroundColor: "white", _xMargin: 0, _yMargin: 0, _createDocOnCR: true }, funcs: {title: 'self.text?.Text'}}, ]; @@ -320,16 +319,16 @@ export class CurrentUserUtils { const btn = dragCreatorDoc ? DocListCast(dragCreatorDoc.data).find(doc => doc.title === reqdOpts.title): undefined; const opts:DocumentOptions = {...OmitKeys(reqdOpts, ["funcs", "scripts", "backgroundColor"]).omit, _width: 35, _height: 35, _hideContextMenu: true, _stayInCollection: true, - btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, system: true, + btnType: ButtonType.ToolButton, backgroundColor: reqdOpts.backgroundColor ?? Colors.DARK_GRAY, color: Colors.WHITE, isSystem: true, _removeDropProperties: new List(["_stayInCollection"]), }; return DocUtils.AssignScripts(DocUtils.AssignOpts(btn, opts) ?? Docs.Create.FontIconDocument(opts), reqdOpts.scripts, reqdOpts.funcs); }); const reqdOpts:DocumentOptions = { - title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, system: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, - childDropAction: 'alias' + title: "Basic Item Creators", _layout_showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, isSystem: true, + _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, + childDropAction: 'embed' }; const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; return DocUtils.AssignScripts(DocUtils.AssignOpts(dragCreatorDoc, reqdOpts, creatorBtns) ?? Docs.Create.MasonryDocument(creatorBtns, reqdOpts), reqdScripts); @@ -354,7 +353,7 @@ export class CurrentUserUtils { /// the empty panel that is filled with whichever left menu button's panel has been selected static setupLeftSidebarPanel(doc: Doc, field="myLeftSidebarPanel") { - DocUtils.AssignDocField(doc, field, (opts) => ((doc:Doc) => {doc.system = true; return doc;})(new Doc()), {system:true}); + DocUtils.AssignDocField(doc, field, (opts) => ((doc:Doc) => {doc.isSystem = true; return doc;})(new Doc()), {isSystem:true}); } /// Initializes the left sidebar menu buttons and the panels they open up @@ -364,8 +363,8 @@ export class CurrentUserUtils { const menuBtns = CurrentUserUtils.leftSidebarMenuBtnDescriptions(doc).map(({ title, target, icon, scripts, funcs }) => { const btnDoc = myLeftSidebarMenu ? DocListCast(myLeftSidebarMenu.data).find(doc => doc.title === title) : undefined; const reqdBtnOpts:DocumentOptions = { - title, icon, target, btnType: ButtonType.MenuButton, system: true, dontUndo: true, dontRegisterView: true, - _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + title, icon, target, btnType: ButtonType.MenuButton, isSystem: true, dontUndo: true, dontRegisterView: true, + _width: 60, _height: 60, _stayInCollection: true, _hideContextMenu: true, _removeDropProperties: new List(["_stayInCollection"]), }; return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), scripts, funcs); @@ -373,14 +372,14 @@ export class CurrentUserUtils { const reqdStackOpts:DocumentOptions ={ title: "menuItemPanel", childDropAction: "same", backgroundColor: Colors.DARK_GRAY, boxShadow: "rgba(0,0,0,0)", dontRegisterView: true, ignoreClick: true, - _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, system: true, + _chromeHidden: true, _gridGap: 0, _yMargin: 0, _yPadding: 0, _xMargin: 0, _layout_autoHeight: false, _width: 60, _columnWidth: 60, _lockedPosition: true, isSystem: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdStackOpts, menuBtns, { dropConverter: "convertToButtons(dragData)" }); } // Sets up mobile menu if it is undefined creates a new one, otherwise returns existing menu static setupActiveMobileMenu(doc: Doc, field="activeMobileMenu") { - const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, system: true, _chromeHidden: true,}; + const reqdOpts = { _width: 980, ignoreClick: true, _lockedPosition: false, title: "home", _yMargin: 100, isSystem: true, _chromeHidden: true,}; DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(this.setupMobileButtons(), opts), reqdOpts); } @@ -401,9 +400,9 @@ export class CurrentUserUtils { title: data.title, _lockedPosition: true, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, - backgroundColor: data.backgroundColor, system: true + backgroundColor: data.backgroundColor, isSystem: true }, - [this.createToolButton({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", system: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])]) + [this.createToolButton({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)", isSystem: true, btnType: ButtonType.ClickButton, }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])]) ); } @@ -411,51 +410,51 @@ export class CurrentUserUtils { static mobileButton = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MulticolumnDocument(docs, { ...opts, _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15, - borderRounding: "5px", boxShadow: "0 0", system: true + borderRounding: "5px", boxShadow: "0 0", isSystem: true }) as any as Doc // sets up the text container for the information contained within the mobile button static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.MultirowDocument(docs, { ...opts, _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25, - backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, system: true + backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", ignoreClick: true, isSystem: true }) as any as Doc // Sets up the title of the button static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => Docs.Create.TextDocument(buttonTitle, { ...opts, - title: buttonTitle, _fontSize: "37px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", system: true + title: buttonTitle, _fontSize: "37px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", isSystem: true }) as any as Doc // Sets up the description of the button static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => Docs.Create.TextDocument(buttonInfo, { ...opts, - title: "info", _fontSize: "25px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, system: true + title: "info", _fontSize: "25px", _xMargin: 0, _yMargin: 0, ignoreClick: true, backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, isSystem: true }) as any as Doc static setupMobileInkingDoc(userDoc: Doc) { - return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white", system: true }); + return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white", isSystem: true }); } static setupMobileUploadDoc(userDoc: Doc) { // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" }) const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", { - title: "Upload Images From the Web", _lockedPosition: true, system: true + title: "Upload Images From the Web", _lockedPosition: true, isSystem: true }); const uploadDoc = Docs.Create.StackingDocument([], { - title: "Mobile Upload Collection", backgroundColor: "white", _lockedPosition: true, system: true, _chromeHidden: true, + title: "Mobile Upload Collection", backgroundColor: "white", _lockedPosition: true, isSystem: true, _chromeHidden: true, }); return Docs.Create.StackingDocument([webDoc, uploadDoc], { - _width: screen.width, _lockedPosition: true, title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray", system: true, _chromeHidden: true, + _width: screen.width, _lockedPosition: true, title: "Upload", _layout_autoHeight: true, _yMargin: 80, backgroundColor: "lightgray", isSystem: true, _chromeHidden: true, }); } /// Search option on the left side button panel static setupSearcher(doc: Doc, field:string) { return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.SearchDocument(opts), { - dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", system: true, childDropAction: "alias", + dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, title: "Search Panel", isSystem: true, childDropAction: "embed", _lockedPosition: true, _viewType: CollectionViewType.Schema, _searchDoc: true, }); } @@ -465,8 +464,8 @@ export class CurrentUserUtils { const creatorBtns = CurrentUserUtils.setupCreatorButtons(doc, DocListCast(myTools?.data)?.length ? DocListCast(myTools.data)[0]:undefined); const templateBtns = CurrentUserUtils.setupExperimentalTemplateButtons(doc,DocListCast(myTools?.data)?.length > 1 ? DocListCast(myTools.data)[1]:undefined); const reqdToolOps:DocumentOptions = { - title: "My Tools", system: true, ignoreClick: true, boxShadow: "0 0", - _showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, + title: "My Tools", isSystem: true, ignoreClick: true, boxShadow: "0 0", + _layout_showTitle: "title", _width: 500, _yMargin: 20, _lockedPosition: true, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, }; return DocUtils.AssignDocField(doc, field, (opts, items) => Docs.Create.StackingDocument(items??[], opts), reqdToolOps, [creatorBtns, templateBtns]); } @@ -479,7 +478,7 @@ export class CurrentUserUtils { const newDashboard = `createNewDashboard()`; const reqdBtnOpts:DocumentOptions = { _forceActive: true, _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, - title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", system: true }; + title: "new dashboard", btnType: ButtonType.ClickButton, toolTip: "Create new dashboard", buttonText: "New trail", icon: "plus", isSystem: true }; const reqdBtnScript = {onClick: newDashboard,} const newDashboardButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myDashboards?.buttonMenuDoc), reqdBtnOpts) ?? Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); @@ -492,9 +491,9 @@ export class CurrentUserUtils { const childContextMenuIcons = ["chalkboard", "tv", "camera", "users", "times", "trash"]; // entries must be kept in synch with childContextMenuScripts, childContextMenuLabels, and childContextMenuFilters const reqdOpts:DocumentOptions = { title: "My Dashboards", childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, boxShadow: "0 0", childDontRegisterViews: true, - targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, system: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, - buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "alias", - _showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, + targetDropAction: "same", treeViewType: TreeViewType.fileSystem, isFolder: true, isSystem: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, + buttonMenu: true, buttonMenuDoc: newDashboardButton, childDropAction: "embed", + _layout_showTitle: "title", _height: 400, _gridGap: 5, _forceActive: true, _lockedPosition: true, contextMenuLabels:new List(contextMenuLabels), contextMenuIcons:new List(contextMenuIcons), childContextMenuLabels:new List(childContextMenuLabels), @@ -517,20 +516,20 @@ export class CurrentUserUtils { /// initializes the left sidebar File system pane static setupFilesystem(doc: Doc, field:string) { var myFilesystem = DocCast(doc[field]); - const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", _stayInCollection: true, system: true, isFolder: true }); + const myFileOrphans = DocUtils.AssignDocField(doc, "myFileOrphans", (opts) => Docs.Create.TreeDocument([], opts), { title: "Unfiled", _stayInCollection: true, isSystem: true, isFolder: true }); const newFolder = `TreeView_addNewFolder()`; const newFolderOpts: DocumentOptions = { _forceActive: true, _stayInCollection: true, _hideContextMenu: true, _width: 30, _height: 30, - title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", system: true + title: "New folder", btnType: ButtonType.ClickButton, toolTip: "Create new folder", buttonText: "New folder", icon: "folder-plus", isSystem: true }; const newFolderScript = { onClick: newFolder}; const newFolderButton = DocUtils.AssignScripts(DocUtils.AssignOpts(DocCast(myFilesystem?.buttonMenuDoc), newFolderOpts) ?? Docs.Create.FontIconDocument(newFolderOpts), newFolderScript); - const reqdOpts:DocumentOptions = { _showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, - title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", system: true, + const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _height: 100, _gridGap: 5, _forceActive: true, _lockedPosition: true, + title: "My Documents", buttonMenu: true, buttonMenuDoc: newFolderButton, treeViewHideTitle: true, targetDropAction: "proto", isSystem: true, isFolder: true, treeViewType: TreeViewType.fileSystem, childHideLinkButton: true, boxShadow: "0 0", childDontRegisterViews: true, - treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "alias", + treeViewTruncateTitleWidth: 350, ignoreClick: true, childDropAction: "embed", childContextMenuLabels: new List(["Create new folder"]), childContextMenuIcons: new List(["plus"]), explainer: "This is your file manager where you can create folders to keep track of documents independently of your dashboard." @@ -545,8 +544,8 @@ export class CurrentUserUtils { /// initializes the panel displaying docs that have been recently closed static setupRecentlyClosed(doc: Doc, field:string) { - const reqdOpts:DocumentOptions = { _showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, - title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "alias", system: true, + const reqdOpts:DocumentOptions = { _layout_showTitle: "title", _lockedPosition: true, _gridGap: 5, _forceActive: true, + title: "My Recently Closed", buttonMenu: true, childHideLinkButton: true, treeViewHideTitle: true, childDropAction: "embed", isSystem: true, treeViewTruncateTitleWidth: 350, ignoreClick: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", contextMenuLabels: new List(["Empty recently closed"]), contextMenuIcons:new List(["trash"]), @@ -556,7 +555,7 @@ export class CurrentUserUtils { const clearAll = (target:string) => `getProto(${target}).data = new List([])`; const clearBtnsOpts:DocumentOptions = { _width: 30, _height: 30, _forceActive: true, _stayInCollection: true, _hideContextMenu: true, - title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, buttonText: "Empty", icon: "trash", system: true, + title: "Empty", target: recentlyClosed, btnType: ButtonType.ClickButton, buttonText: "Empty", icon: "trash", isSystem: true, toolTip: "Empty recently closed",}; const clearDocsButton = DocUtils.AssignDocField(recentlyClosed, "clearDocsBtn", (opts) => Docs.Create.FontIconDocument(opts), clearBtnsOpts, undefined, {onClick: clearAll("self.target")}); @@ -572,7 +571,7 @@ export class CurrentUserUtils { static setupUserDocView(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { _lockedPosition: true, _gridGap: 5, _forceActive: true, title: Doc.CurrentUserEmail +"-view", - boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, system: true, + boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", ignoreClick: true, isSystem: true, treeViewHideTitle: true, treeViewTruncateTitleWidth: 350 }; if (!doc[field]) DocUtils.AssignOpts(doc, {treeViewOpen: true, treeViewExpandedView: "fields" }); @@ -582,13 +581,13 @@ export class CurrentUserUtils { static linearButtonList = (opts: DocumentOptions, docs: Doc[]) => Docs.Create.LinearDocument(docs, { ...opts, _gridGap: 0, _xMargin: 5, _yMargin: 5, boxShadow: "0 0", _forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - _lockedPosition: true, system: true, flexDirection: "row" + _lockedPosition: true, isSystem: true, flexDirection: "row" }) static createToolButton = (opts: DocumentOptions) => Docs.Create.FontIconDocument({ btnType: ButtonType.ToolButton, _forceActive: true, _hideContextMenu: true, _removeDropProperties: new List([ "_hideContextMenu", "stayInCollection"]), - _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true, ...opts, + _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, isSystem: true, ...opts, }) /// initializes the required buttons in the expanding button menu at the bottom of the Dash window @@ -606,7 +605,7 @@ export class CurrentUserUtils { ]; const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts)); const dockBtnsReqdOpts:DocumentOptions = { - title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'alias', + title: "docked buttons", _height: 40, flexGap: 0, boxShadow: "standard", childDropAction: 'embed', childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true }; reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(btns.find(btn => btn.title === "redo")!).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); @@ -623,7 +622,7 @@ export class CurrentUserUtils { } static viewTools(): Button[] { return [ - { title: "Snap\xA0Lines", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snap lines", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform + { title: "Snap\xA0Lines", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"grid", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform { title: "View\xA0All", icon: "object-group", toolTip: "Fit all Docs to View",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"viewAll", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform { title: "Clusters", icon: "braille", toolTip: "Show Doc Clusters", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"clusters", funcs: {}, scripts: { onClick: 'showFreeform(self.toolType, _readOnly_)'}}, // Only when floating document is selected in freeform @@ -635,7 +634,7 @@ export class CurrentUserUtils { return [ { title: "Font", toolTip: "Font", width: 100, btnType: ButtonType.DropdownList, toolType:"font", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, btnList: new List(["Roboto", "Roboto Mono", "Nunito", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]) }, - { title: "Size", toolTip: "Font size (%size)", btnType: ButtonType.NumberButton, width: 75, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0, numBtnType: NumButtonType.DropdownOptions }, + { title: "Size", toolTip: "Font size (%size)", btnType: ButtonType.NumberDropdownButton, width: 75, toolType:"fontSize", ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}, numBtnMax: 200, numBtnMin: 0 }, { title: "Color", toolTip: "Font color (%color)", btnType: ButtonType.ColorButton, icon: "font", toolType:"fontColor",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'}}, { title: "Highlight",toolTip:"Font highlight", btnType: ButtonType.ColorButton, icon: "highlighter", toolType:"highlight",ignoreClick: true, scripts: {script: '{ return setFontAttr(self.toolType, value, _readOnly_);}'},funcs: {hidden: "IsNoviceMode()"} }, { title: "Bold", toolTip: "Bold (Ctrl+B)", btnType: ButtonType.ToggleButton, icon: "bold", toolType:"bold", scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} }, @@ -663,7 +662,7 @@ export class CurrentUserUtils { { title: "Square", toolTip: "Square (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "square", toolType:GestureUtils.Gestures.Rectangle, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, { title: "Line", toolTip: "Line (double tap to lock mode)", btnType: ButtonType.ToggleButton, icon: "minus", toolType:GestureUtils.Gestures.Line, scripts: {onClick:`{ return setActiveTool(self.toolType, false, _readOnly_);}`, onDoubleClick:`{ return setActiveTool(self.toolType, true, _readOnly_);}`} }, { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle",toolType: "inkMask", scripts: {onClick:'{ return setInkProperty(self.toolType, value, _readOnly_);}'} }, - { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnType: NumButtonType.Slider, numBtnMin: 1}, + { title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: "strokeWidth", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'}, numBtnMin: 1}, { title: "Ink", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: "strokeColor", ignoreClick: true, scripts: {script: '{ return setInkProperty(self.toolType, value, _readOnly_);}'} }, ]; } @@ -712,7 +711,7 @@ export class CurrentUserUtils { const reqdOpts:DocumentOptions = { ...OmitKeys(params, ["scripts", "funcs", "subMenu"]).omit, backgroundColor: params.backgroundColor ??"transparent", /// a bit hacky. if an onClick is specified, then assume a toggle uses onClick to get the backgroundColor (see below). Otherwise, assume a transparent background - color: Colors.WHITE, system: true, dontUndo: true, + color: Colors.WHITE, isSystem: true, dontUndo: true, _nativeWidth: params.width ?? 30, _width: params.width ?? 30, _height: 30, _nativeHeight: 30, linearBtnWidth: params.linearBtnWidth, toolType: params.toolType, expertMode: params.expertMode, @@ -728,7 +727,7 @@ export class CurrentUserUtils { /// Initializes all the default buttons for the top bar context menu static setupContextMenuButtons(doc: Doc, field="myContextMenuBtns") { - const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'alias', childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; + const reqdCtxtOpts:DocumentOptions = { title: "context menu buttons", flexGap: 0, childDropAction: 'embed', childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 }; const ctxtMenuBtnsDoc = DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), reqdCtxtOpts, undefined); const ctxtMenuBtns = CurrentUserUtils.contextMenuTools().map(params => { const menuBtnDoc = DocListCast(ctxtMenuBtnsDoc?.data).find(doc => doc.title === params.title); @@ -750,11 +749,11 @@ export class CurrentUserUtils { /// collection of documents rendered in the overlay layer above all tabs and other UI static setupOverlays(doc: Doc, field = "myOverlayDocs") { - return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", system: true }); + return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", isSystem: true }); } static setupPublished(doc:Doc, field = "myPublishedDocs") { - return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", system: true }); + return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", isSystem: true }); } /// The database of all links on all documents @@ -788,9 +787,9 @@ export class CurrentUserUtils { childContextMenuLabels: new List(["Add to Dashboards",]), childContextMenuIcons: new List(["user-plus",]), "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment, - childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, - // NOTE: treeViewHideTitle & _showTitle is for a TreeView's editable title, _showTitle is for DocumentViews title bar - _showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, + childDropAction: "embed", isSystem: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 0, _gridGap: 15, childDontRegisterViews:true, + // NOTE: treeViewHideTitle & _layout_showTitle is for a TreeView's editable title, _layout_showTitle is for DocumentViews title bar + _layout_showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true, explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'" }; @@ -800,16 +799,16 @@ export class CurrentUserUtils { /// Import option on the left side button panel static setupImportSidebar(doc: Doc, field:string) { const reqdOpts:DocumentOptions = { - title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _showTitle: "title", + title: "My Imports", _forceActive: true, buttonMenu: true, ignoreClick: true, _layout_showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0, - childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true, + childDropAction: "copy", _layout_autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, isSystem: true, _chromeHidden: true, dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go." }; const myImports = DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.StackingDocument([], opts), reqdOpts); const reqdBtnOpts:DocumentOptions = { _forceActive: true, toolTip: "Import from computer", _width: 30, _height: 30, _stayInCollection: true, _hideContextMenu: true, title: "Import", btnType: ButtonType.ClickButton, - buttonText: "Import", icon: "upload", system: true }; + buttonText: "Import", icon: "upload", isSystem: true }; DocUtils.AssignDocField(myImports, "buttonMenuDoc", (opts) => Docs.Create.FontIconDocument(opts), reqdBtnOpts, undefined, { onClick: "importDocument()" }); return myImports; } @@ -818,13 +817,13 @@ export class CurrentUserUtils { /// whether to revert to "default" values, or to leave them as the user/system last set them. static updateUserDocument(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) { DocUtils.AssignDocField(doc, "globalGroupDatabase", () => Docs.Prototypes.MainGroupDocument(), {}); - reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data-lastModified"]), + reaction(() => DateCast(DocCast(doc.globalGroupDatabase)["data_modificationDate"]), async () => { const groups = await DocListCastAsync(DocCast(doc.globalGroupDatabase).data); const mygroups = groups?.filter(group => JSON.parse(StrCast(group.members)).includes(Doc.CurrentUserEmail)) || []; SetCachedGroups(["Public", ...mygroups?.map(g => StrCast(g.title))]); }, { fireImmediately: true }); - doc.system ?? (doc.system = true); + doc.isSystem ?? (doc.isSystem = true); doc.title ?? (doc.title = Doc.CurrentUserEmail); Doc.noviceMode ?? (Doc.noviceMode = true); doc._raiseWhenDragged ?? (doc._raiseWhenDragged = true); @@ -860,7 +859,7 @@ export class CurrentUserUtils { this.setupDocTemplates(doc); // sets up the template menu of templates this.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", (opts) => Docs.Prototypes.MainScriptDocument(), {}); - DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", system: true }); // drop down panel at top of dashboard for stashing documents + DocUtils.AssignDocField(doc, "myHeaderBar", (opts) => Docs.Create.MulticolumnDocument([], opts), { title: "header bar", isSystem: true }); // drop down panel at top of dashboard for stashing documents Doc.AddDocToList(Doc.MyFilesystem, undefined, Doc.MySharedDocs) @@ -874,13 +873,13 @@ export class CurrentUserUtils { return doc; } static setupFieldInfos(doc:Doc, field="fieldInfos") { - const fieldInfoOpts = { title: "Field Infos", system: true}; // bcz: all possible document options have associated field infos which are stored onn the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object + const fieldInfoOpts = { title: "Field Infos", isSystem: true}; // bcz: all possible document options have associated field infos which are stored onn the FieldInfos document **except for title and system which are used as part of the definition of the fieldInfos object const infos = DocUtils.AssignDocField(doc, field, opts => Doc.assign(new Doc(), opts as any), fieldInfoOpts); const entries = Object.entries(new DocumentOptions()); entries.forEach(pair => { if (!Array.from(Object.keys(fieldInfoOpts)).includes(pair[0])) { const options = pair[1] as FInfo; - const opts:DocumentOptions = { system: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")}; + const opts:DocumentOptions = { isSystem: true, title: pair[0], ...OmitKeys(options, ["values"]).omit, fieldIsLayout: pair[0].startsWith("_")}; switch (options.fieldType) { case "boolean": opts.fieldValues = new List(options.values as any); break; case "number": opts.fieldValues = new List(options.values as any); break; diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index e116ae14b..1cce21034 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -327,7 +327,7 @@ export namespace DictationManager { 'new outline', { action: (target: DocumentView) => { - const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _autoHeight: true }); + const newBox = Docs.Create.TextDocument('', { _width: 400, _height: 200, title: 'My Outline', _layout_autoHeight: true }); const proto = newBox.proto!; const prompt = 'Press alt + r to start dictating here...'; const head = 3; diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 695b003a6..6eed4dc86 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -69,12 +69,12 @@ export class DocumentManager { public AddView = (view: DocumentView) => { //console.log("MOUNT " + view.props.Document.title + "/" + view.props.LayoutTemplateString); if (view.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const viewAnchorIndex = view.props.LayoutTemplateString.includes('anchor2') ? 'anchor2' : 'anchor1'; + const viewAnchorIndex = view.props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1'; const link = view.rootDoc; this.LinkAnchorBoxViews?.filter(dv => Doc.AreProtosEqual(dv.rootDoc, link) && !dv.props.LayoutTemplateString?.includes(viewAnchorIndex)).forEach(otherView => this.LinkedDocumentViews.push({ - a: viewAnchorIndex === 'anchor2' ? otherView : view, - b: viewAnchorIndex === 'anchor2' ? view : otherView, + a: viewAnchorIndex === 'link_anchor_2' ? otherView : view, + b: viewAnchorIndex === 'link_anchor_2' ? view : otherView, l: link, }) ); @@ -173,7 +173,7 @@ export class DocumentManager { // heuristic to return the "best" documents first: // choose a document in the lightbox first - // choose an exact match over an alias match + // choose an exact match over an embedding match lightViews.map(view => view.rootDoc === toFind && toReturn.push(view)); lightViews.map(view => view.rootDoc !== toFind && Doc.AreProtosEqual(view.rootDoc, toFind) && toReturn.push(view)); docViews.map(view => view.rootDoc === toFind && toReturn.push(view)); @@ -184,15 +184,15 @@ export class DocumentManager { static GetContextPath(doc: Opt, includeExistingViews?: boolean) { if (!doc) return []; - const srcContext = DocCast(doc.annotationOn, DocCast(doc.context)); + const srcContext = DocCast(doc.annotationOn, DocCast(doc.embedContainer)); var containerDocContext = srcContext ? [srcContext, doc] : [doc]; while ( containerDocContext.length && - containerDocContext[0]?.context && - DocCast(containerDocContext[0].context)?.viewType !== CollectionViewType.Docking && + containerDocContext[0]?.embedContainer && + DocCast(containerDocContext[0].embedContainer)?.viewType !== CollectionViewType.Docking && (includeExistingViews || !DocumentManager.Instance.getDocumentView(containerDocContext[0])) ) { - containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext]; + containerDocContext = [Cast(containerDocContext[0].embedContainer, Doc, null), ...containerDocContext]; } return containerDocContext; } @@ -256,7 +256,7 @@ export class DocumentManager { if (options.openLocation === OpenWhere.lightbox) { // 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.context)); + const contextView = this.getDocumentView(DocCast(target.embedContainer)); if (contextView?.docView?._componentView?.addDocTab?.(target, OpenWhere.lightbox)) { await new Promise(waitres => setTimeout(() => waitres())); } @@ -275,7 +275,7 @@ export class DocumentManager { focusViewsInPath = async (docView: DocumentView, options: DocFocusOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt; childDocView: Opt }>) => { let contextView: DocumentView | undefined; // view containing context that contains target while (true) { - docView.rootDoc.layoutKey === 'layout_icon' ? await new Promise(res => docView.iconify(res)) : undefined; + docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise(res => docView.iconify(res)) : undefined; docView.props.focus(docView.rootDoc, options); // focus the view within its container const { childDocView, viewSpec } = await iterator(docView); if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView }; @@ -315,7 +315,7 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) { DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc)); } else { - const container = DocCast(containingDoc ?? doc.context); + const container = DocCast(containingDoc ?? doc.embedContainer); const showDoc = !Doc.IsSystem(container) ? container : doc; options.toggleTarget = undefined; DocumentManager.Instance.showDocument(showDoc, options, () => DocumentManager.Instance.showDocument(doc, { ...options, openLocation: undefined })).then(() => { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index b6de5604d..070e0f918 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager'; import { SnappingManager } from './SnappingManager'; import { UndoManager } from './UndoManager'; -export type dropActionType = 'alias' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties +export type dropActionType = 'embed' | 'copy' | 'move' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call removeDropProperties /** * Initialize drag @@ -131,7 +131,7 @@ export namespace DragManager { canEmbed?: boolean; userDropAction: dropActionType; // the user requested drop action -- this will be honored as specified by modifier keys defaultDropAction?: dropActionType; // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action - dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move' + dropAction: dropActionType; // a drop action request by the initiating code. the actual drop action may be different -- eg, if the request is 'embed', but the document is dropped within the same collection, the drop action will be switched to 'move' removeDropProperties?: string[]; moveDocument?: MoveFunction; removeDocument?: RemoveFunction; @@ -193,7 +193,7 @@ export namespace DragManager { }; } - // drag a document and drop it (or make an alias/copy on drop) + // drag a document and drop it (or make an embed/copy on drop) export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions, dropEvent?: () => any) { const addAudioTag = (dropDoc: any) => { dropDoc && !dropDoc.creationDate && (dropDoc.creationDate = new DateField()); @@ -210,8 +210,8 @@ export namespace DragManager { dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) - : docDragData.dropAction === 'alias' - ? Doc.BestAlias(d) + : docDragData.dropAction === 'embed' + ? Doc.BestEmbedding(d) : docDragData.dropAction === 'proto' ? Doc.GetProto(d) : docDragData.dropAction === 'copy' @@ -487,7 +487,7 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop if (dragData instanceof DocumentDragData) { - dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'alias' : dragData.defaultDropAction; + dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'embed' : dragData.defaultDropAction; } if (((e.target as any)?.className === 'lm_tabs' || (e.target as any)?.className === 'lm_header' || e?.shiftKey) && dragData.draggedDocuments.length === 1) { if (!startWindowDragTimer) { diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 2e1d6ba23..f46ea393a 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -58,8 +58,8 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) { // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes('FontIconBox')) { if (data.removeDropProperties || dbox.removeDropProperties) { - //dbox = Doc.MakeAlias(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon - dbox = Doc.MakeAlias(dbox); + //dbox = Doc.MakeEmbedding(doc); // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon + dbox = Doc.MakeEmbedding(dbox); const dragProps = Cast(dbox.removeDropProperties, listSpec('string'), []); const remProps = (data.removeDropProperties || []).concat(Array.from(dragProps)); remProps.map(prop => (dbox[prop] = undefined)); diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index c8b784390..da947aba6 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -155,7 +155,7 @@ export class GroupManager extends React.Component<{}> { addGroup(groupDoc: Doc): boolean { if (this.GroupManagerDoc) { Doc.AddDocToList(this.GroupManagerDoc, 'data', groupDoc); - this.GroupManagerDoc['data-lastModified'] = new DateField(); + this.GroupManagerDoc['data_modificationDate'] = new DateField(); return true; } return false; @@ -176,7 +176,7 @@ export class GroupManager extends React.Component<{}> { const index = DocListCast(this.GroupManagerDoc.data).findIndex(grp => grp === group); index !== -1 && Cast(this.GroupManagerDoc.data, listSpec(Doc), [])?.splice(index, 1); } - this.GroupManagerDoc['data-lastModified'] = new DateField(); + this.GroupManagerDoc['data_modificationDate'] = new DateField(); if (group === this.currentGroup) { this.currentGroup = undefined; } @@ -197,7 +197,7 @@ export class GroupManager extends React.Component<{}> { !memberList.includes(email) && memberList.push(email); groupDoc.members = JSON.stringify(memberList); SharingManager.Instance.shareWithAddedMember(groupDoc, email); - this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField()); + this.GroupManagerDoc && (this.GroupManagerDoc['data_modificationDate'] = new DateField()); } } @@ -214,7 +214,7 @@ export class GroupManager extends React.Component<{}> { const user = memberList.splice(index, 1)[0]; groupDoc.members = JSON.stringify(memberList); SharingManager.Instance.removeMember(groupDoc, email); - this.GroupManagerDoc && (this.GroupManagerDoc['data-lastModified'] = new DateField()); + this.GroupManagerDoc && (this.GroupManagerDoc['data_modificationDate'] = new DateField()); } } } diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 297520d5d..151f18d6f 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -20,7 +20,7 @@ export namespace Hypothesis { export const getSourceWebDoc = async (uri: string) => { const result = await findWebDoc(uri); console.log(result ? 'existing doc found' : 'existing doc NOT found'); - return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, useCors: true }); // create and return a new Web doc with given uri if no matching docs are found + return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, data_useCors: true }); // create and return a new Web doc with given uri if no matching docs are found }; /** diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index 9bd92a316..55d37f544 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,12 +1,11 @@ -import { Doc } from "../../../fields/Doc"; -import { ImageField } from "../../../fields/URLField"; -import { Cast, StrCast, NumCast } from "../../../fields/Types"; -import { Networking } from "../../Network"; -import { Id } from "../../../fields/FieldSymbols"; -import { Utils } from "../../../Utils"; +import { Doc } from '../../../fields/Doc'; +import { ImageField } from '../../../fields/URLField'; +import { Cast, StrCast, NumCast } from '../../../fields/Types'; +import { Networking } from '../../Network'; +import { Id } from '../../../fields/FieldSymbols'; +import { Utils } from '../../../Utils'; export namespace ImageUtils { - export const ExtractExif = async (document: Doc): Promise => { const field = Cast(document.data, ImageField); if (!field) { @@ -17,23 +16,22 @@ export namespace ImageUtils { contentSize, nativeWidth, nativeHeight, - exifData: { error, data } - } = await Networking.PostToServer("/inspectImage", { source }); + exifData: { error, data }, + } = await Networking.PostToServer('/inspectImage', { source }); document.exif = error || Doc.Get.FromJson({ data }); const proto = Doc.GetProto(document); - nativeWidth && (document._height = NumCast(document._width) * nativeHeight / nativeWidth); - proto["data-nativeWidth"] = nativeWidth; - proto["data-nativeHeight"] = nativeHeight; - proto["data-path"] = source; - proto.contentSize = contentSize ? contentSize : undefined; + nativeWidth && (document._height = (NumCast(document._width) * nativeHeight) / nativeWidth); + proto['data_nativeWidth'] = nativeWidth; + proto['data_nativeHeight'] = nativeHeight; + proto['data-path'] = source; + proto.data_contentSize = contentSize ? contentSize : undefined; return data !== undefined; }; export const ExportHierarchyToFileSystem = async (collection: Doc): Promise => { - const a = document.createElement("a"); + const a = document.createElement('a'); a.href = Utils.prepend(`/imageHierarchyExport/${collection[Id]}`); a.download = `Dash Export [${StrCast(collection.title)}].zip`; a.click(); }; - -} \ No newline at end of file +} diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 9591dbed3..043f0f1f3 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -161,6 +161,7 @@ export namespace InteractionUtils { diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index ba2edb65c..246f5bb8c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -12,8 +12,8 @@ import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; /* * link doc: - * - anchor1: doc - * - anchor2: doc + * - link_anchor_1: doc + * - link_anchor_2: doc * * group doc: * - type: string representing the group type/name/category @@ -43,10 +43,10 @@ export class LinkFollower { public static traverseLink(link: Opt, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) { const linkDocs = link ? [link] : LinkManager.Links(sourceDoc); - const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1 - const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2 - const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor2 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor2 as Doc).annotationOn) : (d.anchor2 as Doc)).length === 0); - const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor1 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor1 as Doc).annotationOn) : (d.anchor1 as Doc)).length === 0); + const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.link_anchor_1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is link_anchor_1 + const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.link_anchor_2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.link_anchor_2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is link_anchor_2 + const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.link_anchor_2 as Doc).type === DocumentType.MARKER ? DocCast((d.link_anchor_2 as Doc).annotationOn) : (d.link_anchor_2 as Doc)).length === 0); + const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews((d.link_anchor_1 as Doc).type === DocumentType.MARKER ? DocCast((d.link_anchor_1 as Doc).annotationOn) : (d.link_anchor_1 as Doc)).length === 0); const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView; const linkDocList = linkWithoutTargetDoc && !sourceDoc.followAllLinks ? [linkWithoutTargetDoc] : traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs; const followLinks = sourceDoc.followLinkToggle || sourceDoc.followAllLinks ? linkDocList : linkDocList.slice(0, 1); @@ -55,13 +55,13 @@ export class LinkFollower { if (!followLinks.length) finished?.(); followLinks.forEach(async linkDoc => { const target = ( - sourceDoc === linkDoc.anchor1 - ? linkDoc.anchor2 - : sourceDoc === linkDoc.anchor2 - ? linkDoc.anchor1 - : Doc.AreProtosEqual(sourceDoc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc) - ? linkDoc.anchor2 - : linkDoc.anchor1 + sourceDoc === linkDoc.link_anchor_1 + ? linkDoc.link_anchor_2 + : sourceDoc === linkDoc.link_anchor_2 + ? linkDoc.link_anchor_1 + : Doc.AreProtosEqual(sourceDoc, linkDoc.link_anchor_1 as Doc) || Doc.AreProtosEqual((linkDoc.link_anchor_1 as Doc).annotationOn as Doc, sourceDoc) + ? linkDoc.link_anchor_2 + : linkDoc.link_anchor_1 ) as Doc; if (target) { const doFollow = (canToggle?: boolean) => { @@ -92,16 +92,16 @@ export class LinkFollower { }; let movedTarget = false; if (sourceDoc.followLinkLocation === OpenWhere.inParent) { - const sourceDocParent = DocCast(sourceDoc.context); - if (target.context instanceof Doc && target.context !== sourceDocParent) { - Doc.RemoveDocFromList(target.context, Doc.LayoutFieldKey(target.context), target); + const sourceDocParent = DocCast(sourceDoc.embedContainer); + if (target.embedContainer instanceof Doc && target.embedContainer !== sourceDocParent) { + Doc.RemoveDocFromList(target.embedContainer, Doc.LayoutFieldKey(target.embedContainer), target); movedTarget = true; } if (!DocListCast(sourceDocParent[Doc.LayoutFieldKey(sourceDocParent)]).includes(target)) { Doc.AddDocToList(sourceDocParent, Doc.LayoutFieldKey(sourceDocParent), target); movedTarget = true; } - target.context = sourceDocParent; + target.embedContainer = sourceDocParent; const moveTo = [NumCast(sourceDoc.x) + NumCast(sourceDoc.followLinkXoffset), NumCast(sourceDoc.y) + NumCast(sourceDoc.followLinkYoffset)]; if (sourceDoc.followLinkXoffset !== undefined && moveTo[0] !== target.x) { target.x = moveTo[0]; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 555215417..5e6107e5f 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -7,8 +7,8 @@ import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types'; import { ScriptingGlobals } from './ScriptingGlobals'; /* * link doc: - * - anchor1: doc - * - anchor2: doc + * - link_anchor_1: doc + * - link_anchor_2: doc * * group doc: * - type: string representing the group type/name/category @@ -33,7 +33,7 @@ export class LinkManager { await Promise.all( ((await DocListCastAsync(linkDb.data)) ?? []).map(link => // makes sure link anchors are loaded to avoid incremental updates to computedFns in LinkManager - [PromiseValue(link?.anchor1), PromiseValue(link?.anchor2)] + [PromiseValue(link?.link_anchor_1), PromiseValue(link?.link_anchor_2)] ) ); LinkManager.userLinkDBs.push(linkDb); @@ -42,13 +42,13 @@ export class LinkManager { static _links: Doc[] = []; constructor() { LinkManager._instance = this; - this.createLinkrelationshipLists(); + this.createlink_relationshipLists(); LinkManager.userLinkDBs = []; const addLinkToDoc = (link: Doc) => { Promise.all([link]).then(linkdoc => { const link = DocCast(linkdoc[0]); Promise.all([link.proto]).then(linkproto => { - Promise.all([link.anchor1, link.anchor2]).then(linkdata => { + Promise.all([link.link_anchor_1, link.link_anchor_2]).then(linkdata => { const a1 = DocCast(linkdata[0]); const a2 = DocCast(linkdata[1]); a1 && @@ -64,8 +64,8 @@ export class LinkManager { }); }; const remLinkFromDoc = (link: Doc) => { - const a1 = link?.anchor1; - const a2 = link?.anchor2; + const a1 = link?.link_anchor_1; + const a2 = link?.link_anchor_2; Promise.all([a1, a2]).then( action(() => { if (a1 instanceof Doc && a2 instanceof Doc && ((a1.author !== undefined && a2.author !== undefined) || link.author === Doc.CurrentUserEmail)) { @@ -130,11 +130,11 @@ export class LinkManager { LinkManager.addLinkDB(Doc.LinkDBDoc()); } - public createLinkrelationshipLists = () => { + public createlink_relationshipLists = () => { //create new lists for link relations and their associated colors if the lists don't already exist - !Doc.UserDoc().linkRelationshipList && (Doc.UserDoc().linkRelationshipList = new List()); + !Doc.UserDoc().link_relationshipList && (Doc.UserDoc().link_relationshipList = new List()); !Doc.UserDoc().linkColorList && (Doc.UserDoc().linkColorList = new List()); - !Doc.UserDoc().linkRelationshipSizes && (Doc.UserDoc().linkRelationshipSizes = new List()); + !Doc.UserDoc().link_relationshipSizes && (Doc.UserDoc().link_relationshipSizes = new List()); }; public addLink(linkDoc: Doc, checkExists = false) { @@ -162,7 +162,7 @@ export class LinkManager { return []; } const dirLinks = Doc.GetProto(anchor)[DirectLinksSym]; - const annos = DocListCast(anchor[Doc.LayoutFieldKey(anchor) + '-annotations']); + const annos = DocListCast(anchor[Doc.LayoutFieldKey(anchor) + '_annotations']); if (!annos) debugger; return annos.reduce((list, anno) => [...list, ...LinkManager.Instance.relatedLinker(anno)], Array.from(dirLinks).slice()); }, true); @@ -171,9 +171,9 @@ export class LinkManager { public getRelatedGroupedLinks(anchor: Doc): Map> { const anchorGroups = new Map>(); this.relatedLinker(anchor).forEach(link => { - if (link.linkRelationship && link.linkRelationship !== '-ungrouped-') { - const relation = StrCast(link.linkRelationship); - const anchorRelation = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), anchor) ? 0 : 1] : relation; + if (link.link_relationship && link.link_relationship !== '-ungrouped-') { + const relation = StrCast(link.link_relationship); + const anchorRelation = relation.indexOf(':') !== -1 ? relation.split(':')[Doc.AreProtosEqual(Cast(link.link_anchor_1, Doc, null), anchor) ? 0 : 1] : relation; const group = anchorGroups.get(anchorRelation); anchorGroups.set(anchorRelation, group ? [...group, link] : [link]); } else { @@ -189,8 +189,8 @@ export class LinkManager { //TODO This should probably return undefined if there isn't an opposite anchor //TODO This should also await the return value of the anchor so we don't filter out promises public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined { - const a1 = Cast(linkDoc.anchor1, Doc, null); - const a2 = Cast(linkDoc.anchor2, Doc, null); + const a1 = Cast(linkDoc.link_anchor_1, Doc, null); + const a2 = Cast(linkDoc.link_anchor_2, Doc, null); if (Doc.AreProtosEqual(anchor, a1)) return a2; if (Doc.AreProtosEqual(anchor, a2)) return a1; if (Doc.AreProtosEqual(anchor, a1.annotationOn as Doc)) return a2; diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts index 22cca4a2e..cbc465d6a 100644 --- a/src/client/util/ReplayMovements.ts +++ b/src/client/util/ReplayMovements.ts @@ -127,8 +127,8 @@ export class ReplayMovements { zoomAndPan = (movement: Movement, document: CollectionFreeFormView) => { const { panX, panY, scale } = movement; scale !== 0 && document.zoomSmoothlyAboutPt([panX, panY], scale, 0); - document.Document._panX = panX; - document.Document._panY = panY; + document.Document._freeform_panX = panX; + document.Document._freeform_panY = panY; }; getFirstMovements = (movements: Movement[]): Map => { diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 79759a71d..d154c48a4 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -24,51 +24,57 @@ export namespace SearchUtil { export interface SearchParams { hl?: string; - "hl.fl"?: string; + 'hl.fl'?: string; start?: number; rows?: number; fq?: string; sort?: string; - allowAliases?: boolean; - onlyAliases?: boolean; - "facet"?: string; - "facet.field"?: 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"); + 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.onlyAliases) { - const header = query.match(/_[atnb]?:/) ? replacedQuery : "DEFAULT:" + replacedQuery; + 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); + 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 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[][] = []; - 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])); - })); - } - + // 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[][] = []; @@ -86,7 +92,7 @@ export namespace SearchUtil { 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.allowAliases || testDoc.proto === undefined || theDocs.findIndex(d => Doc.AreProtosEqual(d, testDoc)) === -1)) { + 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 { @@ -97,48 +103,46 @@ export namespace SearchUtil { return { docs: theDocs, numFound: Math.max(0, result.numFound), highlighting, lines: theLines }; } - export async function GetAliasesOfDocument(doc: Doc): Promise; - export async function GetAliasesOfDocument(doc: Doc, returnDocs: false): Promise; - export async function GetAliasesOfDocument(doc: Doc, returnDocs = true): Promise { + 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}"`, allowAliases: true })).docs; + return (await Search('', returnDocs, { fq: `proto_i:"${protoId}"`, allowEmbeddings: true })).docs; } else { - return (await Search("", returnDocs, { fq: `proto_i:"${protoId}"`, allowAliases: true })).ids; + 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]}"` }); + const results = await Search('', true, { fq: `proto_i:"${doc[Id]}"` }); return results.docs; } - export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> { - const docContexts = (await Search("", true, { fq: `data_l:"${doc[Id]}"` })).docs; - const aliases = await GetAliasesOfDocument(doc, false); - const aliasContexts = (await Promise.all(aliases.map(doc => Search("", true, { fq: `data_l:"${doc}"` })))); - const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] }; - aliasContexts.forEach(result => contexts.aliasContexts.push(...result.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[], aliasContexts: string[] }> { - const docContexts = (await Search("", false, { fq: `data_l:"${doc[Id]}"` })).ids; - const aliases = await GetAliasesOfDocument(doc, false); - const aliasContexts = (await Promise.all(aliases.map(doc => Search("", false, { fq: `data_l:"${doc}"` })))); - const contexts = { contexts: docContexts, aliasContexts: [] as string[] }; - aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids)); + 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 query = '*'; const response = await rp.get(Utils.prepend('/dashsearch'), { - qs: - { start: 0, rows: 10000, q: query }, - + qs: { start: 0, rows: 10000, q: query }, }); const result: IdSearchResult = JSON.parse(response); const { ids, numFound, highlighting } = result; diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 396d754b6..a3a924b75 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -74,7 +74,7 @@ export class SettingsManager extends React.Component<{}> { }; @undoBatch selectUserMode = action((e: React.ChangeEvent) => (Doc.noviceMode = (e.currentTarget as any)?.value === 'Novice')); - @undoBatch changeShowTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().showTitle = (e.currentTarget as any).value ? 'title' : undefined)); + @undoBatch changelayout_showTitle = action((e: React.ChangeEvent) => (Doc.UserDoc().layout_showTitle = (e.currentTarget as any).value ? 'title' : undefined)); @undoBatch changeFontFamily = action((e: React.ChangeEvent) => (Doc.UserDoc().fontFamily = (e.currentTarget as any).value)); @undoBatch changeFontSize = action((e: React.ChangeEvent) => (Doc.UserDoc().fontSize = (e.currentTarget as any).value)); @undoBatch switchActiveBackgroundColor = action((color: ColorState) => (Doc.UserDoc().activeCollectionBackground = String(color.hex))); @@ -176,7 +176,7 @@ export class SettingsManager extends React.Component<{}> { return (
- (Doc.UserDoc().showTitle = Doc.UserDoc().showTitle ? undefined : 'creationDate')} checked={Doc.UserDoc().showTitle !== undefined} /> + (Doc.UserDoc().layout_showTitle = Doc.UserDoc().layout_showTitle ? undefined : 'creationDate')} checked={Doc.UserDoc().layout_showTitle !== undefined} />
Show doc header
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 4937866f8..0eecb31cf 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -172,7 +172,7 @@ export class SharingManager extends React.Component<{}> { this.setDashboardBackground(doc, permission as SharingPermissions); if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc); - else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc) || doc); + return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.createdFrom as Doc) || doc); }) .some(success => !success); }; @@ -215,7 +215,7 @@ export class SharingManager extends React.Component<{}> { return users .map(({ user, sharingDoc }) => { if (permission !== SharingPermissions.None) return Doc.AddDocToList(sharingDoc, storage, doc); // add the doc to the sharingDoc if it hasn't already been added - else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.aliasOf as Doc) || doc); // remove the doc from the list if it already exists + else return GetEffectiveAcl(doc, user.email) === AclPrivate && Doc.RemoveDocFromList(sharingDoc, storage, (doc.createdFrom as Doc) || doc); // remove the doc from the list if it already exists }) .some(success => !success); } diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts index 2c0a1da8b..ed9819fc0 100644 --- a/src/client/util/SnappingManager.ts +++ b/src/client/util/SnappingManager.ts @@ -40,9 +40,9 @@ export namespace SnappingManager { } export function SetShowSnapLines(show: boolean) { - runInAction(() => (Doc.UserDoc().showSnapLines = show)); + runInAction(() => (Doc.UserDoc().freeform_snapLines = show)); } export function GetShowSnapLines() { - return Doc.UserDoc().showSnapLines; + return Doc.UserDoc().freeform_snapLines; } } diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts index cb8225643..a755c5dc9 100644 --- a/src/client/util/TrackMovements.ts +++ b/src/client/util/TrackMovements.ts @@ -68,7 +68,7 @@ export class TrackMovements { } const disposeFunc = reaction( - () => ({ x: NumCast(doc.panX, -1), y: NumCast(doc.panY, -1), scale: NumCast(doc.viewScale, 0) }), + () => ({ x: NumCast(doc.freeform_panX, -1), y: NumCast(doc.freeform_panY, -1), scale: NumCast(doc.freeform_scale, 0) }), res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, doc, res.scale) ); this.recordingFFViews?.set(doc, disposeFunc); diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx index 525c0ce5a..14c922526 100644 --- a/src/client/views/AudioWaveform.tsx +++ b/src/client/views/AudioWaveform.tsx @@ -1,27 +1,25 @@ -import React = require("react"); -import axios from "axios"; -import { action, computed, IReactionDisposer, reaction } from "mobx"; -import { observer } from "mobx-react"; -import Waveform from "react-audio-waveform"; -import { Doc } from "../../fields/Doc"; -import { List } from "../../fields/List"; -import { listSpec } from "../../fields/Schema"; -import { Cast } from "../../fields/Types"; -import { numberRange } from "../../Utils"; -import "./AudioWaveform.scss"; -import { Colors } from "./global/globalEnums"; - +import React = require('react'); +import axios from 'axios'; +import { action, computed, IReactionDisposer, reaction } from 'mobx'; +import { observer } from 'mobx-react'; +import Waveform from 'react-audio-waveform'; +import { Doc } from '../../fields/Doc'; +import { List } from '../../fields/List'; +import { listSpec } from '../../fields/Schema'; +import { Cast } from '../../fields/Types'; +import { numberRange } from '../../Utils'; +import './AudioWaveform.scss'; +import { Colors } from './global/globalEnums'; /** * AudioWaveform - * + * * Used in CollectionStackedTimeline to render a canvas with a visual of an audio waveform for AudioBox and VideoBox documents. * Uses react-audio-waveform package. * Bins the audio data into audioBuckets which are passed to package to render the lines. * Calculates new buckets each time a new zoom factor or new set of trim bounds is created and stores it in a field on the layout doc with a title indicating the bounds and zoom for that list (see audioBucketField) */ - export interface AudioWaveformProps { duration: number; // length of media clip rawDuration: number; // length of underlying media data @@ -32,6 +30,7 @@ export interface AudioWaveformProps { zoomFactor: number; PanelHeight: number; PanelWidth: number; + fieldKey: string; } @observer @@ -40,80 +39,71 @@ export class AudioWaveform extends React.Component { _disposer: IReactionDisposer | undefined; - @computed get waveHeight() { return Math.max(50, this.props.PanelHeight); } - - @computed get clipStart() { return this.props.clipStart; } - @computed get clipEnd() { return this.props.clipEnd; } - @computed get zoomFactor() { return this.props.zoomFactor; } + @computed get waveHeight() { + return Math.max(50, this.props.PanelHeight); + } - @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec("number"), []); } - audioBucketField = (start: number, end: number, zoomFactor: number) => "audioBuckets/" + "/" + start.toFixed(2).replace(".", "_") + "/" + end.toFixed(2).replace(".", "_") + "/" + (zoomFactor * 10); + @computed get clipStart() { + return this.props.clipStart; + } + @computed get clipEnd() { + return this.props.clipEnd; + } + @computed get zoomFactor() { + return this.props.zoomFactor; + } + @computed get audioBuckets() { + return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec('number'), []); + } + audioBucketField = (start: number, end: number, zoomFactor: number) => this.props.fieldKey + '_audioBuckets/' + '/' + start.toFixed(2).replace('.', '_') + '/' + end.toFixed(2).replace('.', '_') + '/' + zoomFactor * 10; componentWillUnmount() { this._disposer?.(); } componentDidMount() { - this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }), + this._disposer = reaction( + () => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }), ({ clipStart, clipEnd, fieldKey, zoomFactor }) => { if (!this.props.layoutDoc[fieldKey]) { // setting these values here serves as a "lock" to prevent multiple attempts to create the waveform at nerly the same time. - const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec("number")); - this.props.layoutDoc[fieldKey] = waveform && new List(waveform.slice(clipStart / this.props.rawDuration * waveform.length, clipEnd / this.props.rawDuration * waveform.length)); + const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec('number')); + this.props.layoutDoc[fieldKey] = waveform && new List(waveform.slice((clipStart / this.props.rawDuration) * waveform.length, (clipEnd / this.props.rawDuration) * waveform.length)); setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd, zoomFactor)); } - }, { fireImmediately: true }); + }, + { fireImmediately: true } + ); } // decodes the audio file into peaks for generating the waveform createWaveformBuckets = async (fieldKey: string, clipStart: number, clipEnd: number, zoomFactor: number) => { - axios({ url: this.props.mediaPath, responseType: "arraybuffer" }).then( - (response) => { - const context = new window.AudioContext(); - context.decodeAudioData( - response.data, - action((buffer) => { - const rawDecodedAudioData = buffer.getChannelData(0); - const startInd = clipStart / this.props.rawDuration; - const endInd = clipEnd / this.props.rawDuration; - const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length)); - const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor); + axios({ url: this.props.mediaPath, responseType: 'arraybuffer' }).then(response => { + const context = new window.AudioContext(); + context.decodeAudioData( + response.data, + action(buffer => { + const rawDecodedAudioData = buffer.getChannelData(0); + const startInd = clipStart / this.props.rawDuration; + const endInd = clipEnd / this.props.rawDuration; + const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length)); + const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor); - const bucketDataSize = Math.floor( - decodedAudioData.length / numBuckets - ); - const brange = Array.from(Array(bucketDataSize)); - const bucketList = numberRange(numBuckets).map( - (i: number) => - brange.reduce( - (p, x, j) => - Math.abs( - Math.max(p, decodedAudioData[i * bucketDataSize + j]) - ), - 0 - ) / 2 - ); - this.props.layoutDoc[fieldKey] = new List(bucketList); - }) - ); - } - ); - } + const bucketDataSize = Math.floor(decodedAudioData.length / numBuckets); + const brange = Array.from(Array(bucketDataSize)); + const bucketList = numberRange(numBuckets).map((i: number) => brange.reduce((p, x, j) => Math.abs(Math.max(p, decodedAudioData[i * bucketDataSize + j])), 0) / 2); + this.props.layoutDoc[fieldKey] = new List(bucketList); + }) + ); + }); + }; render() { return (
- +
); } -} \ No newline at end of file +} diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx index dee161931..02c5085a2 100644 --- a/src/client/views/DashboardView.tsx +++ b/src/client/views/DashboardView.tsx @@ -358,15 +358,15 @@ export class DashboardView extends React.Component { y: 400, _width: 1500, _height: 1000, - _fitWidth: true, - _backgroundGridShow: true, + _layout_fitWidth: true, + _freeform_backgroundGrid: true, backgroundColor: background, title: `Untitled Tab 1`, }; const title = name ? name : `Dashboard ${dashboardCount}`; const freeformDoc = Doc.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: title }, id, 'row'); - freeformDoc.context = dashboardDoc; + freeformDoc.embedContainer = dashboardDoc; // switching the tabs from the datadoc to the regular doc const dashboardTabs = DocListCast(dashboardDoc[DataSym].data); @@ -396,7 +396,7 @@ export class DashboardView extends React.Component { btnType: ButtonType.ClickButton, buttonText: 'New trail', icon: 'plus', - system: true, + isSystem: true, }; const reqdBtnScript = { onClick: `createNewPresentation()` }; const myTrailsBtn = DocUtils.AssignScripts(Docs.Create.FontIconDocument(reqdBtnOpts), reqdBtnScript); @@ -406,13 +406,13 @@ export class DashboardView extends React.Component { // but we don't want to create the list of trails here-- but rather in createDashboard const reqdOpts: DocumentOptions = { title: 'My Trails', - _showTitle: 'title', + _layout_showTitle: 'title', _height: 100, treeViewHideTitle: true, - _fitWidth: true, + _layout_fitWidth: true, _gridGap: 5, _forceActive: true, - childDropAction: 'alias', + childDropAction: 'embed', treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, @@ -423,7 +423,7 @@ export class DashboardView extends React.Component { boxShadow: '0 0', childDontRegisterViews: true, targetDropAction: 'same', - system: true, + isSystem: true, explainer: 'All of the trails that you have created will appear here.', }; const myTrails = DocUtils.AssignScripts(Docs.Create.TreeDocument([], reqdOpts), { treeViewChildDoubleClick: 'openPresentation(documentView.rootDoc)' }); @@ -453,7 +453,7 @@ ScriptingGlobals.add(function resetDashboard(dashboard: Doc) { DashboardView.resetDashboard(dashboard); }, 'move all dashboard tabs to single stack'); ScriptingGlobals.add(function addToDashboards(dashboard: Doc) { - DashboardView.openDashboard(Doc.MakeAlias(dashboard)); + DashboardView.openDashboard(Doc.MakeEmbedding(dashboard)); }, 'adds Dashboard to set of Dashboards'); ScriptingGlobals.add(function snapshotDashboard() { DashboardView.snapshotDashboard(); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index eba55e30c..ffb2d92f6 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -133,7 +133,7 @@ export function ViewBoxAnnotatableComponent

() protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer; @computed public get annotationKey() { - return this.fieldKey + (this._annotationKeySuffix() ? '-' + this._annotationKeySuffix() : ''); + return this.fieldKey + (this._annotationKeySuffix() ? '_' + this._annotationKeySuffix() : ''); } @action.bound @@ -152,7 +152,7 @@ export function ViewBoxAnnotatableComponent

() toRemove.forEach(doc => { leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey); Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc); - doc.context = undefined; + doc.embedContainer = undefined; if (recent) { Doc.RemoveDocFromList(recent, 'data', doc); doc.type !== DocumentType.LOADING && Doc.AddDocToList(recent, 'data', doc, undefined, true, true); @@ -193,18 +193,19 @@ export function ViewBoxAnnotatableComponent

() } const added = docs; if (added.length) { - if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym]).length) { + const aclKeys = Object.keys(this.props.Document[AclSym] ?? {}); + aclKeys.forEach(key => added.forEach(d => { - for (const key of Object.keys(this.props.Document[AclSym])) { - if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d); + if (d.author === denormalizeEmail(key.substring(4)) && !d.createdFrom) { + distributeAcls(key, SharingPermissions.Admin, d); } - }); - } + }) + ); if (effectiveAcl === AclAugment) { added.map(doc => { if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc)) && Doc.ActiveDashboard) inheritParentAcls(Doc.ActiveDashboard, doc); - doc.context = this.props.Document; + doc.embedContainer = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document; Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc); }); @@ -215,7 +216,7 @@ export function ViewBoxAnnotatableComponent

() // only make a pushpin if we have acl's to edit the document //DocUtils.LeavePushpin(doc); doc._stayInCollection = undefined; - doc.context = this.props.Document; + doc.embedContainer = this.props.Document; if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.rootDoc; Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc); @@ -223,7 +224,7 @@ export function ViewBoxAnnotatableComponent

() const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List; if (annoDocs instanceof List) annoDocs.push(...added); else targetDataDoc[annotationKey ?? this.annotationKey] = new List(added); - targetDataDoc[(annotationKey ?? this.annotationKey) + '-lastModified'] = new DateField(new Date(Date.now())); + targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now())); } } return true; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 30e41b06c..547d844ca 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -178,7 +178,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV e.preventDefault(); let googleDoc = await Cast(dataDoc.googleDoc, Doc); if (!googleDoc) { - const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, useCors: false }; + const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, data_useCors: false }; googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } @@ -473,17 +473,17 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV ); } - @observable _aliasDown = false; + @observable _embedDown = false; onTemplateButton = action((e: React.PointerEvent): void => { this._tooltipOpen = false; - setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction); + setupMoveUpEvents(this, e, this.onEmbedButtonMoved, emptyFunction, emptyFunction); }); - onAliasButtonMoved = () => { + onEmbedButtonMoved = () => { if (this._dragRef.current) { const dragDocView = this.view0!; const dragData = new DragManager.DocumentDragData([dragDocView.props.Document]); const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - dragData.defaultDropAction = 'alias'; + dragData.defaultDropAction = 'embed'; dragData.canEmbed = true; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false }); return true; @@ -498,14 +498,14 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const view0 = this.view0; const views = this.props.views(); return !view0 ? null : ( - Tap to Customize Layout. Drag an embeddable alias

} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom"> + Tap to Customize Layout. Drag an embedding
} open={this._tooltipOpen} onClose={action(() => (this._tooltipOpen = false))} placement="bottom">
!this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}> (this._aliasDown = true))} - onClose={action(() => (this._aliasDown = false))} + onOpen={action(() => (this._embedDown = true))} + onClose={action(() => (this._embedDown = false))} content={ - !this._aliasDown ? null : ( + !this._embedDown ? null : (
{' '} v).map(v => v as DocumentView)} /> @@ -564,7 +564,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV const anchor = rootView.ComponentView?.getAnchor?.(false) ?? rootDoc; const trail = DocCast(anchor.presTrail) ?? Doc.MakeCopy(DocCast(Doc.UserDoc().emptyTrail), true); if (trail !== anchor.presTrail) { - DocUtils.MakeLink(anchor, trail, { linkRelationship: 'link trail' }); + DocUtils.MakeLink(anchor, trail, { link_relationship: 'link trail' }); anchor.presTrail = trail; } Doc.ActivePresentation = trail; @@ -589,7 +589,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV (link.linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))} + linkCreated={link => (link.layout_linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))} linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)} linkFrom={() => this.props.views().lastElement()?.rootDoc} /> diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 26b64bfdd..39073d763 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -121,7 +121,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P titleFieldKey && SelectionManager.Views().forEach(d => { if (titleFieldKey === 'title') { - d.dataDoc['title-custom'] = !this._accumulatedTitle.startsWith('-'); + d.dataDoc.title_custom = !this._accumulatedTitle.startsWith('-'); if (StrCast(d.rootDoc.title).startsWith('@') && !this._accumulatedTitle.startsWith('@')) { Doc.RemoveDocFromList(Doc.MyPublishedDocs, undefined, d.rootDoc); } @@ -138,12 +138,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (curKey !== title) { if (title) { if (d.dataDoc[title] === undefined || d.dataDoc[title] instanceof RichTextField || typeof d.dataDoc[title] === 'string') { - d.rootDoc.layoutKey = `layout_${title}`; + d.rootDoc.layout_fieldKey = `layout_${title}`; d.rootDoc[`layout_${title}`] = FormattedTextBox.LayoutString(title); - d.rootDoc[`${title}-nativeWidth`] = d.rootDoc[`${title}-nativeHeight`] = 0; + d.rootDoc[`${title}_nativeWidth`] = d.rootDoc[`${title}_nativeHeight`] = 0; } } else { - d.rootDoc.layoutKey = undefined; + d.rootDoc.layout_fieldKey = undefined; } } } else { @@ -272,22 +272,22 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const selectedDocs = SelectionManager.Views(); if (selectedDocs.length) { if (e.ctrlKey) { - // open an alias in a new tab with Ctrl Key - CollectionDockingView.AddSplit(Doc.BestAlias(selectedDocs[0].props.Document), OpenWhereMod.right); + // open an embedding in a new tab with Ctrl Key + CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].props.Document), OpenWhereMod.right); } else if (e.shiftKey) { // open centered in a new workspace with Shift Key - const alias = Doc.MakeAlias(selectedDocs[0].props.Document); - alias.context = undefined; - alias.x = -alias[WidthSym]() / 2; - alias.y = -alias[HeightSym]() / 2; - CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([alias], { title: 'Tab for ' + alias.title }), OpenWhereMod.right); + const embedding = Doc.MakeEmbedding(selectedDocs[0].props.Document); + embedding.embedContainer = undefined; + embedding.x = -embedding[WidthSym]() / 2; + embedding.y = -embedding[HeightSym]() / 2; + CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right); } else if (e.altKey) { // open same document in new tab CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, OpenWhereMod.right); } else { var openDoc = selectedDocs[0].props.Document; - if (openDoc.layoutKey === 'layout_icon') { - openDoc = DocListCast(openDoc.aliases).find(alias => !alias.context) ?? Doc.MakeAlias(openDoc); + if (openDoc.layout_fieldKey === 'layout_icon') { + openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); Doc.deiconifyView(openDoc); } LightboxView.SetLightboxDoc( @@ -368,8 +368,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const newloccentern = seldocview.props.ScreenToLocalTransform().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.rootDoc._rotation) / 180) * Math.PI); - seldocview.rootDoc.rotateCenterX = final.x / NumCast(seldocview.layoutDoc._width); - seldocview.rootDoc.rotateCenterY = final.y / NumCast(seldocview.layoutDoc._height); + seldocview.rootDoc.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); + seldocview.rootDoc.rotation_centerY = final.y / NumCast(seldocview.layoutDoc._height); }; @action @@ -386,8 +386,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P action(action(() => (this._isRotating = false))), // upEvent action((e, doubleTap) => { if (doubleTap) { - seldocview.rootDoc.rotateCenterX = 0.5; - seldocview.rootDoc.rotateCenterY = 0.5; + seldocview.rootDoc.rotation_centerX = 0.5; + seldocview.rootDoc.rotation_centerY = 0.5; } }) ); @@ -586,7 +586,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P let dW = docwidth * (dWin / refWidth); let dH = docheight * (dHin / refHeight); const scale = docView.props.ScreenToLocalTransform().Scale; - const modifyNativeDim = (e.ctrlKey || doc.forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen); + const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen); if (nwidth && nheight) { if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) { docheight = (nheight / nwidth) * docwidth; @@ -602,7 +602,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P let dX = !dWin ? 0 : scale * refCent[0] * (1 - (1 + dWin / refWidth)); let dY = !dHin ? 0 : scale * refCent[1] * (1 - (1 + dHin / refHeight)); const preserveNativeDim = doc._nativeHeightUnfrozen === false && doc._nativeDimModifiable === false; - const fixedAspect = nwidth && nheight && (!doc._fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable); + const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable); if (fixedAspect) { if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) { if (dragRight && modifyNativeDim) { @@ -610,7 +610,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P doc._nativeWidth = (actualdW / (docwidth || 1)) * Doc.NativeWidth(doc); } } else { - if (!doc._fitWidth || preserveNativeDim) { + if (!doc._layout_fitWidth || preserveNativeDim) { actualdH = (nheight / nwidth) * actualdW; doc._height = actualdH; } else if (!modifyNativeDim || dragBotRight) { @@ -619,14 +619,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } doc._width = actualdW; } else { - if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._fitWidth))) { + if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._layout_fitWidth))) { // frozen web pages, PDFs, and some RTFS have frozen nativewidth/height. But they are marked to allow their nativeHeight // to be explicitly modified with fitWidth and vertical resizing. (ie, with fitWidth they can't grow horizontally to match // a vertical resize so it makes more sense to change their nativeheight even if the ctrl key isn't used) doc._nativeHeight = (actualdH / (docheight || 1)) * Doc.NativeHeight(doc); - doc._autoHeight = false; + doc._layout_autoHeight = false; } else { - if (!doc._fitWidth || preserveNativeDim) { + if (!doc._layout_fitWidth || preserveNativeDim) { actualdW = (nwidth / nheight) * actualdH; doc._width = actualdW; } else if (!modifyNativeDim || dragBotRight) { @@ -642,10 +642,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const rotCtr = [docwidth / 2, docheight / 2]; const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI); - const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '-scrollHeight']))) * docView.NativeDimScaling(); + const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '_scrollHeight']))) * docView.NativeDimScaling(); dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH); dW && (doc._width = actualdW); - dH && (doc._autoHeight = false); + dH && (doc._layout_autoHeight = false); const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2]; const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._rotation) / 180) * Math.PI); @@ -654,7 +654,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } doc.x = NumCast(doc.x) + dX; doc.y = NumCast(doc.y) + dY; - doc._lastModified = new DateField(); + doc._layout_modificationDate = new DateField(); } const val = this._dragHeights.get(docView.layoutDoc); if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) }); @@ -670,11 +670,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P this._resizeUndo?.end(); SnappingManager.clearSnapLines(); - // detect autoHeight gesture and apply + // detect layout_autoHeight gesture and apply SelectionManager.Views() .map(docView => ({ doc: docView.layoutDoc, hgts: this._dragHeights.get(docView.layoutDoc) })) .filter(pair => pair.hgts && pair.hgts.lowest < pair.hgts.start && pair.hgts.lowest <= 20) - .forEach(pair => (pair.doc._autoHeight = true)); + .forEach(pair => (pair.doc._layout_autoHeight = true)); //need to change points for resize, or else rotation/control points will fail. this._inkDragDocs .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] })) @@ -713,7 +713,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } @computed get hasIcons() { - return SelectionManager.Views().some(docView => docView.rootDoc.layoutKey === 'layout_icon'); + return SelectionManager.Views().some(docView => docView.rootDoc.layout_fieldKey === 'layout_icon'); } @observable _showRotCenter = false; @@ -722,8 +722,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (SelectionManager.Views().length) { const seldocview = SelectionManager.Views()[0]; const loccenter = Utils.rotPt( - NumCast(seldocview.rootDoc.rotateCenterX) * NumCast(seldocview.layoutDoc._width), - NumCast(seldocview.rootDoc.rotateCenterY) * NumCast(seldocview.layoutDoc._height), + NumCast(seldocview.rootDoc.rotation_centerX) * NumCast(seldocview.layoutDoc._width), + NumCast(seldocview.rootDoc.rotation_centerY) * NumCast(seldocview.layoutDoc._height), (NumCast(seldocview.rootDoc._rotation) / 180) * Math.PI ); return seldocview.props @@ -746,8 +746,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } // hide the decorations if the parent chooses to hide it or if the document itself hides it const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations; - const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.hideResizeHandles || this._isRounding || this._isRotating; - const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.hideDecorationTitle || this._isRounding || this._isRotating; + const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating; + const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating; const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating; // if multiple documents have been opened at the same time, then don't show open button const hideOpenButton = @@ -765,7 +765,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P seldocview.rootDoc.hideDeleteButton || SelectionManager.Views().some(docView => { const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit; - return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin); + return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin); }); const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( @@ -871,7 +871,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P {hideDeleteButton ? null : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} {hideTitle ? null : titleArea} - {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')} + {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as new embedding, shift: in new collection)')}
{hideResizers ? null : ( <> diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx index 84b2e1407..75e0e7c4c 100644 --- a/src/client/views/FilterPanel.tsx +++ b/src/client/views/FilterPanel.tsx @@ -46,14 +46,14 @@ export class FilterPanel extends React.Component { @computed get _allFacets() { // trace(); const noviceReqFields = ['author', 'tags', 'text', 'type']; - const noviceLayoutFields: string[] = []; //["_curPage"]; + const noviceLayoutFields: string[] = []; //["_layout_curPage"]; const noviceFields = [...noviceReqFields, ...noviceLayoutFields]; const keys = new Set(noviceFields); this.allDocs.forEach(doc => SearchBox.documentKeys(doc).filter(key => keys.add(key))); const sortedKeys = Array.from(keys.keys()) .filter(key => key[0]) - .filter(key => key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode) + .filter(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('_')) || noviceFields.includes(key) || !Doc.noviceMode) .sort(); noviceFields.forEach(key => sortedKeys.splice(sortedKeys.indexOf(key), 1)); return [...noviceFields, ...sortedKeys]; @@ -88,7 +88,7 @@ export class FilterPanel extends React.Component { (facetVal === true || facetVal == false) && valueSet.add(Field.toString(!facetVal)); const fieldKey = Doc.LayoutFieldKey(t); const annos = !Field.toString(Doc.LayoutField(t) as Field).includes('CollectionView'); - DocListCast(t[annos ? fieldKey + '-annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); + DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); }); subDocs = newarray; } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index b04769c1e..141e99c66 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -102,7 +102,7 @@ export class GestureOverlay extends Touchable { icon: 'clipboard', pointerUp: 'GestureOverlay.Instance.closeFloatingDoc()', pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', - clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, system: true }), + clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300, isSystem: true }), backgroundColor: 'orange', }, { title: 'interpret text', icon: 'font', toolType: 'inktotext', pointerUp: "setToolglass('none')", pointerDown: 'setToolglass(self.toolType)', backgroundColor: 'orange' }, @@ -125,7 +125,7 @@ export class GestureOverlay extends Touchable { onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined, backgroundColor: data.backgroundColor, dragFactory: data.dragFactory, - system: true, + isSystem: true, }) ); } @@ -138,19 +138,19 @@ export class GestureOverlay extends Touchable { ignoreClick: true, _lockedPosition: true, title: 'buttons', - _autoHeight: true, + _layout_autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: 'white', - system: true, + isSystem: true, }); thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], { _width: 300, _height: 25, - _autoHeight: true, + _layout_autoHeight: true, linearViewIsExpanded: true, flexDirection: 'column', - system: true, + isSystem: true, }); userDoc.thumbDoc = thumbDoc; } @@ -916,7 +916,7 @@ export class GestureOverlay extends Touchable { @computed get elements() { const selView = GestureOverlay.DownDocView; - const width = Number(ActiveInkWidth()) * NumCast(selView?.rootDoc._viewScale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1); + const width = Number(ActiveInkWidth()) * NumCast(selView?.rootDoc._freeform_scale, 1); // * (selView?.props.ScreenToLocalTransform().Scale || 1); const rect = this._overlayRef.current?.getBoundingClientRect(); const B = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 }; //this.getBounds(this._points, true); B.left = B.left - width / 2; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 0f8b46dbe..b9b92dd2b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -374,10 +374,10 @@ export class KeyManager { if (count === docids.length) { const added = await Promise.all(list.filter(d => !docList.includes(d)).map(async d => (clone ? (await Doc.MakeClone(d, true)).clone : d))); if (added.length) { - added.map(doc => (doc.context = targetDataDoc)); + added.map(doc => (doc.embedContainer = targetDataDoc)); undoBatch(() => { targetDataDoc[fieldKey] = new List([...docList, ...added]); - targetDataDoc[fieldKey + '-lastModified'] = new DateField(new Date(Date.now())); + targetDataDoc[fieldKey + '_modificationDate'] = new DateField(new Date(Date.now())); })(); } } diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 156825f41..d28981e17 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -50,21 +50,21 @@ export class InkStrokeProperties { if (!requireCurrPoint || this._currentPoint !== -1) { const doc = inkView.rootDoc; if (doc.type === DocumentType.INK && doc.width && doc.height) { - const ink = Cast(doc.data, InkField)?.inkData; + const ink = Cast(doc.stroke, InkField)?.inkData; if (ink) { const oldXrange = (xs => ({ coord: NumCast(doc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X)); const oldYrange = (ys => ({ coord: NumCast(doc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y)); - const ptsXscale = (NumCast(doc._width) - NumCast(doc.strokeWidth)) / (oldXrange.max - oldXrange.min || 1) || 1; - const ptsYscale = (NumCast(doc._height) - NumCast(doc.strokeWidth)) / (oldYrange.max - oldYrange.min || 1) || 1; - const newPoints = func(inkView, ink, ptsXscale, ptsYscale, NumCast(doc.strokeWidth)); + const ptsXscale = (NumCast(doc._width) - NumCast(doc.stroke_width)) / (oldXrange.max - oldXrange.min || 1) || 1; + const ptsYscale = (NumCast(doc._height) - NumCast(doc.stroke_width)) / (oldYrange.max - oldYrange.min || 1) || 1; + const newPoints = func(inkView, ink, ptsXscale, ptsYscale, NumCast(doc.stroke_width)); if (newPoints) { const newXrange = (xs => ({ min: Math.min(...xs), max: Math.max(...xs) }))(newPoints.map(p => p.X)); const newYrange = (ys => ({ min: Math.min(...ys), max: Math.max(...ys) }))(newPoints.map(p => p.Y)); - doc._width = (newXrange.max - newXrange.min) * ptsXscale + NumCast(doc.strokeWidth); - doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.strokeWidth); + doc._width = (newXrange.max - newXrange.min) * ptsXscale + NumCast(doc.stroke_width); + doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.stroke_width); doc.x = oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale; doc.y = oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale; - Doc.GetProto(doc).data = new InkField(newPoints); + Doc.GetProto(doc).stroke = new InkField(newPoints); appliedFunc = true; } } diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index 246b887a6..d6a6a64bf 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -172,7 +172,7 @@ export class InkTranscription extends React.Component { if (!selected) { return; } - const ctx = await Cast(selected[0].context, Doc); + const ctx = await Cast(selected[0].embedContainer, Doc); if (!ctx) { return; } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 2fd6cc4d6..14c5dc58d 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -6,7 +6,7 @@ point 1, tangent pt 1, tangent pt 2, point 2, point 3, tangent pt 3, ... (Note that segment endpoints are duplicated ie Point2 = Point 3) brokenIndices - an array of indexes into the data field where the incoming and outgoing tangents are not constrained to be equal text - a text field that will be centered within a closed ink stroke - isInkMask - a flag that makes the ink stroke render as a mask over its collection where the stroke itself is mixBlendMode multiplied by + stroke_isInkMask - a flag that makes the ink stroke render as a mask over its collection where the stroke itself is mixBlendMode multiplied by the underlying collection content, and everything outside the stroke is covered by a semi-opaque dark gray mask. The coordinates of the ink data need to be mapped to the screen since ink points are not changed when the DocumentView is translated or scaled. @@ -134,7 +134,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { * dimmed by a semi-opaque overlay mask. */ public static toggleMask = action((inkDoc: Doc) => { - inkDoc.isInkMask = !inkDoc.isInkMask; + inkDoc.stroke_isInkMask = !inkDoc.stroke_isInkMask; }); @observable controlUndo: UndoManager.Batch | undefined; /** @@ -241,7 +241,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { */ inkScaledData = () => { const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? []; - const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1); + const inkStrokeWidth = NumCast(this.rootDoc.stroke_width, 1); const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2; const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2; const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2; @@ -310,8 +310,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { .map(p => ({ X: p[0], Y: p[1] })); const screenHdlPts = screenPts; - const startMarker = StrCast(this.layoutDoc.strokeStartMarker); - const endMarker = StrCast(this.layoutDoc.strokeEndMarker); + const startMarker = StrCast(this.layoutDoc.stroke_startMarker); + const endMarker = StrCast(this.layoutDoc.stroke_endMarker); const markerScale = NumCast(this.layoutDoc.strokeMarkerScale); return SnappingManager.GetIsDragging() ? null : !InkStrokeProperties.Instance._controlButton ? ( !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : ( @@ -330,12 +330,12 @@ export class InkingStroke extends ViewBoxBaseComponent() { screenSpaceCenterlineStrokeWidth, StrCast(inkDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(inkDoc.strokeBezier), + StrCast(inkDoc.stroke_bezier), 'none', startMarker, endMarker, markerScale * Math.min(screenSpaceCenterlineStrokeWidth, screenInkWidth[0] / screenSpaceCenterlineStrokeWidth), - StrCast(inkDoc.strokeDash), + StrCast(inkDoc.stroke_dash), 1, 1, '', @@ -355,11 +355,11 @@ export class InkingStroke extends ViewBoxBaseComponent() { TraceMobx(); const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData(); - const startMarker = StrCast(this.layoutDoc.strokeStartMarker); - const endMarker = StrCast(this.layoutDoc.strokeEndMarker); + const startMarker = StrCast(this.layoutDoc.stroke_startMarker); + const endMarker = StrCast(this.layoutDoc.stroke_endMarker); const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1); const closed = InkingStroke.IsClosed(inkData); - const isInkMask = BoolCast(this.layoutDoc.isInkMask); + const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.FillColor) ?? 'transparent'; const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); @@ -381,12 +381,12 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkStrokeWidth, StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(this.layoutDoc.strokeBezier), + StrCast(this.layoutDoc.stroke_bezier), !closed ? 'none' : fillColor === 'transparent' ? 'none' : fillColor, startMarker, endMarker, markerScale, - StrCast(this.layoutDoc.strokeDash), + StrCast(this.layoutDoc.stroke_dash), inkScaleX, inkScaleY, '', @@ -408,7 +408,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkStrokeWidth + (fillColor ? (closed ? 2 : (highlightIndex ?? 0) + 2) : 2), StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), - StrCast(this.layoutDoc.strokeBezier), + StrCast(this.layoutDoc.stroke_bezier), !closed ? 'none' : !isInkMask && (fillColor === 'transparent' || suppressFill) ? 'none' : fillColor, '', '', @@ -444,7 +444,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { () { setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text) yPadding={10} xPadding={10} - fieldKey={'text'} + fieldKey="text" fontSize={fsize} dontRegisterView={true} noSidebar={true} diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index c18a89481..1b309a6be 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -31,7 +31,7 @@ type LightboxSavedState = { panY: Opt; scale: Opt; scrollTop: Opt; - layoutKey: Opt; + layout_fieldKey: Opt; }; @observer export class LightboxView extends React.Component { @@ -51,11 +51,11 @@ export class LightboxView extends React.Component { static path: { doc: Opt; target: Opt; history: Opt<{ doc: Doc; target?: Doc }[]>; future: Opt; saved: Opt }[] = []; @action public static SetLightboxDoc(doc: Opt, target?: Doc, future?: Doc[], layoutTemplate?: Doc | string) { if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) { - if (this._savedState.panX !== undefined) this.LightboxDoc._panX = this._savedState.panX; - if (this._savedState.panY !== undefined) this.LightboxDoc._panY = this._savedState.panY; - if (this._savedState.scrollTop !== undefined) this.LightboxDoc._scrollTop = this._savedState.scrollTop; - if (this._savedState.scale !== undefined) this.LightboxDoc._viewScale = this._savedState.scale; - this.LightboxDoc.layoutKey = this._savedState.layoutKey; + if (this._savedState.panX !== undefined) this.LightboxDoc._freeform_panX = this._savedState.panX; + if (this._savedState.panY !== undefined) this.LightboxDoc._freeform_panY = this._savedState.panY; + if (this._savedState.scrollTop !== undefined) this.LightboxDoc._layout_scrollTop = this._savedState.scrollTop; + if (this._savedState.scale !== undefined) this.LightboxDoc._freeform_scale = this._savedState.scale; + this.LightboxDoc.layout_fieldKey = this._savedState.layout_fieldKey; } if (!doc) { this._docFilters && (this._docFilters.length = 0); @@ -64,17 +64,17 @@ export class LightboxView extends React.Component { MainView.Instance._exploreMode = false; } else { const l = DocUtils.MakeLinkToActiveAudio(() => doc).lastElement(); - l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen'); + l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); CollectionStackedTimeline.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.()); //TabDocView.PinDoc(doc, { hidePresBox: true }); this._history ? this._history.push({ doc, target }) : (this._history = [{ doc, target }]); if (doc !== LightboxView.LightboxDoc) { this._savedState = { - layoutKey: StrCast(doc.layoutKey), - panX: Cast(doc.panX, 'number', null), - panY: Cast(doc.panY, 'number', null), - scale: Cast(doc.viewScale, 'number', null), - scrollTop: Cast(doc.scrollTop, 'number', null), + layout_fieldKey: StrCast(doc.layout_fieldKey), + panX: Cast(doc.freeform_panX, 'number', null), + panY: Cast(doc.freeform_panY, 'number', null), + scale: Cast(doc.freeform_scale, 'number', null), + scrollTop: Cast(doc.layout_scrollTop, 'number', null), }; } } @@ -91,7 +91,7 @@ export class LightboxView extends React.Component { this._doc = doc; this._layoutTemplate = layoutTemplate instanceof Doc ? layoutTemplate : undefined; if (doc && (typeof layoutTemplate === 'string' ? layoutTemplate : undefined)) { - doc.layoutKey = layoutTemplate; + doc.layout_fieldKey = layoutTemplate; } this._docTarget = target || doc; @@ -142,7 +142,7 @@ export class LightboxView extends React.Component { return LightboxView.SetLightboxDoc( doc, undefined, - [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '-annotations']).filter(anno => anno.annotationOn !== doc), ...(LightboxView._future ?? [])].sort( + [...DocListCast(doc[Doc.LayoutFieldKey(doc)]), ...DocListCast(doc[Doc.LayoutFieldKey(doc) + '_annotations']).filter(anno => anno.annotationOn !== doc), ...(LightboxView._future ?? [])].sort( (a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow) ), layoutTemplate @@ -156,17 +156,17 @@ export class LightboxView extends React.Component { const targetDocView = target && DocumentManager.Instance.getLightboxDocumentView(target); if (targetDocView && target) { const l = DocUtils.MakeLinkToActiveAudio(() => targetDocView.ComponentView?.getAnchor?.(true) || target).lastElement(); - l && (Cast(l.anchor2, Doc, null).backgroundColor = 'lightgreen'); + l && (Cast(l.link_anchor_2, Doc, null).backgroundColor = 'lightgreen'); DocumentManager.Instance.showDocument(target, { willZoomCentered: true, zoomScale: 0.9 }); if (LightboxView._history?.lastElement().target !== target) LightboxView._history?.push({ doc, target }); } else { if (!target && LightboxView.path.length) { const saved = LightboxView._savedState; if (LightboxView.LightboxDoc && saved) { - LightboxView.LightboxDoc._panX = saved.panX; - LightboxView.LightboxDoc._panY = saved.panY; - LightboxView.LightboxDoc._viewScale = saved.scale; - LightboxView.LightboxDoc._scrollTop = saved.scrollTop; + LightboxView.LightboxDoc._freeform_panX = saved.panX; + LightboxView.LightboxDoc._freeform_panY = saved.panY; + LightboxView.LightboxDoc._freeform_scale = saved.scale; + LightboxView.LightboxDoc._layout_scrollTop = saved.scrollTop; } const pop = LightboxView.path.pop(); if (pop) { @@ -210,7 +210,7 @@ export class LightboxView extends React.Component { const coll = LightboxView._docTarget; if (coll) { const fieldKey = Doc.LayoutFieldKey(coll); - const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; + const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '_annotations'])]; const links = LinkManager.Links(coll) .map(link => LinkManager.getOppositeAnchor(link, coll)) .filter(doc => doc) @@ -305,9 +305,9 @@ export class LightboxView extends React.Component { title="toggle fit width" onClick={e => { e.stopPropagation(); - LightboxView.LightboxDoc!._fitWidth = !LightboxView.LightboxDoc!._fitWidth; + LightboxView.LightboxDoc!._layout_fitWidth = !LightboxView.LightboxDoc!._layout_fitWidth; }}> - +
dv.rootDoc.showSnapLines) ? null : ( + return !SelectionManager.Views().some(dv => dv.rootDoc.freeform_snapLines) ? null : (
{SnappingManager.horizSnapLines().map(l => ( diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 556d9b6a0..eb0fd0c7a 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -123,9 +123,9 @@ export class MarqueeAnnotator extends React.Component { DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { dragComplete: e => { if (!e.aborted && e.linkDocument) { - Doc.GetProto(e.linkDocument).linkRelationship = 'cropped image'; + Doc.GetProto(e.linkDocument).link_relationship = 'cropped image'; Doc.GetProto(e.linkDocument).title = 'crop: ' + this.props.docView.rootDoc.title; - Doc.GetProto(e.linkDocument).linkDisplay = false; + Doc.GetProto(e.linkDocument).layout_linkDisplay = false; } }, }); @@ -153,10 +153,10 @@ export class MarqueeAnnotator extends React.Component { annotationOn: this.props.rootDoc, title: 'Annotation on ' + this.props.rootDoc.title, }); - marqueeAnno.x = NumCast(this.props.docView.props.Document.panXMin) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._viewScale, 1); - marqueeAnno.y = NumCast(this.props.docView.props.Document.panYMin) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._viewScale, 1) + NumCast(this.props.scrollTop); - marqueeAnno._height = parseInt(anno.style.height || '0') / scale / NumCast(this.props.docView.props.Document._viewScale, 1); - marqueeAnno._width = parseInt(anno.style.width || '0') / scale / NumCast(this.props.docView.props.Document._viewScale, 1); + marqueeAnno.x = NumCast(this.props.docView.props.Document.freeform_panXMin) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1); + marqueeAnno.y = NumCast(this.props.docView.props.Document.freeform_panYMin) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1) + NumCast(this.props.scrollTop); + marqueeAnno._height = parseInt(anno.style.height || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1); + marqueeAnno._width = parseInt(anno.style.width || '0') / scale / NumCast(this.props.docView.props.Document._freeform_scale, 1); anno.remove(); savedAnnoMap.clear(); return marqueeAnno; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index c7a603897..f7fb443c0 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -57,7 +57,7 @@ export class PreviewCursor extends React.Component<{}> { title: url, _width: 500, _height: 300, - useCors: true, + data_useCors: true, x: newPoint[0], y: newPoint[1], }) diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index cf808f801..86230ca78 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -74,7 +74,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get maskButton() { return this.propertyToggleBtn( 'Mask', - 'isInkMask', + 'stroke_isInkMask', on => (on ? 'Make plain ink' : 'Make highlight mask'), on => 'paint-brush', (dv, doc) => InkingStroke.toggleMask(dv?.layoutDoc || doc) @@ -91,7 +91,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get clustersButton() { return this.propertyToggleBtn( 'Clusters', - '_useClusters', + '_freeform_useClusters', on => `${on ? 'Hide' : 'Show'} clusters`, on => 'braille' ); @@ -115,7 +115,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get fitContentButton() { return this.propertyToggleBtn( 'View All', - '_fitContentsToBox', + '_freeform_fitContentsToBox', on => `${on ? "Don't" : 'Do'} fit content to container visible area`, on => 'object-group' ); @@ -136,20 +136,20 @@ export class PropertiesButtons extends React.Component<{}, {}> { // containerDoc.noShadow = // containerDoc.disableDocBrushing = // containerDoc._forceActive = - //containerDoc._fitContentsToBox = + //containerDoc._freeform_fitContentsToBox = containerDoc._isLightbox = !containerDoc._isLightbox; //containerDoc._xPadding = containerDoc._yPadding = containerDoc._isLightbox ? 10 : undefined; const containerContents = DocListCast(dv.dataDoc[dv.props.fieldKey ?? Doc.LayoutFieldKey(containerDoc)]); //dv.rootDoc.onClick = ScriptField.MakeScript('{self.data = undefined; documentView.select(false)}', { documentView: 'any' }); - containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.linkDisplay = false))); + containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.layout_linkDisplay = false))); }); } ); } - @computed get fitWidthButton() { + @computed get layout_fitWidthButton() { return this.propertyToggleBtn( 'Fit\xA0Width', - '_fitWidth', + '_layout_fitWidth', on => `${on ? "Don't" : 'Do'} fit content to width of container`, on => 'arrows-alt-h' ); @@ -157,10 +157,10 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get captionButton() { return this.propertyToggleBtn( 'Caption', - '_showCaption', + '_layout_showCaption', on => `${on ? 'Hide' : 'Show'} caption footer`, on => 'closed-captioning', - (dv, doc) => ((dv?.rootDoc || doc)._showCaption = (dv?.rootDoc || doc)._showCaption === undefined ? 'caption' : undefined) + (dv, doc) => ((dv?.rootDoc || doc)._layout_showCaption = (dv?.rootDoc || doc)._layout_showCaption === undefined ? 'caption' : undefined) ); } @computed get chromeButton() { @@ -175,20 +175,20 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get titleButton() { return this.propertyToggleBtn( 'Title', - '_showTitle', + '_layout_showTitle', on => 'Switch between title styles', on => 'text-width', (dv, doc) => { const tdoc = dv?.rootDoc || doc; - const newtitle = !tdoc._showTitle ? 'title' : tdoc._showTitle === 'title' ? 'title:hover' : ''; - tdoc._showTitle = newtitle; + const newtitle = !tdoc._layout_showTitle ? 'title' : tdoc._layout_showTitle === 'title' ? 'title:hover' : ''; + tdoc._layout_showTitle = newtitle; } ); } - @computed get autoHeightButton() { + @computed get layout_autoHeightButton() { return this.propertyToggleBtn( 'Auto\xA0Size', - '_autoHeight', + '_layout_autoHeight', on => `Automatical vertical sizing to show all content`, on => 'arrows-alt-v' ); @@ -196,7 +196,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get gridButton() { return this.propertyToggleBtn( 'Grid', - '_backgroundGridShow', + '_freeform_backgroundGrid', on => `Display background grid in collection`, on => 'border-all' ); @@ -236,7 +236,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { @computed get snapButton() { return this.propertyToggleBtn( 'Snap\xA0Lines', - 'showSnapLines', + 'freeform_snapLines', on => `Display snapping lines when objects are dragged`, on => 'th', undefined, @@ -412,12 +412,12 @@ export class PropertiesButtons extends React.Component<{}, {}> { {toggle(this.captionButton)} {toggle(this.lockButton)} {toggle(this.onClickButton)} - {toggle(this.fitWidthButton)} + {toggle(this.layout_fitWidthButton)} {toggle(this.freezeThumb)} {toggle(this.forceActiveButton, { display: !isFreeForm && !isMap ? 'none' : '' })} {toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })} {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })} - {toggle(this.autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })} + {toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })} {toggle(this.maskButton, { display: !isInk ? 'none' : '' })} {toggle(this.hideImageButton, { display: !isImage ? 'none' : '' })} {toggle(this.chromeButton, { display: !isCollection || isNovice ? 'none' : '' })} diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 935d551c6..46e6fd188 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -25,7 +25,7 @@ export class PropertiesDocBacklinksSelector extends React.Component alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set()); - const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases)); + const embeddings = DocListCast(target.proto_embeddings); + const containerProtos = embeddings.filter(embedding => 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)); const containers = containerSets.reduce((p, set) => { set.map(s => p.add(s)); return p; }, new Set()); - const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.aliases)); + const doclayoutSets = Array.from(containers.keys()).map(dp => DocListCast(dp.proto_embeddings)); const doclayouts = Array.from( doclayoutSets .reduce((p, set) => { @@ -48,7 +48,7 @@ export class PropertiesDocContextSelector extends React.Component { if (!this.props.DocView) return; - col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col; + col = Doc.IsDocDataProto(col) ? Doc.MakeDelegate(col) : col; DocFocusOrOpen(Doc.GetProto(this.props.DocView.props.Document), undefined, col); }; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 0b14c7b10..19c138a21 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -123,7 +123,7 @@ export class PropertiesView extends React.Component { docWidth = () => { if (this.selectedDoc) { const layoutDoc = this.selectedDoc; - const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._fitWidth); + const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._layout_fitWidth); if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20)); return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20; } else { @@ -141,7 +141,7 @@ export class PropertiesView extends React.Component { this.MAX_EMBED_HEIGHT, Doc.NativeAspect(layoutDoc, undefined, true) ? this.docWidth() / Doc.NativeAspect(layoutDoc, undefined, true) - : layoutDoc._fitWidth + : layoutDoc._layout_fitWidth ? !Doc.NativeHeight(this.dataDoc) ? NumCast(this.props.height) : Math.min((this.docWidth() * Doc.NativeHeight(layoutDoc)) / Doc.NativeWidth(layoutDoc) || NumCast(this.props.height)) @@ -199,8 +199,8 @@ export class PropertiesView extends React.Component { } @computed get noviceFields() { - const noviceReqFields = ['author', 'creationDate', 'tags', '_curPage']; - return this.editableFields(key => key.indexOf('lastModified') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl')), noviceReqFields); + const noviceReqFields = ['author', 'creationDate', 'tags', '_layout_curPage']; + return this.editableFields(key => key.indexOf('modificationDate') !== -1 || (key[0] === key[0].toUpperCase() && !key.startsWith('acl')), noviceReqFields); } @undoBatch @@ -576,7 +576,7 @@ export class PropertiesView extends React.Component { this.selectedDoc && (this.selectedDoc.y = NumCast(this.selectedDoc?.y) + (dirs === 'up' ? 10 : -10)); break; case 'stk': - this.selectedDoc && (this.selectedDoc.strokeWidth = NumCast(this.selectedDoc?.strokeWidth) + (dirs === 'up' ? 0.1 : -0.1)); + this.selectedDoc && (this.selectedDoc.stroke_width = NumCast(this.selectedDoc?.stroke_width) + (dirs === 'up' ? 0.1 : -0.1)); break; case 'wid': const oldWidth = NumCast(this.selectedDoc?._width); @@ -813,25 +813,25 @@ export class PropertiesView extends React.Component { } @computed get solidStk() { - return this.selectedDoc?.color && (!this.selectedDoc?.strokeDash || this.selectedDoc?.strokeDash === '0') ? true : false; + return this.selectedDoc?.color && (!this.selectedDoc?.stroke_dash || this.selectedDoc?.stroke_dash === '0') ? true : false; } @computed get dashdStk() { - return this.selectedDoc?.strokeDash || ''; + return this.selectedDoc?.stroke_dash || ''; } @computed get unStrokd() { return this.selectedDoc?.color ? true : false; } @computed get widthStk() { - return this.getField('strokeWidth') || '1'; + return this.getField('stroke_width') || '1'; } @computed get markScal() { return Number(this.getField('strokeMakerScale') || '1'); } @computed get markHead() { - return this.getField('strokeStartMarker') || ''; + return this.getField('stroke_startMarker') || ''; } @computed get markTail() { - return this.getField('strokeEndMarker') || ''; + return this.getField('stroke_endMarker') || ''; } set solidStk(value) { this.dashdStk = ''; @@ -839,22 +839,22 @@ export class PropertiesView extends React.Component { } set dashdStk(value) { value && (this._lastDash = value) && (this.unStrokd = false); - this.selectedDoc && (this.selectedDoc.strokeDash = value ? this._lastDash : undefined); + this.selectedDoc && (this.selectedDoc.stroke_dash = value ? this._lastDash : undefined); } set markScal(value) { this.selectedDoc && (this.selectedDoc.strokeMarkerScale = Number(value)); } set widthStk(value) { - this.selectedDoc && (this.selectedDoc.strokeWidth = Number(value)); + this.selectedDoc && (this.selectedDoc.stroke_width = Number(value)); } set unStrokd(value) { this.colorStk = value ? '' : this._lastLine; } set markHead(value) { - this.selectedDoc && (this.selectedDoc.strokeStartMarker = value); + this.selectedDoc && (this.selectedDoc.stroke_startMarker = value); } set markTail(value) { - this.selectedDoc && (this.selectedDoc.strokeEndMarker = value); + this.selectedDoc && (this.selectedDoc.stroke_endMarker = value); } @computed get stkInput() { @@ -1151,16 +1151,16 @@ export class PropertiesView extends React.Component { } @computed get description() { - return Field.toString(LinkManager.currentLink?.description as any as Field); + return Field.toString(LinkManager.currentLink?.link_description as any as Field); } @computed get relationship() { - return StrCast(LinkManager.currentLink?.linkRelationship); + return StrCast(LinkManager.currentLink?.link_relationship); } @observable private relationshipButtonColor: string = ''; // @action - // handleDescriptionChange = (e: React.ChangeEvent) => { this.description = e.target.value; } - // handleRelationshipChange = (e: React.ChangeEvent) => { this.relationship = e.target.value; } + // handleDescriptionChange = (e: React.ChangeEvent) => { this.link_description = e.target.value; } + // handleRelationshipChange = (e: React.ChangeEvent) => { this.link_relationship = e.target.value; } @undoBatch handleDescriptionChange = action((value: string) => { @@ -1171,9 +1171,9 @@ export class PropertiesView extends React.Component { }); @undoBatch - handleLinkRelationshipChange = action((value: string) => { + handlelinkRelationshipChange = action((value: string) => { if (LinkManager.currentLink && this.selectedDoc) { - this.setLinkRelationshipValue(value); + this.setlinkRelationshipValue(value); return true; } }); @@ -1181,19 +1181,19 @@ export class PropertiesView extends React.Component { @undoBatch setDescripValue = action((value: string) => { if (LinkManager.currentLink) { - Doc.GetProto(LinkManager.currentLink).description = value; + Doc.GetProto(LinkManager.currentLink).link_description = value; return true; } }); @undoBatch - setLinkRelationshipValue = action((value: string) => { + setlinkRelationshipValue = action((value: string) => { if (LinkManager.currentLink) { - const prevRelationship = LinkManager.currentLink.linkRelationship as string; - LinkManager.currentLink.linkRelationship = value; - Doc.GetProto(LinkManager.currentLink).linkRelationship = value; - const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); - const linkRelationshipSizes = NumListCast(Doc.UserDoc().linkRelationshipSizes); + const prevRelationship = StrCast(LinkManager.currentLink.link_relationship); + LinkManager.currentLink.link_relationship = value; + Doc.GetProto(LinkManager.currentLink).link_relationship = value; + const linkRelationshipList = StrListCast(Doc.UserDoc().link_relationshipList); + const linkRelationshipSizes = NumListCast(Doc.UserDoc().link_relationshipSizes); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); // if the relationship does not exist in the list, add it and a corresponding unique randomly generated color @@ -1264,13 +1264,13 @@ export class PropertiesView extends React.Component { }; onSelectOutRelationship = () => { - this.setLinkRelationshipValue(this.relationship); + this.setlinkRelationshipValue(this.relationship); document.getElementById('link_relationship_input')?.blur(); }; onRelationshipKey = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - this.setLinkRelationshipValue(this.relationship); + this.setlinkRelationshipValue(this.relationship); document.getElementById('link_relationship_input')?.blur(); } }; @@ -1283,7 +1283,7 @@ export class PropertiesView extends React.Component { const ldoc = LinkManager.currentLink; const lanch = this.selectedDocumentView?.anchorViewDoc ?? LinkManager.currentLinkAnchor; if (ldoc && lanch) return LinkManager.getOppositeAnchor(ldoc, lanch) ?? lanch; - return ldoc ? DocCast(ldoc.anchor2) : ldoc; + return ldoc ? DocCast(ldoc.link_anchor_2) : ldoc; } @computed get sourceAnchor() { @@ -1314,10 +1314,10 @@ export class PropertiesView extends React.Component {

Show link

} placement="top"> + @@ -657,7 +657,7 @@ export class CollectionViewBaseChrome extends React.Component {this.notACollection || this.props.type === CollectionViewType.Invalid ? null : this.viewModes}
- {this.aliasButton} + {this.embedButton} {/* {this.pinButton} */} {this.toggleOverlayButton}
@@ -691,7 +691,7 @@ export class CollectionFreeFormViewChrome extends React.Component key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); + const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); return keys.filter(key => key.toLowerCase().indexOf(val) > -1); - } else { - const keys = new Set(); - docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); - const noviceKeys = Array.from(keys).filter( - key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_') - ); - return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); } + const keys = new Set(); + docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); + const noviceKeys = Array.from(keys).filter( + key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_') + ); + return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); } if (docs instanceof Doc) { @@ -1125,13 +1124,13 @@ export class CollectionNoteTakingViewChrome extends React.Component key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); + const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_')); return keys.filter(key => key.toLowerCase().indexOf(val) > -1); } else { const keys = new Set(); docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key))); const noviceKeys = Array.from(keys).filter( - key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('lastModified') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_') + key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('creationDate') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_') ); return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1); } @@ -1235,9 +1234,9 @@ export class CollectionSchemaViewChrome extends React.Component 0; return ( diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 99d4d0bee..a65e23911 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -49,12 +49,12 @@ export class CollectionNoteTakingView extends CollectionSubView() { return BoolCast(this.layoutDoc.chromeHidden); } // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns - @computed get columnHeaders() { - const columnHeaders = Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null); - const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset')); - if (needsUnsetCategory || columnHeaders === undefined || columnHeaders.length === 0) { + @computed get colHeaderData() { + const colHeaderData = Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null); + const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !colHeaderData?.find(sh => sh.heading === 'unset')); + if (needsUnsetCategory || colHeaderData === undefined || colHeaderData.length === 0) { setTimeout(() => { - const columnHeaders = Array.from(Cast(this.dataDoc.columnHeaders, listSpec(SchemaHeaderField), null) ?? []); + const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null) ?? []); const needsUnsetCategory = this.childDocs.some(d => !d[this.notetakingCategoryField] && !columnHeaders?.find(sh => sh.heading === 'unset')); if (needsUnsetCategory || columnHeaders.length === 0) { columnHeaders.push(new SchemaHeaderField('unset', undefined, undefined, 1)); @@ -62,7 +62,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } }); } - return columnHeaders ?? ([] as SchemaHeaderField[]); + return colHeaderData ?? ([] as SchemaHeaderField[]); } @computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); @@ -78,7 +78,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } // numGroupColumns returns the number of columns @computed get numGroupColumns() { - return this.columnHeaders.length; + return this.colHeaderData.length; } // PanelWidth returns the size of the total available space the view occupies @computed get PanelWidth() { @@ -117,7 +117,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // (2) documentView gets unmounted as you remove it from the list @computed get Sections() { TraceMobx(); - const columnHeaders = this.columnHeaders; + const columnHeaders = this.colHeaderData; // filter out the currently dragged docs from the child docs, since we will insert them later const docs = this.childDocs.filter(d => !DragManager.docsBeingDragged.includes(d)); const sections = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); @@ -149,9 +149,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { componentDidMount() { super.componentDidMount?.(); document.addEventListener('pointerup', this.removeDocDragHighlight, true); - this._disposers.autoHeight = reaction( - () => this.layoutDoc._autoHeight, - autoHeight => autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))))) + this._disposers.layout_autoHeight = reaction( + () => this.layoutDoc._layout_autoHeight, + layout_autoHeight => + layout_autoHeight && this.props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))))) ); } @@ -230,7 +231,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { PanelHeight={height} styleProvider={this.styleProvider} docViewPath={this.props.docViewPath} - fitWidth={this.props.childFitWidth} + layout_fitWidth={this.props.childLayoutFitWidth} isContentActive={emptyFunction} onKey={this.onKeyDown} //TODO: change this from a prop to a parameter passed into a function @@ -238,12 +239,12 @@ export class CollectionNoteTakingView extends CollectionSubView() { isDocumentActive={this.isContentActive} LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} - NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox - NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childFitWidth?.(doc) || (doc._fitWidth && !Doc.NativeHeight(doc)) ? height : undefined} + NativeWidth={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeWidth(doc)) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox + NativeHeight={this.props.childIgnoreNativeSize ? returnZero : this.props.childLayoutFitWidth?.(doc) || (doc._layout_fitWidth && !Doc.NativeHeight(doc)) ? height : undefined} dontCenter={this.props.childIgnoreNativeSize ? 'xy' : undefined} dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.childDontRegisterViews, this.props.dontRegisterView)} rootSelected={this.rootSelected} - showTitle={this.props.childShowTitle} + layout_showTitle={this.props.childlayout_showTitle} dropAction={StrCast(this.layoutDoc.childDropAction) as dropActionType} onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} @@ -280,10 +281,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { // if a note doc. Otherwise, returns the normal width (for graphs, images, etc...) getDocWidth(d: Doc) { const heading = !d[this.notetakingCategoryField] ? 'unset' : Field.toString(d[this.notetakingCategoryField] as Field); - const existingHeader = this.columnHeaders.find(sh => sh.heading === heading); + const existingHeader = this.colHeaderData.find(sh => sh.heading === heading); const existingWidth = existingHeader?.width ? existingHeader.width : 0; const maxWidth = existingWidth > 0 ? existingWidth * this.availableWidth : this.maxColWidth; - const width = d.fitWidth ? maxWidth : d[WidthSym](); + const width = d.layout_fitWidth ? maxWidth : d[WidthSym](); return Math.min(maxWidth - CollectionNoteTakingViewColumn.ColumnMargin, width < maxWidth ? width : maxWidth); } @@ -293,14 +294,14 @@ export class CollectionNoteTakingView extends CollectionSubView() { const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); const childDataDoc = !d.isTemplateDoc && !d.isTemplateForField ? undefined : this.props.DataDoc; const maxHeight = (lim => (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0); if (nw && nh) { const docWid = this.getDocWidth(d); return Math.min(maxHeight, (docWid * nh) / nw); } const childHeight = NumCast(childLayoutDoc._height); - const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; + const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; return Math.min(childHeight, maxHeight, panelHeight); } @@ -318,7 +319,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const n = headers.length; const curWidths = headers.reduce((sum, hdr) => sum + Math.abs(hdr.width), 0); const scaleFactor = 1 / curWidths; - this.dataDoc.columnHeaders = new List( + this.dataDoc[this.fieldKey + '_columnHeaders'] = new List( headers.map(h => { h.setWidth(Math.abs(h.width) * scaleFactor); return h; @@ -352,7 +353,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { }); // we alter the pivot fields of the docs in case they are moved to a new column. const colIndex = this.getColumnFromXCoord(xCoord); - const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading); + const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading); DragManager.docsBeingDragged.forEach(d => (d[this.notetakingCategoryField] = colHeader)); // used to notify sections to re-render this.docsDraggedRowCol.length = 0; @@ -365,12 +366,12 @@ export class CollectionNoteTakingView extends CollectionSubView() { // This function is used to know which document a column SHOULD be in while it is being dragged. getColumnFromXCoord = (xCoord: number): number | undefined => { let colIndex: number | undefined = undefined; - const numColumns = this.columnHeaders.length; + const numColumns = this.colHeaderData.length; const coords = []; let colStartXCoord = 0; for (let i = 0; i < numColumns; i++) { coords.push(colStartXCoord); - colStartXCoord += this.columnHeaders[i].width * this.availableWidth + this.DividerWidth; + colStartXCoord += this.colHeaderData[i].width * this.availableWidth + this.DividerWidth; } coords.push(this.PanelWidth); for (let i = 0; i < numColumns; i++) { @@ -386,7 +387,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { getDocsFromXCoord = (xCoord: number): Doc[] => { const docsMatchingHeader: Doc[] = []; const colIndex = this.getColumnFromXCoord(xCoord); - const colHeader = colIndex === undefined ? 'unset' : StrCast(this.columnHeaders[colIndex].heading); + const colHeader = colIndex === undefined ? 'unset' : StrCast(this.colHeaderData[colIndex].heading); this.childDocs?.map(d => { if (d instanceof Promise) return; const sectionValue = (d[this.notetakingCategoryField] as object) ?? 'unset'; @@ -401,7 +402,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { @action onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => { const docView = fieldProps.DocumentView?.(); - if (docView && (e.ctrlKey || docView.rootDoc._singleLine) && ['Enter'].includes(e.key)) { + if (docView && (e.ctrlKey || docView.rootDoc._createDocOnCR) && ['Enter'].includes(e.key)) { e.stopPropagation?.(); const newDoc = Doc.MakeCopy(docView.rootDoc, true); Doc.GetProto(newDoc).text = undefined; @@ -436,10 +437,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { } } } - } else if (de.complete.linkDragData?.dragDocument.context === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { - const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _fitWidth: true, title: 'dropped annotation' }); + } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) { + const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' }); this.props.addDocument?.(source); - de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { linkRelationship: 'doc annotation' }); // TODODO this is where in text links get passed + de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed e.stopPropagation(); } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData); return false; @@ -468,7 +469,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { this.onPointerMove(true, e.clientX, e.clientY); docus?.map((doc: Doc) => this.addDocument(doc)); const newDoc = this.childDocs.lastElement(); - const colHeader = colInd === undefined ? 'unset' : StrCast(this.columnHeaders[colInd].heading); + const colHeader = colInd === undefined ? 'unset' : StrCast(this.colHeaderData[colInd].heading); newDoc[this.notetakingCategoryField] = colHeader; const docs = this.childDocList; if (docs && targInd !== -1) { @@ -502,7 +503,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { this.refList.push(ref); this.observer = new _global.ResizeObserver( action((entries: any) => { - if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { 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())) { this.props.setHeight?.(height); @@ -516,7 +517,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { select={this.props.select} addDocument={this.addDocument} chromeHidden={this.chromeHidden} - columnHeaders={this.columnHeaders} + colHeaderData={this.colHeaderData} Document={this.props.Document} DataDoc={this.props.DataDoc} resizeColumns={this.resizeColumns} @@ -524,6 +525,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { numGroupColumns={this.numGroupColumns} gridGap={this.gridGap} pivotField={this.notetakingCategoryField} + fieldKey={this.fieldKey} dividerWidth={this.DividerWidth} maxColWidth={this.maxColWidth} availableWidth={this.availableWidth} @@ -546,15 +548,15 @@ export class CollectionNoteTakingView extends CollectionSubView() { @undoBatch @action addGroup = (value: string) => { - if (this.columnHeaders) { - for (const header of this.columnHeaders) { + if (this.colHeaderData) { + for (const header of this.colHeaderData) { if (header.heading === value) { alert('You cannot use an existing column name. Please try a new column name'); return value; } } } - const columnHeaders = Array.from(Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null)); + const columnHeaders = Array.from(Cast(this.dataDoc[this.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null)); const newColWidth = 1 / (this.numGroupColumns + 1); columnHeaders.push(new SchemaHeaderField(value, undefined, undefined, newColWidth)); value && this.resizeColumns(columnHeaders); @@ -566,7 +568,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (!e.isPropagationStopped()) { const subItems: ContextMenuProps[] = []; subItems.push({ description: `${this.layoutDoc._columnsFill ? 'Variable Size' : 'Autosize'} Column`, event: () => (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' }); - subItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' }); + subItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: 'plus' }); subItems.push({ description: 'Clear All', event: () => (this.dataDoc.data = new List([])), icon: 'times' }); ContextMenu.Instance.addItem({ description: 'Options...', subitems: subItems, icon: 'eye' }); } @@ -576,8 +578,8 @@ export class CollectionNoteTakingView extends CollectionSubView() { @action setColumnStartXCoords = (movementXScreen: number, colIndex: number) => { const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0]; - const leftHeader = this.columnHeaders[colIndex]; - const rightHeader = this.columnHeaders[colIndex + 1]; + const leftHeader = this.colHeaderData[colIndex]; + const rightHeader = this.colHeaderData[colIndex + 1]; leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth); rightHeader.setWidth(rightHeader.width - movementX / this.availableWidth); }; diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 28bdd0cb9..63becac1e 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -29,8 +29,9 @@ interface CSVFieldColumnProps { docList: Doc[]; heading: string; pivotField: string; + fieldKey: string | undefined; chromeHidden?: boolean; - columnHeaders: SchemaHeaderField[] | undefined; + colHeaderData: SchemaHeaderField[] | undefined; headingObject: SchemaHeaderField | undefined; yMargin: number; numGroupColumns: number; @@ -61,9 +62,9 @@ export class CollectionNoteTakingViewColumn extends React.Component { const castedValue = this.getValue(value); if (castedValue) { - if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { + if (this.props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { return false; } this.props.docList.forEach(d => (d[this.props.pivotField] = castedValue)); @@ -127,7 +128,7 @@ export class CollectionNoteTakingViewColumn extends React.Component { if (!value && !forceEmptyNote) return false; const key = this.props.pivotField; - const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true }); + const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true }); const colValue = this.getValue(this.props.heading); newDoc[key] = colValue; FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -141,11 +142,11 @@ export class CollectionNoteTakingViewColumn extends React.Component { - const columnHeaders = Array.from(Cast(this.props.Document.columnHeaders, listSpec(SchemaHeaderField), null)); + const colHdrData = Array.from(Cast(this.props.Document[this.props.fieldKey + '_columnHeaders'], listSpec(SchemaHeaderField), null)); if (this.props.headingObject) { this.props.docList.forEach(d => (d[this.props.pivotField] = undefined)); - columnHeaders.splice(columnHeaders.indexOf(this.props.headingObject), 1); - this.props.resizeColumns(columnHeaders); + colHdrData.splice(colHdrData.indexOf(this.props.headingObject), 1); + this.props.resizeColumns(colHdrData); } }; @@ -211,7 +212,7 @@ export class CollectionNoteTakingViewColumn extends React.Component { Doc.GetProto(this.props.Document)[name] = ''; - const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true }); + const created = Docs.Create.TextDocument('', { title: name, _width: 250, _layout_autoHeight: true }); if (created) { if (this.props.Document.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(created, this.props.Document); @@ -243,7 +244,7 @@ export class CollectionNoteTakingViewColumn extends React.Component evContents} isEditingCallback={isEditing => isEditing && this.props.select(false)} SetValue={this.headingChanged} contents={evContents} oneLine={true} />
- {(this.props.columnHeaders?.length ?? 0) > 1 && ( + {(this.props.colHeaderData?.length ?? 0) > 1 && ( diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 5b96a8682..ea0fbbc54 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -82,8 +82,8 @@ export class CollectionPileView extends CollectionSubView() { this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize); DocUtils.pileup(this.childDocs, undefined, undefined, NumCast(this.layoutDoc._width) / 2, false); - this.layoutDoc._panX = 0; - this.layoutDoc._panY = -10; + this.layoutDoc._freeform_panX = 0; + this.layoutDoc._freeform_panY = -10; this.props.Document._pileLayoutEngine = computePassLayout.name; } else { const defaultSize = NumCast(this.rootDoc._starburstDiameter, 500); @@ -91,7 +91,7 @@ export class CollectionPileView extends CollectionSubView() { this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2; this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym](); this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym](); - this.layoutDoc._panX = this.layoutDoc._panY = 0; + this.layoutDoc._freeform_panX = this.layoutDoc._freeform_panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; this.props.Document._pileLayoutEngine = computeStarburstLayout.name; } diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 22a575989..6b4c8a3e9 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -24,7 +24,7 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { AudioWaveform } from '../AudioWaveform'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import './CollectionStackedTimeline.scss'; @@ -41,7 +41,9 @@ export type CollectionStackedTimelineProps = { mediaPath: string; dictationKey: string; rawDuration: number; + dataFieldKey: string; fieldKey: string; + thumbnails?: () => string[]; }; // trimming state: shows full clip, current trim bounds, or not trimming @@ -80,6 +82,9 @@ export class CollectionStackedTimeline extends CollectionSubView 0 ? new ImageField(thumbnails[nearest]) : undefined; + const imgField = this.thumbnails.length > 0 ? new ImageField(this.thumbnails[nearest]) : undefined; this._thumbnail = imgField?.url?.href ? imgField.url.href.replace('.png', '_m.png') : undefined; } } @@ -401,11 +405,9 @@ export class CollectionStackedTimeline extends CollectionSubView NumCast(this.layoutDoc._currentTimecode)) { + if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) && endTime > NumCast(this.layoutDoc._layout_currentTimecode)) { if (!this.layoutDoc.autoPlayAnchors && this.props.playing()) { this.props.Pause(); } else { @@ -455,7 +457,7 @@ export class CollectionStackedTimeline extends CollectionSubView NumCast(this.layoutDoc._currentTimecode) - 1e-4) { + if (seekTimeInSeconds < NumCast(this.layoutDoc._layout_currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._layout_currentTimecode) - 1e-4) { if (this.props.playing()) this.props.Pause(); else if (this.layoutDoc.autoPlayAnchors) this.props.Play(); else if (!this.layoutDoc.autoPlayAnchors) { @@ -596,6 +598,7 @@ export class CollectionStackedTimeline extends CollectionSubView void; + addDocTab: (doc: Doc, where: OpenWhere) => boolean; rangeClickScript: () => ScriptField; rangePlayScript: () => ScriptField; left: number; @@ -709,7 +714,7 @@ class StackedTimelineAnchor extends React.Component () => this.props.currentTimecode(), time => { const dictationDoc = Cast(this.props.layoutDoc['data-dictation'], Doc, null); - const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc); + const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.link_anchor_1, Doc, null)?.annotationOn === dictationDoc); if ( !LightboxView.LightboxDoc && // bcz: when should links be followed? we don't want to move away from the video to follow a link but we can open it in a sidebar/etc. But we don't know that upfront. @@ -808,11 +813,9 @@ class StackedTimelineAnchor extends React.Component isDocumentActive={this.props.isDocumentActive} PanelWidth={width} PanelHeight={height} - fitWidth={returnTrue} + layout_fitWidth={returnTrue} ScreenToLocalTransform={screenXf} - addDocTab={returnFalse} pinToPres={emptyFunction} - whenChildContentsActiveChanged={emptyFunction} focus={focusFunc} isContentActive={returnFalse} searchFilterDocs={returnEmptyDoclist} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index eedf639aa..404ca5d65 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -49,7 +49,7 @@ export class CollectionStackingView extends CollectionSubView number; width: () => number; stackedDocTransform: () => Transform }[] = []; // Doesn't look like this field is being used anywhere. Obsolete? @@ -65,8 +65,8 @@ export class CollectionStackingView extends CollectionSubView(); + this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List(); } } @@ -154,14 +154,14 @@ export class CollectionStackingView extends CollectionSubView(); + if (!this.pivotField || this.colHeaderData instanceof Promise) return new Map(); - if (this.columnHeaders === undefined) { - setTimeout(() => (this.layoutDoc._columnHeaders = new List()), 0); + if (this.colHeaderData === undefined) { + setTimeout(() => (this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List()), 0); return new Map(); } - const columnHeaders = Array.from(this.columnHeaders); - const fields = new Map(columnHeaders.map(sh => [sh, []] as [SchemaHeaderField, []])); + const colHeaderData = Array.from(this.colHeaderData); + const fields = new Map(colHeaderData.map(sh => [sh, []] as [SchemaHeaderField, []])); let changed = false; this.filteredChildren.map(d => { const sectionValue = (d[this.pivotField] ? d[this.pivotField] : `NO ${this.pivotField.toUpperCase()} VALUE`) as object; @@ -170,13 +170,13 @@ export class CollectionStackingView extends CollectionSubView sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`)); + const existingHeader = colHeaderData.find(sh => sh.heading === (castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`)); if (existingHeader) { fields.get(existingHeader)!.push(d); } else { const newSchemaHeader = new SchemaHeaderField(castedSectionValue ? castedSectionValue.toString() : `NO ${this.pivotField.toUpperCase()} VALUE`); fields.set(newSchemaHeader, [d]); - columnHeaders.push(newSchemaHeader); + colHeaderData.push(newSchemaHeader); changed = true; } }); @@ -187,13 +187,13 @@ export class CollectionStackingView extends CollectionSubView !fields.get(key)!.length) .map(header => { fields.delete(header); - columnHeaders.splice(columnHeaders.indexOf(header), 1); + colHeaderData.splice(colHeaderData.indexOf(header), 1); changed = true; }); } changed && setTimeout( - action(() => this.columnHeaders?.splice(0, this.columnHeaders.length, ...columnHeaders)), + action(() => this.colHeaderData?.splice(0, this.colHeaderData.length, ...colHeaderData)), 0 ); return fields; @@ -206,12 +206,12 @@ export class CollectionStackingView extends CollectionSubView this.pivotField, - () => (this.layoutDoc._columnHeaders = new List()) + () => (this.layoutDoc['_' + this.fieldKey + '_columnHeaders'] = new List()) ); - this._autoHeightDisposer = reaction( - () => this.layoutDoc._autoHeight, - autoHeight => - autoHeight && + this._layout_autoHeightDisposer = reaction( + () => this.layoutDoc._layout_autoHeight, + layout_autoHeight => + layout_autoHeight && this.props.setHeight?.( Math.min( NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), @@ -224,7 +224,7 @@ export class CollectionStackingView extends CollectionSubView this.props.isAnyChildContentActive(); @@ -282,12 +282,12 @@ export class CollectionStackingView extends CollectionSubView([]) : undefined; - if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) { - newDoc[layoutKey] = docView.rootDoc[layoutKey]; + if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -327,19 +327,19 @@ export class CollectionStackingView extends CollectionSubView (lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim))(NumCast(this.layoutDoc.childLimitHeight, -1)); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[WidthSym]() : 0); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._fitWidth || this.props.childFitWidth?.(d)) ? d[HeightSym]() : 0); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[WidthSym]() : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!(childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d)) ? d[HeightSym]() : 0); if (nw && nh) { const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); return Math.min(maxHeight, (docWid * nh) / nw); } const childHeight = NumCast(childLayoutDoc._height); - const panelHeight = childLayoutDoc._fitWidth || this.props.childFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; + const panelHeight = childLayoutDoc._layout_fitWidth || this.props.childLayoutFitWidth?.(d) ? Number.MAX_SAFE_INTEGER : this.props.PanelHeight() - 2 * this.yMargin; return Math.min(childHeight, maxHeight, panelHeight); } @@ -460,10 +460,10 @@ export class CollectionStackingView extends CollectionSubView { - if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { 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())) { this.props.setHeight?.(height); @@ -539,7 +539,7 @@ export class CollectionStackingView extends CollectionSubView { - if (this.layoutDoc._autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { + if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.GetIsDragging()) { const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0); this.props.setHeight?.(this.headerMargin + height); } @@ -608,9 +608,9 @@ export class CollectionStackingView extends CollectionSubView { - if (value && this.columnHeaders) { + if (value && this.colHeaderData) { const schemaHdrField = new SchemaHeaderField(value); - this.columnHeaders.push(schemaHdrField); + this.colHeaderData.push(schemaHdrField); return true; } return false; @@ -630,7 +630,7 @@ export class CollectionStackingView extends CollectionSubView (this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill), icon: 'plus' }); - optionItems.push({ description: `${this.layoutDoc._autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight), icon: 'plus' }); + optionItems.push({ description: `${this.layoutDoc._layout_autoHeight ? 'Variable Height' : 'Auto Height'}`, event: () => (this.layoutDoc._layout_autoHeight = !this.layoutDoc._layout_autoHeight), icon: 'plus' }); optionItems.push({ description: 'Clear All', event: () => (this.dataDoc[this.fieldKey ?? 'data'] = new List([])), icon: 'times' }); !options && cm.addItem({ description: 'Options...', subitems: optionItems, icon: 'compass' }); } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index d62c4dc62..243550c0b 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -34,7 +34,7 @@ interface CSVFieldColumnProps { heading: string; pivotField: string; chromeHidden?: boolean; - columnHeaders: SchemaHeaderField[] | undefined; + colHeaderData: SchemaHeaderField[] | undefined; headingObject: SchemaHeaderField | undefined; yMargin: number; columnWidth: number; @@ -93,7 +93,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) }; - drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false)); + this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false)); }); getValue = (value: string): any => { const parsed = parseInt(value); @@ -107,7 +107,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { const castedValue = this.getValue(value); if (castedValue) { - if (this.props.columnHeaders?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { + if (this.props.colHeaderData?.map(i => i.heading).indexOf(castedValue.toString()) !== -1) { return false; } this.props.docList.forEach(d => (d[this.props.pivotField] = castedValue)); @@ -134,7 +134,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { if (!value && !forceEmptyNote) return false; const key = this.props.pivotField; - const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _fitWidth: true, title: value, _autoHeight: true }); + const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true }); newDoc[key] = this.getValue(this.props.heading); const maxHeading = this.props.docList.reduce((maxHeading, doc) => (NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading), 0); const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3; @@ -147,9 +147,9 @@ export class CollectionStackingViewFieldColumn extends React.Component { this.props.docList.forEach(d => (d[this.props.pivotField] = undefined)); - if (this.props.columnHeaders && this.props.headingObject) { - const index = this.props.columnHeaders.indexOf(this.props.headingObject); - this.props.columnHeaders.splice(index, 1); + if (this.props.colHeaderData && this.props.headingObject) { + const index = this.props.colHeaderData.indexOf(this.props.headingObject); + this.props.colHeaderData.splice(index, 1); } }; @@ -163,15 +163,15 @@ export class CollectionStackingViewFieldColumn extends React.Component { - // is MakeAlias a way to make a copy of a doc without rendering it? - const alias = Doc.MakeAlias(this.props.Document); - alias._width = this.props.columnWidth / (this.props.columnHeaders?.length || 1); - alias._pivotField = undefined; + // is MakeEmbedding a way to make a copy of a doc without rendering it? + const embedding = Doc.MakeEmbedding(this.props.Document); + embedding._width = this.props.columnWidth / (this.props.colHeaderData?.length || 1); + embedding._pivotField = undefined; let value = this.getValue(this._heading); value = typeof value === 'string' ? `"${value}"` : value; - alias.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name }); - if (alias.viewSpecScript) { - DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY); + embedding.viewSpecScript = ScriptField.MakeFunction(`doc.${this.props.pivotField} === ${value}`, { doc: Doc.name }); + if (embedding.viewSpecScript) { + DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([embedding]), e.clientX, e.clientY); return true; } return false; @@ -266,7 +266,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { Doc.GetProto(this.props.Document)[name] = ''; - const created = Docs.Create.TextDocument('', { title: name, _width: 250, _autoHeight: true }); + const created = Docs.Create.TextDocument('', { title: name, _width: 250, _layout_autoHeight: true }); if (created) { if (this.props.Document.isTemplateDoc) { Doc.MakeMetadataFieldTemplate(created, this.props.Document); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5b9453666..008de1944 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -129,7 +129,7 @@ export function CollectionSubView(moreProps?: X) { notFiltered = (!searchDocs.length || searchDocs.includes(d)) && DocUtils.FilterDocs([d], childDocFilters, docRangeFilters, this.props.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]; + const data = d[annos ? fieldKey + '_annotations' : fieldKey]; if (data !== undefined) { let subDocs = DocListCast(data); if (subDocs.length > 0) { @@ -141,7 +141,7 @@ export function CollectionSubView(moreProps?: X) { const fieldKey = Doc.LayoutFieldKey(t); const annos = !Field.toString(Doc.LayoutField(t) as Field).includes(CollectionView.name); notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!childDocFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], childDocFilters, docRangeFilters, d).length)); - DocListCast(t[annos ? fieldKey + '-annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); + DocListCast(t[annos ? fieldKey + '_annotations' : fieldKey]).forEach(newdoc => newarray.push(newdoc)); }); subDocs = newarray; } @@ -188,9 +188,9 @@ export function CollectionSubView(moreProps?: X) { protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) { if (de.complete.docDragData) { - // if targetDropAction is, say 'alias', but we're just dragging within a collection, we want to ignore the targetAction. + // if targetDropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction. // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys) - if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.context === this.props.Document && this.childDocs.includes(d))) { + if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) { de.complete.docDragData.dropAction = targetAction; } e.stopPropagation(); @@ -282,7 +282,7 @@ export function CollectionSubView(moreProps?: X) { addDocument(Docs.Create.WebDocument(href, { ...options, title: href })); } } else if (text) { - addDocument(Docs.Create.TextDocument(text, { ...options, _showTitle: StrCast(Doc.UserDoc().showTitle), _width: 100, _height: 25 })); + addDocument(Docs.Create.TextDocument(text, { ...options, _layout_showTitle: StrCast(Doc.UserDoc().layout_showTitle), _width: 100, _height: 25 })); } return; } @@ -375,7 +375,7 @@ export function CollectionSubView(moreProps?: X) { _width: 400, _height: 512, _nativeWidth: 850, - useCors: true, + data_useCors: true, }) ); return; @@ -417,7 +417,7 @@ export function CollectionSubView(moreProps?: X) { proto._height = 20; return proto; }), - { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _singleLine: true } + { _width: 150, _height: 600, title: 'across', backgroundColor: 'white', _createDocOnCR: true } ) ); }); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 3cdb460a3..6135154c3 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -35,7 +35,7 @@ export class CollectionTimeView extends CollectionSubView() { async componentDidMount() { this.props.setContentView?.(this); //const detailView = (await DocCastAsync(this.props.Document.childClickedOpenTemplateView)) || DocUtils.findTemplate("detailView", StrCast(this.rootDoc.type), ""); - ///const childText = "const alias = getAlias(self); switchView(alias, detailView); alias.dropAction='alias'; useRightSplit(alias, shiftKey); "; + ///const childText = "const embedding = getEmbedding(self); switchView(embedding, detailView); embedding.dropAction='embed'; useRightSplit(embedding, shiftKey); "; runInAction(() => { this._childClickedScript = ScriptField.MakeScript('openInLightbox(self)', { this: Doc.name }); this._viewDefDivClick = ScriptField.MakeScript('pivotColumnClick(this,payload)', { payload: 'any' }); @@ -55,10 +55,10 @@ export class CollectionTimeView extends CollectionSubView() { if (addAsAnnotation) { // when added as an annotation, links to anchors can be found as links to the document even if the anchors are not rendered - if (Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), null) !== undefined) { - Cast(this.dataDoc[this.props.fieldKey + '-annotations'], listSpec(Doc), []).push(anchor); + if (Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), null) !== undefined) { + Cast(this.dataDoc[this.props.fieldKey + '_annotations'], listSpec(Doc), []).push(anchor); } else { - this.dataDoc[this.props.fieldKey + '-annotations'] = new List([anchor]); + this.dataDoc[this.props.fieldKey + '_annotations'] = new List([anchor]); } } return anchor; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index f774781ab..095e34c39 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -104,7 +104,7 @@ export class CollectionTreeView extends CollectionSubView this.rootDoc.autoHeight, + () => this.rootDoc.layout_autoHeight, auto => auto && this.computeHeight(), { fireImmediately: true } ); @@ -114,25 +114,25 @@ export class CollectionTreeView extends CollectionSubView p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6; - this.layoutDoc._autoHeightMargins = bodyHeight; + this.layoutDoc._layout_autoHeightMargins = bodyHeight; !this.props.dontRegisterView && this.props.setHeight?.(bodyHeight + titleHeight); } }; unobserveHeight = (ref: any) => { this.refList.delete(ref); - this.rootDoc.autoHeight && this.computeHeight(); + this.rootDoc.layout_autoHeight && this.computeHeight(); }; observeHeight = (ref: any) => { if (ref) { this.refList.add(ref); this.observer = new _global.ResizeObserver( action((entries: any) => { - if (this.rootDoc.autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { + if (this.rootDoc.layout_autoHeight && ref && this.refList.size && !SnappingManager.GetIsDragging()) { this.computeHeight(); } }) ); - this.rootDoc.autoHeight && this.computeHeight(); + this.rootDoc.layout_autoHeight && this.computeHeight(); this.observer.observe(ref); } }; @@ -144,7 +144,7 @@ export class CollectionTreeView extends CollectionSubView { const dragData = de.complete.docDragData; if (dragData) { - const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.context === this.doc && this.childDocs.includes(d)); + const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d)); dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction; } }; @@ -176,7 +176,7 @@ export class CollectionTreeView extends CollectionSubView (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => { const res = flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before); - res && (doc.context = this.props.Document); + res && (doc.embedContainer = this.props.Document); return res; }, true); if (this.doc.resolvedDataDoc instanceof Promise) return false; @@ -234,7 +234,7 @@ export class CollectionTreeView extends CollectionSubView NumCast(this.doc._yMargin); marginBot = () => NumCast(this.doc._yMargin); documentTitleWidth = () => Math.min(this.layoutDoc?.[WidthSym](), this.panelWidth()); - documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.autoHeightMargins); + documentTitleHeight = () => (this.layoutDoc?.[HeightSym]() || 0) - NumCast(this.layoutDoc.layout_autoHeightMargins); truncateTitleWidth = () => this.treeViewtruncateTitleWidth; onChildClick = () => this.props.onChildClick?.() || ScriptCast(this.doc.onChildClick); panelWidth = () => Math.max(0, this.props.PanelWidth() - 2 * this.marginX() * (this.props.NativeDimScaling?.() || 1)); - addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}-annotations`) || false; - remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}-annotations`) || false; + addAnnotationDocument = (doc: Doc | Doc[]) => this.addDocument(doc, `${this.props.fieldKey}_annotations`) || false; + remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this.props.fieldKey}_annotations`) || false; moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => - this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}-annotations`) || false; + this.moveDocument(doc, targetCollection, addDocument, `${this.props.fieldKey}_annotations`) || false; @observable _headerHeight = 0; @computed get content() { @@ -430,7 +430,7 @@ export class CollectionTreeView extends CollectionSubView {!(this.doc instanceof Doc) || !this.treeChildren ? null : this.doc.treeViewHasOverlay ? ( @@ -443,7 +443,7 @@ export class CollectionTreeView extends CollectionSubView boolean | undefined; // whether child documents can be dragged if collection can be dragged (eg., in a when a Pile document is in startburst mode) childContentsActive?: () => boolean | undefined; - childFitWidth?: (child: Doc) => boolean; - childShowTitle?: () => string; + childLayoutFitWidth?: (child: Doc) => boolean; + childlayout_showTitle?: () => string; childOpacity?: () => number; childContextMenuItems?: () => { script: ScriptField; label: string }[]; childHideTitle?: () => boolean; // whether to hide the documentdecorations title for children @@ -134,8 +134,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent func(CollectionViewType.Freeform), icon: 'signature' }, { description: 'Schema', event: () => func(CollectionViewType.Schema), icon: 'th-list' }, { description: 'Tree', event: () => func(CollectionViewType.Tree), icon: 'tree' }, - { description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._autoHeight = true), icon: 'ellipsis-v' }, - { description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._autoHeight = true), icon: 'ellipsis-v' }, + { description: 'Stacking', event: () => (func(CollectionViewType.Stacking)._layout_autoHeight = true), icon: 'ellipsis-v' }, + { description: 'Notetaking', event: () => (func(CollectionViewType.NoteTaking)._layout_autoHeight = true), icon: 'ellipsis-v' }, { description: 'Multicolumn', event: () => func(CollectionViewType.Multicolumn), icon: 'columns' }, { description: 'Multirow', event: () => func(CollectionViewType.Multirow), icon: 'columns' }, { description: 'Masonry', event: () => func(CollectionViewType.Masonry), icon: 'columns' }, @@ -159,7 +159,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const newRendition = Doc.MakeAlias(this.rootDoc); + const newRendition = Doc.MakeEmbedding(this.rootDoc); newRendition._viewType = vtype; this.props.addDocTab(newRendition, OpenWhere.addRight); return newRendition; @@ -190,9 +190,9 @@ export class CollectionView extends ViewBoxAnnotatableComponent { - const alias = Doc.MakeAlias(this.rootDoc); - DocUtils.makeCustomViewClicked(alias, undefined, func.key); - this.props.addDocTab(alias, OpenWhere.addRight); + const embedding = Doc.MakeEmbedding(this.rootDoc); + DocUtils.makeCustomViewClicked(embedding, undefined, func.key); + this.props.addDocTab(embedding, OpenWhere.addRight); }, }) ); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 45604c1bf..69963736b 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -252,11 +252,11 @@ export class TabDocView extends React.Component { const pinDoc = Doc.MakeDelegate(anchorDoc && anchorDoc !== doc ? anchorDoc : doc); pinDoc.presentationTargetDoc = anchorDoc ?? doc; pinDoc.title = doc.title + ' - Slide'; - pinDoc.data = new List(); // the children of the alias' layout are the presentation slide children. the alias' data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data + pinDoc.data = new List(); // the children of the embedding's layout are the presentation slide children. the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data pinDoc.presMovement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom; pinDoc.presDuration = pinDoc.presDuration ?? 1000; pinDoc.groupWithUp = false; - pinDoc.context = curPres; + pinDoc.embedContainer = curPres; // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area pinDoc.treeViewHeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling. @@ -264,7 +264,7 @@ export class TabDocView extends React.Component { pinDoc.treeViewFieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field pinDoc.treeViewExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header - const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null); + const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null); if (pinProps.pinViewport) PresBox.pinDocView(pinDoc, pinProps, anchorDoc ?? doc); if (!pinProps?.audioRange && duration !== undefined) { @@ -283,7 +283,7 @@ export class TabDocView extends React.Component { pinDoc.title = doc.title + ' (move)'; pinDoc.presMovement = PresMovement.Pan; } - if (pinDoc.isInkMask) { + if (pinDoc.stroke_isInkMask) { pinDoc.presHideAfter = true; pinDoc.presHideBefore = true; pinDoc.presMovement = PresMovement.None; @@ -357,7 +357,7 @@ export class TabDocView extends React.Component { switch (whereFields[0]) { case undefined: case OpenWhere.lightbox: if (this.layoutDoc?._isLightbox) { - const lightboxView = !doc.annotationOn && DocCast(doc.context) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.context)) : undefined; + const lightboxView = !doc.annotationOn && DocCast(doc.embedContainer) ? DocumentManager.Instance.getFirstDocumentView(DocCast(doc.embedContainer)) : undefined; const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)]; if (lightboxView && (!data || data instanceof List)) { lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.rootDoc)] = new List([doc]); @@ -409,7 +409,7 @@ export class TabDocView extends React.Component { miniMapColor = () => this.tabColor; tabView = () => this._view; disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform; - hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap); + hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap); @computed get docView() { return !this._activated || !this._document ? null : ( @@ -449,19 +449,19 @@ export class TabDocView extends React.Component { pinToPres={TabDocView.PinDoc} /> - {this._document.hideMinimap ? 'Open minimap' : 'Close minimap'}
}> + {this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}
}>
e.stopPropagation()} onClick={action(e => { e.stopPropagation(); - this._document!.hideMinimap = !this._document!.hideMinimap; + this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap; })}>
@@ -559,8 +559,8 @@ export class TabMinimapView extends React.Component { this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - doc._panX = clamp(NumCast(doc._panX) + (delta[0] / miniSize) * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim); - doc._panY = clamp(NumCast(doc._panY) + (delta[1] / miniSize) * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim); + doc._freeform_panX = clamp(NumCast(doc._freeform_panX) + (delta[0] / miniSize) * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim); + doc._freeform_panY = clamp(NumCast(doc._freeform_panY) + (delta[1] / miniSize) * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim); return false; }), emptyFunction, @@ -569,10 +569,10 @@ export class TabMinimapView extends React.Component { }; render() { if (!this.renderBounds) return null; - const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim) * 100; - const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim) * 100; - const miniLeft = 50 + ((NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2; - const miniTop = 50 + ((NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2; + const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100; + const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100; + const miniLeft = 50 + ((NumCast(this.props.document._freeform_) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2; + const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2; const miniSize = this.returnMiniSize(); return this.props.hideMinimap() ? null : (
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 4adf86683..92b70cb5a 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -102,7 +102,7 @@ export class TreeView extends React.Component { private _treedropDisposer?: DragManager.DragDropDisposer; get treeViewOpenIsTransient() { - return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsPrototype(this.doc); + return this.props.treeView.doc.treeViewOpenIsTransient || Doc.IsDocDataProto(this.doc); } set treeViewOpen(c: boolean) { if (this.treeViewOpenIsTransient) this._transientOpenState = c; @@ -125,7 +125,7 @@ export class TreeView extends React.Component { : this.props.treeView.fileSysMode ? this.doc.isFolder ? this.fieldKey - : 'aliases' // for displaying + : 'embeddings' // for displaying : this.props.treeView.outlineMode || this.childDocs ? this.fieldKey : Doc.noviceMode @@ -160,11 +160,11 @@ export class TreeView extends React.Component { @computed get childLinks() { return this.childDocList('links'); } - @computed get childAliases() { - return this.childDocList('aliases'); + @computed get childEmbeddings() { + return this.childDocList('proto_embeddings'); } @computed get childAnnos() { - return this.childDocList(this.fieldKey + '-annotations'); + return this.childDocList(this.fieldKey + '_annotations'); } @computed get selected() { return SelectionManager.IsSelected(this._docRef); @@ -219,11 +219,13 @@ export class TreeView extends React.Component { if (this.props.document.isFolder || Doc.IsSystem(this.props.document)) { this.treeViewOpen = !this.treeViewOpen; } else { - // choose an appropriate alias or make one. --- choose the first alias that (1) user owns, (2) has no context field ... otherwise make a new alias - const bestAlias = - docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail); - const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail); - this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), OpenWhere.lightbox); + // choose an appropriate embedding or make one. --- choose the first embedding that (1) user owns, (2) has no context field ... otherwise make a new embedding + const bestEmbedding = + docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsDocDataProto(docView.props.Document) + ? docView.props.Document + : DocListCast(this.props.document.proto_embeddings).find(doc => !doc.embedContainer && doc.author === Doc.CurrentUserEmail); + const nextBestEmbedding = DocListCast(this.props.document.proto_embeddings).find(doc => doc.author === Doc.CurrentUserEmail); + this.props.addDocTab(bestEmbedding ?? nextBestEmbedding ?? Doc.MakeEmbedding(this.props.document), OpenWhere.lightbox); } }; @@ -311,16 +313,16 @@ export class TreeView extends React.Component { treeViewExpandedViewLock: true, treeViewExpandedView: 'data', _viewType: CollectionViewType.Tree, - hideLinkButton: true, - _showSidebar: true, - _fitWidth: true, + layout_hideLinkButton: true, + _layout_showSidebar: true, + _layout_fitWidth: true, treeViewType: TreeViewType.outline, x: 0, y: 0, _xMargin: 0, _yMargin: 0, - _autoHeight: true, - _singleLine: true, + _layout_autoHeight: true, + _createDocOnCR: true, _width: 1000, _height: 10, }); @@ -359,7 +361,7 @@ export class TreeView extends React.Component { if (de.complete.linkDragData) { const sourceDoc = de.complete.linkDragData.linkSourceGetAnchor(); const destDoc = this.doc; - DocUtils.MakeLink(sourceDoc, destDoc, { linkRelationship: 'tree link' }); + DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' }); e.stopPropagation(); } const docDragData = de.complete.docDragData; @@ -378,7 +380,7 @@ export class TreeView extends React.Component { const innerAdd = (doc: Doc) => { const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[this.fieldKey])) instanceof ComputedField; const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, this.fieldKey, doc); - dataIsComputed && (doc.context = this.doc.context); + dataIsComputed && (doc.embedContainer = this.doc.embedContainer); return added; }; return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean); @@ -413,7 +415,7 @@ export class TreeView extends React.Component { (() => { const aspect = Doc.NativeAspect(layoutDoc); if (aspect) return this.embeddedPanelWidth() / (aspect || 1); - return layoutDoc._fitWidth + return layoutDoc._layout_fitWidth ? !Doc.NativeHeight(layoutDoc) ? NumCast(layoutDoc._height) : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height))) @@ -441,7 +443,7 @@ export class TreeView extends React.Component { const innerAdd = (doc: Doc) => { const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField; const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); - dataIsComputed && (doc.context = this.doc.context); + dataIsComputed && (doc.embedContainer = this.doc.embedContainer); return added; }; return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean); @@ -527,7 +529,7 @@ export class TreeView extends React.Component { TraceMobx(); const expandKey = this.treeViewExpandedView; const sortings = (this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.TreeViewSortings) as { [key: string]: { color: string; label: string } }) ?? {}; - if (['links', 'annotations', 'aliases', this.fieldKey].includes(expandKey)) { + if (['links', 'annotations', 'embeddings', this.fieldKey].includes(expandKey)) { const sorting = StrCast(this.doc.treeViewSortCriterion, TreeSort.None); const sortKeys = Object.keys(sortings); const curSortIndex = Math.max( @@ -549,12 +551,12 @@ export class TreeView extends React.Component { } const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField; const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); - !dataIsComputed && added && (doc.context = this.doc.context); + !dataIsComputed && added && (doc.embedContainer = this.doc.embedContainer); return added; }; const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true); - const docs = expandKey === 'aliases' ? this.childAliases : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs; + const docs = expandKey === 'embeddings' ? this.childEmbeddings : expandKey === 'links' ? this.childLinks : expandKey === 'annotations' ? this.childAnnos : this.childDocs; let downX = 0, downY = 0; if (docs?.length && this._renderCount < docs?.length) { @@ -706,13 +708,13 @@ export class TreeView extends React.Component { } @computed get validExpandViewTypes() { - const annos = () => (DocListCast(this.doc[this.fieldKey + '-annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : ''); + const annos = () => (DocListCast(this.doc[this.fieldKey + '_annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : ''); const links = () => (LinkManager.Links(this.doc).length && !this.props.treeView.dashboardMode ? 'links' : ''); const data = () => (this.childDocs || this.props.treeView.dashboardMode ? this.fieldKey : ''); - const aliases = () => (this.props.treeView.dashboardMode ? '' : 'aliases'); + const embeddings = () => (this.props.treeView.dashboardMode ? '' : 'embeddings'); const fields = () => (Doc.noviceMode ? '' : 'fields'); const layout = Doc.noviceMode || this.doc.viewType === CollectionViewType.Docking ? [] : ['layout']; - return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [aliases(), links(), annos()] : []), fields()].filter(m => m); + return [data(), ...layout, ...(this.props.treeView.fileSysMode ? [embeddings(), links(), annos()] : []), fields()].filter(m => m); } @action expandNextviewType = () => { @@ -759,7 +761,7 @@ export class TreeView extends React.Component { const makeFolder = { script: ScriptField.MakeFunction(`scriptContext.makeFolder()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'New Folder' }; const deleteItem = { script: ScriptField.MakeFunction(`scriptContext.deleteItem()`, { scriptContext: 'any' })!, icon: 'folder-plus', label: 'Delete' }; const folderOp = this.childDocs?.length ? [makeFolder] : []; - const openAlias = { script: ScriptField.MakeFunction(`openDoc(getAlias(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Alias' }; + const openEmbedding = { script: ScriptField.MakeFunction(`openDoc(getEmbedding(self), ${OpenWhere.addRight})`)!, icon: 'copy', label: 'Open Embedding' }; const focusDoc = { script: ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!, icon: 'eye', label: 'Focus or Open' }; return [ ...(this.props.contextMenuItems ?? []).filter(mi => (!mi.filter ? true : mi.filter.script.run({ doc: this.doc })?.result)), @@ -768,10 +770,10 @@ export class TreeView extends React.Component { : Doc.IsSystem(this.doc) ? [] : this.props.treeView.fileSysMode && this.doc === Doc.GetProto(this.doc) - ? [openAlias, makeFolder] + ? [openEmbedding, makeFolder] : this.doc.viewType === CollectionViewType.Docking ? [] - : [deleteItem, openAlias, focusDoc]), + : [deleteItem, openEmbedding, focusDoc]), ]; }; childContextMenuItems = () => { @@ -896,7 +898,7 @@ export class TreeView extends React.Component { } })} Document={this.doc} - fitWidth={returnTrue} + layout_fitWidth={returnTrue} DataDoc={undefined} scriptContext={this} hideDecorationTitle={this.props.treeView.outlineMode} @@ -985,7 +987,7 @@ export class TreeView extends React.Component { ref={action((r: DocumentView | null) => (this._dref = r))} Document={this.doc} DataDoc={undefined} - fitWidth={this.fitWidthFilter} + layout_fitWidth={this.fitWidthFilter} PanelWidth={this.embeddedPanelWidth} PanelHeight={this.embeddedPanelHeight} LayoutTemplateString={asText ? FormattedTextBox.LayoutString('text') : undefined} @@ -1179,7 +1181,7 @@ export class TreeView extends React.Component { TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined; Doc.AddDocToList(newParent, fieldKey, child, addAfter, false); newParent.treeViewOpen = true; - child.context = treeView.Document; + child.embedContainer = treeView.Document; } }; const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1])); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 0dfd119d7..68ba3d368 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -34,11 +34,11 @@ export class CollectionFreeFormLinkView extends React.Component [ this.props.A.props.ScreenToLocalTransform(), - Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop, - Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.[CssSym], + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[CssSym], this.props.B.props.ScreenToLocalTransform(), - Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop, - Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.[CssSym], + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, + Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[CssSym], ], action(() => { this._start = Date.now(); @@ -58,7 +58,7 @@ export class CollectionFreeFormLinkView extends React.Component (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), + action(() => (!LinkDocs.length || !linkDoc.layout_linkDisplay) && (this._opacity = 0.05)), 750 ); // this will unhighlight the link line. const a = A.ContentDiv.getBoundingClientRect(); @@ -72,36 +72,36 @@ export class CollectionFreeFormLinkView extends React.Component= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100; - if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100; + if (mpx >= 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; else linkDoc.opacity = 1; } if (!targetBhyperlink) { - if (linkDoc.linkAutoMove) { - linkDoc.anchor2_x = ((bpt.point.x - bleft) / bwidth) * 100; - linkDoc.anchor2_y = ((bpt.point.y - btop) / bheight) * 100; + if (linkDoc.layout_autoMoveAnchors) { + linkDoc.link_anchor_2_x = ((bpt.point.x - bleft) / bwidth) * 100; + linkDoc.link_anchor_2_y = ((bpt.point.y - btop) / bheight) * 100; } } else { const m = targetBhyperlink.getBoundingClientRect(); const mp = B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5); const mpx = mp[0] / B.props.PanelWidth(); const mpy = mp[1] / B.props.PanelHeight(); - if (mpx >= 0 && mpx <= 1) linkDoc.anchor2_x = mpx * 100; - if (mpy >= 0 && mpy <= 1) linkDoc.anchor2_y = mpy * 100; + if (mpx >= 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; else linkDoc.opacity = 1; } @@ -112,8 +112,8 @@ export class CollectionFreeFormLinkView extends React.Component { - this.props.LinkDocs[0].linkOffsetX = NumCast(this.props.LinkDocs[0].linkOffsetX) + delta[0]; - this.props.LinkDocs[0].linkOffsetY = NumCast(this.props.LinkDocs[0].linkOffsetY) + 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, @@ -205,8 +205,8 @@ export class CollectionFreeFormLinkView extends React.Component; + const linkRelationship = Field.toString(link?.link_relationship as any as Field); //get string representing relationship + const linkRelationshipList = Doc.UserDoc().link_relationshipList as List; const linkColorList = Doc.UserDoc().linkColorList as List; - const linkRelationshipSizes = Doc.UserDoc().linkRelationshipSizes as List; + const linkRelationshipSizes = Doc.UserDoc().link_relationshipSizes as List; const currRelationshipIndex = linkRelationshipList.indexOf(linkRelationship); - const linkDescription = Field.toString(link.description as any as Field); + const linkDescription = Field.toString(link.link_description as any as Field); const linkSize = currRelationshipIndex === -1 || currRelationshipIndex >= linkRelationshipSizes.length ? -1 : linkRelationshipSizes[currRelationshipIndex]; @@ -261,11 +261,11 @@ export class CollectionFreeFormLinkView extends React.Component @@ -294,7 +294,7 @@ export class CollectionFreeFormLinkView extends React.Component {textX === undefined || !linkDescription ? null : ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 08e3174d1..4d18ebeea 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -100,13 +100,13 @@ export class CollectionFreeFormView extends CollectionSubView { if (this.props.DocumentView?.().nativeWidth) return; const vals = this.fitToContentVals; - this.layoutDoc._panX = vals.bounds.cx; - this.layoutDoc._panY = vals.bounds.cy; - this.layoutDoc._viewScale = vals.scale; + this.layoutDoc._freeform_panX = vals.bounds.cx; + this.layoutDoc._freeform_panY = vals.bounds.cy; + this.layoutDoc._freeform_scale = vals.scale; }; freeformData = (force?: boolean) => (!this._firstRender && (this.fitContentsToBox || force) ? this.fitToContentVals : undefined); reverseNativeScaling = () => (this.fitContentsToBox ? true : false); - // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. + // freeform_panx, freeform_pany, freeform_scale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image - panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); - panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); + panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1)); + panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1)); zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); contentTransform = () => this.props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; @@ -297,7 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView= -1e-4 && curTime <= endTime); } @@ -348,7 +348,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout) .slice() .sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); - zsorted.forEach((doc, index) => (doc.zIndex = doc.isInkMask ? 5000 : index + 1)); + zsorted.forEach((doc, index) => (doc.zIndex = doc.stroke_isInkMask ? 5000 : index + 1)); const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000)); const dropPos = this.Document._currentFrame !== undefined ? [NumCast(dvals.x), NumCast(dvals.y)] : [NumCast(refDoc.x), NumCast(refDoc.y)]; @@ -366,7 +366,7 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout) .reduce((cluster, cd) => { - const grouping = this.props.Document._useClusters ? NumCast(cd.cluster, -1) : NumCast(cd.group, -1); + const grouping = this.props.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; @@ -463,10 +463,10 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster); + const eles = this.childLayoutPairs.map(pair => 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 { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 }; - const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined); + const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'embed' : undefined); de.moveDocument = this.props.moveDocument; de.offset = this.getTransform().transformDirection(ptsParent.clientX - left, ptsParent.clientY - top); DragManager.StartDocumentDrag( @@ -485,8 +485,8 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).map(c => this.updateCluster(c)); } @@ -494,38 +494,43 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout); - if (this.props.Document._useClusters) { + if (this.props.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.cluster); - docs.map(doc => (doc.cluster = -1)); + const preferredInd = NumCast(docFirst.layout_cluster); + docs.map(doc => (doc.layout_cluster = -1)); docs.map(doc => this._clusterSets.map((set, i) => set.map(member => { - if (docFirst.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { - docFirst.cluster = i; + if (docFirst.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { + docFirst.layout_cluster = i; } }) ) ); - if (docFirst.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) { - docFirst.cluster = preferredInd; + if ( + docFirst.layout_cluster === -1 && + preferredInd !== -1 && + this._clusterSets.length > preferredInd && + (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) + ) { + docFirst.layout_cluster = preferredInd; } this._clusterSets.map((set, i) => { - if (docFirst.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) { - docFirst.cluster = i; + if (docFirst.layout_cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) { + docFirst.layout_cluster = i; } }); - if (docFirst.cluster === -1) { + if (docFirst.layout_cluster === -1) { docs.map(doc => { - doc.cluster = this._clusterSets.length; + doc.layout_cluster = this._clusterSets.length; this._clusterSets.push([doc]); }); } else if (this._clusterSets.length) { - for (let i = this._clusterSets.length; i <= NumCast(docFirst.cluster); i++) !this._clusterSets[i] && this._clusterSets.push([]); - docs.map(doc => this._clusterSets[(doc.cluster = NumCast(docFirst.cluster))].push(doc)); + for (let i = this._clusterSets.length; i <= NumCast(docFirst.layout_cluster); i++) !this._clusterSets[i] && this._clusterSets.push([]); + docs.map(doc => this._clusterSets[(doc.layout_cluster = NumCast(docFirst.layout_cluster))].push(doc)); } - childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.cluster === i) && this.updateCluster(child)); + childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.layout_cluster === i) && this.updateCluster(child)); } } @@ -533,31 +538,31 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout); - if (this.props.Document._useClusters) { + if (this.props.Document._freeform_useClusters) { this._clusterSets.forEach(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1)); - const preferredInd = NumCast(doc.cluster); - doc.cluster = -1; + const preferredInd = NumCast(doc.layout_cluster); + doc.layout_cluster = -1; this._clusterSets.forEach((set, i) => set.forEach(member => { - if (doc.cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { - doc.cluster = i; + if (doc.layout_cluster === -1 && Doc.IndexOf(member, childLayouts) !== -1 && Doc.overlapping(doc, member, this._clusterDistance)) { + doc.layout_cluster = i; } }) ); - if (doc.cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) { - doc.cluster = preferredInd; + if (doc.layout_cluster === -1 && preferredInd !== -1 && this._clusterSets.length > preferredInd && (!this._clusterSets[preferredInd] || !this._clusterSets[preferredInd].filter(member => Doc.IndexOf(member, childLayouts) !== -1).length)) { + doc.layout_cluster = preferredInd; } this._clusterSets.forEach((set, i) => { - if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) { - doc.cluster = i; + if (doc.layout_cluster === -1 && !set.filter(member => Doc.IndexOf(member, childLayouts) !== -1).length) { + doc.layout_cluster = i; } }); - if (doc.cluster === -1) { - doc.cluster = this._clusterSets.length; + if (doc.layout_cluster === -1) { + doc.layout_cluster = this._clusterSets.length; this._clusterSets.push([doc]); } else if (this._clusterSets.length) { - for (let i = this._clusterSets.length; i <= doc.cluster; i++) !this._clusterSets[i] && this._clusterSets.push([]); - this._clusterSets[doc.cluster ?? 0].push(doc); + for (let i = this._clusterSets.length; i <= doc.layout_cluster; i++) !this._clusterSets[i] && this._clusterSets.push([]); + this._clusterSets[doc.layout_cluster ?? 0].push(doc); } } } @@ -566,8 +571,8 @@ export class CollectionFreeFormView extends CollectionSubView doc && this.updateCluster(doc)); } else { @@ -591,7 +596,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._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster); + 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); this.selectDocuments(eles); return true; } @@ -678,7 +683,6 @@ export class CollectionFreeFormView extends CollectionSubView { if (!this._deleteList.includes(intersect.inkView)) { this._deleteList.push(intersect.inkView); - SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.strokeWidth?.toString()) || '1'); + SetActiveInkWidth(StrCast(intersect.inkView.rootDoc.stroke_width?.toString()) || '1'); SetActiveInkColor(StrCast(intersect.inkView.rootDoc.color?.toString()) || 'black'); // create a new curve by appending all curves of the current segment together in order to render a single new stroke. if (!e.shiftKey) { @@ -1021,19 +1025,19 @@ export class CollectionFreeFormView extends CollectionSubView 20) { deltaScale = 20 / invTransform.Scale; } - if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) { + if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) { this.setPan(0, 0); return; } - if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) { - deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale; + if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._freeform_scaleMin, 1) && this.isAnnotationOverlay) { + deltaScale = NumCast(this.rootDoc._freeform_scaleMin, 1) / invTransform.Scale; } const localTransform = invTransform.scaleAbout(deltaScale, x, y); if (localTransform.Scale >= 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.scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); + this.setPan(-localTransform.TranslateX / safeScale, (this.props.originTopLeft ? undefined : NumCast(this.props.Document.layout_scrollTop) * safeScale) || -localTransform.TranslateY / safeScale); } }; @@ -1113,26 +1117,26 @@ export class CollectionFreeFormView extends CollectionSubView (this.rootDoc.scrollTop = relTop * maxScrollTop), 10); + setTimeout(() => (this.rootDoc.layout_scrollTop = relTop * maxScrollTop), 10); newPanY = minPanY; } !this.Document._verticalScroll && (this.Document[this.panXFieldKey] = this.isAnnotationOverlay ? newPanX : panX); @@ -1143,7 +1147,7 @@ export class CollectionFreeFormView extends CollectionSubView { const collectionDoc = this.props.docViewPath().lastElement().rootDoc; - if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) { + if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._freeform_ !== undefined) { 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 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(), @@ -1162,7 +1166,7 @@ export class CollectionFreeFormView extends CollectionSubView NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); let zfirst = docs.length ? NumCast(docs[0].zIndex) : 0; doc.zIndex = zfirst - 1; - } else if (doc.isInkMask) { + } else if (doc.stroke_isInkMask) { doc.zIndex = 5000; } else { const docs = this.childLayoutPairs.map(pair => pair.layout).slice(); @@ -1222,8 +1226,8 @@ export class CollectionFreeFormView extends CollectionSubView { const docView = fieldProps.DocumentView?.(); - if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._singleLine) && ['Tab', 'Enter'].includes(e.key)) { + if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) { e.stopPropagation?.(); const below = !e.altKey && e.key !== 'Tab'; - const layoutKey = StrCast(docView.LayoutFieldKey); + const layout_fieldKey = StrCast(docView.LayoutFieldKey); const newDoc = Doc.MakeCopy(docView.rootDoc, true); const dataField = docView.rootDoc[Doc.LayoutFieldKey(newDoc)]; newDoc[DataSym][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List([]) : undefined; if (below) newDoc.y = NumCast(docView.rootDoc.y) + NumCast(docView.rootDoc._height) + 10; else newDoc.x = NumCast(docView.rootDoc.x) + NumCast(docView.rootDoc._width) + 10; - if (layoutKey !== 'layout' && docView.rootDoc[layoutKey] instanceof Doc) { - newDoc[layoutKey] = docView.rootDoc[layoutKey]; + if (layout_fieldKey !== 'layout' && docView.rootDoc[layout_fieldKey] instanceof Doc) { + newDoc[layout_fieldKey] = docView.rootDoc[layout_fieldKey]; } Doc.GetProto(newDoc).text = undefined; FormattedTextBox.SelectOnLoad = newDoc[Id]; @@ -1315,7 +1319,7 @@ export class CollectionFreeFormView extends CollectionSubView { @@ -1521,7 +1525,7 @@ export class CollectionFreeFormView extends CollectionSubView([anchor]); + this.dataDoc[this.props.fieldKey + '_annotations'] = new List([anchor]); } } return anchor; @@ -1644,8 +1648,8 @@ export class CollectionFreeFormView extends CollectionSubView { this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc['icon-nativeWidth'] = nativeWidth; - this.dataDoc['icon-nativeHeight'] = nativeHeight; + this.dataDoc['icon_nativeWidth'] = nativeWidth; + this.dataDoc['icon_nativeHeight'] = nativeHeight; } ); @@ -1762,7 +1766,7 @@ export class CollectionFreeFormView extends CollectionSubView (Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards), icon: 'eye' }); appearanceItems.push({ description: `${this.fitContentsToBox ? 'Make Zoomable' : 'Scale to Window'}`, - event: () => (this.Document._fitContentsToBox = !this.fitContentsToBox), + event: () => (this.Document._freeform_fitContentsToBox = !this.fitContentsToBox), icon: !this.fitContentsToBox ? 'expand-arrows-alt' : 'compress-arrows-alt', }); appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, { pinViewport: MarqueeView.CurViewBounds(this.rootDoc, this.props.PanelWidth(), this.props.PanelHeight()) }), icon: 'map-pin' }); @@ -1781,7 +1785,7 @@ export class CollectionFreeFormView extends CollectionSubView SnappingManager.SetShowSnapLines(!SnappingManager.GetShowSnapLines()), icon: 'compress-arrows-alt' }) : null; - !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._useClusters), icon: 'braille' }) : null; + !Doc.noviceMode ? viewCtrlItems.push({ description: (this.Document._freeform_useClusters ? 'Hide' : 'Show') + ' Clusters', event: () => this.updateClusters(!this.Document._freeform_useClusters), icon: 'braille' }) : null; !viewctrls && ContextMenu.Instance.addItem({ description: 'UI Controls...', subitems: viewCtrlItems, icon: 'eye' }); const options = ContextMenu.Instance.findByDescription('Options...'); @@ -1897,7 +1901,7 @@ export class CollectionFreeFormView extends CollectionSubView - {this.layoutDoc._backgroundGridShow ? ( + {this.layoutDoc._freeform_backgroundGrid ? (
this.nativeDimScaling; @@ -2310,7 +2314,7 @@ ScriptingGlobals.add(function sendToBack(doc: Doc) { }); ScriptingGlobals.add(function resetView() { SelectionManager.Docs().forEach(doc => { - doc._panX = doc._panY = 0; - doc._viewScale = 1; + doc._freeform_panX = doc._freeform_panY = 0; + doc._freeform_scale = 1; }); }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 11d466b0f..fdff13b54 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -52,8 +52,8 @@ export interface MarqueeViewBounds { @observer export class MarqueeView extends React.Component { public static CurViewBounds(pinDoc: Doc, panelWidth: number, panelHeight: number) { - const ps = NumCast(pinDoc._viewScale, 1); - return { left: NumCast(pinDoc._panX) - panelWidth / 2 / ps, top: NumCast(pinDoc._panY) - panelHeight / 2 / ps, width: panelWidth / ps, height: panelHeight / ps }; + 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 }; } private _commandExecuted = false; @@ -110,7 +110,7 @@ export class MarqueeView extends React.Component this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', useCors: true }), OpenWhere.addRight)); + cm.setDefaultItem('?', (str: string) => this.props.addDocTab(Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, title: 'bing', data_useCors: true }), OpenWhere.addRight)); cm.displayMenu(this._downX, this._downY, undefined, true); e.stopPropagation(); @@ -196,7 +196,7 @@ export class MarqueeView extends React.Component 1) { @@ -204,7 +204,7 @@ export class MarqueeView extends React.Component (docDataProto[columns[i]] = values.length > i ? (values[i].indexOf(Number(values[i]).toString()) !== -1 ? Number(values[i]) : values[i]) : undefined)); if (groupAttr) { docDataProto._group = groupAttr; @@ -379,10 +379,10 @@ export class MarqueeView extends React.Component(selected); Doc.GetProto(doc).title = makeGroup ? 'grouping' : 'nested freeform'; !this.props.isAnnotationOverlay && Doc.AddFileOrphan(Doc.GetProto(doc)); - doc._panX = doc._panY = 0; + doc._freeform_panX = doc._freeform_panY = 0; return doc; })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true)); - newCollection.system = undefined; + newCollection.isSystem = undefined; newCollection._width = this.Bounds.width; newCollection._height = this.Bounds.height; newCollection._isGroup = makeGroup; @@ -390,8 +390,8 @@ export class MarqueeView extends React.Component (d.context = newCollection)); + newCollection.layout_fitWidth = true; + selected.forEach(d => (d.embedContainer = newCollection)); this.hideMarquee(); return newCollection; }); @@ -516,9 +516,19 @@ export class MarqueeView extends React.Component Doc.AreProtosEqual(DocCast(doc.context), this.rootDoc)); + return SelectionManager.Docs().filter(doc => Doc.AreProtosEqual(DocCast(doc.embedContainer), this.rootDoc)); } @computed get documentKeys() { @@ -87,7 +87,7 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get previewWidth() { - return NumCast(this.layoutDoc.schemaPreviewWidth); + return NumCast(this.layoutDoc.schema_previewWidth); } @computed get tableWidth() { @@ -95,12 +95,12 @@ export class CollectionSchemaView extends CollectionSubView() { } @computed get columnKeys() { - return Cast(this.layoutDoc.columnKeys, listSpec('string'), defaultColumnKeys); + return Cast(this.layoutDoc.schema_columnKeys, listSpec('string'), defaultColumnKeys); } @computed get storedColumnWidths() { const widths = NumListCast( - this.layoutDoc.columnWidths, + this.layoutDoc.schema_columnWidths, this.columnKeys.map(() => (this.tableWidth - CollectionSchemaView._rowMenuWidth) / this.columnKeys.length) ); @@ -243,7 +243,7 @@ export class CollectionSchemaView extends CollectionSubView() { let currKeys = [...this.columnKeys]; currKeys[index] = newKey; - this.layoutDoc.columnKeys = new List(currKeys); + this.layoutDoc.schema_columnKeys = new List(currKeys); }; @undoBatch @@ -257,11 +257,11 @@ export class CollectionSchemaView extends CollectionSubView() { const currWidths = this.storedColumnWidths.slice(); currWidths.splice(0, 0, newColWidth); const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0); - this.layoutDoc.columnWidths = new List(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth))); + this.layoutDoc.schema_columnWidths = new List(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth))); let currKeys = this.columnKeys.slice(); currKeys.splice(0, 0, key); - this.layoutDoc.columnKeys = new List(currKeys); + this.layoutDoc.schema_columnKeys = new List(currKeys); }; @action @@ -274,11 +274,11 @@ export class CollectionSchemaView extends CollectionSubView() { const currWidths = this.storedColumnWidths.slice(); currWidths.splice(index, 1); const newDesiredTableWidth = currWidths.reduce((w, cw) => w + cw, 0); - this.layoutDoc.columnWidths = new List(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth))); + this.layoutDoc.schema_columnWidths = new List(currWidths.map(w => (w / newDesiredTableWidth) * (this.tableWidth - CollectionSchemaView._rowMenuWidth))); let currKeys = this.columnKeys.slice(); currKeys.splice(index, 1); - this.layoutDoc.columnKeys = new List(currKeys); + this.layoutDoc.schema_columnKeys = new List(currKeys); }; @action @@ -317,7 +317,7 @@ export class CollectionSchemaView extends CollectionSubView() { @action finishResize = () => { - this.layoutDoc.columnWidths = new List(this._displayColumnWidths); + this.layoutDoc.schema_columnWidths = new List(this._displayColumnWidths); this._displayColumnWidths = undefined; }; @@ -326,11 +326,11 @@ export class CollectionSchemaView extends CollectionSubView() { moveColumn = (fromIndex: number, toIndex: number) => { let currKeys = this.columnKeys.slice(); currKeys.splice(toIndex, 0, currKeys.splice(fromIndex, 1)[0]); - this.layoutDoc.columnKeys = new List(currKeys); + this.layoutDoc.schema_columnKeys = new List(currKeys); let currWidths = this.storedColumnWidths.slice(); currWidths.splice(toIndex, 0, currWidths.splice(fromIndex, 1)[0]); - this.layoutDoc.columnWidths = new List(currWidths); + this.layoutDoc.schema_columnWidths = new List(currWidths); }; @action @@ -480,14 +480,14 @@ export class CollectionSchemaView extends CollectionSubView() { const maxWidth = 1000; const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth; - this.layoutDoc.schemaPreviewWidth = width; + this.layoutDoc.schema_previewWidth = width; return false; }; @action addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => { if (!value && !forceEmptyNote) return false; - const newDoc = Docs.Create.TextDocument(value, { title: value, _autoHeight: true }); + const newDoc = Docs.Create.TextDocument(value, { title: value, _layout_autoHeight: true }); FormattedTextBox.SelectOnLoad = newDoc[Id]; FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' '; return this.addRow(newDoc) || false; @@ -500,7 +500,7 @@ export class CollectionSchemaView extends CollectionSubView() { ContextMenu.Instance.setDefaultItem('::', (name: string): void => { Doc.GetProto(this.props.Document)[name] = ''; - this.addRow(Docs.Create.TextDocument('', { title: name, _autoHeight: true })); + this.addRow(Docs.Create.TextDocument('', { title: name, _layout_autoHeight: true })); }); ContextMenu.Instance.displayMenu(x, y, undefined, true); }; @@ -837,7 +837,7 @@ export class CollectionSchemaView extends CollectionSubView() { }); return { docs }; } - rowHeightFunc = () => (BoolCast(this.layoutDoc._singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight); + 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); @@ -968,7 +968,7 @@ class CollectionSchemaViewDocs extends React.Component diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx index 34631e0b7..45bfe4f77 100644 --- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx +++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx @@ -59,7 +59,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent() { onPointerMove = (e: any) => { if (!SnappingManager.GetIsDragging()) return; - const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.context === this.schemaDoc); // this.schemaView?._selectedDocs.has(doc) ?? false; + const dragIsRow = DragManager.docsBeingDragged.some(doc => doc.embedContainer === this.schemaDoc); // this.schemaView?._selectedDocs.has(doc) ?? false; if (this._ref && dragIsRow) { const rect = this._ref.getBoundingClientRect(); diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx index 9f659752a..42bf32475 100644 --- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx +++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx @@ -73,7 +73,7 @@ export class SchemaTableCell extends React.Component { isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, - dropAction: 'alias' as dropActionType, + dropAction: 'embed', bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, @@ -83,7 +83,7 @@ export class SchemaTableCell extends React.Component { addDocTab: SchemaTableCell.addFieldDoc, pinToPres: returnZero, Document, - fieldKey, + fieldKey: fieldKey, PanelWidth: columnWidth, PanelHeight: props.rowHeight, }; diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index d02a1c4eb..b9d56541a 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -24,12 +24,12 @@ export class LinkMenuGroup extends React.Component { private _menuRef = React.createRef(); getBackgroundColor = (): string => { - const linkRelationshipList = StrListCast(Doc.UserDoc().linkRelationshipList); + const link_relationshipList = StrListCast(Doc.UserDoc().link_relationshipList); const linkColorList = StrListCast(Doc.UserDoc().linkColorList); let color = 'white'; // if this link's relationship property is not default "link", set its color - if (linkRelationshipList) { - const relationshipIndex = linkRelationshipList.indexOf(this.props.groupType); + if (link_relationshipList) { + const relationshipIndex = link_relationshipList.indexOf(this.props.groupType); const RGBcolor: string = linkColorList[relationshipIndex]; if (RGBcolor) { //set opacity to 0.25 by modifiying the rgb string @@ -47,17 +47,18 @@ export class LinkMenuGroup extends React.Component { const sourceDoc = this.props.docView.anchorViewDoc ?? (this.props.docView.rootDoc.type === DocumentType.LINK // - ? this.props.docView.props.LayoutTemplateString?.includes('anchor1') - ? DocCast(linkDoc.anchor1) - : DocCast(linkDoc.anchor2) + ? 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.rootDoc.type === DocumentType.LINK - ? this.props.docView.props.LayoutTemplateString?.includes('anchor1') - ? DocCast(linkDoc.anchor2) - : DocCast(linkDoc.anchor1) - : LinkManager.getOppositeAnchor(linkDoc, sourceDoc) || LinkManager.getOppositeAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, null).annotationOn === sourceDoc ? Cast(linkDoc.anchor2, Doc, null) : Cast(linkDoc.anchor1, 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 : ( void; } -// drag links and drop link targets (aliasing them if needed) +// drag links and drop link targets (embedding them if needed) export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) { const draggedDocs = (specificLinks ? specificLinks : LinkManager.Links(sourceDoc)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[]; @@ -45,7 +43,7 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs); dragData.canEmbed = true; - dragData.dropAction = 'alias'; + dragData.dropAction = 'embed'; DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined); } @@ -65,9 +63,9 @@ export class LinkMenuItem extends React.Component { @computed get sourceAnchor() { const ldoc = this.props.linkDoc; - if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) { - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1); - if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2); + if (this.props.sourceDoc !== ldoc.link_anchor_1 && this.props.sourceDoc !== ldoc.link_anchor_2) { + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_1); + if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.link_anchor_2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.link_anchor_2); } return this.props.sourceDoc; } @@ -79,7 +77,7 @@ export class LinkMenuItem extends React.Component { this, e, e => { - const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'alias'); + const dragData = new DragManager.DocumentDragData([this.props.linkDoc], 'embed'); dragData.removeDropProperties = ['hidden']; DragManager.StartDocumentDrag([this._editRef.current!], dragData, e.x, e.y); return true; @@ -89,7 +87,7 @@ export class LinkMenuItem extends React.Component { const trail = DocCast(this.props.docView.rootDoc.presTrail); if (trail) { Doc.ActivePresentation = trail; - MainView.addDocTabFunc(trail, OpenWhere.replaceRight); + DocumentViewInternal.addDocTabFunc(trail, OpenWhere.replaceRight); } else { SelectionManager.SelectView(this.props.docView, false); if ((SettingsManager.propertiesWidth ?? 0) < 100) { @@ -118,10 +116,10 @@ export class LinkMenuItem extends React.Component { this.props.itemHandler?.(this.props.linkDoc); } else { const focusDoc = - Cast(this.props.linkDoc.anchor1, Doc, null)?.annotationOn === this.props.sourceDoc - ? Cast(this.props.linkDoc.anchor1, Doc, null) - : Cast(this.props.linkDoc.anchor2, Doc, null)?.annotationOn === this.props.sourceDoc - ? Cast(this.props.linkDoc.anchor12, Doc, null) + Cast(this.props.linkDoc.link_anchor_1, Doc, null)?.annotationOn === this.props.sourceDoc + ? Cast(this.props.linkDoc.link_anchor_1, Doc, null) + : Cast(this.props.linkDoc.link_anchor_2, Doc, null)?.annotationOn === this.props.sourceDoc + ? Cast(this.props.linkDoc.link_anchor_12, Doc, null) : undefined; if (focusDoc) this.props.docView.props.focus(focusDoc, { instant: true }); @@ -149,7 +147,7 @@ export class LinkMenuItem extends React.Component { return (
-
+
{ {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? 'Annotation in' : ''} {StrCast(title)}

- {!this.props.linkDoc.description ? null :

{StrCast(this.props.linkDoc.description)}

} + {!this.props.linkDoc.link_description ? null :

{StrCast(this.props.linkDoc.link_description)}

}
diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 53da880e4..9662b2fea 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,8 +1,8 @@ -import { observer } from "mobx-react"; +import { observer } from 'mobx-react'; import './LinkEditor.scss'; -import React = require("react"); +import React = require('react'); -interface LinkRelationshipSearchProps { +interface link_relationshipSearchProps { results: string[] | undefined; display: string; //callback fn to set rel + hide dropdown upon setting @@ -10,48 +10,48 @@ interface LinkRelationshipSearchProps { toggleSearch: () => void; } @observer -export class LinkRelationshipSearch extends React.Component { - +export class link_relationshipSearch extends React.Component { handleResultClick = (e: React.MouseEvent) => { const relationship = (e.target as HTMLParagraphElement).textContent; if (relationship) { this.props.handleRelationshipSearchChange(relationship); } - } + }; handleMouseEnter = () => { this.props.toggleSearch(); - } + }; handleMouseLeave = () => { this.props.toggleSearch(); - } + }; /** - * Render an empty div to increase the height of LinkEditor to accommodate 2+ results - */ + * Render an empty div to increase the height of LinkEditor to accommodate 2+ results + */ emptyDiv = () => { - if (this.props.results && this.props.results.length > 2 && this.props.display === "block") { - return
; + if (this.props.results && this.props.results.length > 2 && this.props.display === 'block') { + return
; } - } + }; render() { return (
-
- { // return a dropdown of relationship results if there exist results - this.props.results - ? this.props.results.map(result => { - return

- {result} -

; +
+ { + // return a dropdown of relationship results if there exist results + this.props.results ? ( + this.props.results.map(result => { + return ( +

+ {result} +

+ ); }) - :

No matching relationships

+ ) : ( +

No matching relationships

+ ) }
@@ -60,4 +60,4 @@ export class LinkRelationshipSearch extends React.Component ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 68fb19208..8e83cf121 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -76,7 +76,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.getLinkData(l)) .forEach(({ la1, la2, linkTime }) => { - if (linkTime > NumCast(this.layoutDoc._currentTimecode) && linkTime < this._ele!.currentTime) { + if (linkTime > NumCast(this.layoutDoc._layout_currentTimecode) && linkTime < this._ele!.currentTime) { Doc.linkFollowHighlight(la1); } }); - this.layoutDoc._currentTimecode = this._ele.currentTime; - this.timeline?.scrollToTime(NumCast(this.layoutDoc._currentTimecode)); + this.layoutDoc._layout_currentTimecode = this._ele.currentTime; + this.timeline?.scrollToTime(NumCast(this.layoutDoc._layout_currentTimecode)); } }; @@ -221,7 +221,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent l.anchor1 === link || l.anchor2 === link) + .filter(l => l.link_anchor_1 === link || l.link_anchor_2 === link) .forEach(l => { const { la1, la2 } = this.getLinkData(l); const startTime = this.timeline?.anchorStart(la1) || this.timeline?.anchorStart(la2); @@ -435,7 +435,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight); - setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._currentTimecode = time); + setPlayheadTime = (time: number) => (this._ele!.currentTime = this.layoutDoc._layout_currentTimecode = time); playing = () => this.mediaState === media_state.Playing; @@ -547,7 +547,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent
-
{formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode)))}
+
{formatTime(Math.round(NumCast(this.layoutDoc._layout_currentTimecode)))}
) : (
@@ -623,7 +623,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent -
{this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))}
+
{this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._layout_currentTimecode) - NumCast(this.timeline.clipStart)))}
{this.miniPlayer ? (
/
) : ( @@ -656,6 +656,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent (this._stackedTimeline = r))} {...this.props} CollectionFreeFormDocumentView={undefined} + dataFieldKey={this.fieldKey} fieldKey={this.annotationKey} dictationKey={this.fieldKey + '-dictation'} mediaPath={this.path} @@ -689,7 +690,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this._ele?.duration && this._ele?.duration !== Infinity && (this.dataDoc[this.fieldKey + '-duration'] = this._ele.duration))}> + onLoadedData={action(e => this._ele?.duration && this._ele?.duration !== Infinity && (this.dataDoc[this.fieldKey + '_duration'] = this._ele.duration))}> Not supported. diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 862d0da8c..6710cee63 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -36,13 +36,13 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames @@ -154,8 +154,8 @@ export class CollectionFreeFormDocumentView extends DocComponent (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode))); CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => (doc[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', doc, currTimecode))); const targetDoc = doc; // data fields, like rtf 'text' exist on the data doc, so - //doc !== targetDoc && (targetDoc.context = doc.context); // the computed fields don't see the layout doc -- need to copy the context to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!) - targetDoc.activeFrame = ComputedField.MakeFunction('self.context?._currentFrame||0'); + //doc !== targetDoc && (targetDoc.embedContainer = doc.embedContainer); // the computed fields don't see the layout doc -- need to copy the embedContainer to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!) + targetDoc.activeFrame = ComputedField.MakeFunction('self.embedContainer?._currentFrame||0'); targetDoc.dataTransition = 'inherit'; }); } @@ -202,7 +202,7 @@ export class CollectionFreeFormDocumentView extends DocComponent() { } render() { - const scaling = Math.min(this.layoutDoc.fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]()); + const scaling = Math.min(this.layoutDoc.layout_fitWidth ? 10000 : this.props.PanelHeight() / this.rootDoc[HeightSym](), this.props.PanelWidth() / this.rootDoc[WidthSym]()); return (
() { SetActiveInkWidth(e.target.value); SelectionManager.Views() .filter(i => StrCast(i.rootDoc.type) === DocumentType.INK) - .map(i => (i.rootDoc.strokeWidth = Number(e.target.value))); + .map(i => (i.rootDoc.stroke_width = Number(e.target.value))); }} />
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index ace388c57..3be2d9a77 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, observable } from 'mobx'; +import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; @@ -26,6 +26,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { // on click, animate slider movement to the targetWidth this._animating = 'all 200ms'; - this.layoutDoc._clipWidth = (targetWidth * 100) / this.props.PanelWidth(); + this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this.props.PanelWidth(); setTimeout( action(() => (this._animating = '')), 200 @@ -71,9 +78,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - const width = movementX * this.props.ScreenToLocalTransform().Scale + (NumCast(this.layoutDoc._clipWidth) / 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._clipWidth = (width * 100) / this.props.PanelWidth(); + this.layoutDoc[this.clipWidthKey] = (width * 100) / this.props.PanelWidth(); } return false; }; @@ -101,7 +108,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { return (
{ 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)}
); @@ -151,16 +157,16 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent - {displayBox(this.fieldKey === 'data' ? 'compareBox-after' : `${this.fieldKey}2`, 1, this.props.PanelWidth() - 3)} -
- {displayBox(this.fieldKey === 'data' ? 'compareBox-before' : `${this.fieldKey}1`, 0, 0)} + {displayBox(`${this.fieldKey}_2`, 1, this.props.PanelWidth() - 3)} +
+ {displayBox(`${this.fieldKey}_1`, 0, 0)}
(this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined, + left: `calc(${this.clipWidth + '%'} - 0.5px)`, + cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this.props.PanelWidth() - 5) / this.props.PanelWidth() ? 'w-resize' : undefined, }} onPointerDown={e => this.registerSliding(e, this.props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ > diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index eb25d3264..5876efb01 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, StrListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; -import { Cast, NumCast, StrCast } from '../../../../fields/Types'; +import { Cast, CsvCast, NumCast, StrCast } from '../../../../fields/Types'; import { CsvField } from '../../../../fields/URLField'; import { Docs } from '../../../documents/Documents'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; @@ -29,7 +29,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // @observable private pairs: { [key: string]: FieldResult }[] = []; static pairSet = new ObservableMap(); @computed.struct get pairs() { - return DataVizBox.pairSet.get(StrCast(this.rootDoc.fileUpload)); + return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href); } private _chartRenderer: LineChart | undefined; // // another way would be store a schema that defines the type of data we are expecting from an imported doc @@ -61,7 +61,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { @action restoreView = (data: Doc) => { const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView); - const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._dataVizAxes = new List(StrListCast(data.presDataVizAxes))); + const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List(StrListCast(data.presDataVizAxes))); const func = () => this._chartRenderer?.restoreView(data); if (changedView || changedAxes) { setTimeout(func, 100); @@ -88,14 +88,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }; @computed.struct get axes() { - return StrListCast(this.layoutDoc.dataVizAxes); + return StrListCast(this.layoutDoc.data_vizAxes); } - selectAxes = (axes: string[]) => (this.layoutDoc.dataVizAxes = new List(axes)); + selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List(axes)); @computed get selectView() { const width = this.props.PanelWidth() * 0.9; const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9; - const margin = { top: 10, right: 25, bottom: 50, left:25}; + const margin = { top: 10, right: 25, bottom: 50, left: 25 }; if (!this.pairs) return 'no data'; // prettier-ignore switch (this.dataVizView) { @@ -113,10 +113,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } fetchData() { - if (DataVizBox.pairSet.has(StrCast(this.rootDoc.fileUpload))) return; - DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), []); + if (DataVizBox.pairSet.has(CsvCast(this.rootDoc[this.fieldKey]).url.href)) return; + DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, []); fetch('/csvData?uri=' + this.dataUrl?.url.href) // - .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(StrCast(this.rootDoc.fileUpload), res)))); + .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res)))); } // handle changing the view using a button diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 777bf2f66..11f62a61f 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -56,8 +56,8 @@ export class LineChart extends React.Component { } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links - .filter(link => link.anchor1 !== this.props.rootDoc) // get links where this chart doc is the target of the link - .map(link => DocCast(link.anchor1)); // then return the source of the link + .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link + .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get incomingSelected() { return this.incomingLinks // all links that are pointing to this node @@ -87,7 +87,7 @@ export class LineChart extends React.Component { { fireImmediately: true } ); this._disposers.annos = reaction( - () => DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']), + () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), annotations => { // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way // could be blue colored to make it look like anchor @@ -123,7 +123,7 @@ export class LineChart extends React.Component { element.classList.remove('selected'); } }; - // gets called whenever the "data-annotations" fields gets updated + // gets called whenever the "data_annotations" fields gets updated drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => { // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY @@ -228,15 +228,15 @@ export class LineChart extends React.Component { // creating the x and y scales const xScale = scaleCreatorNumerical(xMin, xMax, 0, width); - const yScale = scaleCreatorNumerical(0, yMax,height, 0); + const yScale = scaleCreatorNumerical(0, yMax, height, 0); // adding svg const margin = this.props.margin; const svg = (this._lineChartSvg = d3 .select(this._lineChartRef.current) .append('svg') - .attr('width', `${width +margin.left + margin.right}`) - .attr('height', `${height + margin.top + margin.bottom }`) + .attr('width', `${width + margin.left + margin.right}`) + .attr('height', `${height + margin.top + margin.bottom}`) .append('g') .attr('transform', `translate(${margin.left}, ${margin.top})`)); diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 0d69ac890..3816bddfa 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -47,17 +47,17 @@ export class TableBox extends React.Component { e => { const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; const targetCreator = (annotationOn: Doc | undefined) => { - const alias = Doc.MakeAlias(this.props.docView?.()!.rootDoc!); - alias._dataVizView = DataVizView.LINECHART; - alias._dataVizAxes = new List([col, col]); - alias.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; - return alias; + const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); + embedding._dataVizView = DataVizView.LINECHART; + embedding._data_vizAxes = new List([col, col]); + embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; + return embedding; }; if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.linkDocument.linkDisplay = true; + e.linkDocument.layout_linkDisplay = true; // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; // e.annoDragData.linkSourceDoc.followLinkZoom = false; } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 76a5ce7b3..348ef910a 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -120,15 +120,15 @@ export class DocumentContentsView extends React.Component< select: (ctrl: boolean) => void; NativeDimScaling?: () => number; setHeight?: (height: number) => void; - layoutKey: string; + layout_fieldKey: string; } > { @computed get layout(): string { TraceMobx(); if (this.props.LayoutTemplateString) return this.props.LayoutTemplateString; if (!this.layoutDoc) return '

awaiting layout

'; - if (this.props.layoutKey === 'layout_keyValue') return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString()); - const layout = Cast(this.layoutDoc[this.layoutDoc === this.props.Document && this.props.layoutKey ? this.props.layoutKey : StrCast(this.layoutDoc.layoutKey, 'layout')], 'string'); + 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 (layout === undefined) return this.props.Document.data ? "" : KeyValueBox.LayoutString(); if (typeof layout === 'string') return layout; return '

Loading layout

'; @@ -140,12 +140,12 @@ export class DocumentContentsView extends React.Component< } 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.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined); + // 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?.() || (this.props.LayoutTemplateString && this.props.Document) || - (this.props.layoutKey && StrCast(this.props.Document[this.props.layoutKey]) && this.props.Document) || - Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined); + (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); return Doc.expandTemplateLayout(template, this.props.Document); } diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 47705d53d..d5ca30957 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -52,7 +52,7 @@ export class DocumentLinksButton extends React.Component { if (this.props.View && dropEv.linkDocument) { // dropEv.linkDocument equivalent to !dropEve.aborted since linkDocument is only assigned on a completed drop - !dropEv.linkDocument.linkRelationship && (Doc.GetProto(dropEv.linkDocument).linkRelationship = 'hyperlink'); + !dropEv.linkDocument.link_relationship && (Doc.GetProto(dropEv.linkDocument).link_relationship = 'hyperlink'); } linkDrag?.end(); }, @@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component(this.props.View.allLinks)).forEach(link => { - if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.anchor2 as Doc], filters, []).length || DocUtils.FilterDocs([link.anchor1 as Doc], filters, []).length) { + if (DocUtils.FilterDocs([link], filters, []).length || DocUtils.FilterDocs([link.link_anchor_2 as Doc], filters, []).length || DocUtils.FilterDocs([link.link_anchor_1 as Doc], filters, []).length) { results.push(link); } }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ffbde18ca..d8494e58e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -131,7 +131,7 @@ export interface DocComponentView { setData?: (data: Field | Promise) => boolean; componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element | null; incrementalRendering?: () => void; - fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox) + layout_fitWidth?: () => boolean; // whether the component always fits width (eg, KeyValueBox) overridePointerEvents?: () => 'all' | 'none' | undefined; // if the conmponent overrides the pointer events for the document fieldKey?: string; annotationKey?: string; @@ -150,7 +150,7 @@ export interface DocumentViewSharedProps { Document: Doc; DataDoc?: Doc; contentBounds?: () => undefined | { x: number; y: number; r: number; b: number }; - fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document + fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document suppressSetHeight?: boolean; thumbShown?: () => boolean; setContentView?: (view: DocComponentView) => any; @@ -164,11 +164,11 @@ export interface DocumentViewSharedProps { styleProvider: Opt; setTitleFocus?: () => void; focus: DocFocusFunc; - fitWidth?: (doc: Doc) => boolean | undefined; + layout_fitWidth?: (doc: Doc) => boolean | undefined; docFilters: () => string[]; docRangeFilters: () => string[]; searchFilterDocs: () => Doc[]; - showTitle?: () => string; + layout_showTitle?: () => string; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: OpenWhere) => boolean; @@ -275,8 +275,8 @@ export class DocumentViewInternal extends DocComponent; + @computed get layout_showTitle() { + return this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.layout_showTitle) as Opt; } @computed get NativeDimScaling() { return this.props.NativeDimScaling?.() || 1; @@ -305,8 +305,8 @@ export class DocumentViewInternal extends DocComponent { - if (!StrCast(this.layoutDoc._showTitle)) this.layoutDoc._showTitle = 'title'; + if (!StrCast(this.layoutDoc._layout_showTitle)) this.layoutDoc._layout_showTitle = 'title'; setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined }; @@ -539,7 +539,7 @@ export class DocumentViewInternal extends DocComponent this.props.removeDocument?.(this.props.Document); @undoBatch setToggleDetail = () => (this.Document.onClick = ScriptField.MakeScript( - `toggleDetail(documentView, "${StrCast(this.Document.layoutKey) + `toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey) .replace('layout_', '') .replace(/^layout$/, 'detail')}")`, { documentView: 'any' } @@ -611,7 +611,7 @@ export class DocumentViewInternal extends DocComponent { - const portalLink = this.allLinks.find(d => d.anchor1 === this.props.Document && d.linkRelationship === 'portal to:portal from'); + const portalLink = this.allLinks.find(d => d.link_anchor_1 === this.props.Document && d.link_relationship === 'portal to:portal from'); if (!portalLink) { DocUtils.MakeLink( this.props.Document, - Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }), - { linkRelationship: 'portal to:portal from' } + Docs.Create.FreeformDocument([], { _width: NumCast(this.layoutDoc._width) + 10, _height: NumCast(this.layoutDoc._height), _isLightbox: true, _layout_fitWidth: true, title: StrCast(this.props.Document.title) + ' [Portal]' }), + { link_relationship: 'portal to:portal from' } ); } this.Document.followLinkLocation = OpenWhere.lightbox; @@ -699,7 +699,7 @@ export class DocumentViewInternal extends DocComponent item.label && cm.addItem({ description: item.label, event: () => item.script.script.run({ this: this.layoutDoc, scriptContext: this.props.scriptContext, self: this.rootDoc }), icon: item.icon as IconProp })); if (!this.props.Document.isFolder) { - const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layoutKey)], Doc, null); + const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null); const appearance = cm.findByDescription('UI Controls...'); const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : []; !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); @@ -742,7 +742,7 @@ export class DocumentViewInternal extends DocComponent this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getAlias(this.dragFactory)')) }); + funcs.push({ description: 'Drag an Embedding', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getEmbedding(this.dragFactory)')) }); funcs.push({ description: 'Drag a Copy', icon: 'edit', event: () => this.Document.dragFactory && (this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)')) }); funcs.push({ description: 'Drag Document', icon: 'edit', event: () => (this.layoutDoc.onDragStart = undefined) }); cm.addItem({ description: 'OnDrag...', noexpand: true, subitems: funcs, icon: 'asterisk' }); @@ -910,7 +910,7 @@ export class DocumentViewInternal extends DocComponent {this.layoutDoc.hideAllLinks ? null : this.allLinkEndpoints}
@@ -922,7 +922,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string): any => { // prettier-ignore switch (property.split(':')[0]) { - case StyleProp.ShowTitle: return ''; + case StyleProp.layout_showTitle: return ''; case StyleProp.PointerEvents: return 'none'; case StyleProp.Highlighting: return undefined; } @@ -938,22 +938,22 @@ export class DocumentViewInternal extends DocComponent - Doc.AreProtosEqual(link.anchor1 as Doc, this.rootDoc) || - Doc.AreProtosEqual(link.anchor2 as Doc, this.rootDoc) || - ((link.anchor1 as Doc)?.unrendered && Doc.AreProtosEqual((link.anchor1 as Doc)?.annotationOn as Doc, this.rootDoc)) || - ((link.anchor2 as Doc)?.unrendered && Doc.AreProtosEqual((link.anchor2 as Doc)?.annotationOn as Doc, this.rootDoc)) + Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc) || + Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc) || + ((link.link_anchor_1 as Doc)?.unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) || + ((link.link_anchor_2 as Doc)?.unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc)) ); } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } - hideLink = computedFn((link: Doc) => () => (link.linkDisplay = false)); + hideLink = computedFn((link: Doc) => () => (link.layout_linkDisplay = false)); @computed get allLinkEndpoints() { // the small blue dots that mark the endpoints of links TraceMobx(); - if (this.props.hideLinkAnchors || this.layoutDoc.hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.unrendered) return null; - const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.linkDisplay); + if (this.props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this.props.dontRegisterView || this.layoutDoc.unrendered) return null; + const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => d.layout_linkDisplay); return filtered.map(link => (
)); @@ -1046,9 +1046,9 @@ export class DocumentViewInternal extends DocComponent this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.ScreenToLocalTransform().Scale || 1; - const showTitle = this.ShowTitle?.split(':')[0]; - const showTitleHover = this.ShowTitle?.includes(':hover'); - const captionView = !this.showCaption ? null : ( + const layout_showTitle = this.layout_showTitle?.split(':')[0]; + const layout_showTitleHover = this.layout_showTitle?.includes(':hover'); + const captionView = !this.layout_showCaption ? null : (
); - const targetDoc = showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc; + const targetDoc = layout_showTitle?.startsWith('_') ? this.layoutDoc : this.rootDoc; const background = StrCast( SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor, - Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)' + Doc.UserDoc().layout_showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)' ); - const sidebarWidthPercent = +StrCast(this.layoutDoc.sidebarWidthPercent).replace('%', ''); - const titleView = !showTitle ? null : ( + const layout_sidebarWidthPercent = +StrCast(this.layoutDoc.layout_sidebarWidthPercent).replace('%', ''); + const titleView = !layout_showTitle ? null : (
field.trim()) .map(field => targetDoc[field]?.toString()) @@ -1100,27 +1100,27 @@ export class DocumentViewInternal extends DocComponent { this.props.select(false); - return showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle; + return layout_showTitle.split(';').length === 1 ? layout_showTitle + '=' + Field.toString(targetDoc[layout_showTitle.split(';')[0]] as any as Field) : '#' + layout_showTitle; }} SetValue={undoBatch((input: string) => { if (input?.startsWith('#')) { - if (this.props.showTitle) { - this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined; + if (this.props.layout_showTitle) { + this.rootDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined; } else { - Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate'; + Doc.UserDoc().layout_showTitle = input?.substring(1) ? input.substring(1) : 'creationDate'; } } else { - var value = input.replace(new RegExp(showTitle + '='), '') as string | number; - if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value); - if (showTitle.includes('Date') || showTitle === 'author') return true; - Doc.SetInPlace(targetDoc, showTitle, value, true); + var value = input.replace(new RegExp(layout_showTitle + '='), '') as string | number; + if (layout_showTitle !== 'title' && Number(value).toString() === value) value = Number(value); + if (layout_showTitle.includes('Date') || layout_showTitle === 'author') return true; + Doc.SetInPlace(targetDoc, layout_showTitle, value, true); } return true; })} />
); - return this.props.hideTitle || (!showTitle && !this.showCaption) ? ( + return this.props.hideTitle || (!layout_showTitle && !this.layout_showCaption) ? ( this.contents ) : (
@@ -1319,11 +1319,11 @@ export class DocumentView extends React.Component { get LayoutFieldKey() { return this.docView?.LayoutFieldKey || 'layout'; } - @computed get fitWidth() { - return this.docView?._componentView?.fitWidth?.() ?? this.props.fitWidth?.(this.rootDoc) ?? this.layoutDoc?.fitWidth; + @computed get layout_fitWidth() { + return this.docView?._componentView?.layout_fitWidth?.() ?? this.props.layout_fitWidth?.(this.rootDoc) ?? this.layoutDoc?.layout_fitWidth; } @computed get anchorViewDoc() { - return this.props.LayoutTemplateString?.includes('anchor2') ? DocCast(this.rootDoc['anchor2']) : this.props.LayoutTemplateString?.includes('anchor1') ? DocCast(this.rootDoc['anchor1']) : undefined; + return this.props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.rootDoc['link_anchor_2']) : this.props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.rootDoc['link_anchor_1']) : undefined; } @computed get hideLinkButton() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HideLinkButton + (this.isSelected() ? ':selected' : '')); @@ -1339,13 +1339,13 @@ export class DocumentView extends React.Component { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); } @computed get nativeWidth() { - return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.fitWidth)); + return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth)); } @computed get nativeHeight() { - return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.fitWidth)); + return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, !this.layout_fitWidth)); } @computed get shouldNotScale() { - return (this.fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._viewType as any); + return (this.layout_fitWidth && !this.nativeWidth) || [CollectionViewType.Docking].includes(this.Document._viewType as any); } @computed get effectiveNativeWidth() { return this.shouldNotScale ? 0 : this.nativeWidth || NumCast(this.layoutDoc.width); @@ -1356,8 +1356,8 @@ export class DocumentView extends React.Component { @computed get nativeScaling() { if (this.shouldNotScale) return 1; const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; - if (this.fitWidth || this.props.PanelHeight() / (this.effectiveNativeHeight || 1) > this.props.PanelWidth() / (this.effectiveNativeWidth || 1)) { - return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or fitWidth + if (this.layout_fitWidth || this.props.PanelHeight() / (this.effectiveNativeHeight || 1) > this.props.PanelWidth() / (this.effectiveNativeWidth || 1)) { + return Math.max(minTextScale, this.props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or layout_fitWidth } return Math.max(minTextScale, this.props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled } @@ -1365,7 +1365,7 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); } @computed get panelHeight() { - if (this.effectiveNativeHeight && (!this.fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) { + if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) { return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling); } return this.props.PanelHeight(); @@ -1374,7 +1374,10 @@ export class DocumentView extends React.Component { return this.effectiveNativeWidth ? Math.max(0, (this.props.PanelWidth() - this.effectiveNativeWidth * this.nativeScaling) / 2) : 0; } @computed get Yshift() { - return this.effectiveNativeWidth && this.effectiveNativeHeight && Math.abs(this.Xshift) < 0.001 && (!this.layoutDoc.nativeHeightUnfrozen || (!this.fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) + return this.effectiveNativeWidth && + this.effectiveNativeHeight && + Math.abs(this.Xshift) < 0.001 && + (!this.layoutDoc.nativeHeightUnfrozen || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight())) ? Math.max(0, (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2) : 0; } @@ -1410,10 +1413,10 @@ export class DocumentView extends React.Component { finished?.(); this.docView && (this.docView._animateScaleTime = animTime); }); - const layoutKey = Cast(this.Document.layoutKey, 'string', null); - if (layoutKey !== 'layout_icon') { + const layout_fieldKey = Cast(this.Document.layout_fieldKey, 'string', null); + if (layout_fieldKey !== 'layout_icon') { this.switchViews(true, 'icon', finalFinished); - if (layoutKey && layoutKey !== 'layout' && layoutKey !== 'layout_icon') this.Document.deiconifyLayout = layoutKey.replace('layout_', ''); + if (layout_fieldKey && layout_fieldKey !== 'layout' && layout_fieldKey !== 'layout_icon') this.Document.deiconifyLayout = layout_fieldKey.replace('layout_', ''); } else { const deiconifyLayout = Cast(this.Document.deiconifyLayout, 'string', null); this.switchViews(deiconifyLayout ? true : false, deiconifyLayout, finalFinished); @@ -1433,7 +1436,7 @@ export class DocumentView extends React.Component { setTimeout( action(() => { if (useExistingLayout && custom && this.rootDoc['layout_' + view]) { - this.rootDoc.layoutKey = 'layout_' + view; + this.rootDoc.layout_fieldKey = 'layout_' + view; } else { this.setCustomView(custom, view); } @@ -1520,7 +1523,7 @@ export class DocumentView extends React.Component { width: xshift ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, height: this.props.forceAutoHeight ? undefined - : yshift ?? (this.fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), + : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(((100 * this.effectiveNativeHeight) / this.effectiveNativeWidth) * this.props.PanelWidth()) / this.props.PanelHeight()}%`), }}> Doc.AreProtosEqual(d, otherdoc))) { - const alias = Doc.MakeAlias(otherdoc); - alias.x = wid; - alias.y = 0; - alias._lockedPosition = false; + const embedding = Doc.MakeEmbedding(otherdoc); + embedding.x = wid; + embedding.y = 0; + embedding._lockedPosition = false; wid += otherdoc[WidthSym](); - Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', alias); + Doc.AddDocToList(Doc.GetProto(linkCollection), 'data', embedding); } }); return links; diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 163c5a9ed..f17ab06e7 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -90,7 +90,7 @@ export class EquationBox extends ViewBoxBaseComponent() { }; render() { TraceMobx(); - const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); + const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1); return (
this.updateSize()} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 7eae4e938..85dd779fc 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -50,7 +50,7 @@ export class FieldView extends React.Component { @computed get field(): FieldResult { - const { Document, fieldKey } = this.props; + const { Document, fieldKey: fieldKey } = this.props; return Document[fieldKey]; } render() { diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx index b43e359ff..db72209ab 100644 --- a/src/client/views/nodes/FunctionPlotBox.tsx +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -90,7 +90,7 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc); } - // if (this.autoHeight) this.tryUpdateScrollHeight(); + // if (this.layout_autoHeight) this.tryUpdateScrollHeight(); }; @computed get theGraph() { return
r && this.createGraph(r)} style={{ position: 'absolute', width: '100%', height: '100%' }} onPointerDown={e => e.stopPropagation()} />; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c9be10d3a..7d1d50cc7 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -79,9 +79,9 @@ 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._viewScale, 1), + scrSize: (this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.rootDoc._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'), @@ -116,7 +116,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent this.layoutDoc._scrollTop, + () => this.layoutDoc.layout_scrollTop, s_top => { this._forcedScroll = true; !this._ignoreScroll && this._mainCont.current && (this._mainCont.current.scrollTop = NumCast(s_top)); @@ -144,7 +144,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop); - this.rootDoc[this.fieldKey + '-usePath'] = 'alternate:hover'; + this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover'; e.stopPropagation(); }) ); @@ -167,28 +167,28 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._viewScale, 1); + const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1); const nscale = NumCast(this.props.PanelWidth()) / scaling; - const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']); - const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']); - this.dataDoc[this.fieldKey + '-nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']) * nh; - this.dataDoc[this.fieldKey + '-nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']) * nh; - this.rootDoc._panX = nh * NumCast(this.rootDoc._panX); - this.rootDoc._panY = nh * NumCast(this.rootDoc._panY); - this.dataDoc._panXMax = this.dataDoc._panXMax ? nh * NumCast(this.dataDoc._panXMax) : undefined; - this.dataDoc._panXMin = this.dataDoc._panXMin ? nh * NumCast(this.dataDoc._panXMin) : undefined; - this.dataDoc._panYMax = this.dataDoc._panYMax ? nw * NumCast(this.dataDoc._panYMax) : undefined; - this.dataDoc._panYMin = this.dataDoc._panYMin ? nw * NumCast(this.dataDoc._panYMin) : undefined; + const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']); + const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); + this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nh; + this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nh; + this.rootDoc._freeform_panX = nh * NumCast(this.rootDoc._freeform_panX); + this.rootDoc._freeform_panY = nh * NumCast(this.rootDoc._freeform_panY); + this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nh * NumCast(this.dataDoc._freeform_panXMax) : undefined; + this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nh * NumCast(this.dataDoc._freeform_panXMin) : undefined; + this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined; + this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined; }); @undoBatch rotate = action(() => { - const nw = NumCast(this.dataDoc[this.fieldKey + '-nativeWidth']); - const nh = NumCast(this.dataDoc[this.fieldKey + '-nativeHeight']); + const nw = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); + const nh = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']); const w = this.layoutDoc._width; const h = this.layoutDoc._height; this.dataDoc[this.fieldKey + '-rotation'] = (NumCast(this.dataDoc[this.fieldKey + '-rotation']) + 90) % 360; - this.dataDoc[this.fieldKey + '-nativeWidth'] = nh; - this.dataDoc[this.fieldKey + '-nativeHeight'] = nw; + this.dataDoc[this.fieldKey + '_nativeWidth'] = nh; + this.dataDoc[this.fieldKey + '_nativeHeight'] = nw; this.layoutDoc._width = h; this.layoutDoc._height = w; }); @@ -204,7 +204,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; }; - getScrollHeight = () => (this.props.fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._viewScale, 1) === NumCast(this.rootDoc._viewScaleMin, 1) ? this.nativeSize.nativeHeight : undefined); + getScrollHeight = () => (this.props.layout_fitWidth?.(this.rootDoc) !== false && NumCast(this.rootDoc._freeform_scale, 1) === NumCast(this.rootDoc._freeform_scaleMin, 1) ? this.nativeSize.nativeHeight : undefined); @computed private get considerDownloadIcon() { @@ -358,13 +358,13 @@ 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.rootDoc[`_${this.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : usePath === 'alternate' ? 'alternate:hover' : undefined))} style={{ display: (SnappingManager.GetIsDragging() && DragManager.DocDragData?.canEmbed) || DocListCast(this.dataDoc[this.fieldKey + '-alternates']).length ? 'block' : 'none', width: 'min(10%, 25px)', @@ -431,7 +431,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent (this._isHovering = true))} onPointerLeave={action(() => (this._isHovering = false))} key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}> @@ -459,9 +459,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } - screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop) * this.props.ScreenToLocalTransform().Scale); + screenToLocalTransform = () => 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._viewScale, 1) <= NumCast(this.rootDoc.viewScaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { + 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)) { setupMoveUpEvents( this, e, @@ -497,9 +497,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent { if (!this._forcedScroll) { - if (this.layoutDoc._scrollTop || this._mainCont.current?.scrollTop) { + if (this.layoutDoc._layout_scrollTop || this._mainCont.current?.scrollTop) { this._ignoreScroll = true; - this.layoutDoc._scrollTop = this._mainCont.current?.scrollTop; + this.layoutDoc._layout_scrollTop = this._mainCont.current?.scrollTop; this._ignoreScroll = false; } } @@ -510,7 +510,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { } reverseNativeScaling = returnTrue; able = returnAlways; - fitWidth = returnTrue; + layout_fitWidth = returnTrue; overridePointerEvents = returnAll; onClickScriptDisable = returnAlways; @observable private rows: KeyValuePair[] = []; + @observable _splitPercentage = 50; - @computed get splitPercentage() { - return NumCast(this.props.Document.schemaSplitPercentage, 50); - } get fieldDocToLayout() { return this.props.fieldKey ? DocCast(this.props.Document[this.props.fieldKey], DocCast(this.props.Document)) : this.props.Document; } @@ -147,7 +145,9 @@ export class KeyValueBox extends React.Component { const rows: JSX.Element[] = []; let i = 0; const self = this; - for (const key of Object.keys(ids).slice().sort()) { + const keys = Object.keys(ids).slice(); + //for (const key of [...keys.filter(id => id !== 'layout' && !id.includes('_')).sort(), ...keys.filter(id => id === 'layout' || id.includes('_')).sort()]) { + for (const key of keys.sort()) { rows.push( { if (el) self.rows.push(el); }; })()} - keyWidth={100 - this.splitPercentage} + keyWidth={100 - this._splitPercentage} rowStyle={'keyValueBox-' + (i++ % 2 ? 'oddRow' : 'evenRow')} key={key} keyName={key} @@ -180,7 +180,7 @@ export class KeyValueBox extends React.Component { this._keyInput.current!.select(); e.stopPropagation(); }} - style={{ width: `${100 - this.splitPercentage}%` }}> + style={{ width: `${100 - this._splitPercentage}%` }}> { this._valInput.current!.select(); e.stopPropagation(); }} - style={{ width: `${this.splitPercentage}%` }}> + style={{ width: `${this._splitPercentage}%` }}> @@ -199,7 +199,7 @@ export class KeyValueBox extends React.Component { @action onDividerMove = (e: PointerEvent): void => { const nativeWidth = this._mainCont.current!.getBoundingClientRect(); - this.props.Document.schemaSplitPercentage = Math.max(0, 100 - Math.round(((e.clientX - nativeWidth.left) / nativeWidth.width) * 100)); + this._splitPercentage = Math.max(0, 100 - Math.round(((e.clientX - nativeWidth.left) / nativeWidth.width) * 100)); }; @action onDividerUp = (e: PointerEvent): void => { @@ -216,7 +216,7 @@ export class KeyValueBox extends React.Component { getFieldView = async () => { const rows = this.rows.filter(row => row.isChecked); if (rows.length > 1) { - const parent = Docs.Create.StackingDocument([], { _autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true }); + const parent = Docs.Create.StackingDocument([], { _layout_autoHeight: true, _width: 300, title: `field views for ${DocCast(this.props.Document.data).title}`, _chromeHidden: true }); for (const row of rows) { const field = this.createFieldView(DocCast(this.props.Document.data), row); field && Doc.AddDocToList(parent, 'data', field); @@ -229,9 +229,9 @@ export class KeyValueBox extends React.Component { createFieldView = (templateDoc: Doc, row: KeyValuePair) => { const metaKey = row.props.keyName; - const fieldTemplate = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeAlias(templateDoc); + const fieldTemplate = Doc.IsDelegateField(templateDoc, metaKey) ? Doc.MakeDelegate(templateDoc) : Doc.MakeEmbedding(templateDoc); fieldTemplate.title = metaKey; - fieldTemplate.fitWidth = true; + fieldTemplate.layout_fitWidth = true; fieldTemplate._xMargin = 10; fieldTemplate._yMargin = 10; fieldTemplate._width = 100; @@ -284,8 +284,8 @@ export class KeyValueBox extends React.Component { render() { const dividerDragger = - this.splitPercentage === 0 ? null : ( -
+ this._splitPercentage === 0 ? null : ( +
); @@ -295,10 +295,10 @@ export class KeyValueBox extends React.Component { - - diff --git a/src/client/views/nodes/KeyValuePair.scss b/src/client/views/nodes/KeyValuePair.scss index 57d36932e..2b4867321 100644 --- a/src/client/views/nodes/KeyValuePair.scss +++ b/src/client/views/nodes/KeyValuePair.scss @@ -19,6 +19,7 @@ position: relative; margin: 0; } + .keyValuePair-keyFieldMod, .keyValuePair-keyField { width: 100%; margin-left: 20px; @@ -27,6 +28,9 @@ overflow: auto; display: inline; } + .keyValuePair-keyFieldMod { + margin-left: 35px; + } } } .keyValuePair-td-value { diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 85641124f..509bb667e 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -66,7 +66,7 @@ export class KeyValuePair extends React.Component { isSelected: returnFalse, setHeight: returnFalse, select: emptyFunction, - dropAction: 'alias', + dropAction: 'embed', bringToFront: emptyFunction, renderDepth: 1, isContentActive: returnFalse, @@ -108,8 +108,8 @@ export class KeyValuePair extends React.Component { })}> X - -
+ +
{'('.repeat(parenCount)} {props.fieldKey} {')'.repeat(parenCount)} diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index 916458dfd..32026ea9c 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -37,7 +37,7 @@ export class LabelBox extends ViewBoxBaseComponent { @@ -82,7 +82,7 @@ export class LabelBox extends ViewBoxBaseComponent { + fitTextToBox = (r: any) => { const singleLine = BoolCast(this.rootDoc._singleLine, true); const params = { rotateText: null, @@ -141,9 +141,9 @@ export class LabelBox extends ViewBoxBaseComponent - this.fitTextToBox(r))}> + this.fitTextToBox(r))}> {label.startsWith('#') ? null : label.replace(/([^a-zA-Z])/g, '$1\u200b')}
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 31f1775e5..f38ef634c 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -46,14 +46,14 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY)); if (separation > 100) { const dragData = new DragManager.DocumentDragData([this.rootDoc]); - dragData.dropAction = 'alias'; - dragData.removeDropProperties = ['anchor1_x', 'anchor1_y', 'anchor2_x', 'anchor2_y', 'onClick']; + dragData.dropAction = 'embed'; + dragData.removeDropProperties = ['link_anchor_1_x', 'link_anchor_1_y', 'link_anchor_2_x', 'link_anchor_2_y', 'onClick']; DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]); return true; } else { this.rootDoc[this.fieldKey + '_x'] = ((pt[0] - bounds.left) / bounds.width) * 100; this.rootDoc[this.fieldKey + '_y'] = ((pt[1] - bounds.top) / bounds.height) * 100; - this.rootDoc.linkAutoMove = false; + this.rootDoc.layout_autoMoveAnchors = false; } } return false; @@ -67,10 +67,14 @@ export class LinkAnchorBox extends ViewBoxBaseComponent() { const x = NumCast(this.rootDoc[this.fieldKey + '_x'], 100); const y = NumCast(this.rootDoc[this.fieldKey + '_y'], 100); const background = this.props.styleProvider?.(this.dataDoc, this.props, StyleProp.BackgroundColor + ':anchor'); - const anchor = this.fieldKey === 'anchor1' ? 'anchor2' : 'anchor1'; - const anchorScale = !this.dataDoc[this.fieldKey + '-useLinkSmallAnchor'] && (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : 0.25; + const anchor = this.fieldKey === 'link_anchor_1' ? 'link_anchor_2' : 'link_anchor_1'; + const anchorScale = !this.dataDoc[this.fieldKey + '_useLinkSmallAnchor'] && (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('anchor1') ? 'anchor1' : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('anchor2') ? 'anchor2' : ''; + const selView = SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_1') + ? 'link_anchor_1' + : SelectionManager.Views().lastElement()?.props.LayoutTemplateString?.includes('link_anchor_2') + ? 'link_anchor_2' + : ''; return (
() { - public static LayoutString(fieldKey: string) { + public static LayoutString(fieldKey: string = 'link') { return FieldView.LayoutString(LinkBox, fieldKey); } @@ -23,7 +23,7 @@ export class LinkBox extends ViewBoxBaseComponent() {
{ onDismiss = (add: boolean) => { LinkDescriptionPopup.descriptionPopup = false; if (add) { - LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).description = this.description); + LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).link_description = this.description); } }; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index c58b5dd8c..c6172ee01 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -58,13 +58,13 @@ export class LinkDocPreview extends React.Component { var linkTarget = this.props.linkDoc; this._linkSrc = this.props.linkSrc; this._linkDoc = this.props.linkDoc; - const anchor1 = this._linkDoc?.anchor1 as Doc; - const anchor2 = this._linkDoc?.anchor2 as Doc; - if (anchor1 && anchor2) { - linkTarget = Doc.AreProtosEqual(anchor1, this._linkSrc) || Doc.AreProtosEqual(anchor1?.annotationOn as Doc, this._linkSrc) ? anchor2 : anchor1; + const link_anchor_1 = this._linkDoc?.link_anchor_1 as Doc; + const link_anchor_2 = this._linkDoc?.link_anchor_2 as Doc; + if (link_anchor_1 && link_anchor_2) { + linkTarget = Doc.AreProtosEqual(link_anchor_1, this._linkSrc) || Doc.AreProtosEqual(link_anchor_1?.annotationOn as Doc, this._linkSrc) ? link_anchor_2 : link_anchor_1; } if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { - // want to show annotation context document if annotation is not text + // want to show annotation embedContainer document if annotation is not text linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno))); } else { this._markerTargetDoc = this._targetDoc = linkTarget; @@ -111,7 +111,7 @@ export class LinkDocPreview extends React.Component { action(anchor => { if (anchor instanceof Doc && LinkManager.Links(anchor).length) { this._linkDoc = this._linkDoc ?? LinkManager.Links(anchor)[0]; - const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords; + const automaticLink = this._linkDoc.link_relationship === LinkManager.AutoKeywords; if (automaticLink) { // automatic links specify the target in the link info, not the source const linkTarget = anchor; @@ -175,7 +175,7 @@ export class LinkDocPreview extends React.Component { } else if (this.props.hrefs?.length) { const webDoc = Array.from(SearchBox.staticSearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ?? - Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, useCors: true }); + Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true }); this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox); } }; @@ -208,7 +208,7 @@ export class LinkDocPreview extends React.Component {
{StrCast(this._markerTargetDoc.title).length > 16 ? StrCast(this._markerTargetDoc.title).substr(0, 16) + '...' : StrCast(this._markerTargetDoc.title)} -

{StrCast(this._linkDoc.description)}

+

{StrCast(this._linkDoc.link_description)}

Next Link
} placement="top"> @@ -263,7 +263,7 @@ export class LinkDocPreview extends React.Component { isDocumentActive={returnFalse} isContentActive={returnFalse} addDocument={returnFalse} - showTitle={returnEmptyString} + layout_showTitle={returnEmptyString} removeDocument={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} @@ -278,7 +278,7 @@ export class LinkDocPreview extends React.Component { pointerEvents={returnNone} focus={emptyFunction} whenChildContentsActiveChanged={returnFalse} - ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size. + ignoreAutoHeight={true} // need to ignore layout_autoHeight otherwise layout_autoHeight text boxes will expand beyond the preview panel size. bringToFront={returnFalse} NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined} NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined} diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 36be7d257..9b0fddce4 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -98,7 +98,7 @@ export class MapBox extends ViewBoxAnnotatableComponent void); @computed get inlineTextAnnotations() { @@ -126,7 +126,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } }, 250); // listener to addmarker event @@ -282,7 +282,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapLat = this._map.getCenter()?.lat(); this.dataDoc.mapLng = this._map.getCenter()?.lng(); @@ -292,7 +292,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapZoom = this._map.getZoom(); }; @@ -327,7 +327,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { console.log('print all sidebar Docs'); - if (!this.layoutDoc._showSidebar) this.toggleSidebar(); + if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { if (doc.lat !== undefined && doc.lng !== undefined) { @@ -351,7 +351,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (this.layoutDoc._showSidebar) this.toggleSidebar(); + if (this.layoutDoc._layout_showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; return this.removeDocument(doc, sidebarKey); }; @@ -375,11 +375,11 @@ export class MapBox extends ViewBoxAnnotatableComponent 0) { this._showSidebar = true; this.layoutDoc._width = fullWidth + localDelta[0]; - this.layoutDoc._sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; + this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; } else { this._showSidebar = false; this.layoutDoc._width = mapWidth; - this.layoutDoc._sidebarWidthPercent = '0%'; + this.layoutDoc._layout_sidebarWidthPercent = '0%'; } return false; }), @@ -388,12 +388,12 @@ export class MapBox extends ViewBoxAnnotatableComponent (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); - @computed get sidebarWidthPercent() { - return StrCast(this.layoutDoc._sidebarWidthPercent, '0%'); + sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + @computed get layout_sidebarWidthPercent() { + return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } @computed get sidebarColor() { - return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4')); + return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); } /** @@ -453,7 +453,7 @@ export class MapBox extends ViewBoxAnnotatableComponent @@ -467,8 +467,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { //1.2 * w * ? = .2 * w .2/1.2 const prevWidth = this.sidebarWidth(); - this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%'; - this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); + this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%'; + this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); }; sidebarDown = (e: React.PointerEvent) => { @@ -476,8 +476,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { const bounds = this._ref.current!.getBoundingClientRect(); - this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; - this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%'; + this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; + this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%'; e.preventDefault(); return false; }; @@ -548,7 +548,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._scrollTop)); + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; infoWidth = () => this.props.PanelWidth() / 5; @@ -616,7 +616,7 @@ export class MapBox extends ViewBoxAnnotatableComponent + style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
{renderAnnotations(this.transparentFilter)}
{renderAnnotations(this.opaqueFilter)} {SnappingManager.GetIsDragging() ? null : renderAnnotations()} @@ -667,7 +667,7 @@ export class MapBox extends ViewBoxAnnotatableComponent {/* */} -
+
void); @computed get inlineTextAnnotations() { @@ -123,7 +123,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } }, 250); // listener to addmarker event @@ -279,7 +279,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapLat = this._map.getCenter()?.lat(); this.dataDoc.mapLng = this._map.getCenter()?.lng(); @@ -289,7 +289,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { if (this._loadPending && this._map.getBounds()) { this._loadPending = false; - this.layoutDoc.fitContentsToBox && this.fitBounds(this._map); + this.layoutDoc.freeform_fitContentsToBox && this.fitBounds(this._map); } this.dataDoc.mapZoom = this._map.getZoom(); }; @@ -324,7 +324,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { console.log('print all sidebar Docs'); - if (!this.layoutDoc._showSidebar) this.toggleSidebar(); + if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; docs.forEach(doc => { if (doc.lat !== undefined && doc.lng !== undefined) { @@ -348,7 +348,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { - if (this.layoutDoc._showSidebar) this.toggleSidebar(); + if (this.layoutDoc._layout_showSidebar) this.toggleSidebar(); const docs = doc instanceof Doc ? [doc] : doc; return this.removeDocument(doc, sidebarKey); }; @@ -372,11 +372,11 @@ export class MapBox2 extends ViewBoxAnnotatableComponent 0) { this._showSidebar = true; this.layoutDoc._width = fullWidth + localDelta[0]; - this.layoutDoc._sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; + this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; } else { this._showSidebar = false; this.layoutDoc._width = mapWidth; - this.layoutDoc._sidebarWidthPercent = '0%'; + this.layoutDoc._layout_sidebarWidthPercent = '0%'; } return false; }), @@ -385,12 +385,12 @@ export class MapBox2 extends ViewBoxAnnotatableComponent (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); - @computed get sidebarWidthPercent() { - return StrCast(this.layoutDoc._sidebarWidthPercent, '0%'); + sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + @computed get layout_sidebarWidthPercent() { + return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } @computed get sidebarColor() { - return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '-backgroundColor'], '#e4e4e4')); + return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); } /** @@ -450,7 +450,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent @@ -464,8 +464,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { //1.2 * w * ? = .2 * w .2/1.2 const prevWidth = this.sidebarWidth(); - this.layoutDoc._showSidebar = (this.layoutDoc._sidebarWidthPercent = StrCast(this.layoutDoc._sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%'; - this.layoutDoc._width = this.layoutDoc._showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); + this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%'; + this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); }; sidebarDown = (e: React.PointerEvent) => { @@ -473,8 +473,8 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { const bounds = this._ref.current!.getBoundingClientRect(); - this.layoutDoc._sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; - this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== '0%'; + this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; + this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%'; e.preventDefault(); return false; }; @@ -545,7 +545,7 @@ export class MapBox2 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._scrollTop)); + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()]; opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()]; infoWidth = () => this.props.PanelWidth() / 5; @@ -566,7 +566,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent { e.button === 0 && !e.ctrlKey && e.stopPropagation(); }} - style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}> + style={{ width: `calc(100% - ${this.layout_sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}>
{renderAnnotations(this.transparentFilter)}
{renderAnnotations(this.opaqueFilter)} {SnappingManager.GetIsDragging() ? null : renderAnnotations()} @@ -616,7 +616,7 @@ export class MapBox2 extends ViewBoxAnnotatableComponent {/* */} -
+
{ setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => { - const newBox = Docs.Create.TextDocument('Note', { _autoHeight: true }); + const newBox = Docs.Create.TextDocument('Note', { _layout_autoHeight: true }); FormattedTextBox.SelectOnLoad = newBox[Id]; // track the new text box so we can give it a prop that tells it to focus itself when it's displayed Doc.AddDocToList(this.props.place, 'data', newBox); this._stack?.scrollToBottom(); @@ -42,7 +42,7 @@ export class MapBoxInfoWindow extends React.Component doc.type === DocumentType.RTF; + childLayoutFitWidth = (doc: Doc) => doc.type === DocumentType.RTF; addDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.AddDocToList(this.props.place, 'data', d), true as boolean); removeDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((p, d) => p && Doc.RemoveDocFromList(this.props.place, 'data', d), true as boolean); render() { @@ -69,7 +69,7 @@ export class MapBoxInfoWindow extends React.Component (this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href))); else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href)) PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(action((pdf: any) => (this._pdf = pdf))); @@ -122,15 +122,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent { @@ -173,15 +173,15 @@ export class PDFBox extends ViewBoxAnnotatableComponent { setTimeout(() => { this.dataDoc.icon = new ImageField(iconFile); - this.dataDoc['icon-nativeWidth'] = nativeWidth; - this.dataDoc['icon-nativeHeight'] = nativeHeight; + this.dataDoc['icon_nativeWidth'] = nativeWidth; + this.dataDoc['icon_nativeHeight'] = nativeHeight; }, 500); } ); @@ -201,13 +201,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.rootDoc.scrollTop, + () => this.rootDoc.layout_scrollTop, () => { - if (!(ComputedField.WithoutComputed(() => FieldValue(this.props.Document[this.SidebarKey + '-panY'])) instanceof ComputedField)) { - this.props.Document[this.SidebarKey + '-panY'] = ComputedField.MakeFunction('this.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 + '-viewScale'] = 1; - this.props.Document[this.SidebarKey + '-panX'] = 0; + this.props.Document[this.SidebarKey + '_freeform_scale'] = 1; + this.props.Document[this.SidebarKey + '_freeform_panX'] = 0; } ); } @@ -215,7 +215,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.brushView(view); sidebarAddDocTab = (doc: Doc, where: OpenWhere) => { - if (DocListCast(this.props.Document[this.props.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { + if (DocListCast(this.props.Document[this.props.fieldKey + '_sidebar']).includes(doc) && !this.SidebarShown) { this.toggleSidebar(false); return true; } @@ -239,7 +239,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent { const anchor = Docs.Create.TextanchorDocument({ - title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._scrollTop)?.toFixed(0)), + title: StrCast(this.rootDoc.title + '@' + NumCast(this.layoutDoc._layout_scrollTop)?.toFixed(0)), unrendered: true, annotationOn: this.rootDoc, }); @@ -258,11 +258,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - this.dataDoc[this.props.fieldKey + '-numPages'] = np; + this.dataDoc[this.props.fieldKey + '_numPages'] = np; Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), (nw * 96) / 72)); Doc.SetNativeHeight(this.dataDoc, (nh * 96) / 72); this.layoutDoc._height = this.layoutDoc[WidthSym]() / (Doc.NativeAspect(this.dataDoc) || 1); - !this.Document._fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); + !this.Document._layout_fitWidth && (this.Document._height = this.Document[WidthSym]() * (nh / nw)); }; public search = action((searchString: string, bwd?: boolean, clear: boolean = false) => { @@ -279,14 +279,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._pdfViewer?.prevAnnotation(); public nextAnnotation = () => this._pdfViewer?.nextAnnotation(); public backPage = () => { - this.Document._curPage = Math.max(1, (NumCast(this.Document._curPage) || 1) - 1); + this.Document._layout_curPage = Math.max(1, (NumCast(this.Document._layout_curPage) || 1) - 1); return true; }; public forwardPage = () => { - this.Document._curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + '-numPages']), (NumCast(this.Document._curPage) || 1) + 1); + this.Document._layout_curPage = Math.min(NumCast(this.dataDoc[this.props.fieldKey + '_numPages']), (NumCast(this.Document._layout_curPage) || 1) + 1); return true; }; - public gotoPage = (p: number) => (this.Document._curPage = p); + public gotoPage = (p: number) => (this.Document._layout_curPage = p); @undoBatch onKeyDown = action((e: KeyboardEvent) => { @@ -316,9 +316,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent) => (this._searchString = e.currentTarget.value); // adding external documents; to sidebar key - // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"-annotation") + // if (doc.Geolocation) this.addDocument(doc, this.fieldkey+"_annotation") sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { - if (!this.layoutDoc._showSidebar) this.toggleSidebar(); + if (!this.layoutDoc._show_sidebar) this.toggleSidebar(); return this.addDocument(doc, sidebarKey); }; sidebarBtnDown = (e: React.PointerEvent, onButton: boolean) => { @@ -332,13 +332,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent= 1) { this.layoutDoc.nativeWidth = nativeWidth * ratio; onButton && (this.layoutDoc._width = this.layoutDoc[WidthSym]() + localDelta[0]); - this.layoutDoc._showSidebar = nativeWidth !== this.layoutDoc._nativeWidth; + this.layoutDoc._show_sidebar = nativeWidth !== this.layoutDoc._nativeWidth; } return false; }, @@ -352,7 +352,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent = undefined; @observable _previewWidth: Opt = undefined; toggleSidebar = action((preview: boolean = false) => { - const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '-nativeWidth']); + const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth; const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth); @@ -363,7 +363,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent ); const searchTitle = `${!this._searching ? 'Open' : 'Close'} Search Bar`; - const curPage = NumCast(this.Document._curPage) || 1; + const curPage = NumCast(this.Document._layout_curPage) || 1; return !this.props.isContentActive() || this._pdfViewer?.isAnnotating ? null : (
99 ? 4 : 3}ch`, pointerEvents: 'all' }} - onChange={e => (this.Document._curPage = Number(e.currentTarget.value))} + onChange={e => (this.Document._layout_curPage = Number(e.currentTarget.value))} onKeyDown={e => e.stopPropagation()} onClick={action(() => (this._pageControls = !this._pageControls))} /> @@ -470,7 +470,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this._sidebarRef.current?.anchorMenuClick; @observable _showSidebar = false; @computed get SidebarShown() { - return this._showSidebar || this.layoutDoc._showSidebar ? true : false; + return this._showSidebar || this.layoutDoc._show_sidebar ? true : false; } @computed get sidebarHandle() { return ( @@ -480,7 +480,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent this.sidebarBtnDown(e, true)}> @@ -490,10 +490,10 @@ export class PDFBox extends ViewBoxAnnotatableComponent 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined, + height: this.props.Document._layout_scrollTop && !this.Document._layout_fitWidth && window.screen.width > 600 ? (NumCast(this.Document._height) * this.props.PanelWidth()) / NumCast(this.Document._width) : undefined, }}>
this.sidebarBtnDown(e, false)} />
{ this.result = info; this.dataDoc.type = DocumentType.VID; - this.dataDoc[this.fieldKey + '-duration'] = this.videoDuration; + this.dataDoc[this.fieldKey + '_duration'] = this.videoDuration; this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey); this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.client); diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 75e61bbeb..7bf765042 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -129,7 +129,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { - const startTime = Cast(this.layoutDoc._currentTimecode, 'number', null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined); + 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; }; @@ -236,13 +236,13 @@ 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)); - dictationText._autoHeight = false; + dictationText._layout_autoHeight = false; const dictationTextProto = Doc.GetProto(dictationText); dictationTextProto.recordingSource = this.dataDoc; dictationTextProto.recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.props.fieldKey}-recordingStart"]`); dictationTextProto.mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState'); this.dataDoc[this.fieldKey + '-dictation'] = dictationText; }; - videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '-nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '-nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth(); + videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], this.layoutDoc[HeightSym]()) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], this.layoutDoc[WidthSym]())) * this.props.PanelWidth(); formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); render() { TraceMobx(); diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index f09962b22..37fda14fc 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -167,7 +167,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { - this.rootDoc.layoutKey = 'layout'; + this.rootDoc.layout_fieldKey = 'layout'; }; // displays error message @@ -702,7 +702,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent - {!StrCast(this.rootDoc.layoutKey).startsWith('layout_on') ? null : ( + {!StrCast(this.rootDoc.layout_fieldKey).startsWith('layout_on') ? null : (
+ Key + Fields