aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CurrentUserUtils.ts134
-rw-r--r--src/client/util/DragManager.ts2
-rw-r--r--src/client/util/History.ts6
-rw-r--r--src/client/util/RecordingApi.ts269
-rw-r--r--src/client/util/Scripting.ts2
5 files changed, 49 insertions, 364 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b4e18a8bb..51bfdbbd2 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -7,8 +7,8 @@ import { List } from "../../fields/List";
import { PrefetchProxy } from "../../fields/Proxy";
import { RichTextField } from "../../fields/RichTextField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
-import { BoolCast, Cast, DateCast, DocCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
-import { ImageField, nullAudio } from "../../fields/URLField";
+import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
+import { nullAudio } from "../../fields/URLField";
import { SharingPermissions } from "../../fields/util";
import { Utils } from "../../Utils";
import { DocServer } from "../DocServer";
@@ -22,10 +22,11 @@ import { TreeView } from "../views/collections/TreeView";
import { Colors } from "../views/global/globalEnums";
import { MainView } from "../views/MainView";
import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox";
+import { LabelBox } from "../views/nodes/LabelBox";
import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView";
import { OverlayView } from "../views/OverlayView";
import { DocumentManager } from "./DocumentManager";
-import { DragManager } from "./DragManager";
+import { DragManager, dropActionType } from "./DragManager";
import { makeTemplate, MakeTemplate } from "./DropConverter";
import { HistoryUtil } from "./History";
import { LinkManager } from "./LinkManager";
@@ -271,8 +272,8 @@ export class CurrentUserUtils {
doc.emptyScreenshot = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "empty screenshot", _width: 400, _height: 200 });
}
if (doc.emptyWall === undefined) {
- doc.emptyWall = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
- (doc.emptyWall as Doc).recording = true;
+ doc.emptyWall = Docs.Create.ScreenshotDocument({ ...standardOps(), title: "screen snapshot", _width: 400, _height: 200, });
+ (doc.emptyWall as Doc).videoWall = true;
}
if (doc.emptyAudio === undefined) {
doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { ...standardOps(), title: "audio recording", x: 200, y: 200, _width: 200, _height: 100, });
@@ -354,7 +355,6 @@ export class CurrentUserUtils {
}
static menuBtnDescriptions(doc: Doc) {
- const badgeValue = ScriptField.MakeFunction("((len) => len ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length)")
return [
{ title: "Dashboards", target: Cast(doc.myDashboards, Doc, null), icon: "desktop", click: 'selectMainMenu(self)' },
{ title: "Search", target: Cast(doc.mySearchPanel, Doc, null), icon: "search", click: 'selectMainMenu(self)' },
@@ -362,7 +362,7 @@ export class CurrentUserUtils {
{ title: "Tools", target: Cast(doc.myTools, Doc, null), icon: "wrench", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" },
{ title: "Imports", target: Cast(doc.myImportDocs, Doc, null), icon: "upload", click: 'selectMainMenu(self)' },
{ title: "Recently Closed", target: Cast(doc.myRecentlyClosedDocs, Doc, null), icon: "archive", click: 'selectMainMenu(self)' },
- { title: "Shared with me", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', badgeValue},
+ { title: "Shared with me", target: Cast(doc.mySharedDocs, Doc, null), icon: "users", click: 'selectMainMenu(self)', watchedDocuments: doc.mySharedDocs as Doc },
{ title: "Trails", target: Cast(doc.myTrails, Doc, null), icon: "pres-trail", click: 'selectMainMenu(self)' },
{ title: "User Doc", target: Cast(doc.myUserDoc, Doc, null), icon: "address-card", click: 'selectMainMenu(self)', hidden: "IsNoviceMode()" },
];
@@ -370,9 +370,8 @@ export class CurrentUserUtils {
static async setupMenuPanel(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
if (doc.menuStack === undefined) {
- await this.setupLinkDocs(doc, linkDatabaseId);
- await this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing
- const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, badgeValue, hidden }) =>
+ await this.setupSharingSidebar(doc, sharingDocumentId, linkDatabaseId); // sets up the right sidebar collection for mobile upload documents and sharing
+ const menuBtns = CurrentUserUtils.menuBtnDescriptions(doc).map(({ title, target, icon, click, watchedDocuments, hidden }) =>
Docs.Create.FontIconDocument({
icon,
btnType: ButtonType.MenuButton,
@@ -383,13 +382,12 @@ export class CurrentUserUtils {
dontUndo: true,
title,
target,
- dontRegisterView: true,
hidden: hidden ? ComputedField.MakeFunction("IsNoviceMode()") as any : undefined,
_dropAction: "alias",
_removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
_width: 60,
_height: 60,
- badgeValue,
+ watchedDocuments,
onClick: ScriptField.MakeScript(click, { scriptContext: "any" })
})
);
@@ -402,7 +400,6 @@ export class CurrentUserUtils {
_chromeHidden: true,
backgroundColor: Colors.DARK_GRAY,
boxShadow: "rgba(0,0,0,0)",
- dontRegisterView: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
ignoreClick: true,
_gridGap: 0,
@@ -723,7 +720,7 @@ export class CurrentUserUtils {
];
doc.dockedBtns = CurrentUserUtils.linearButtonList({
title: "docked buttons", _height: 40, flexGap: 0, linearViewFloating: true,
- childDontRegisterViews: true, linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
+ linearViewIsExpanded: true, linearViewExpandable: true, ignoreClick: true
}, btnDescs.map(desc => doc[`dockedBtn-${desc.title}`] as Doc ?? (doc[`dockedBtn-${desc.title}`] = dockBtn({ title: desc.title, ...desc.opts() }))));
}
}
@@ -837,13 +834,12 @@ export class CurrentUserUtils {
});
if (doc.contextMenuBtns === undefined) {
doc.contextMenuBtns = CurrentUserUtils.linearButtonList(
- { title: "menu buttons", flexGap: 0, childDontRegisterViews: true, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 },
+ { title: "menu buttons", flexGap: 0, linearViewIsExpanded: true, ignoreClick: true, linearViewExpandable: false, _height: 35 },
CurrentUserUtils.contextMenuTools(doc).map(params =>
!params.subMenu ?
btnFunc(params) :
CurrentUserUtils.linearButtonList({
title: params.title,
- childDontRegisterViews: true,
linearViewSubMenu: true, flexGap: 0, ignoreClick: true,
linearViewExpandable: true, icon: params.title, _height: 30,
linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined,
@@ -859,7 +855,6 @@ export class CurrentUserUtils {
btnFunc(params) :
CurrentUserUtils.linearButtonList({
title: params.title,
- childDontRegisterViews: true,
linearViewSubMenu: true, flexGap: 0, ignoreClick: true,
linearViewExpandable: true, icon: params.title, _height: 30,
linearViewIsExpanded: params.expanded ? !(ComputedField.MakeFunction(params.expanded) as any) : undefined,
@@ -902,7 +897,10 @@ export class CurrentUserUtils {
}
// Sharing sidebar is where shared documents are contained
- static async setupLinkDocs(doc: Doc, linkDatabaseId: string) {
+ static async setupSharingSidebar(doc: Doc, sharingDocumentId: string, linkDatabaseId: string) {
+ if (doc.myPublishedDocs === undefined) {
+ doc.myPublishedDocs = new List<Doc>();
+ }
if (doc.myLinkDatabase === undefined) {
let linkDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(linkDatabaseId);
if (!linkDocs) {
@@ -914,41 +912,29 @@ export class CurrentUserUtils {
}
doc.myLinkDatabase = new PrefetchProxy(linkDocs);
}
- }
- // A user's sharing document is where all documents that are shared to that user are placed.
- // When the user views one of these documents, it will be added to the sharing documents 'viewed' list field
- // The sharing document also stores the user's color value which helps distinguish shared documents from personal documents
- static async setupSharedDocs(doc: Doc, sharingDocumentId: string) {
- const addToDashboards = ScriptField.MakeScript(`addToDashboards(self)`);
- const dashboardFilter = ScriptField.MakeFunction(`doc._viewType === '${CollectionViewType.Docking}'`, { doc: Doc.name });
- const dblClkScript = ScriptField.MakeScript("{scriptContext.openLevel(documentView); addDocToList(scriptContext.props.treeView.props.Document, 'viewed', documentView.rootDoc);}", {scriptContext:"any", documentView:Doc.name})
-
- const sharedDocOpts:DocumentOptions = {
- title: "My Shared Docs",
- userColor: "rgb(202, 202, 202)",
- childContextMenuFilters: new List<ScriptField>([dashboardFilter!,]),
- childContextMenuScripts: new List<ScriptField>([addToDashboards!,]),
- childContextMenuLabels: new List<string>(["Add to Dashboards",]),
- childContextMenuIcons: new List<string>(["user-plus",]),
- treeViewChildDoubleClick: dblClkScript,
- };
- const sharedRequiredDocOpts:DocumentOptions = {
- "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
- childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 50, _gridGap: 15,
- // NOTE: treeViewHideTitle & _showTitle is for a TreeView's editable title, _showTitle is for DocumentViews title bar
- _showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", _chromeHidden: true, dontRegisterView: true,
- explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
- };
-
- const sharedDocs = Docs.newAccount ? undefined : DocCast(doc.mySharedDocs) ?? DocCast(await DocServer.GetRefField(sharingDocumentId + "outer"));
- if (!(sharedDocs instanceof Doc)) {
- doc.mySharedDocs = new PrefetchProxy(
- Docs.Create.TreeDocument([], {...sharedDocOpts, ...sharedRequiredDocOpts}, sharingDocumentId + "outer", sharingDocumentId));
- } else {
- Object.entries(sharedRequiredDocOpts).forEach(pair => {
- const targetDoc = pair[0].startsWith("_") ? sharedDocs as Doc : Doc.GetProto(sharedDocs as Doc);
- targetDoc[pair[0]] = pair[1];
- });
+ // TODO:glr NOTE: treeViewHideTitle & _showTitle may be confusing, treeViewHideTitle is for the editable title (just for tree view), _showTitle is to show the Document title for any document
+ if (doc.mySharedDocs === undefined) {
+ let sharedDocs = Docs.newAccount ? undefined : await DocServer.GetRefField(sharingDocumentId + "outer");
+ if (!sharedDocs) {
+ sharedDocs = Docs.Create.TreeDocument([], {
+ title: "My SharedDocs", childDropAction: "alias", system: true, contentPointerEvents: "all", childLimitHeight: 0, _yMargin: 50, _gridGap: 15,
+ _showTitle: "title", treeViewHideTitle: true, ignoreClick: true, _lockedPosition: true, "acl-Public": SharingPermissions.Augment, "_acl-Public": SharingPermissions.Augment,
+ _chromeHidden: true, boxShadow: "0 0",
+ explainer: "This is where documents or dashboards that other users have shared with you will appear. To share a document or dashboard right click and select 'Share'"
+ }, sharingDocumentId + "outer", sharingDocumentId);
+ (sharedDocs as Doc)["acl-Public"] = (sharedDocs as Doc)[DataSym]["acl-Public"] = SharingPermissions.Augment;
+ }
+ if (sharedDocs instanceof Doc) {
+ Doc.GetProto(sharedDocs).userColor = sharedDocs.userColor || "rgb(202, 202, 202)";
+ const addToDashboards = ScriptField.MakeScript(`addToDashboards(self)`);
+ const dashboardFilter = ScriptField.MakeFunction(`doc._viewType === '${CollectionViewType.Docking}'`, { doc: Doc.name });
+ sharedDocs.childContextMenuFilters = new List<ScriptField>([dashboardFilter!,]);
+ sharedDocs.childContextMenuScripts = new List<ScriptField>([addToDashboards!,]);
+ sharedDocs.childContextMenuLabels = new List<string>(["Add to Dashboards",]);
+ sharedDocs.childContextMenuIcons = new List<string>(["user-plus",]);
+
+ }
+ doc.mySharedDocs = new PrefetchProxy(sharedDocs as Doc);
}
}
@@ -959,7 +945,7 @@ export class CurrentUserUtils {
doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], {
title: "My Imports", _forceActive: true, buttonMenu: true, buttonMenuDoc: newImportButton, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true, childLimitHeight: 0,
childDropAction: "copy", _autoHeight: true, _yMargin: 50, _gridGap: 15, boxShadow: "0 0", _lockedPosition: true, system: true, _chromeHidden: true,
- dontRegisterView: true, explainer: "This is where documents that are Imported into Dash will go."
+ explainer: "This is where documents that are Imported into Dash will go."
}));
}
}
@@ -968,7 +954,7 @@ export class CurrentUserUtils {
static setupSearchSidebar(doc: Doc) {
if (doc.mySearchPanel === undefined) {
doc.mySearchPanel = new PrefetchProxy(Docs.Create.SearchDocument({
- dontRegisterView: true, backgroundColor: "dimgray", ignoreClick: true, _searchDoc: true,
+ backgroundColor: "dimgray", ignoreClick: true, _searchDoc: true,
childDropAction: "alias", _lockedPosition: true, _viewType: CollectionViewType.Schema, title: "Search Panel", system: true
})) as any as Doc;
}
@@ -1056,7 +1042,6 @@ export class CurrentUserUtils {
doc.savedFilters = new List<Doc>();
doc.filterDocCount = 0;
doc.freezeChildren = "remove|add";
- doc.myPublishedDocs = doc.myPublishedDocs ?? new List<Doc>();
doc.myHeaderBarDoc = doc.myHeaderBarDoc ?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true });
this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
this.setupDocTemplates(doc); // sets up the template menu of templates
@@ -1109,7 +1094,6 @@ export class CurrentUserUtils {
Docs.newAccount = !(field instanceof Doc);
await Docs.Prototypes.initialize();
const userDoc = Docs.newAccount ? new Doc(userDocumentId, true) : field as Doc;
- Docs.newAccount &&(userDoc.activePage = "home");
const updated = this.updateUserDocument(Doc.SetUserDoc(userDoc), sharingDocumentId, linkDatabaseId);
(await DocListCastAsync(Cast(Doc.UserDoc().myLinkDatabase, Doc, null)?.data))?.forEach(async link => { // make sure anchors are loaded to avoid incremental updates to computedFn's in LinkManager
const a1 = await Cast(link?.anchor1, Doc, null);
@@ -1127,9 +1111,6 @@ export class CurrentUserUtils {
public static openDashboard = (userDoc: Doc, doc: Doc, fromHistory = false) => {
CurrentUserUtils.MainDocId = doc[Id];
- if (!DocListCast(CurrentUserUtils.MyDashboards.data).includes(doc)) {
- Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", doc);
- }
if (doc) { // this has the side-effect of setting the main container since we're assigning the active/guest dashboard
!("presentationView" in doc) && (doc.presentationView = new List<Doc>([Docs.Create.TreeDocument([], { title: "Presentation" })]));
@@ -1203,42 +1184,18 @@ export class CurrentUserUtils {
input.click();
}
- public static CaptureDashboardThumbnail() {
- const docView = CollectionDockingView.Instance.props.DocumentView?.();
- const content = docView?.ContentDiv;
- if (docView && content) {
- const _width = Number(getComputedStyle(content).width.replace("px",""));
- const _height = Number(getComputedStyle(content).height.replace("px",""));
- return CollectionFreeFormView.UpdateIcon(
- docView.layoutDoc[Id] + "-icon" + (new Date()).getTime(),
- content,
- _width, _height,
- _width, _height, 0, 1, true, docView.layoutDoc[Id] + "-icon",
- (iconFile, _nativeWidth, _nativeHeight) => {
- const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: docView.rootDoc.title+"-icon", _width, _height, _nativeWidth, _nativeHeight});
- const proto = Cast(img.proto, Doc, null)!;
- proto["data-nativeWidth"] = _width;
- proto["data-nativeHeight"] = _height;
- Doc.GetProto(CurrentUserUtils.ActiveDashboard).thumb = img;
- });
- }
-
- }
-
public static async snapshotDashboard(userDoc: Doc) {
const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard);
Doc.AddDocToList(Cast(userDoc.myDashboards, Doc, null), "data", copy);
CurrentUserUtils.openDashboard(userDoc, copy);
}
- public static closeActiveDashboard = () => {
- Doc.UserDoc().activeDashboard = undefined;
- }
-
public static createNewDashboard = async (userDoc: Doc, id?: string) => {
const presentation = Doc.MakeCopy(userDoc.emptyPresentation as Doc, true);
const dashboards = await Cast(userDoc.myDashboards, Doc) as Doc;
const dashboardCount = DocListCast(dashboards.data).length + 1;
+ const emptyPane = Cast(userDoc.emptyPane, Doc, null);
+ emptyPane["dragFactory-count"] = NumCast(emptyPane["dragFactory-count"]) + 1;
const freeformOptions: DocumentOptions = {
x: 0,
y: 400,
@@ -1246,7 +1203,7 @@ export class CurrentUserUtils {
_height: 1000,
_fitWidth: true,
_backgroundGridShow: true,
- title: `Untitled Tab 1`,
+ title: `Untitled Tab ${NumCast(emptyPane["dragFactory-count"])}`,
};
const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
const dashboardDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600 }], { title: `Dashboard ${dashboardCount}` }, id, "row");
@@ -1255,12 +1212,11 @@ export class CurrentUserUtils {
// switching the tabs from the datadoc to the regular doc
const dashboardTabs = DocListCast(dashboardDoc[DataSym].data);
dashboardDoc.data = new List<Doc>(dashboardTabs);
- dashboardDoc["pane-count"] = 1;
userDoc.activePresentation = presentation;
Doc.AddDocToList(dashboards, "data", dashboardDoc);
- // CurrentUserUtils.openDashboard(userDoc, dashboardDoc);
+ CurrentUserUtils.openDashboard(userDoc, dashboardDoc);
}
public static GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, noMargins?: boolean, annotationOn?: Doc, maxHeight?: number, backgroundColor?: string) {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index dbfba8992..9f8c49081 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -455,7 +455,7 @@ export namespace DragManager {
if (dragData instanceof DocumentDragData) {
dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction;
}
- if (((e.target as any)?.className === "lm_tabs" || (e.target as any)?.className === "lm_header" || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
+ if (((e.target as any)?.className === "lm_tabs" || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
if (!startWindowDragTimer) {
startWindowDragTimer = setTimeout(async () => {
startWindowDragTimer = undefined;
diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index 632348306..e6f75a7db 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -58,10 +58,8 @@ export namespace HistoryUtil {
export function getState(): ParsedUrl {
const state = copyState(history.state);
- if (state) {
- state.initializers = state.initializers || {};
- }
- return state ?? {initializers:{}};
+ state.initializers = state.initializers || {};
+ return state;
}
// export function addHandler(handler: (state: ParsedUrl | null) => void) {
diff --git a/src/client/util/RecordingApi.ts b/src/client/util/RecordingApi.ts
deleted file mode 100644
index 021feee9a..000000000
--- a/src/client/util/RecordingApi.ts
+++ /dev/null
@@ -1,269 +0,0 @@
-import { CollectionFreeFormView } from "../views/collections/collectionFreeForm";
-import { IReactionDisposer, observable, reaction } from "mobx";
-import { NumCast } from "../../fields/Types";
-import { Doc } from "../../fields/Doc";
-import { VideoBox } from "../views/nodes/VideoBox";
-import { scaleDiverging } from "d3-scale";
-import { Transform } from "./Transform";
-
-type Movement = {
- time: number,
- panX: number,
- panY: number,
- scale: number,
-}
-
-type Presentation = {
- movements: Array<Movement> | null
- meta: Object,
-}
-
-export class RecordingApi {
-
- private static NULL_PRESENTATION: Presentation = {
- movements: null,
- meta: {},
- }
-
- // instance variables
- private currentPresentation: Presentation;
- private isRecording: boolean;
- private absoluteStart: number;
-
-
- // create static instance and getter for global use
- @observable static _instance: RecordingApi;
- public static get Instance(): RecordingApi { return RecordingApi._instance }
- public constructor() {
- // init the global instance
- RecordingApi._instance = this;
-
- // init the instance variables
- this.currentPresentation = RecordingApi.NULL_PRESENTATION
- this.isRecording = false;
- this.absoluteStart = -1;
-
- // used for tracking movements in the view frame
- this.disposeFunc = null;
- this.recordingFFView = null;
-
- // for now, set playFFView
- this.playFFView = null;
- this.timers = null;
- }
-
- // little helper :)
- private get isInitPresenation(): boolean {
- return this.currentPresentation.movements === null
- }
-
- public start = (meta?: Object): Error | undefined => {
- // check if already init a presentation
- if (!this.isInitPresenation) {
- console.error('[recordingApi.ts] start() failed: current presentation data exists. please call clear() first.')
- return new Error('[recordingApi.ts] start()')
- }
-
- // update the presentation mode
- Doc.UserDoc().presentationMode = 'recording'
-
- // (1a) get start date for presenation
- const startDate = new Date()
- // (1b) set start timestamp to absolute timestamp
- this.absoluteStart = startDate.getTime()
-
- // (2) assign meta content if it exists
- this.currentPresentation.meta = meta || {}
- // (3) assign start date to currentPresenation
- this.currentPresentation.movements = []
- // (4) set isRecording true to allow trackMovements
- this.isRecording = true
- }
-
- public clear = (): Error | Presentation => {
- // TODO: maybe archive the data?
- if (this.isRecording) {
- console.error('[recordingApi.ts] clear() failed: currently recording presentation. call pause() first')
- return new Error('[recordingApi.ts] clear()')
- }
-
- // update the presentation mode
- Doc.UserDoc().presentationMode = 'none'
- // set the previus recording view to the play view
- this.playFFView = this.recordingFFView
-
- const presCopy = { ...this.currentPresentation }
-
- // clear presenation data
- this.currentPresentation = RecordingApi.NULL_PRESENTATION
- // clear isRecording
- this.isRecording = false
- // clear absoluteStart
- this.absoluteStart = -1
- // clear the disposeFunc
- this.removeRecordingFFView()
-
- return presCopy;
- }
-
- public pause = (): Error | undefined => {
- if (this.isInitPresenation) {
- console.error('[recordingApi.ts] pause() failed: no presentation started. try calling init() first')
- return new Error('[recordingApi.ts] pause(): no presentation')
- }
- // don't allow track movments
- this.isRecording = false
-
- // set adjust absoluteStart to add the time difference
- const timestamp = new Date().getTime()
- this.absoluteStart = timestamp - this.absoluteStart
- }
-
- public resume = () => {
- this.isRecording = true
- // set absoluteStart to the difference in time
- this.absoluteStart = new Date().getTime() - this.absoluteStart
- }
-
- private trackMovements = (panX: number, panY: number, scale: number = 0): Error | undefined => {
- // ensure we are recording
- if (!this.isRecording) {
- return new Error('[recordingApi.ts] trackMovements()')
- }
- // check to see if the presetation is init
- if (this.isInitPresenation) {
- return new Error('[recordingApi.ts] trackMovements(): no presentation')
- }
-
- // get the time
- const time = new Date().getTime() - this.absoluteStart
- // make new movement object
- const movement: Movement = { time, panX, panY, scale }
-
- // add that movement to the current presentation data's movement array
- this.currentPresentation.movements && this.currentPresentation.movements.push(movement)
- }
-
- // instance variable for the FFView
- private disposeFunc: IReactionDisposer | null;
- private recordingFFView: CollectionFreeFormView | null;
-
- // set the FFView that will be used in a reaction to track the movements
- public setRecordingFFView = (view: CollectionFreeFormView): void => {
- // set the view to the current view
- if (view === this.recordingFFView || view == null) return;
-
- // this.recordingFFView = view;
- // set the reaction to track the movements
- this.disposeFunc = reaction(
- () => ({ x: NumCast(view.Document.panX, -1), y: NumCast(view.Document.panY, -1), scale: NumCast(view.Document.viewScale, -1) }),
- (res) => (res.x !== -1 && res.y !== -1 && this.isRecording) && this.trackMovements(res.x, res.y, res.scale)
- )
-
- // for now, set the most recent recordingFFView to the playFFView
- this.recordingFFView = view;
- }
-
- // call on dispose function to stop tracking movements
- public removeRecordingFFView = (): void => {
- this.disposeFunc?.();
- this.disposeFunc = null;
- }
-
- // TODO: extract this into different class with pause and resume recording
- // TODO: store the FFview with the movements
- private playFFView: CollectionFreeFormView | null;
- private timers: NodeJS.Timeout[] | null;
-
- public setPlayFFView = (view: CollectionFreeFormView): void => {
- this.playFFView = view
- }
-
- // pausing movements will dispose all timers that are planned to replay the movements
- // play movemvents will recreate them when the user resumes the presentation
- public pauseMovements = (): undefined | Error => {
- if (this.playFFView === null) {
- return new Error('[recordingApi.ts] pauseMovements() failed: no view')
- }
-
- if (!this._isPlaying) {
- //return new Error('[recordingApi.ts] pauseMovements() failed: not playing')
- return
- }
- this._isPlaying = false
- // TODO: set userdoc presentMode to browsing
- this.timers?.map(timer => clearTimeout(timer))
-
- // this.videoBox = null;
- }
-
- private videoBox: VideoBox | null = null;
-
- // by calling pause on the VideoBox, the pauseMovements will be called
- public pauseVideoAndMovements = (): boolean => {
- this.videoBox?.Pause()
-
- this.pauseMovements()
- return this.videoBox == null
- }
-
- public _isPlaying = false;
-
- public playMovements = (presentation: Presentation, timeViewed: number = 0, videoBox?: VideoBox): undefined | Error => {
- if (presentation.movements === null || this.playFFView === null) {
- return new Error('[recordingApi.ts] followMovements() failed: no presentation data or no view')
- }
- if(this._isPlaying) return;
-
- this._isPlaying = true;
- Doc.UserDoc().presentationMode = 'watching';
-
- // TODO: consider this bug at the end of the clip on seek
- this.videoBox = videoBox || null;
-
- // only get the movements that are remaining in the video time left
- const filteredMovements = presentation.movements.filter(movement => movement.time > timeViewed * 1000)
-
- // helper to replay a movement
- const document = this.playFFView
- let preScale = -1;
- const zoomAndPan = (movement: Movement) => {
- const { panX, panY, scale } = movement;
- (scale !== -1 && preScale !== scale) && document.zoomSmoothlyAboutPt([panX, panY], scale, 0);
- document.Document._panX = panX;
- document.Document._panY = panY;
-
- preScale = scale;
- }
-
- // set the first frame to be at the start of the pres
- zoomAndPan(filteredMovements[0]);
-
- // make timers that will execute each movement at the correct replay time
- this.timers = filteredMovements.map(movement => {
- const timeDiff = movement.time - timeViewed*1000
- return setTimeout(() => {
- // replay the movement
- zoomAndPan(movement)
- // if last movement, presentation is done -> set the instance var
- if (movement === filteredMovements[filteredMovements.length - 1]) RecordingApi.Instance._isPlaying = false;
- }, timeDiff)
- })
- }
-
- // Unfinished code for tracing multiple free form views
- // export let pres: Map<CollectionFreeFormView, IReactionDisposer> = new Map()
-
- // export function AddRecordingFFView(ffView: CollectionFreeFormView): void {
- // pres.set(ffView,
- // reaction(() => ({ x: ffView.panX, y: ffView.panY }),
- // (pt) => RecordingApi.trackMovements(ffView, pt.x, pt.y)))
- // )
- // }
-
- // export function RemoveRecordingFFView(ffView: CollectionFreeFormView): void {
- // const disposer = pres.get(ffView);
- // disposer?.();
- // pres.delete(ffView)
- // }
-}
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 223b0268c..3b0a47b54 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -223,7 +223,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
paramList.push(`${key}: ${typeof val === "object" ? Object.getPrototypeOf(val).constructor.name : typeof val}`);
}
const paramString = paramList.join(", ");
- const body = addReturn ? `return ${script};` : script;
+ const body = addReturn ? `return ${script};` : `return ${script};`;
const reqTypes = requiredType ? `: ${requiredType}` : '';
const funcScript = `(function(${paramString})${reqTypes} { ${body} })`;
host.writeFile("file.ts", funcScript);