diff options
Diffstat (limited to 'src')
24 files changed, 121 insertions, 163 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4dc1c3b71..251e432ef 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { action, runInAction } from 'mobx'; import { basename } from 'path'; import { DateField } from '../../fields/DateField'; -import { Doc, DocListCast, DocListCastAsync, Field, Initializing, Opt, updateCachedAcls } from '../../fields/Doc'; +import { Doc, DocListCast, Field, Initializing, Opt, updateCachedAcls } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { HtmlField } from '../../fields/HtmlField'; import { InkField, PointData } from '../../fields/InkField'; @@ -403,7 +403,6 @@ export namespace Docs { nativeDimModifiable: true, nativeHeightUnfrozen: true, forceReflow: true, - links: '@links(self)', }, }, ], @@ -411,35 +410,35 @@ export namespace Docs { DocumentType.SEARCH, { layout: { view: SearchBox, dataField: defaultDataKey }, - options: { _width: 400, links: '@links(self)' }, + options: { _width: 400 }, }, ], [ DocumentType.COLOR, { layout: { view: ColorBox, dataField: defaultDataKey }, - options: { _nativeWidth: 220, _nativeHeight: 300, links: '@links(self)' }, + options: { _nativeWidth: 220, _nativeHeight: 300 }, }, ], [ DocumentType.IMG, { layout: { view: ImageBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.WEB, { layout: { view: WebBox, dataField: defaultDataKey }, - options: { _height: 300, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, links: '@links(self)' }, + options: { _height: 300, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true }, }, ], [ DocumentType.COL, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { _fitWidth: true, _panX: 0, _panY: 0, _viewScale: 1, links: '@links(self)' }, + options: { _fitWidth: true, _panX: 0, _panY: 0, _viewScale: 1 }, }, ], [ @@ -453,35 +452,35 @@ export namespace Docs { DocumentType.VID, { layout: { view: VideoBox, dataField: defaultDataKey }, - options: { _currentTimecode: 0, links: '@links(self)' }, + options: { _currentTimecode: 0 }, }, ], [ DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 100, backgroundColor: 'lightGray', _fitWidth: true, forceReflow: true, nativeDimModifiable: true, links: '@links(self)' }, + options: { _height: 100, forceReflow: true, nativeDimModifiable: true }, }, ], [ DocumentType.REC, { layout: { view: VideoBox, dataField: defaultDataKey }, - options: { _height: 100, backgroundColor: 'pink', links: '@links(self)' }, + options: { _height: 100, backgroundColor: 'pink' }, }, ], [ DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, - options: { _curPage: 1, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, links: '@links(self)' }, + options: { _curPage: 1, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true }, }, ], [ DocumentType.MAP, { layout: { view: MapBox, dataField: defaultDataKey }, - options: { _height: 600, _width: 800, nativeDimModifiable: true, links: '@links(self)' }, + options: { _height: 600, _width: 800, nativeDimModifiable: true }, }, ], [ @@ -502,7 +501,6 @@ export namespace Docs { description: '', showCaption: 'description', backgroundColor: 'lightblue', // lightblue is default color for linking dot and link documents text comment area - links: '@links(self)', _removeDropProperties: new List(['isLinkButton']), }, }, @@ -527,7 +525,7 @@ export namespace Docs { DocumentType.SCRIPTING, { layout: { view: ScriptingBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ @@ -540,56 +538,56 @@ export namespace Docs { DocumentType.LABEL, { layout: { view: LabelBox, dataField: defaultDataKey }, - options: { links: '@links(self)', _singleLine: true }, + options: { _singleLine: true }, }, ], [ DocumentType.EQUATION, { layout: { view: EquationBox, dataField: defaultDataKey }, - options: { links: '@links(self)', nativeDimModifiable: true, fontSize: '14px', hideResizeHandles: true, hideDecorationTitle: true }, + options: { nativeDimModifiable: true, fontSize: '14px', hideResizeHandles: true, hideDecorationTitle: true }, }, ], [ DocumentType.FUNCPLOT, { layout: { view: FunctionPlotBox, dataField: defaultDataKey }, - options: { nativeDimModifiable: true, links: '@links(self)' }, + options: { nativeDimModifiable: true }, }, ], [ DocumentType.BUTTON, { layout: { view: LabelBox, dataField: 'onClick' }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.SLIDER, { layout: { view: SliderBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.PRES, { layout: { view: PresBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.FONTICON, { layout: { view: FontIconBox, dataField: defaultDataKey }, - options: { allowClickBeforeDoubleClick: true, hideLinkButton: true, _width: 40, _height: 40, borderRounding: '100%', links: '@links(self)' }, + options: { allowClickBeforeDoubleClick: true, hideLinkButton: true, _width: 40, _height: 40, borderRounding: '100%' }, }, ], [ DocumentType.WEBCAM, { layout: { view: RecordingBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ @@ -603,7 +601,7 @@ export namespace Docs { DocumentType.MARKER, { layout: { view: CollectionView, dataField: defaultDataKey }, - options: { links: '@links(self)', hideLinkButton: true, pointerEvents: 'none' }, + options: { hideLinkButton: true, pointerEvents: 'none' }, }, ], [ @@ -611,21 +609,21 @@ export namespace Docs { { // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method layout: { view: InkingStroke, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.SCREENSHOT, { layout: { view: ScreenshotBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.COMPARISON, { layout: { view: ComparisonBox, dataField: defaultDataKey }, - options: { clipWidth: 50, nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'alias', links: '@links(self)' }, + options: { clipWidth: 50, nativeDimModifiable: true, backgroundColor: 'gray', targetDropAction: 'alias' }, }, ], [ @@ -640,21 +638,21 @@ export namespace Docs { DocumentType.GROUP, { layout: { view: EmptyBox, dataField: defaultDataKey }, - options: { links: '@links(self)' }, + options: {}, }, ], [ DocumentType.DATAVIZ, { layout: { view: DataVizBox, dataField: defaultDataKey }, - options: { _fitWidth: true, nativeDimModifiable: true, links: '@links(self)' }, + options: { _fitWidth: true, nativeDimModifiable: true }, }, ], [ DocumentType.LOADING, { layout: { view: LoadingBox, dataField: '' }, - options: { _fitWidth: true, _fitHeight: true, nativeDimModifiable: true, links: '@links(self)' }, + options: { _fitWidth: true, _fitHeight: true, nativeDimModifiable: true }, }, ], ]); @@ -881,15 +879,7 @@ export namespace Docs { } export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) { - return InstanceFromProto( - Prototypes.get(DocumentType.AUDIO), - new AudioField(url), - { ...options, backgroundColor: ComputedField.MakeFunction("this._mediaState === 'playing' ? 'green':'gray'") as any }, - undefined, - undefined, - undefined, - overwriteDoc - ); + return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url), options, undefined, undefined, undefined, overwriteDoc); } export function RecordingDocument(url: string, options: DocumentOptions = {}) { @@ -992,7 +982,6 @@ export namespace Docs { I.creationDate = new DateField(); I['acl-Public'] = Doc.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; //I['acl-Override'] = SharingPermissions.Unset; - I.links = ComputedField.MakeFunction('links(self)'); I[Initializing] = false; return I; } @@ -1282,38 +1271,6 @@ export namespace DocUtils { return rangeFilteredDocs; } - export function Publish(promoteDoc: Doc, targetID: string, addDoc: any, remDoc: any) { - targetID = targetID.replace(/^-/, '').replace(/\([0-9]*\)$/, ''); - DocServer.GetRefField(targetID).then(doc => { - if (promoteDoc !== doc) { - let copy = doc as Doc; - if (copy) { - Doc.Overwrite(promoteDoc, copy, true); - } else { - copy = Doc.MakeCopy(promoteDoc, true, targetID); - } - !doc && (copy.title = undefined) && (Doc.GetProto(copy).title = targetID); - addDoc && addDoc(copy); - remDoc && remDoc(promoteDoc); - if (!doc) { - DocListCastAsync(promoteDoc.links).then(links => { - links && - links.map(async link => { - if (link) { - const a1 = await Cast(link.anchor1, Doc); - if (a1 && Doc.AreProtosEqual(a1, promoteDoc)) link.anchor1 = copy; - const a2 = await Cast(link.anchor2, Doc); - if (a2 && Doc.AreProtosEqual(a2, promoteDoc)) link.anchor2 = copy; - LinkManager.Instance.deleteLink(link); - LinkManager.Instance.addLink(link); - } - }); - }); - } - } - }); - } - export function DefaultFocus(doc: Doc, options: DocFocusOptions) { return undefined; } @@ -1711,7 +1668,7 @@ 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 = DocListCast(doc.links).some(l => (l.anchor2 === doc && Cast(l.anchor1, Doc, null)?.annotationOn === context) || (l.anchor1 === doc && Cast(l.anchor2, Doc, null)?.annotationOn === context)); + 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)); 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', diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index 735b06f6d..c9fcc84a3 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -2,12 +2,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast } from '../../fields/Doc'; -import { StrCast } from '../../fields/Types'; +import { Doc } from '../../fields/Doc'; +import { DocCast, StrCast } from '../../fields/Types'; import { addStyleSheet } from '../../Utils'; import { LightboxView } from '../views/LightboxView'; import { MainViewModal } from '../views/MainViewModal'; import './CaptureManager.scss'; +import { LinkManager } from './LinkManager'; import { SelectionManager } from './SelectionManager'; @observer @@ -48,16 +49,14 @@ export class CaptureManager extends React.Component<{}> { const doc = this._document; const order: JSX.Element[] = []; if (doc) { - DocListCast(doc.links).forEach((l, i) => { - if (l) { - order.push( - <div className="list-item"> - <div className="number">{i}</div> - {StrCast((l.anchor1 as Doc).title)} - </div> - ); - } - }); + LinkManager.Links(doc).forEach((l, i) => + order.push( + <div className="list-item"> + <div className="number">{i}</div> + {StrCast(DocCast(l.anchor1)?.title)} + </div> + ) + ); } return ( diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 2b0a2cdac..c4fb4788c 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -22,7 +22,7 @@ import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; import { OverlayView } from "../views/OverlayView"; -import { DragManager, dropActionType } from "./DragManager"; +import { DragManager } from "./DragManager"; import { MakeTemplate } from "./DropConverter"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; @@ -949,6 +949,5 @@ ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Do ScriptingGlobals.add(function createNewPresentation() { return MainView.Instance.createNewPresentation(); }, "creates a new presentation when called"); ScriptingGlobals.add(function openPresentation(pres:Doc) { return MainView.Instance.openPresentation(pres); }, "creates a new presentation when called"); ScriptingGlobals.add(function createNewFolder() { return MainView.Instance.createNewFolder(); }, "creates a new folder in myFiles when called"); -ScriptingGlobals.add(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); ScriptingGlobals.add(function importDocument() { return CurrentUserUtils.importDocument(); }, "imports files from device directly into the import sidebar"); ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
\ No newline at end of file diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index e28687561..eacbcc0e3 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -6,6 +6,7 @@ import { DocumentDecorations } from '../views/DocumentDecorations'; import { DocFocusOptions, DocumentViewSharedProps, OpenWhere } 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'; @@ -41,7 +42,7 @@ export class LinkFollower { }; public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) { - const linkDocs = link ? [link] : DocListCast(sourceDoc.links); + 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); diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index 46d44fea4..555215417 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -4,6 +4,7 @@ import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field, Opt } from ' import { List } from '../../fields/List'; import { ProxyField } from '../../fields/Proxy'; import { Cast, DocCast, PromiseValue, StrCast } from '../../fields/Types'; +import { ScriptingGlobals } from './ScriptingGlobals'; /* * link doc: * - anchor1: doc @@ -24,6 +25,10 @@ export class LinkManager { public static get Instance() { return LinkManager._instance; } + + public static Links(doc: Doc | undefined) { + return doc ? LinkManager.Instance.getAllRelatedLinks(doc) : []; + } public static addLinkDB = async (linkDb: any) => { await Promise.all( ((await DocListCastAsync(linkDb.data)) ?? []).map(link => @@ -34,7 +39,7 @@ export class LinkManager { LinkManager.userLinkDBs.push(linkDb); }; public static AutoKeywords = 'keywords:Usages'; - static links: Doc[] = []; + static _links: Doc[] = []; constructor() { LinkManager._instance = this; this.createLinkrelationshipLists(); @@ -72,7 +77,7 @@ export class LinkManager { ); }; const watchUserLinkDB = (userLinkDBDoc: Doc) => { - LinkManager.links.push(...DocListCast(userLinkDBDoc.data)); + LinkManager._links.push(...DocListCast(userLinkDBDoc.data)); const toRealField = (field: Field) => (field instanceof ProxyField ? field.value : field); // see List.ts. data structure is not a simple list of Docs, but a list of ProxyField/Fields if (userLinkDBDoc.data) { observe( @@ -193,3 +198,11 @@ export class LinkManager { if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc; } } + +ScriptingGlobals.add( + function links(doc: any) { + return new List(LinkManager.Links(doc)); + }, + 'returns all the links to the document or its annotations', + '(doc: any)' +); diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 646942569..c0fc25376 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,6 +1,6 @@ import { action, observable, ObservableMap } from 'mobx'; import { computedFn } from 'mobx-utils'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; +import { Doc, Opt } from '../../fields/Doc'; import { DocCast } from '../../fields/Types'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocumentView } from '../views/nodes/DocumentView'; @@ -22,7 +22,7 @@ export namespace SelectionManager { // if doc is not in SelectedDocuments, add it if (!manager.SelectedViews.get(docView) && docView.props.Document.type !== DocumentType.MARKER) { if (!ctrlPressed) { - if (LinkManager.currentLink && !DocListCast(docView.rootDoc.links).includes(LinkManager.currentLink) && docView.rootDoc !== LinkManager.currentLink) { + if (LinkManager.currentLink && !LinkManager.Links(docView.rootDoc).includes(LinkManager.currentLink) && docView.rootDoc !== LinkManager.currentLink) { LinkManager.currentLink = undefined; } this.DeselectAll(); diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index 2567d44bb..976c8763e 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -4,9 +4,8 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { InkTool } from '../../fields/InkField'; -import { List } from '../../fields/List'; -import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../Utils'; +import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../Utils'; import { DocUtils } from '../documents/Documents'; import { DocumentManager } from '../util/DocumentManager'; import { LinkManager } from '../util/LinkManager'; @@ -88,7 +87,7 @@ export class LightboxView extends React.Component<LightboxViewProps> { ...future .slice() .sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)) - .sort((a, b) => DocListCast(a.links).length - DocListCast(b.links).length), + .sort((a, b) => LinkManager.Links(a).length - LinkManager.Links(b).length), ]; } this._doc = doc; @@ -214,7 +213,7 @@ export class LightboxView extends React.Component<LightboxViewProps> { if (coll) { const fieldKey = Doc.LayoutFieldKey(coll); const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '-annotations'])]; - const links = DocListCast(coll.links) + const links = LinkManager.Links(coll) .map(link => LinkManager.getOppositeAnchor(link, coll)) .filter(doc => doc) .map(doc => doc!); diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index ac1b66013..ebbe20077 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -9,8 +9,10 @@ import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, ScriptCast, StrCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; +import { Utils } from '../../Utils'; import { DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; import { undoBatch } from '../util/UndoManager'; import { Colors } from './global/globalEnums'; @@ -19,8 +21,6 @@ import { DocumentView, OpenWhere } from './nodes/DocumentView'; import { pasteImageBitmap } from './nodes/WebBoxRenderer'; import './PropertiesButtons.scss'; import React = require('react'); -import { LinkManager } from '../util/LinkManager'; -import { Utils } from '../../Utils'; const higflyout = require('@hig/flyout'); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -139,9 +139,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { 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 => { - DocListCast(doc.links).forEach(link => (link.linkDisplay = false)); - }); + containerContents.forEach(doc => LinkManager.Links(doc).forEach(link => (link.linkDisplay = false))); }); } ); @@ -330,7 +328,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { const click = () => this.handleOptionChange(value[0]); const linkButton = BoolCast(this.selectedDoc._isLinkButton); const followLoc = this.selectedDoc._followLinkLocation; - const linkedToLightboxView = () => DocListCast(this.selectedDoc.links).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); + const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox); let active = false; // prettier-ignore diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 7a985628f..03b4100a7 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -4,10 +4,10 @@ import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-soli 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, computed, Lambda, observable } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; -import { AclAdmin, AclSym, HierarchyMapping, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc'; +import { AclAdmin, AclSym, DataSym, Doc, Field, HeightSym, HierarchyMapping, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { List } from '../../fields/List'; @@ -23,10 +23,10 @@ import { SharingManager } from '../util/SharingManager'; import { Transform } from '../util/Transform'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { EditableView } from './EditableView'; +import { FilterPanel } from './FilterPanel'; import { Colors } from './global/globalEnums'; import { InkStrokeProperties } from './InkStrokeProperties'; import { DocumentView, OpenWhere, StyleProviderFunc } from './nodes/DocumentView'; -import { FilterPanel } from './FilterPanel'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; import { PropertiesButtons } from './PropertiesButtons'; @@ -1486,7 +1486,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { const zoom = Number((NumCast(this.sourceAnchor?.followLinkZoomScale, 1) * 100).toPrecision(3)); const targZoom = this.sourceAnchor?.followLinkZoom; const indent = 30; - const hasSelectedAnchor = SelectionManager.Views().some(dv => DocListCast(this.sourceAnchor?.links).includes(LinkManager.currentLink!)); + const hasSelectedAnchor = LinkManager.Links(this.sourceAnchor).includes(LinkManager.currentLink!); if (!this.selectedDoc && !this.isPres) { return ( <div className="propertiesView" style={{ width: this.props.width }}> diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx index 74ea624a6..7519cbb05 100644 --- a/src/client/views/SidebarAnnos.tsx +++ b/src/client/views/SidebarAnnos.tsx @@ -3,10 +3,12 @@ import { observer } from 'mobx-react'; import { Doc, DocListCast, Field, FieldResult, StrListCast } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { List } from '../../fields/List'; +import { RichTextField } from '../../fields/RichTextField'; import { DocCast, NumCast, StrCast } from '../../fields/Types'; import { emptyFunction, OmitKeys, returnAll, returnOne, returnTrue, returnZero } from '../../Utils'; import { Docs, DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { LinkManager } from '../util/LinkManager'; import { Transform } from '../util/Transform'; import { CollectionStackingView } from './collections/CollectionStackingView'; import { FieldViewProps } from './nodes/FieldView'; @@ -15,7 +17,6 @@ import { SearchBox } from './search/SearchBox'; import './SidebarAnnos.scss'; import { StyleProp } from './StyleProvider'; import React = require('react'); -import { RichTextField } from '../../fields/RichTextField'; interface ExtraProps { fieldKey: string; @@ -174,8 +175,8 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> { showTitle = () => 'title'; setHeightCallback = (height: number) => this.props.setHeight?.(height + this.filtersHeight()); sortByLinkAnchorY = (a: Doc, b: Doc) => { - const ay = DocListCast(a.links).length && DocCast(DocListCast(a.links)[0].anchor1).y; - const by = DocListCast(b.links).length && DocCast(DocListCast(b.links)[0].anchor1).y; + const ay = LinkManager.Links(a).length && DocCast(LinkManager.Links(a)[0].anchor1).y; + const by = LinkManager.Links(b).length && DocCast(LinkManager.Links(b)[0].anchor1).y; return NumCast(ay) - NumCast(by); }; render() { diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 153c30052..ce764c7bf 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -1,12 +1,15 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Shadows } from 'browndash-components'; import { action, runInAction } from 'mobx'; import { extname } from 'path'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { BoolCast, Cast, DocCast, ImageCast, NumCast, StrCast } from '../../fields/Types'; +import { Doc, Opt } from '../../fields/Doc'; +import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types'; import { DashColor, emptyFunction, lightOrDark } from '../../Utils'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; import { DocFocusOrOpen } from '../util/DocumentManager'; +import { LinkManager } from '../util/LinkManager'; +import { SelectionManager } from '../util/SelectionManager'; import { ColorScheme } from '../util/SettingsManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeView'; @@ -18,8 +21,6 @@ import { FieldViewProps } from './nodes/FieldView'; import { SliderBox } from './nodes/SliderBox'; import './StyleProvider.scss'; import React = require('react'); -import { Shadows } from 'browndash-components'; -import { SelectionManager } from '../util/SelectionManager'; export enum StyleProp { TreeViewIcon = 'treeViewIcon', @@ -261,7 +262,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps case StyleProp.BoxShadow: { if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow) if (doc.boxShadow === 'standard') return Shadows.STANDARD_SHADOW; - if (doc?.isLinkButton && DocListCast(doc?.links).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em'); + if (doc?.isLinkButton && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em'); switch (doc?.type) { case DocumentType.COL: return StrCast( diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 572fbfec2..5bdff347c 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -2,7 +2,7 @@ import React = require('react'); import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; @@ -15,6 +15,7 @@ import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; +import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -740,14 +741,14 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps> () => this.props.currentTimecode(), time => { const dictationDoc = Cast(this.props.layoutDoc['data-dictation'], Doc, null); - const isDictation = dictationDoc && DocListCast(this.props.mark.links).some(link => Cast(link.anchor1, Doc, null)?.annotationOn === dictationDoc); + const isDictation = dictationDoc && LinkManager.Links(this.props.mark).some(link => Cast(link.anchor1, 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. // for now, we won't follow any links when the lightbox is oepn to avoid "losing" the video. /*(isDictation || !Doc.AreProtosEqual(LightboxView.LightboxDoc, this.props.layoutDoc))*/ !this.props.layoutDoc.dontAutoFollowLinks && - DocListCast(this.props.mark.links).length && + LinkManager.Links(this.props.mark).length && time > NumCast(this.props.mark[this.props.startTag]) && time < NumCast(this.props.mark[this.props.endTag]) && this._lastTimecode < NumCast(this.props.mark[this.props.startTag]) - 1e-5 diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c88ae314e..e46220f02 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,5 +1,4 @@ import { action, computed, observable } from 'mobx'; -import ReactLoading from 'react-loading'; import * as rp from 'request-promise'; import CursorField from '../../../fields/CursorField'; import { AclPrivate, Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index 08ffa1466..2bdcf472f 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -15,6 +15,7 @@ import { Docs, DocUtils } from '../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager, dropActionType } from '../../util/DragManager'; +import { LinkManager } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -708,7 +709,7 @@ export class TreeView extends React.Component<TreeViewProps> { @computed get validExpandViewTypes() { const annos = () => (DocListCast(this.doc[this.fieldKey + '-annotations']).length && !this.props.treeView.dashboardMode ? 'annotations' : ''); - const links = () => (DocListCast(this.doc.links).length && !this.props.treeView.dashboardMode ? 'links' : ''); + 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 fields = () => (Doc.noviceMode ? '' : 'fields'); diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index c9112eec3..3f6369898 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -1,7 +1,6 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { Doc } from '../../../fields/Doc'; -import { DocCast } from '../../../fields/Types'; import { LinkManager } from '../../util/LinkManager'; import { DocumentView } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index cdac91a62..4741fc6f2 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, DocListCast } from '../../../fields/Doc'; +import { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; @@ -15,11 +15,11 @@ import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; +import { MainView } from '../MainView'; import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; import React = require('react'); -import { MainView } from '../MainView'; interface LinkMenuItemProps { groupType: string; @@ -34,7 +34,7 @@ interface LinkMenuItemProps { // drag links and drop link targets (aliasing them if needed) export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: DocumentView, downX: number, downY: number, sourceDoc: Doc, specificLinks?: Doc[]) { - const draggedDocs = (specificLinks ? specificLinks : DocListCast(sourceDoc.links)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[]; + const draggedDocs = (specificLinks ? specificLinks : LinkManager.Links(sourceDoc)).map(link => LinkManager.getOppositeAnchor(link, sourceDoc)).filter(l => l) as Doc[]; if (draggedDocs.length) { const moddrag: Doc[] = []; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 4c26468b9..890ecc1b2 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -11,6 +11,7 @@ import { emptyFunction, formatTime, OmitKeys, returnFalse, setupMoveUpEvents } f import { DocUtils } from '../../documents/Documents'; import { Networking } from '../../Network'; import { DragManager } from '../../util/DragManager'; +import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; @@ -84,7 +85,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp return this.props.PanelHeight() < 50; } // used to collapse timeline when node is shrunk @computed get links() { - return DocListCast(this.dataDoc.links); + return LinkManager.Links(this.dataDoc); } @computed get mediaState() { return this.dataDoc.mediaState as media_state; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2b6629913..964231e9d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -929,7 +929,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps }, icon: 'eye', }); - DocListCast(this.Document.links).length && + LinkManager.Links(this.Document).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? 'Show' : 'Hide'} Link Button`, event: action(() => (this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton)), icon: 'eye' }); !appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' }); @@ -969,7 +969,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Target Visibility Toggle', event: () => this.toggleFollowLink(false, true), icon: 'map-pin' }); onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', addDivider: true, noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); - } else if (DocListCast(this.Document.links).length) { + } else if (LinkManager.Links(this.Document).length) { onClicks.push({ description: 'Select on Click', event: () => this.selectOnClick(), icon: 'link' }); onClicks.push({ description: 'Follow Link on Click', event: () => this.followLinkOnClick(undefined, false), icon: 'link' }); onClicks.push({ description: 'Toggle Link Target on Click', event: () => this.toggleTargetOnClick(), icon: 'map-pin' }); @@ -1907,7 +1907,7 @@ ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc) { const linkSource = Cast(linkCollection.linkSource, Doc, null); const collectedLinks = DocListCast(Doc.GetProto(linkCollection).data); let wid = linkSource[WidthSym](); - const links = DocListCast(linkSource.links); + const links = LinkManager.Links(linkSource); links.forEach(link => { const other = LinkManager.getOppositeAnchor(link, linkSource); const otherdoc = !other ? undefined : other.annotationOn ? Cast(other.annotationOn, Doc, null) : other; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index bbe9b4323..16b352e4f 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -3,7 +3,7 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import wiki from 'wikijs'; -import { Doc, DocCastAsync, DocListCast, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; +import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; @@ -14,11 +14,10 @@ import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; +import { SearchBox } from '../search/SearchBox'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; import React = require('react'); -import { SearchUtil } from '../../util/SearchUtil'; -import { SearchBox } from '../search/SearchBox'; interface LinkDocPreviewProps { linkDoc?: Doc; @@ -110,8 +109,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { const anchorDoc = anchorDocId ? PromiseValue(DocCast(DocServer.GetCachedRefField(anchorDocId) ?? DocServer.GetRefField(anchorDocId))) : undefined; anchorDoc?.then?.( action(anchor => { - if (anchor instanceof Doc && DocListCast(anchor.links).length) { - this._linkDoc = this._linkDoc ?? DocListCast(anchor.links)[0]; + if (anchor instanceof Doc && LinkManager.Links(anchor).length) { + this._linkDoc = this._linkDoc ?? LinkManager.Links(anchor)[0]; const automaticLink = this._linkDoc.linkRelationship === LinkManager.AutoKeywords; if (automaticLink) { // automatic links specify the target in the link info, not the source diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 7df3d5f24..dc6bf6f9e 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -3,7 +3,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; import { observer } from 'mobx-react'; import { basename } from 'path'; -import { Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc'; +import { Doc, HeightSym, WidthSym } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -14,6 +14,7 @@ import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; +import { LinkManager } from '../../util/LinkManager'; import { ReplayMovements } from '../../util/ReplayMovements'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -85,7 +86,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @observable _scrubbing: boolean = false; @computed get links() { - return DocListCast(this.dataDoc.links); + return LinkManager.Links(this.dataDoc); } @computed get heightPercent() { return NumCast(this.layoutDoc._timelineHeightPercent, 100); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index d9ce9a0b0..a76f9623a 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,7 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { isEqual } from 'lodash'; -import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { baseKeymap, selectAll } from 'prosemirror-commands'; import { history } from 'prosemirror-history'; @@ -11,7 +11,7 @@ import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; import { DateField } from '../../../../fields/DateField'; -import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DataSym, Doc, DocListCast, DocListCastAsync, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym } from '../../../../fields/Doc'; +import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, Doc, DocListCast, Field, ForceServerWrite, HeightSym, Opt, UpdatingFromServer, WidthSym } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { PrefetchProxy } from '../../../../fields/Proxy'; @@ -48,6 +48,7 @@ import { StyleProp } from '../../StyleProvider'; import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { LinkDocPreview } from '../LinkDocPreview'; +import { PinProps, PresBox } from '../trails'; import { DashDocCommentView } from './DashDocCommentView'; import { DashDocView } from './DashDocView'; import { DashFieldView } from './DashFieldView'; @@ -63,7 +64,6 @@ import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); import React = require('react'); -import { PinProps, PresBox } from '../trails'; const translateGoogleApi = require('translate-google-api'); export const GoogleRef = 'googleDocId'; @@ -363,7 +363,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps let linkTime; let linkAnchor; let link; - DocListCast(this.dataDoc.links).forEach((l, i) => { + LinkManager.Links(this.dataDoc).forEach((l, i) => { const anchor = (l.anchor1 as Doc).annotationOn ? (l.anchor1 as Doc) : (l.anchor2 as Doc).annotationOn ? (l.anchor2 as Doc) : undefined; if (anchor && (anchor.annotationOn as Doc).mediaState === 'recording') { linkTime = NumCast(anchor._timecodeToShow /* audioStart */); @@ -400,7 +400,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps autoLink = () => { const newAutoLinks = new Set<Doc>(); - const oldAutoLinks = DocListCast(this.props.Document.links).filter(link => link.linkRelationship === LinkManager.AutoKeywords); + const oldAutoLinks = LinkManager.Links(this.props.Document).filter(link => link.linkRelationship === LinkManager.AutoKeywords); if (this._editorView?.state.doc.textContent) { const isNodeSel = this._editorView.state.selection instanceof NodeSelection; const f = this._editorView.state.selection.from; @@ -453,7 +453,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { alink = alink ?? - (DocListCast(this.Document.links).find(link => Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || + (LinkManager.Links(this.Document).find(link => Doc.AreProtosEqual(Cast(link.anchor1, Doc, null), this.rootDoc) && Doc.AreProtosEqual(Cast(link.anchor2, Doc, null), target)) || DocUtils.MakeLink({ doc: this.props.Document }, { doc: target }, LinkManager.AutoKeywords)!); newAutoLinks.add(alink); const allAnchors = [{ href: Doc.localServerPath(target), title: 'a link', anchorId: this.props.Document[Id] }]; @@ -687,7 +687,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps @undoBatch deleteAnnotation = (anchor: Doc) => { - LinkManager.Instance.deleteLink(DocListCast(anchor.links)[0]); + LinkManager.Instance.deleteLink(LinkManager.Links(anchor)[0]); // const docAnnotations = DocListCast(this.props.dataDoc[this.fieldKey]); // this.props.dataDoc[this.fieldKey] = new List<Doc>(docAnnotations.filter(a => a !== this.annoTextRegion)); // AnchorMenu.Instance.fadeOut(true); @@ -1014,7 +1014,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps } componentDidMount() { !this.props.dontSelectOnLoad && this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. - this._cachedLinks = DocListCast(this.Document.links); + this._cachedLinks = LinkManager.Links(this.Document); this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation); this._disposers.autoHeight = reaction( () => this.autoHeight, @@ -1041,7 +1041,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps { fireImmediately: true } ); this._disposers.links = reaction( - () => DocListCast(this.dataDoc.links), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks + () => LinkManager.Links(this.dataDoc), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks newLinks => { this._cachedLinks.forEach(l => !newLinks.includes(l) && this.RemoveLinkFromDoc(l)); this._cachedLinks = newLinks; diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index dda96d8e7..be40b3592 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -35,7 +35,6 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; -import { tag } from 'xregexp/types'; const { Howl } = require('howler'); export interface pinDataTypes { @@ -1551,7 +1550,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type; activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0; // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. - // to avoid creating a new slide to correspond to each of the target's data list, we simply reference the target's data list. + // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list. let dataField = Doc.LayoutFieldKey(tagDoc); if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '-annotations'; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 3ba60edd7..fe9b13fbe 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -5,7 +5,6 @@ import * as React from 'react'; import { DirectLinksSym, Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; -import { StopEvent } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DocumentManager } from '../../util/DocumentManager'; @@ -470,7 +469,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() { } } style={{ - fontWeight: DocListCast(fromDoc?.links).find( + fontWeight: LinkManager.Links(fromDoc).find( link => Doc.AreProtosEqual(LinkManager.getOppositeAnchor(link, fromDoc!), result[0] as Doc) || Doc.AreProtosEqual(DocCast(LinkManager.getOppositeAnchor(link, fromDoc!)?.annotationOn), result[0] as Doc) ) ? 'bold' diff --git a/src/fields/util.ts b/src/fields/util.ts index e517e7604..6ff13d5d3 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,8 +1,8 @@ -import { forEach } from 'lodash'; import { $mobx, action, observable, runInAction, trace } from 'mobx'; import { computedFn } from 'mobx-utils'; import { DocServer } from '../client/DocServer'; import { CollectionViewType } from '../client/documents/DocumentTypes'; +import { LinkManager } from '../client/util/LinkManager'; import { SerializationHelper } from '../client/util/SerializationHelper'; import { UndoManager } from '../client/util/UndoManager'; import { returnZero } from '../Utils'; @@ -18,7 +18,6 @@ import { Doc, DocListCast, DocListCastAsync, - FieldResult, ForceServerWrite, HeightSym, HierarchyMapping, @@ -259,7 +258,7 @@ function getEffectiveAcl(target: any, user?: string): symbol { */ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc, inheritingFromCollection?: boolean, visited?: Doc[], isDashboard?: boolean) { if (!visited) visited = [] as Doc[]; - if (visited.includes(target)) return; + if (!target || visited.includes(target)) return; if ((target._viewType === CollectionViewType.Docking && visited.length > 1) || Doc.GetProto(visited[0]) !== Doc.GetProto(target)) { target[key] = acl; @@ -293,26 +292,18 @@ export function distributeAcls(key: string, acl: SharingPermissions, target: Doc } // maps over the links of the document - DocListCast(dataDoc.links).forEach(link => distributeAcls(key, acl, link, inheritingFromCollection, visited)); + LinkManager.Links(dataDoc).forEach(link => distributeAcls(key, acl, link, inheritingFromCollection, visited)); // maps over the children of the document - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + (isDashboard ? '-all' : '')]).map(d => { + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc)]).forEach(d => { distributeAcls(key, acl, d, inheritingFromCollection, visited); - // } - const data = d[DataSym]; - if (data) { - distributeAcls(key, acl, data, inheritingFromCollection, visited); - } + distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited); }); // maps over the annotations of the document - DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '-annotations']).map(d => { + DocListCast(dataDoc[Doc.LayoutFieldKey(dataDoc) + '-annotations']).forEach(d => { distributeAcls(key, acl, d, inheritingFromCollection, visited); - // } - const data = d[DataSym]; - if (data) { - distributeAcls(key, acl, data, inheritingFromCollection, visited); - } + distributeAcls(key, acl, d[DataSym], inheritingFromCollection, visited); }); } |