aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CurrentUserUtils.ts12
-rw-r--r--src/client/util/DocumentManager.ts72
-rw-r--r--src/client/util/LinkManager.ts56
-rw-r--r--src/client/util/type_decls.d4
4 files changed, 68 insertions, 76 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index e7a3ae10d..8cb5e3903 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -210,7 +210,7 @@ export class CurrentUserUtils {
doc["template-button-detail"] = CurrentUserUtils.ficon({
onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
- dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detail view", icon: "window-maximize", system: true
+ dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detailView", icon: "window-maximize", system: true
});
}
@@ -378,7 +378,7 @@ export class CurrentUserUtils {
((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0;
}
if (doc.emptySlide === undefined) {
- const textDoc = Docs.Create.TreeDocument([], { title: "Slide", _viewType: CollectionViewType.Tree, _fontSize: "20px", treeViewOutlineMode: true, _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, _backgroundColor: "transparent", system: true, cloneFieldFilter: new List<string>(["system"]) });
+ const textDoc = Docs.Create.TreeDocument([], { title: "Slide", _viewType: CollectionViewType.Tree, _fontSize: "20px", treeViewType: "outline", _xMargin: 0, _yMargin: 0, _width: 300, _height: 200, _singleLine: true, _backgroundColor: "transparent", system: true, cloneFieldFilter: new List<string>(["system"]) });
Doc.GetProto(textDoc).title = ComputedField.MakeFunction('self.text?.Text');
FormattedTextBox.SelectOnLoad = textDoc[Id];
doc.emptySlide = textDoc;
@@ -548,6 +548,7 @@ export class CurrentUserUtils {
iconShape: "square",
_stayInCollection: true,
_hideContextMenu: true,
+ dontUndo: true,
title,
target,
_backgroundColor: "black",
@@ -578,6 +579,7 @@ export class CurrentUserUtils {
DocListCastAsync(btns).then(bts => bts?.forEach(btn => {
btn.color = "white";
btn._backgroundColor = "";
+ btn.dontUndo = true;
}));
});
});
@@ -851,14 +853,16 @@ export class CurrentUserUtils {
/// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
static setupDockedButtons(doc: Doc) {
if (doc["dockedBtn-undo"] === undefined) {
- doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
+ doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), dontUndo: true, _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
}
if (doc["dockedBtn-redo"] === undefined) {
- doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
+ doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), dontUndo: true, _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
}
if (doc.dockedBtns === undefined) {
doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
}
+ (doc["dockedBtn-undo"] as Doc).dontUndo = true;
+ (doc["dockedBtn-redo"] as Doc).dontUndo = true;
}
// sets up the default set of documents to be shown in the Overlay layer
static setupOverlays(doc: Doc) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 816f7f6be..67e05f8d0 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -7,10 +7,9 @@ import { DocumentType } from '../documents/DocumentTypes';
import { CollectionDockingView } from '../views/collections/CollectionDockingView';
import { CollectionView } from '../views/collections/CollectionView';
import { LightboxView } from '../views/LightboxView';
-import { DocumentView } from '../views/nodes/DocumentView';
+import { DocumentView, ViewAdjustment } from '../views/nodes/DocumentView';
import { Scripting } from './Scripting';
-
-export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void;
+import { CurrentUserUtils } from './CurrentUserUtils';
export class DocumentManager {
@@ -104,7 +103,7 @@ export class DocumentManager {
public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
const docViews = DocumentManager.Instance.DocumentViews;
const views: DocumentView[] = [];
- docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && view.rootDoc === toFind && views.push(view));
+ docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined);
}
public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -141,13 +140,11 @@ export class DocumentManager {
closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there
originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
finished?: () => void,
+ originalTarget?: Doc
): Promise<void> => {
+ originalTarget = originalTarget ?? targetDoc;
const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
const docView = getFirstDocView(targetDoc, originatingDoc);
- const highlight = () => {
- const finalDocView = getFirstDocView(targetDoc);
- finalDocView && Doc.linkFollowHighlight(finalDocView.rootDoc);
- };
const focusAndFinish = (didFocus: boolean) => {
if (originatingDoc?.isPushpin) {
if (!didFocus || targetDoc.hidden) {
@@ -157,36 +154,32 @@ export class DocumentManager {
targetDoc.hidden && (targetDoc.hidden = undefined);
docView?.select(false);
}
- highlight();
finished?.();
return false;
};
- let annotatedDoc = Cast(targetDoc.annotationOn, Doc, null);
+ const annotatedDoc = Cast(targetDoc.annotationOn, Doc, null);
+ const rtfView = annotatedDoc && getFirstDocView(annotatedDoc);
const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
const targetDocContext = contextDoc || annotatedDoc;
const targetDocContextView = targetDocContext && getFirstDocView(targetDocContext);
- if (!docView && annotatedDoc && annotatedDoc !== originatingDoc?.context && targetDoc.type === DocumentType.TEXTANCHOR) {
- const first = getFirstDocView(annotatedDoc);
- if (first) {
- annotatedDoc = first.rootDoc;
- first.focus(targetDoc, false);
- }
- } else if (docView && (targetDocContextView || !targetDocContext)) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight?
- docView.props.focus(docView.rootDoc, willZoom, undefined, (didFocus: boolean) =>
- new Promise<boolean>(res => {
- focusAndFinish(didFocus);
- res();
- })
- );
+ const focusView = !docView && targetDoc.type === DocumentType.TEXTANCHOR && rtfView ? rtfView : docView;
+ if (focusView) {
+ focusView && Doc.linkFollowHighlight(focusView.rootDoc);
+ focusView.focus(targetDoc, {
+ originalTarget, willZoom, afterFocus: (didFocus: boolean) =>
+ new Promise<ViewAdjustment>(res => {
+ focusAndFinish(didFocus);
+ res();
+ })
+ });
} else {
if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc)));
- highlight();
} else { // otherwise try to get a view of the context of the target
if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first..
targetDocContext._viewTransition = "transform 500ms";
- targetDocContextView.props.focus(targetDocContextView.rootDoc, willZoom);
+ targetDocContextView.props.focus(targetDocContextView.rootDoc, { willZoom });
// now find the target document within the context
if (targetDoc._timecodeToShow) { // if the target has a timecode, it should show up once the (presumed) video context scrubs to the display timecode;
@@ -196,18 +189,18 @@ export class DocumentManager {
const findView = (delay: number) => {
const retryDocView = getFirstDocView(targetDoc); // test again for the target view snce we presumably created the context above by focusing on it
if (retryDocView) { // we found the target in the context
- retryDocView.props.focus(targetDoc, willZoom, undefined, (didFocus: boolean) =>
- new Promise<boolean>(res => {
- focusAndFinish(didFocus);
- res();
- })
- ); // focus on the target in the context
- highlight();
+ retryDocView.props.focus(targetDoc, {
+ willZoom, afterFocus: (didFocus: boolean) =>
+ new Promise<ViewAdjustment>(res => {
+ focusAndFinish(didFocus);
+ res();
+ })
+ }); // focus on the target in the context
} else if (delay > 1500) {
// we didn't find the target, so it must have moved out of the context. Go back to just creating it.
if (closeContextIfNotFound) targetDocContextView.props.removeDocument?.(targetDocContextView.rootDoc);
if (targetDoc.layout) { // there will no layout for a TEXTANCHOR type document
- Doc.SetInPlace(targetDoc, "annotationOn", undefined, false);
+ // Doc.SetInPlace(targetDoc, "annotationOn", undefined, false);
createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target
}
} else {
@@ -217,18 +210,13 @@ export class DocumentManager {
findView(0);
}
} else { // there's no context view so we need to create one first and try again when that finishes
- const finishFunc = () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished);
- if (LightboxView.LightboxDoc) {
- runInAction(() => LightboxView.LightboxDoc = targetDocContext);
- setTimeout(() => finishFunc, 250);
- } else {
- createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
- finishFunc);
- }
+ const finishFunc = () => this.jumpToDocument(targetDoc, true, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished, originalTarget);
+ createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
+ finishFunc);
}
}
}
}
}
-Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); }); \ No newline at end of file
+Scripting.addGlobal(function DocFocus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, { willZoom: true })); }); \ No newline at end of file
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 58ccfe645..402cbdd68 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -3,11 +3,12 @@ import { computedFn } from "mobx-utils";
import { Doc, DocListCast, Opt } from "../../fields/Doc";
import { BoolCast, Cast, StrCast } from "../../fields/Types";
import { LightboxView } from "../views/LightboxView";
-import { DocumentViewSharedProps } from "../views/nodes/DocumentView";
-import { CreateViewFunc, DocumentManager } from "./DocumentManager";
+import { DocumentViewSharedProps, ViewAdjustment } from "../views/nodes/DocumentView";
+import { DocumentManager } from "./DocumentManager";
import { SharingManager } from "./SharingManager";
import { UndoManager } from "./UndoManager";
+type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void;
/*
* link doc:
* - anchor1: doc
@@ -104,19 +105,22 @@ export class LinkManager {
const batch = UndoManager.StartBatch("follow link click");
// open up target if it's not already in view ...
const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => {
- const createTabForTarget = (didFocus: boolean) => new Promise<boolean>(res => {
- const where = StrCast(sourceDoc.followLinkLocation) || followLoc;
+ const createTabForTarget = (didFocus: boolean) => new Promise<ViewAdjustment>(res => {
+ const where = LightboxView.LightboxDoc ? "lightbox" : StrCast(sourceDoc.followLinkLocation) || followLoc;
docViewProps.addDocTab(doc, where);
setTimeout(() => {
const targDocView = DocumentManager.Instance.getFirstDocumentView(doc);
if (targDocView) {
- targDocView.props.focus(doc, BoolCast(sourceDoc.followLinkZoom, false), undefined, (didFocus: boolean) => {
- finished?.();
- res(true);
- return new Promise<boolean>(res2 => res2());
+ targDocView.props.focus(doc, {
+ willZoom: BoolCast(sourceDoc.followLinkZoom, false),
+ afterFocus: (didFocus: boolean) => {
+ finished?.();
+ res(ViewAdjustment.resetView);
+ return new Promise<ViewAdjustment>(res2 => res2());
+ }
});
} else {
- res(where !== "inPlace"); // return true to reset the initial focus&zoom (return false for 'inPlace' since resetting the initial focus&zoom will negate the zoom into the target)
+ res(where !== "inPlace" ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target
}
});
});
@@ -125,38 +129,30 @@ export class LinkManager {
createTabForTarget(false);
} else {
// first focus & zoom onto this (the clicked document). Then execute the function to focus on the target
- docViewProps.focus(sourceDoc, BoolCast(sourceDoc.followLinkZoom, true), 1, createTabForTarget);
+ docViewProps.focus(sourceDoc, { willZoom: BoolCast(sourceDoc.followLinkZoom, true), scale: 1, afterFocus: createTabForTarget });
}
};
LinkManager.traverseLink(linkDoc, sourceDoc, createViewFunc, BoolCast(sourceDoc.followLinkZoom, false), docViewProps.ContainingCollectionDoc, batch.end, altKey ? true : undefined);
}
- public static traverseLink(link: Opt<Doc>, doc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) {
- const linkDocs = link ? [link] : DocListCast(doc.links);
- const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor1
- const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor2
+
+ public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) {
+ const linkDocs = link ? [link] : DocListCast(sourceDoc.links);
+ 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).length === 0);
const backLinkWithoutTargetView = secondDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor1 as Doc).length === 0);
const linkWithoutTargetDoc = traverseBacklink === undefined ? fwdLinkWithoutTargetView || backLinkWithoutTargetView : traverseBacklink ? backLinkWithoutTargetView : fwdLinkWithoutTargetView;
const linkDocList = linkWithoutTargetDoc ? [linkWithoutTargetDoc] : (traverseBacklink === undefined ? firstDocs.concat(secondDocs) : traverseBacklink ? secondDocs : firstDocs);
- const followLinks = linkDocList.length ? (doc.isPushpin ? linkDocList : [linkDocList[0]]) : [];
+ const followLinks = linkDocList.length ? (sourceDoc.isPushpin ? linkDocList : [linkDocList[0]]) : [];
followLinks.forEach(async linkDoc => {
if (linkDoc) {
- const target = (doc === linkDoc.anchor1 ? linkDoc.anchor2 : doc === linkDoc.anchor2 ? linkDoc.anchor1 :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? linkDoc.anchor2 : linkDoc.anchor1)) as Doc;
- const targetTimecode = (doc === linkDoc.anchor1 ? Cast(linkDoc.anchor2_timecode, "number") :
- doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
- (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
+ 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)) as Doc;
if (target) {
- if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(doc)) {
- runInAction(() => LightboxView.LightboxDoc = (target.annotationOn as Doc) ?? target);
- finished?.();
- } else {
- const containerDoc = Cast(target.annotationOn, Doc, null) || target;
- targetTimecode !== undefined && (containerDoc._currentTimecode = targetTimecode);
- const targetContext = Cast(containerDoc?.context, Doc, null);
- const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
- DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "add:right"), finished), targetNavContext, linkDoc, undefined, doc, finished);
- }
+ const containerDoc = Cast(target.annotationOn, Doc, null) || target;
+ const targetContext = Cast(containerDoc?.context, Doc, null);
+ const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
+ DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "add:right"), finished), targetNavContext, linkDoc, undefined, sourceDoc, finished);
} else {
finished?.();
}
diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index ab6c94f83..3b23d5d56 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -158,6 +158,10 @@ declare abstract class URLField extends ObjectField {
constructor(url: URL);
}
+declare class RichTextField extends URLField {
+ [Copy](): ObjectField;
+ constructor(data:string, text: string);
+}
declare class AudioField extends URLField { [Copy](): ObjectField; }
declare class VideoField extends URLField { [Copy](): ObjectField; }
declare class ImageField extends URLField { [Copy](): ObjectField; }