diff options
author | bobzel <zzzman@gmail.com> | 2024-05-02 00:39:31 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-05-02 00:39:31 -0400 |
commit | dd08c20ec6df3fad6ecd6b16c787f10b0c23feb4 (patch) | |
tree | 11f2b1b741369997af567983df0316923e08d780 /src/client/views/nodes/DocumentView.tsx | |
parent | 76838b7b3842c9b184e6459e29796dd14de37e8d (diff) |
lots more dependency cycle unwinding.
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 203 |
1 files changed, 96 insertions, 107 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 1e7f1015a..f8ce50c98 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -7,10 +7,10 @@ import { IReactionDisposer, action, computed, makeObservable, observable, reacti import { observer } from 'mobx-react'; import * as React from 'react'; import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; -import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../ClientUtils'; +import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simulateMouseClick } from '../../../ClientUtils'; import { Utils, emptyFunction, emptyPath } from '../../../Utils'; import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; +import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; @@ -20,20 +20,17 @@ import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { AudioField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; +import { AudioAnnoState } from '../../../server/SharedMediaTypes'; import { DocServer } from '../../DocServer'; -import { Networking } from '../../Network'; import { DocUtils, FollowLinkScript } from '../../documents/DocUtils'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { Docs } from '../../documents/Documents'; -import { DictationManager } from '../../util/DictationManager'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { dropActionType } from '../../util/DropActionTypes'; import { MakeTemplate, makeUserTemplateButton } from '../../util/DropConverter'; -import { LinkManager, UPDATE_SERVER_CACHE } from '../../util/LinkManager'; +import { UPDATE_SERVER_CACHE } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SearchUtil } from '../../util/SearchUtil'; -import { SelectionManager } from '../../util/SelectionManager'; import { SharingManager } from '../../util/SharingManager'; import { SnappingManager } from '../../util/SnappingManager'; import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; @@ -42,16 +39,15 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent, ViewBoxInterface } from '../DocComponent'; import { EditableView } from '../EditableView'; import { FieldsDropdown } from '../FieldsDropdown'; -import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { AudioAnnoState, StyleProp } from '../StyleProvider'; +import { PinProps } from '../PinFuncs'; +import { StyleProp } from '../StyleProp'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; import { FieldViewProps, FieldViewSharedProps } from './FieldView'; import { FocusViewOptions } from './FocusViewOptions'; import { KeyValueBox } from './KeyValueBox'; -import { LinkAnchorBox } from './LinkAnchorBox'; import { OpenWhere } from './OpenWhere'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; @@ -90,6 +86,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document // this makes mobx trace() statements more descriptive public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. + /** * This function is filled in by MainView to allow non-viewBox views to add Docs as tabs without * needing to know about/reference MainView @@ -183,11 +180,10 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document // anchors that are not rendered as DocumentViews (marked as 'layout_unrendered' with their 'annotationOn' set to this document). e.g., // - PDF text regions are rendered as an Annotations without generating a DocumentView, ' // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link - // - and links to PDF/Web docs at a certain scroll location never create an explicit view. - // For each of these, we create LinkAnchorBox's on the border of the DocumentView. + // - and links to PDF/Web docs at a certain scroll location never create an explicit anchor view. @computed get directLinks() { TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.Document).filter( + return Doc.Links(this.Document).filter( link => (link.link_matchEmbeddings ? link.link_anchor_1 === this.Document : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.Document)) || (link.link_matchEmbeddings ? link.link_anchor_2 === this.Document : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.Document)) || @@ -197,11 +193,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document } @computed get _allLinks(): Doc[] { TraceMobx(); - return LinkManager.Instance.getAllRelatedLinks(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); + return Doc.Links(this.Document).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.Document || link.link_anchor_2 === this.Document); } @computed get filteredLinks() { - return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); + return DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []); } componentWillUnmount() { @@ -259,7 +255,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) { const docView = this._docView; if (this._mainCont.current && docView) { - const views = SelectionManager.Views.filter(dv => dv.ContentDiv); + const views = DocumentView.Selected().filter(dv => dv.ContentDiv); const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [docView]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); const screenXf = docView.screenToViewTransform(); @@ -289,8 +285,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }; onBrowseClick = (e: React.MouseEvent) => { const browseTransitionTime = 500; - SelectionManager.DeselectAll(); - DocumentManager.Instance.showDocument(this.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { + DocumentView.DeselectAll(); + DocumentView.showDocument(this.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime }; if (!focused && this._docView) { this._docView @@ -327,7 +323,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document UndoManager.RunInBatch(() => this.onDoubleClickHandler.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title); } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') { UndoManager.RunInBatch(() => LightboxView.Instance.AddDocTab(this.Document, OpenWhere.lightbox), 'double tap'); - SelectionManager.DeselectAll(); + DocumentView.DeselectAll(); Doc.UnBrushDoc(this.Document); } else { this._singleClickFunc?.(); @@ -377,7 +373,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; // eslint-disable-next-line no-use-before-define this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000); - if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._docView; + if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView; this._downX = e.clientX; this._downY = e.clientY; @@ -463,7 +459,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }, 'set toggle detail'); drop = undoable((e: Event, de: DragManager.DropEvent) => { - if (this._props.dontRegisterView || this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false; + if (this._props.dontRegisterView) return false; if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); e.preventDefault(); @@ -484,7 +480,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (linkDoc) { de.complete.linkDocument = linkDoc; linkDoc.layout_isSvg = true; - DocumentManager.LinkCommonAncestor(linkDoc)?.ComponentView?.addDocument?.(linkDoc); + DocumentView.linkCommonAncestor(linkDoc)?.ComponentView?.addDocument?.(linkDoc); } } e.stopPropagation(); @@ -516,7 +512,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (e && this.layoutDoc.layout_hideContextMenu && Doc.noviceMode) { e.preventDefault(); e.stopPropagation(); - // !this._props.isSelected(true) && SelectionManager.SelectView(this.DocumentView(), false); + // !this._props.isSelected(true) && DocumentView.SelectView(this.DocumentView(), false); } // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 if (e) { @@ -576,8 +572,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (this._props.bringToFront) { const zorders = cm.findByDescription('ZOrder...'); const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : []; - zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' }); - zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views.forEach(dv => dv._props.bringToFront?.(dv.Document, true)), icon: 'arrow-down' }); + zorderItems.push({ description: 'Bring to Front', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' }); + zorderItems.push({ description: 'Send to Back', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', event: undoBatch( @@ -601,7 +597,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document onClicks.push({ description: this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(false, false), icon: 'link' }); !Doc.noviceMode && onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); - } else if (LinkManager.Links(this.Document).length) { + } else if (Doc.Links(this.Document).length) { onClicks.push({ description: 'Restore On Click default', event: () => this.noOnClick(), icon: 'link' }); onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(), icon: 'link' }); !existingOnClick && cm.addItem({ description: 'OnClick...', subitems: onClicks, icon: 'mouse-pointer' }); @@ -718,7 +714,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document case StyleProp.PointerEvents: return 'none'; case StyleProp.Highlighting: return undefined; case StyleProp.Opacity: { - const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []).filter(d => d.link_displayLine || Doc.UserDoc().showLinkLines); + const filtered = DocUtils.FilterDocs(this.directLinks, this._props.childFilters?.() ?? [], []); return filtered.some(link => link._link_displayArrow) ? 0 : undefined; } default: @@ -726,34 +722,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document return this._props.styleProvider?.(doc, props, property); }; - // eslint-disable-next-line no-return-assign - removeLinkByHiding = (link: Doc) => () => link.link_displayLine = false; // prettier-ignore - @computed get allLinkEndpoints() { - // the small blue dots that mark the endpoints of links - if (this._componentView instanceof KeyValueBox || this._props.hideLinkAnchors || this.layoutDoc.layout_hideLinkAnchors || this._props.dontRegisterView || this.layoutDoc.layout_unrendered) return null; - return this.filteredLinks.map(link => ( - <div className="documentView-anchorCont" key={link[Id]}> - <DocumentView - {...this._props} - isContentActive={returnFalse} - Document={link} - containerViewPath={this._props.docViewPath} - PanelWidth={this.anchorPanelWidth} - PanelHeight={this.anchorPanelHeight} - dontRegisterView={false} - layout_showTitle={returnEmptyString} - hideCaptions - hideLinkAnchors - layout_fitWidth={returnTrue} - removeDocument={this.removeLinkByHiding(link)} - styleProvider={this.anchorStyleProvider} - LayoutTemplate={undefined} - LayoutTemplateString={LinkAnchorBox.LayoutString(`link_anchor_${LinkManager.anchorIndex(link, this.Document)}`)} - /> - </div> - )); - } - @computed get viewBoxContents() { TraceMobx(); const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; @@ -780,7 +748,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document setTitleFocus={this.setTitleFocus} hideClickBehaviors={BoolCast(this.Document.hideClickBehaviors)} /> - {this.layoutDoc.layout_hideAllLinks ? null : this.allLinkEndpoints} </div> ); } @@ -1008,50 +975,45 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document default: return renderDoc; } } - public static recordAudioAnnotation(dataDoc: Doc, field: string, onRecording?: (stop: () => void) => void, onEnd?: () => void) { - let gumStream: any; - let recorder: any; - navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => { - let audioTextAnnos = Cast(dataDoc[field + '_audioAnnotations_text'], listSpec('string'), null); - if (audioTextAnnos) audioTextAnnos.push(''); - else audioTextAnnos = dataDoc[field + '_audioAnnotations_text'] = new List<string>(['']); - DictationManager.Controls.listen({ - interimHandler: value => { audioTextAnnos[audioTextAnnos.length - 1] = value; }, // prettier-ignore - continuous: { indefinite: false }, - }).then(results => { - if (results && [DictationManager.Controls.Infringed].includes(results)) { - DictationManager.Controls.stop(); - } - onEnd?.(); - }); - - gumStream = stream; - recorder = new MediaRecorder(stream); - recorder.ondataavailable = async (e: any) => { - const [{ result }] = await Networking.UploadFilesToServer({ file: e.data }); - if (!(result instanceof Error)) { - const audioField = new AudioField(result.accessPaths.agnostic.client); - const audioAnnos = Cast(dataDoc[field + '_audioAnnotations'], listSpec(AudioField), null); - if (audioAnnos) audioAnnos.push(audioField); - else dataDoc[field + '_audioAnnotations'] = new List([audioField]); - } - }; - recorder.start(); - const stopFunc = () => { - recorder.stop(); - DictationManager.Controls.stop(/* false */); - dataDoc.audioAnnoState = AudioAnnoState.stopped; - gumStream.getAudioTracks()[0].stop(); - }; - if (onRecording) onRecording(stopFunc); - else setTimeout(stopFunc, 5000); - }); - } } @observer export class DocumentView extends DocComponent<DocumentViewProps>() { public static ROOT_DIV = 'documentView-effectsWrapper'; + // LinkFollower + public static FollowLink: (linkDoc: Opt<Doc>, sourceDoc: Doc, altKey: boolean) => boolean; + // selection funcs + public static DeselectAll: (except?: Doc) => void | undefined; + public static DeselectView: (dv: DocumentView | undefined) => void | undefined; + public static SelectView: (dv: DocumentView | undefined, extendSelection: boolean) => void | undefined; + public static Selected: () => DocumentView[]; + public static SelectedDocs: () => Doc[]; + public static SelectSchemaDoc: (doc: Doc, deselectAllFirst?: boolean) => void; + public static SelectedSchemaDoc: () => Opt<Doc>; + // view mgr funcs + public static activateTabView: (tabDoc: Doc) => boolean; + public static allViews: () => DocumentView[]; + public static addView: (dv: DocumentView) => void | undefined; + public static removeView: (dv: DocumentView) => void | undefined; + public static addViewRenderedCb: (doc: Opt<Doc>, func: (dv: DocumentView) => any) => boolean; + public static getFirstDocumentView: (toFind: Doc) => DocumentView | undefined; + public static getDocumentView: (target: Doc | undefined, preferredCollection?: DocumentView) => Opt<DocumentView>; + public static getContextPath: (doc: Opt<Doc>, includeExistingViews?: boolean) => Doc[]; + public static getLightboxDocumentView: (toFind: Doc) => Opt<DocumentView>; + public static showDocumentView: (targetDocView: DocumentView, options: FocusViewOptions) => Promise<void>; + public static showDocument: ( + targetDoc: Doc, // document to display + optionsIn: FocusViewOptions, // options for how to navigate to target + finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. + ) => Promise<void>; + public static linkCommonAncestor: (link: Doc) => DocumentView | undefined; + // pin func + public static PinDoc: (docIn: Doc | Doc[], pinProps: PinProps) => void; + // gesture + public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to. + // media playing + @observable public static CurrentlyPlaying: DocumentView[] = []; + public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore public ContentRef = React.createRef<HTMLDivElement>(); private _htmlOverlayEffect: Opt<Doc>; @@ -1138,14 +1100,14 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { componentDidMount() { runInAction(() => this.Document[DocViews].add(this)); this._disposers.onViewMounted = reaction(() => ScriptCast(this.Document.onViewMounted)?.script?.run({ this: this.Document }).result, emptyFunction); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.AddView(this); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentView.addView(this); } componentWillUnmount() { this._viewTimer && clearTimeout(this._viewTimer); runInAction(() => this.Document[DocViews].delete(this)); Object.values(this._disposers).forEach(disposer => disposer?.()); - !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); + !BoolCast(this.Document.dontRegisterView, this._props.dontRegisterView) && DocumentView.removeView(this); } public set IsSelected(val) { runInAction(() => { this._selected = val; }); } // prettier-ignore @@ -1176,10 +1138,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { const xf = this.screenToContentsTransform().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; - if (this._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const docuBox = this.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); - if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), transition: undefined }; - } // transition is returned so that the bounds will 'update' at the end of an animated transition. This is needed by xAnchor in LinkBox const transition = this.docViewPath().find((parent: DocumentView) => parent.DataTransition?.() || parent.ComponentView?.viewTransition?.()); return { left, top, right, bottom, transition: transition?.DataTransition?.() || transition?.ComponentView?.viewTransition?.() }; @@ -1289,7 +1247,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { if (checkResult) { return Doc.UserDoc().defaultTextLayout; } - const view = SelectionManager.Views[0]?._props.renderDepth > 0 ? SelectionManager.Views[0] : undefined; + const view = DocumentView.Selected()[0]?._props.renderDepth > 0 ? DocumentView.Selected()[0] : undefined; undoable(() => { let tempDoc: Opt<Doc>; if (view) { @@ -1359,11 +1317,11 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { - if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); + if (this.IsSelected && DocumentView.Selected().length > 1) DocumentView.DeselectView(this); else { - SelectionManager.SelectView(this, extendSelection); + DocumentView.SelectView(this, extendSelection); if (focusSelection) { - DocumentManager.Instance.showDocument(this.Document, { + DocumentView.showDocument(this.Document, { willZoomCentered: true, zoomScale: 0.9, zoomTime: 500, @@ -1506,6 +1464,37 @@ export function returnEmptyDocViewList() { return emptyPath; } +// eslint-disable-next-line default-param-last +export function DocFocusOrOpen(docIn: Doc, optionsIn: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { + let doc = docIn; + const options = optionsIn; + const func = () => { + const cv = DocumentView.getDocumentView(containingDoc); + const dv = DocumentView.getDocumentView(doc, cv); + if (dv && (!containingDoc || dv.containerViewPath?.().lastElement()?.Document === containingDoc)) { + DocumentView.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.Document)); + } else { + const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc)); + const showDoc = !Doc.IsSystem(container) && !cv ? container : doc; + options.toggleTarget = undefined; + DocumentView.showDocument(showDoc, options, () => DocumentView.showDocument(doc, { ...options, openLocation: undefined })).then(() => { + const cvFound = DocumentView.getDocumentView(containingDoc); + const dvFound = DocumentView.getDocumentView(doc, cvFound); + dvFound && Doc.linkFollowHighlight(dvFound.Document); + }); + } + }; + if (Doc.IsDataProto(doc) && Doc.GetEmbeddings(doc).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { + doc = Doc.GetEmbeddings(doc).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; + } + if (doc.hidden) { + doc.hidden = false; + options.toggleTarget = false; + setTimeout(func); + } else func(); +} +ScriptingGlobals.add(DocFocusOrOpen); + // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function deiconifyView(documentView: DocumentView) { documentView.iconify(); @@ -1527,9 +1516,9 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSour const collectedLinks = DocListCast(linkCollection[DocData].data); let wid = NumCast(linkSource._width); let embedding: Doc | undefined; - const links = LinkManager.Links(linkSource); + const links = Doc.Links(linkSource); links.forEach(link => { - const other = LinkManager.getOppositeAnchor(link, linkSource); + const other = Doc.getOppositeAnchor(link, linkSource); const otherdoc = DocCast(other?.annotationOn ?? other); if (otherdoc && !collectedLinks?.some(d => Doc.AreProtosEqual(d, otherdoc))) { embedding = Doc.MakeEmbedding(otherdoc); |