aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json130
-rw-r--r--src/client/util/BranchingTrailManager.tsx137
-rw-r--r--src/client/util/CurrentUserUtils.ts26
-rw-r--r--src/client/util/DragManager.ts58
-rw-r--r--src/client/views/Main.tsx2
-rw-r--r--src/client/views/OverlayView.tsx1
-rw-r--r--src/client/views/StyleProvider.tsx4
-rw-r--r--src/client/views/UndoStack.tsx6
-rw-r--r--src/client/views/collections/TreeView.scss19
-rw-r--r--src/client/views/collections/TreeView.tsx65
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx4
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx4
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx205
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx4
-rw-r--r--src/client/views/nodes/VideoBox.tsx5
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx45
-rw-r--r--src/client/views/nodes/trails/PresElementBox.scss4
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx85
18 files changed, 702 insertions, 102 deletions
diff --git a/package-lock.json b/package-lock.json
index 0199d3d31..c3190ddb4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7094,12 +7094,97 @@
"strip-ansi": "^7.0.1"
}
},
+ "string-width-cjs": {
+ "version": "npm:string-width@4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ }
+ }
+ },
"strip-ansi": {
"version": "7.1.0",
"bundled": true,
"requires": {
"ansi-regex": "^6.0.1"
}
+ },
+ "strip-ansi-cjs": {
+ "version": "npm:strip-ansi@6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+ }
+ }
+ },
+ "wrap-ansi-cjs": {
+ "version": "npm:wrap-ansi@7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ }
+ }
}
}
},
@@ -8604,7 +8689,7 @@
}
},
"string-width-cjs": {
- "version": "npm:string-width@4.2.3",
+ "version": "npm:string-width-cjs@4.2.3",
"bundled": true,
"requires": {
"emoji-regex": "^8.0.0",
@@ -8627,7 +8712,7 @@
}
},
"strip-ansi-cjs": {
- "version": "npm:strip-ansi@6.0.1",
+ "version": "npm:strip-ansi-cjs@6.0.1",
"bundled": true,
"requires": {
"ansi-regex": "^5.0.1"
@@ -8786,7 +8871,7 @@
}
},
"wrap-ansi-cjs": {
- "version": "npm:wrap-ansi@7.0.0",
+ "version": "npm:wrap-ansi-cjs@7.0.0",
"bundled": true,
"requires": {
"ansi-styles": "^4.0.0",
@@ -10360,16 +10445,6 @@
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
- "d": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
- "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
- "dev": true,
- "requires": {
- "es5-ext": "^0.10.50",
- "type": "^1.0.1"
- }
- },
"d3": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/d3/-/d3-7.8.4.tgz",
@@ -11750,28 +11825,6 @@
"is-symbol": "^1.0.2"
}
},
- "es5-ext": {
- "version": "0.10.62",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
- "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
- "dev": true,
- "requires": {
- "es6-iterator": "^2.0.3",
- "es6-symbol": "^3.1.3",
- "next-tick": "^1.1.0"
- }
- },
- "es6-iterator": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
- "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
- "dev": true,
- "requires": {
- "d": "1",
- "es5-ext": "^0.10.35",
- "es6-symbol": "^3.1.1"
- }
- },
"es6-promise": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -11783,7 +11836,6 @@
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
"dev": true,
"requires": {
- "d": "^1.0.1",
"ext": "^1.1.2"
}
},
@@ -27596,12 +27648,6 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
- "type": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
- "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
- "dev": true
- },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/src/client/util/BranchingTrailManager.tsx b/src/client/util/BranchingTrailManager.tsx
new file mode 100644
index 000000000..a224b84f4
--- /dev/null
+++ b/src/client/util/BranchingTrailManager.tsx
@@ -0,0 +1,137 @@
+import { action, computed, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../fields/Doc';
+import { Id } from '../../fields/FieldSymbols';
+import { PresBox } from '../views/nodes/trails';
+import { OverlayView } from '../views/OverlayView';
+import { DocumentManager } from './DocumentManager';
+import { Docs } from '../documents/Documents';
+import { nullAudio } from '../../fields/URLField';
+
+@observer
+export class BranchingTrailManager extends React.Component {
+ public static Instance: BranchingTrailManager;
+
+ constructor(props: any) {
+ super(props);
+ if (!BranchingTrailManager.Instance) {
+ BranchingTrailManager.Instance = this;
+ }
+ }
+
+ setupUi = () => {
+ OverlayView.Instance.addWindow(<BranchingTrailManager></BranchingTrailManager>, { x: 100, y: 150, width: 1000, title: 'Branching Trail'});
+ // OverlayView.Instance.forceUpdate();
+ console.log(OverlayView.Instance);
+ // let hi = Docs.Create.TextDocument("beee", {
+ // x: 100,
+ // y: 100,
+ // })
+ // hi.overlayX = 100;
+ // hi.overlayY = 100;
+
+ // Doc.AddToMyOverlay(hi);
+ console.log(DocumentManager._overlayViews);
+ };
+
+
+ // stack of the history
+ @observable private slideHistoryStack: String[] = [];
+ @action setSlideHistoryStack = action((newArr: String[]) => {
+ this.slideHistoryStack = newArr;
+ });
+
+ @observable private containsSet: Set<String> = new Set<String>();
+
+ // prev pres to copmare with
+ @observable private prevPresId: String | null = null;
+ @action setPrevPres = action((newId: String | null) => {
+ this.prevPresId = newId;
+ });
+
+ // docId to Doc map
+ @observable private docIdToDocMap: Map<String, Doc> = new Map<String, Doc>();
+
+ observeDocumentChange = (targetDoc: Doc, pres: PresBox) => {
+ const presId = pres.props.Document[Id];
+ if (this.prevPresId === presId) {
+ return;
+ }
+
+ const targetDocId = targetDoc[Id];
+ this.docIdToDocMap.set(targetDocId, targetDoc);
+
+ if (this.prevPresId === null) {
+ this.setupUi();
+ }
+
+ if (this.prevPresId === null || this.prevPresId !== presId) {
+ Doc.UserDoc().isBranchingMode = true;
+ this.setPrevPres(presId);
+
+ // REVERT THE SET
+ const stringified = [presId, targetDocId].toString();
+ if (this.containsSet.has([presId, targetDocId].toString())) {
+ // remove all the elements after the targetDocId
+ const newStack = this.slideHistoryStack.slice(0, this.slideHistoryStack.indexOf(stringified));
+ const removed = this.slideHistoryStack.slice(this.slideHistoryStack.indexOf(stringified));
+ this.setSlideHistoryStack(newStack);
+
+ removed.forEach(info => this.containsSet.delete(info.toString()));
+ } else {
+ this.setSlideHistoryStack([...this.slideHistoryStack, stringified]);
+ this.containsSet.add(stringified);
+ }
+ }
+ console.log(this.slideHistoryStack.length);
+ if (this.slideHistoryStack.length === 0) {
+ Doc.UserDoc().isBranchingMode = false;
+ }
+ };
+
+ clickHandler = (e: React.PointerEvent<HTMLButtonElement>, targetDocId: string, removeIndex: number) => {
+ const targetDoc = this.docIdToDocMap.get(targetDocId);
+ if (!targetDoc) {
+ return;
+ }
+
+ const newStack = this.slideHistoryStack.slice(0, removeIndex);
+ const removed = this.slideHistoryStack.slice(removeIndex);
+
+ this.setSlideHistoryStack(newStack);
+
+ removed.forEach(info => this.containsSet.delete(info.toString()));
+ DocumentManager.Instance.showDocument(targetDoc, { willZoomCentered: true });
+ if (this.slideHistoryStack.length === 0) {
+ Doc.UserDoc().isBranchingMode = false;
+ }
+ //PresBox.NavigateToTarget(targetDoc, targetDoc);
+ };
+
+ @computed get trailBreadcrumbs() {
+ return (
+ <div style={{ border: '.5rem solid green', padding: '5px', backgroundColor: 'white', minHeight: '50px', minWidth: '1000px' }}>
+ {this.slideHistoryStack.map((info, index) => {
+ const [presId, targetDocId] = info.split(',');
+ const doc = this.docIdToDocMap.get(targetDocId);
+ if (!doc) {
+ return <></>;
+ }
+ return (
+ <span key={targetDocId}>
+ <button key={index} onPointerDown={e => this.clickHandler(e, targetDocId, index)}>
+ {presId.slice(0, 3) + ':' + doc.title}
+ </button>
+ -{'>'}
+ </span>
+ );
+ })}
+ </div>
+ );
+ }
+
+ render() {
+ return <div>{BranchingTrailManager.Instance.trailBreadcrumbs}</div>;
+ }
+}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index d52e389d6..873361587 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -20,7 +20,6 @@ import { DashboardView } from "../views/DashboardView";
import { Colors } from "../views/global/globalEnums";
import { OpenWhere } from "../views/nodes/DocumentView";
import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
-import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
import { OverlayView } from "../views/OverlayView";
import { DragManager, dropActionType } from "./DragManager";
import { MakeTemplate } from "./DropConverter";
@@ -29,6 +28,7 @@ import { LinkManager } from "./LinkManager";
import { ScriptingGlobals } from "./ScriptingGlobals";
import { ColorScheme, SettingsManager } from "./SettingsManager";
import { UndoManager } from "./UndoManager";
+import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
interface Button {
// DocumentOptions fields a button can set
@@ -607,6 +607,7 @@ export class CurrentUserUtils {
{ scripts: { }, opts: { title: "undoStack", layout: "<UndoStack>", toolTip: "Undo/Redo Stack"}}, // note: layout fields are hacks -- they don't actually run through the JSX parser (yet)
{ scripts: { }, opts: { title: "linker", layout: "<LinkingUI>", toolTip: "link started"}},
{ scripts: { }, opts: { title: "currently playing", layout: "<CurrentlyPlayingUI>", toolTip: "currently playing media"}},
+ { scripts: { }, opts: { title: "Branching", layout: "<Branching>", toolTip: "Branch, baby!"}}
];
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', undoIgnoreFields: new List<string>(['opacity']), _dragOnlyWithinContainer: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts:DocumentOptions = {
@@ -714,7 +715,14 @@ export class CurrentUserUtils {
{ title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Always available
{ title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Web is selected
{ title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(), expertMode: false, toolType:CollectionViewType.Schema, funcs: {hidden: `!SelectionManager_selectedDocType(self.toolType, self.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(self.toolType, self.expertMode)`} }, // Only when Schema is selected
- { title: "Audio", icon: "microphone", toolTip: "Dictate", btnType: ButtonType.ToggleButton, expertMode: false, ignoreClick: true, scripts: { onClick: 'return toggleRecording(_readOnly_)'}, funcs: { }}
+ { title: "Video", icon: 'video', toolTip: "Dictate", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `getIsRecording()`}, ignoreClick: true, scripts: { onClick: 'return toggleRecording(_readOnly_)'}},
+ { title: "StopRec", icon: "stop", toolTip: "Stop", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecording()`}, ignoreClick: true, scripts: { onClick: `return toggleRecording(_readOnly_)`}},
+ { title: "Dropdown", toolTip: "Workspace Recordings", btnType: ButtonType.DropdownList, expertMode: false, funcs: {hidden: `renderDropdown()`, btnList: `getWorkspaceRecordings()`}, ignoreClick: true, scripts: { script: `toggleRecPlayback(value)`}},
+ { title: "Play Rec",icon: "play", toolTip: "Play recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsWorkspaceRecPlaying()`}, ignoreClick: true, scripts: { onClick: `return playWorkspaceRec(getCurrentRecording())`}},
+ { title: "Pause Rec",icon: "pause", toolTip: "Pause recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsWorkspaceRecPaused()`}, ignoreClick: true, scripts: { onClick: `return pauseWorkspaceRec(getCurrentRecording())`}},
+ { title: "Stop Rec", icon: "stop", toolTip: "Stop recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `return closeWorkspaceRec(getCurrentRecording())`}},
+ { title: "Add doc", icon: "down", toolTip: "add to doc", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `addRectoWorkspace(getCurrentRecording())`}},
+ { title: "Delete Rec", icon: "trash", toolTip: "delete selected recording", btnType: ButtonType.ToggleButton, expertMode: false, funcs: {hidden: `!getIsRecPlayback()`}, ignoreClick: true, scripts: { onClick: `removeWorkspaceRec(getCurrentRecording())`}}
];
}
@@ -734,9 +742,21 @@ export class CurrentUserUtils {
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs);
}
+
static setupContextMenuBtn(params:Button, menuDoc:Doc):Doc {
const menuBtnDoc = DocListCast(menuDoc?.data).find(doc => doc.title === params.title);
const subMenu = params.subMenu;
+ // Doc.UserDoc().workspaceRecordings = new List<Doc>;
+ if (Doc.UserDoc().currentRecording) {
+ //@ts-ignore
+ Doc.RemFromMyOverlay(Doc.UserDoc().currentRecording);
+ }
+ Doc.UserDoc().isRecording = false;
+ Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().currentRecording = undefined;
+ Doc.UserDoc().isPlaybackPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
if (!subMenu) { // button does not have a sub menu
return this.setupContextMenuButton(params, menuBtnDoc);
}
@@ -995,4 +1015,4 @@ ScriptingGlobals.add(function MySharedDocs() { return Doc.MySharedDocs; }, "docu
ScriptingGlobals.add(function IsNoviceMode() { return Doc.noviceMode; }, "is Dash in novice mode");
ScriptingGlobals.add(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }, "switches between comic and normal document rendering");
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
+ScriptingGlobals.add(function setInkToolDefaults() { Doc.ActiveTool = InkTool.None; });
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 831a22866..5a11f2dca 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -4,7 +4,7 @@ import { Doc, Field, Opt, StrListCast } from '../../fields/Doc';
import { List } from '../../fields/List';
import { PrefetchProxy } from '../../fields/Proxy';
import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, ScriptCast, StrCast } from '../../fields/Types';
import { emptyFunction, Utils } from '../../Utils';
import { Docs, DocUtils } from '../documents/Documents';
import * as globalCssVariables from '../views/global/globalCssVariables.scss';
@@ -14,6 +14,7 @@ import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
import { SnappingManager } from './SnappingManager';
import { UndoManager } from './UndoManager';
+import { listSpec } from '../../fields/Schema';
export type dropActionType = 'embed' | 'copy' | 'move' | 'add' | 'same' | 'proto' | 'none' | undefined; // undefined = move, "same" = move but don't call dropPropertiesToRemove
@@ -235,6 +236,61 @@ export namespace DragManager {
return true;
}
+ export function StartDropdownDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, recordingIndex: number, options?: DragOptions, dropEvent?: () => any,) {
+
+ const addAudioTag = (dropDoc: any) => {
+ dropDoc && !dropDoc.author_date && (dropDoc.author_date = new DateField());
+ dropDoc instanceof Doc && DocUtils.MakeLinkToActiveAudio(() => dropDoc);
+ return dropDoc;
+ };
+ const finishDrag = async (e: DragCompleteEvent) => {
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.RemFromMyOverlay(Doc.UserDoc().currentRecording);
+ Doc.UserDoc().currentRecording = undefined;
+ Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
+ const docDragData = e.docDragData;
+ dropEvent?.(); // glr: optional additional function to be called - in this case with presentation trails
+ if (docDragData && !docDragData.droppedDocuments.length) {
+ docDragData.dropAction = dragData.userDropAction || dragData.dropAction;
+ docDragData.droppedDocuments = (
+ await Promise.all(
+ dragData.draggedDocuments.map(async d =>
+ !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart)
+ ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result)
+ : docDragData.dropAction === 'embed'
+ ? Doc.BestEmbedding(d)
+ : docDragData.dropAction === 'add'
+ ? d
+ : docDragData.dropAction === 'proto'
+ ? Doc.GetProto(d)
+ : docDragData.dropAction === 'copy'
+ ? (
+ await Doc.MakeClone(d)
+ ).clone
+ : d
+ )
+ )
+ ).filter(d => d);
+ !['same', 'proto'].includes(docDragData.dropAction as any) &&
+ docDragData.droppedDocuments
+ // .filter(drop => !drop.dragOnlyWithinContainer || ['embed', 'copy'].includes(docDragData.dropAction as any))
+ .forEach((drop: Doc, i: number) => {
+ const dragProps = StrListCast(dragData.draggedDocuments[i].dropPropertiesToRemove);
+ const remProps = (dragData?.dropPropertiesToRemove || []).concat(Array.from(dragProps));
+ [...remProps, 'dropPropertiesToRemove'].map(prop => (drop[prop] = undefined));
+ });
+ }
+ return e;
+ };
+ dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded
+ StartDrag(eles, dragData, downX, downY, options, finishDrag);
+ return true;
+ }
+
// drag a button template and drop a new button
export function StartButtonDrag(eles: HTMLElement[], script: string, title: string, vars: { [name: string]: Field }, params: string[], initialize: (button: Doc) => void, downX: number, downY: number, options?: DragOptions) {
const finishDrag = (e: DragCompleteEvent) => {
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index a04309d0c..96bd52d39 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -14,6 +14,7 @@ import { TrackMovements } from '../util/TrackMovements';
import { CollectionView } from './collections/CollectionView';
import './global/globalScripts';
import { MainView } from './MainView';
+import { BranchingTrailManager } from '../util/BranchingTrailManager';
dotenv.config();
AssignAllExtensions();
@@ -50,6 +51,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
document.cookie = `loadtime=${loading};${expires};path=/`;
new TrackMovements();
new ReplayMovements();
+ new BranchingTrailManager({});
new PingManager();
root.render(<MainView />);
}, 0);
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 62aa4d1d4..7d65914b3 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -145,6 +145,7 @@ export class OverlayView extends React.Component {
@action
addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+ console.log("adding window");
const remove = action(() => {
const index = this._elements.indexOf(contents);
if (index !== -1) this._elements.splice(index, 1);
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 12935400b..a9e4ac17d 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -237,12 +237,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
switch (doc?.type) {
case DocumentType.COL:
return StrCast(
- doc?.layout_borderRounding,
+ doc?.layout_boxShadow,
doc?._type_collection === CollectionViewType.Pile
? '4px 4px 10px 2px'
: lockedPosition() || doc?._isGroup || docProps?.LayoutTemplateString
? undefined // groups have no drop shadow -- they're supposed to be "invisible". LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
- : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.layout_borderRounding, '0.2vw 0.2vw 0.8vw')}`
+ : `${darkScheme() ? Colors.DARK_GRAY : Colors.MEDIUM_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
);
case DocumentType.LABEL:
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index 8f3ae8e87..cdc389efe 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -39,15 +39,15 @@ export class UndoStack extends React.Component<UndoStackProps> {
}}>
{UndoManager.undoStackNames.map((name, i) => (
<div className="undoStack-resultContainer" key={i}>
- <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
+ <div className="undoStack-commandString">{StrCast(name).replace(/[^\.]*\./, '')}</div>
</div>
))}
{Array.from(UndoManager.redoStackNames)
.reverse()
.map((name, i) => (
<div className="undoStack-resultContainer" key={i}>
- <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: SettingsManager.userBackgroundColor }}>
- {name.replace(/[^\.]*\./, '')}
+ <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+ {StrCast(name).replace(/[^\.]*\./, '')}
</div>
</div>
))}
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index d22e85880..d3ba23b4e 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -23,6 +23,25 @@
.treeView-bulletIcons {
width: 100%;
height: 100%;
+ // position: absolute;
+
+ .treeView-expandIcon {
+ display: none;
+ left: -8px;
+ position: absolute;
+ }
+
+ .treeView-checkIcon {
+ left: 3.5px;
+ top: 2px;
+ position: absolute;
+ }
+
+ &:hover {
+ .treeView-expandIcon {
+ display: unset;
+ }
+ }
position: relative;
display: flex;
flex-direction: row;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 701150769..4f9310434 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
+import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc';
import { DocData, Height, Width } from '../../../fields/DocSymbols';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
@@ -222,6 +222,39 @@ export class TreeView extends React.Component<TreeViewProps> {
}
};
+ @undoBatch
+ @action
+ recurToggle = (childList: Doc[]) => {
+ if (childList.length > 0) {
+ childList.forEach(child => {
+ console.log(child);
+ child.runProcess = !!!child.runProcess;
+ TreeView.ToggleChildrenRun.get(child)?.();
+ });
+ }
+ };
+
+ @undoBatch
+ @action
+ getRunningChildren = (childList: Doc[]) => {
+ if (childList.length === 0) {
+ return [];
+ }
+
+ const runningChildren: FieldResult[] = [];
+ childList.forEach(child => {
+ if (child.runProcess && TreeView.GetRunningChildren.get(child)) {
+ if (child.runProcess) {
+ runningChildren.push(child);
+ }
+ runningChildren.push(...(TreeView.GetRunningChildren.get(child)?.() ?? []));
+ }
+ });
+ return runningChildren;
+ };
+
+ static GetRunningChildren = new Map<Doc, any>();
+ static ToggleChildrenRun = new Map<Doc, () => void>();
constructor(props: any) {
super(props);
if (!TreeView._openLevelScript) {
@@ -230,6 +263,19 @@ export class TreeView extends React.Component<TreeViewProps> {
}
this._openScript = Doc.IsSystem(this.props.document) ? undefined : () => TreeView._openLevelScript!;
this._editTitleScript = Doc.IsSystem(this.props.document) ? () => TreeView._openLevelScript! : () => TreeView._openTitleScript!;
+
+ // set for child processing highligting
+ // this.dataDoc.testing = 'testing';
+ console.log(this.doc, this.dataDoc, this.childDocs);
+ this.dataDoc.hasChildren = this.childDocs.length > 0;
+ // this.dataDoc.children = this.childDocs;
+ TreeView.ToggleChildrenRun.set(this.doc, () => {
+ this.recurToggle(this.childDocs);
+ });
+
+ TreeView.GetRunningChildren.set(this.doc, () => {
+ return this.getRunningChildren(this.childDocs);
+ });
}
_treeEle: any;
@@ -718,15 +764,14 @@ export class TreeView extends React.Component<TreeViewProps> {
)
) : (
<div className="treeView-bulletIcons" style={{ color: Doc.IsSystem(DocCast(this.doc.proto)) ? 'red' : undefined }}>
- {this.onCheckedClick ? (
- <IconButton
- color={color}
- icon={<FontAwesomeIcon size="sm" icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'} />}
- size={Size.XSMALL}
+ <div className={`treeView-${this.onCheckedClick ? 'checkIcon' : 'expandIcon'}`}>
+ <FontAwesomeIcon
+ size="sm"
+ style={{ display: this.childDocs?.length >= 1 ? 'block' : 'none' }}
+ icon={checked === 'check' ? 'check' : checked === 'x' ? 'times' : checked === 'unchecked' ? 'square' : !this.treeViewOpen ? 'caret-right' : 'caret-down'}
/>
- ) : (
- <IconButton color={color} icon={<FontAwesomeIcon icon={iconType as IconProp} />} size={Size.XSMALL} />
- )}
+ </div>
+ {this.onCheckedClick ? null : typeof iconType === 'string' ? <FontAwesomeIcon icon={iconType as IconProp} /> : iconType}
</div>
)}
</div>
@@ -924,8 +969,8 @@ export class TreeView extends React.Component<TreeViewProps> {
}
})}
Document={this.doc}
+ DataDoc={undefined} // or this.dataDoc?
layout_fitWidth={returnTrue}
- DataDoc={undefined}
scriptContext={this}
hideDecorationTitle={this.props.treeView.outlineMode}
hideResizeHandles={this.props.treeView.outlineMode}
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 4bb5c5adf..0854bc611 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -22,6 +22,7 @@ import { CollectionSubView } from '../CollectionSubView';
import './CollectionLinearView.scss';
import { Button, Toggle, ToggleType, Type } from 'browndash-components';
import { Colors } from '../../global/globalEnums';
+import { BranchingTrailManager } from '../../../util/BranchingTrailManager';
import { SettingsManager } from '../../../util/SettingsManager';
/**
@@ -146,6 +147,7 @@ export class CollectionLinearView extends CollectionSubView() {
case '<LinkingUI>': return this.getLinkUI();
case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI();
case '<UndoStack>': return <UndoStack key={doc[Id]} width={200} height={40} inline={true} />;
+ case '<Branching>': return Doc.UserDoc().isBranchingMode ? <BranchingTrailManager /> : null;
}
const nested = doc._type_collection === CollectionViewType.Linear;
@@ -208,7 +210,7 @@ export class CollectionLinearView extends CollectionSubView() {
text={Cast(this.props.Document.icon, 'string', null)}
icon={Cast(this.props.Document.icon, 'string', null) ? undefined : <FontAwesomeIcon color={SettingsManager.userColor} icon={isExpanded ? 'minus' : 'plus'} />}
color={SettingsManager.userColor}
- background={SettingsManager.userVariantColor}
+ // background={SettingsManager.userVariantColor}
type={Type.TERT}
onPointerDown={e => e.stopPropagation()}
toggleType={ToggleType.BUTTON}
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index f286e5a42..1cf66fbdc 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -6,7 +6,7 @@ import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc';
import { ScriptField } from '../../../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { Utils } from '../../../../Utils';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { SelectionManager } from '../../../util/SelectionManager';
@@ -235,7 +235,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
const list: IListItemProps[] = this.buttonList
.filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value))
.map(value => ({
- text: value.charAt(0).toUpperCase() + value.slice(1),
+ text: value === "string" ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title),
val: value,
style: getStyle(value),
onClick: undoable(() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value }), value),
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 8fa2861b6..8a91b8102 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,4 +1,4 @@
-import { action, observable } from 'mobx';
+import { action, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { VideoField } from '../../../../fields/URLField';
@@ -9,12 +9,24 @@ import { VideoBox } from '../VideoBox';
import { RecordingView } from './RecordingView';
import { DocumentType } from '../../../documents/DocumentTypes';
import { Presentation } from '../../../util/TrackMovements';
-import { Doc } from '../../../../fields/Doc';
+import { Doc, DocListCast } from '../../../../fields/Doc';
import { Id } from '../../../../fields/FieldSymbols';
-import { BoolCast, DocCast } from '../../../../fields/Types';
+import { BoolCast, Cast, DocCast } from '../../../../fields/Types';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { DocumentManager } from '../../../util/DocumentManager';
import { Docs } from '../../../documents/Documents';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
+import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
+import { DocumentView } from '../DocumentView';
+import { SettingsManager } from '../../../util/SettingsManager';
+import { PropertiesView } from '../../PropertiesView';
+import { PropertiesSection } from '../../PropertiesSection';
+import { PropertiesDocContextSelector } from '../../PropertiesDocContextSelector';
+import { listSpec } from '../../../../fields/Schema';
+import { DragManager } from '../../../util/DragManager';
+import { SelectionManager } from '../../../util/SelectionManager';
+import { AudioBox } from '../AudioBox';
+import { UndoManager, undoBatch } from '../../../util/UndoManager';
@observer
export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -55,6 +67,146 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
+ /**
+ * This method toggles whether or not we are currently using the RecordingBox to record with the topbar button
+ * @param _readOnly_
+ * @returns
+ */
+ @undoBatch
+ @action
+ public static toggleWorkspaceRecording(_readOnly_: boolean) {
+ if (_readOnly_) return RecordingBox.screengrabber ? true : false;
+ if (RecordingBox.screengrabber) {
+ //if recordingbox is true; when we press the stop button. changed vals temporarily to see if changes happening
+ console.log('grabbing screen!')
+ RecordingBox.screengrabber.Pause?.();
+ const remDoc = RecordingBox.screengrabber.rootDoc;
+ setTimeout(() => {
+ RecordingBox.screengrabber?.Finish?.();
+ RecordingBox.screengrabber!.rootDoc.overlayX = 70; //was 100
+ RecordingBox.screengrabber!.rootDoc.overlayY = 590;
+ console.log(RecordingBox.screengrabber)
+ RecordingBox.screengrabber = undefined;
+ }, 100);
+ //could break if recording takes too long to turn into videobox. If so, either increase time on setTimeout below or find diff place to do this
+ setTimeout(() => {
+ Doc.RemFromMyOverlay(remDoc);
+
+ }, 1000)
+ Doc.UserDoc().isRecording = false;
+ Doc.AddDocToList(Doc.UserDoc(), "workspaceRecordings", RecordingBox.screengrabber.rootDoc);
+ } else {
+ //when we first press mic
+ const screengrabber = Docs.Create.WebCamDocument('', {
+ _width: 205,
+ _height: 115,
+ });
+ screengrabber.overlayX = 70; //was -400
+ screengrabber.overlayY = 590; //was 0
+ screengrabber[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
+ Doc.AddToMyOverlay(screengrabber); //just adds doc to overlay
+ DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
+ RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
+ RecordingBox.screengrabber.Record?.();
+ });
+ Doc.UserDoc().isRecording = true;
+ }
+ }
+
+ /**
+ * This method changes the menu depending on whether or not we are in playback mode
+ * @param value RecordingBox rootdoc
+ */
+ @undoBatch
+ @action
+ public static toggleWorkspaceRecPlayback(value: Doc) {
+ let docval = undefined;
+ Doc.UserDoc().currentRecording = value;
+ console.log(value)
+ value.overlayX =70;
+ value.overlayY = 590;
+ if (!Doc.UserDoc().isAddRecToDocMode) {
+ Doc.UserDoc().isRecPlayback = true;
+ Doc.UserDoc().isWorkspaceRecPlaying = true;
+ Doc.AddToMyOverlay(value);
+ DocumentManager.Instance.AddViewRenderedCb(value, docView => {
+ Doc.UserDoc().currentRecording = docView.ComponentView as RecordingBox;
+ SelectionManager.SelectSchemaViewDoc(value);
+ })} else {
+ let recordingIndex = Array.from(Doc.UserDoc().workspaceRecordings).indexOf(value);
+ DragManager.StartDropdownDrag([document.createElement('div')],new DragManager.DocumentDragData([value]), 1, 1, recordingIndex);
+ }
+ }
+
+ /**
+ * Adds the recording box to the canvas
+ * @param value current recordingbox
+ */
+ @undoBatch
+ @action
+ public static addRecToWorkspace(value: RecordingBox) {
+ console.log("adding rec to doc");
+ console.log(value);
+ let ffView = Array.from(DocumentManager.Instance.DocumentViews).find(view => view.ComponentView instanceof CollectionFreeFormView);
+ (ffView?.ComponentView as CollectionFreeFormView).props.addDocument?.(value.rootDoc);
+ let recordingIndex = Array.from(Doc.UserDoc().workspaceRecordings).indexOf(value.rootDoc);
+ console.log(recordingIndex);
+ Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.RemFromMyOverlay(value.rootDoc);
+ Doc.UserDoc().currentRecording = undefined;
+ Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
+ }
+
+ @undoBatch
+ @action
+ public static playWorkspaceRec(value: VideoBox) {
+ value.Play();
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = true;
+ }
+
+ @undoBatch
+ @action
+ public static pauseWorkspaceRec(value: VideoBox) {
+ value.Pause();
+ Doc.UserDoc().isWorkspaceRecPlaying = true;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
+ }
+
+ @undoBatch
+ @action
+ public static closeWorkspaceRec(value: VideoBox) {
+ value.Pause();
+ Doc.RemFromMyOverlay(value.rootDoc);
+ Doc.UserDoc().currentRecording = undefined;
+ Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
+ Doc.RemFromMyOverlay(value.rootDoc);
+
+ }
+
+ @undoBatch
+ @action
+ public static removeWorkspaceRec(value: VideoBox) {
+ let recordingIndex = Array.from(Doc.UserDoc().workspaceRecordings).indexOf(value.rootDoc);
+ Cast(Doc.UserDoc().workspaceRecordings, listSpec(Doc), null)?.splice(recordingIndex, 1);
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.RemFromMyOverlay(value.rootDoc);
+ Doc.UserDoc().currentRecording = undefined;
+ Doc.UserDoc().isRecPlayback = false;
+ Doc.UserDoc().isAddRecToDocMode = false;
+ Doc.UserDoc().isWorkspaceRecPlaying = false;
+ Doc.UserDoc().isWorkspaceRecPaused = false;
+
+ }
+
+
+
Record: undefined | (() => void);
Pause: undefined | (() => void);
Finish: undefined | (() => void);
@@ -81,28 +233,27 @@ export class RecordingBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
static screengrabber: RecordingBox | undefined;
}
-ScriptingGlobals.add(function toggleRecording(_readOnly_: boolean) {
- if (_readOnly_) return RecordingBox.screengrabber ? true : false;
- if (RecordingBox.screengrabber) {
- RecordingBox.screengrabber.Pause?.();
- setTimeout(() => {
- RecordingBox.screengrabber?.Finish?.();
- RecordingBox.screengrabber!.rootDoc.overlayX = 100;
- RecordingBox.screengrabber!.rootDoc.overlayY = 100;
- RecordingBox.screengrabber = undefined;
- }, 100);
- } else {
- const screengrabber = Docs.Create.WebCamDocument('', {
- _width: 384,
- _height: 216,
- });
- screengrabber.overlayX = -400;
- screengrabber.overlayY = 0;
- screengrabber[Doc.LayoutFieldKey(screengrabber) + '_trackScreen'] = true;
- Doc.AddToMyOverlay(screengrabber);
- DocumentManager.Instance.AddViewRenderedCb(screengrabber, docView => {
- RecordingBox.screengrabber = docView.ComponentView as RecordingBox;
- RecordingBox.screengrabber.Record?.();
- });
+
+ScriptingGlobals.add(function toggleRecording(_readOnly_: boolean) { RecordingBox.toggleWorkspaceRecording(_readOnly_); });
+ScriptingGlobals.add(function toggleRecPlayback(value: Doc) { RecordingBox.toggleWorkspaceRecPlayback(value); });
+ScriptingGlobals.add(function addRectoWorkspace(value: RecordingBox) { RecordingBox.addRecToWorkspace(value); });
+
+ScriptingGlobals.add(function playWorkspaceRec(value: VideoBox) { RecordingBox.playWorkspaceRec(value); });
+ScriptingGlobals.add(function pauseWorkspaceRec(value: VideoBox) { RecordingBox.pauseWorkspaceRec(value); });
+ScriptingGlobals.add(function closeWorkspaceRec(value: VideoBox) { RecordingBox.closeWorkspaceRec(value); });
+ScriptingGlobals.add(function removeWorkspaceRec(value: VideoBox) { RecordingBox.removeWorkspaceRec(value) });
+
+ScriptingGlobals.add(function getWorkspaceRecordings() { return Doc.UserDoc().workspaceRecordings });
+ScriptingGlobals.add(function getIsRecording() { return Doc.UserDoc().isRecording; })
+ScriptingGlobals.add(function getIsRecPlayback() { return Doc.UserDoc().isRecPlayback; })
+ScriptingGlobals.add(function getCurrentRecording() { return Doc.UserDoc().currentRecording; })
+ScriptingGlobals.add(function getIsWorkspaceRecPlaying() { return Doc.UserDoc().isWorkspaceRecPlaying; })
+ScriptingGlobals.add(function getIsWorkspaceRecPaused() { return Doc.UserDoc().isWorkspaceRecPaused; })
+ScriptingGlobals.add(function renderDropdown() {
+ if (!Doc.UserDoc().workspaceRecordings || Array.from(Doc.UserDoc().workspaceRecordings).length === 0) {
+ return true;
}
-}, 'toggle recording');
+ return false;
+})
+
+
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 0e386b093..755f1adc0 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -9,6 +9,7 @@ import { Networking } from '../../../Network';
import { Presentation, TrackMovements } from '../../../util/TrackMovements';
import { ProgressBar } from './ProgressBar';
import './RecordingView.scss';
+import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
export interface MediaSegment {
videoChunks: any[];
@@ -163,8 +164,9 @@ export function RecordingView(props: IRecordingViewProps) {
// if this is called, then we're done recording all the segments
const finish = () => {
// call stop on the video recorder if active
+ console.log(videoRecorder.current?.state);
videoRecorder.current?.state !== 'inactive' && videoRecorder.current?.stop();
-
+ console.log("this it")
// end the streams (audio/video) to remove recording icon
const stream = videoElementRef.current!.srcObject;
stream instanceof MediaStream && stream.getTracks().forEach(track => track.stop());
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 48716b867..5c2d09b0c 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -191,7 +191,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._finished = false;
start = this.timeline.trimStart;
}
-
+ if (this.dataDoc._data_presentation) {
+ console.log("ninja")
+ }
+ console.log(this.dataDoc.data_presentation)
try {
this._audioPlayer && this.player && (this._audioPlayer.currentTime = this.player?.currentTime);
update && this.player && this.playFrom(start, undefined, true);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index f750392f5..b0101d9a7 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -36,6 +36,9 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
+import { BranchingTrailManager } from '../../../util/BranchingTrailManager';
+import { TreeView } from '../../collections/TreeView';
+import { OverlayView } from '../../OverlayView';
const { Howl } = require('howler');
export interface pinDataTypes {
@@ -280,9 +283,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return listItems.filter(doc => !doc.layout_unrendered);
}
};
+
+ // go to documents chain
+ runSubroutines = (childrenToRun: Doc[], normallyNextSlide: Doc) => {
+ console.log(childrenToRun, normallyNextSlide, 'runSUBFUNC');
+ if (childrenToRun === undefined) {
+ console.log('children undefined');
+ return;
+ }
+ if (childrenToRun[0] === normallyNextSlide) {
+ return;
+ }
+
+ childrenToRun.forEach(child => {
+ DocumentManager.Instance.showDocument(child, {});
+ });
+ };
+
// Called when the user activates 'next' - to move to the next part of the pres. trail
@action
next = () => {
+ console.log("next");
const progressiveReveal = (first: boolean) => {
const presIndexed = Cast(this.activeItem?.presentation_indexed, 'number', null);
if (presIndexed !== undefined) {
@@ -320,6 +341,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Case 1: No more frames in current doc and next slide is defined, therefore move to next slide
const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]);
const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex;
+
+ // before moving onto next slide, run the subroutines :)
+ const currentDoc = this.childDocs[this.itemIndex];
+ //could i do this.childDocs[this.itemIndex] for first arg?
+ this.runSubroutines(TreeView.GetRunningChildren.get(currentDoc)?.() , this.childDocs[this.itemIndex + 1]);
+
this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1);
progressiveReveal(true); // shows first progressive document, but without a transition effect
} else {
@@ -359,6 +386,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//it'll also execute the necessary actions if presentation is playing.
@undoBatch
public gotoDocument = action((index: number, from?: Doc, group?: boolean, finished?: () => void) => {
+ console.log("going to document");
Doc.UnBrushAllDocs();
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
@@ -711,6 +739,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
pinDoc.config_viewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
}
}
+
+ @action
+ static reversePin(pinDoc: Doc, targetDoc: Doc) {
+ // const fkey = Doc.LayoutFieldKey(targetDoc);
+ pinDoc.config_data = targetDoc.data;
+
+ console.log(pinDoc.presData);
+ }
+
/**
* This method makes sure that cursor navigates to the element that
* has the option open and last in the group.
@@ -722,6 +759,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
navigateToActiveItem = (afterNav?: () => void) => {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
+ // BranchingTrailManager.Instance.observeDocumentChange(targetDoc, this);
const finished = () => {
afterNav?.();
console.log('Finish Slide Nav: ' + targetDoc.title);
@@ -1111,13 +1149,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//Regular click
@action
selectElement = (doc: Doc, noNav = false) => {
+ // BranchingTrailManager.Instance.observeDocumentChange(doc, this);
CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => clip?.ComponentView?.Pause?.());
if (noNav) {
const index = this.childDocs.indexOf(doc);
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
}
- } else this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+ console.log("no nav")
+ } else {
+ this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+ console.log('e bitch')
+ }
this.updateCurrentPresentation(DocCast(doc.embedContainer));
};
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
index 4f95f0c1f..9ac2b5a94 100644
--- a/src/client/views/nodes/trails/PresElementBox.scss
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -4,6 +4,10 @@ $light-background: #ececec;
$slide-background: #d5dce2;
$slide-active: #5b9fdd;
+.testingv2 {
+ background-color: red;
+}
+
.presItem-container {
cursor: grab;
display: flex;
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 529a5024f..d90f96249 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -25,6 +25,9 @@ import { PresBox } from './PresBox';
import './PresElementBox.scss';
import { PresMovement } from './PresEnums';
import React = require('react');
+import { TreeView } from '../../collections/TreeView';
+import { BranchingTrailManager } from '../../../util/BranchingTrailManager';
+import { MultiToggle, Type } from 'browndash-components';
/**
* This class models the view a document added to presentation will have in the presentation.
* It involves some functionality for its buttons and options.
@@ -301,8 +304,28 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
activeItem.config_rotation = NumCast(targetDoc.rotation);
activeItem.config_width = NumCast(targetDoc.width);
activeItem.config_height = NumCast(targetDoc.height);
- activeItem.config_pinLayout = true;
+ activeItem.config_pinLayout = !activeItem.config_pinLayout;
+ // activeItem.config_pinLayout = true;
};
+
+ //wait i dont think i have to do anything here since by default it'll revert to the previously saved if I don't save
+ //so basically, don't have an onClick for this, just let it do nada for now
+ @undoBatch
+ @action
+ revertToPreviouslySaved = (presTargetDoc: Doc, activeItem: Doc) => {
+ console.log('reverting');
+ // console.log("reverting to previosly saved\n");
+ // console.log(this.prevTarget);
+ console.log("Content continuously updating");
+ const target = DocCast(activeItem.annotationOn) ?? activeItem;
+ console.log(presTargetDoc.pinData)
+ PresBox.reversePin(activeItem, target);
+ // console.log("new target\n");
+ // console.log(target);
+ // PresBox.pinDocView(activeItem, { pinData: PresBox.pinDataTypes(this.prevTarget) }, this.prevTarget ? this.prevTarget : target);
+ //figure out how to make it go back to the previously saved one
+ }
+
/**
* Method called for updating the view of the currently selected document
*
@@ -365,7 +388,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
@action
- startRecording = (e: React.MouseEvent, activeItem: Doc) => {
+ startRecording = (e: React.MouseEvent, activeItem: Doc) => {
e.stopPropagation();
if (PresElementBox.videoIsRecorded(activeItem)) {
// if we already have an existing recording
@@ -399,6 +422,19 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
+ @undoBatch
+ @action
+ lfg = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ console.log('lfg called');
+ // TODO: fix this bug
+ const { toggleChildrenRun } = this.rootDoc;
+ TreeView.ToggleChildrenRun.get(this.rootDoc)?.();
+
+ // call this.rootDoc.recurChildren() to get all the children
+ // if (iconClick) PresElementBox.showVideo = false;
+ };
+
@computed
get toolbarWidth(): number {
const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
@@ -414,8 +450,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
const targetDoc: Doc = this.targetDoc;
const activeItem: Doc = this.rootDoc;
+ const hasChildren: boolean = Cast(this.rootDoc?.hasChildren, 'boolean') || false;
const items: JSX.Element[] = [];
+
items.push(
<Tooltip key="slide" title={<div className="dash-tooltip">Update captured doc layout</div>}>
<div
@@ -426,16 +464,31 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</Tooltip>
);
+ // items.push(
+ // <Tooltip key="flex" title={<div className="dash-tooltip">Update captured doc content</div>}>
+ // <div
+ // className="slideButton"
+ // onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))}
+ // style={{ opacity: activeItem.config_pinData || activeItem.config_pinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}>
+ // C
+ // </div>
+ // </Tooltip>
+ // );
items.push(
<Tooltip key="flex" title={<div className="dash-tooltip">Update captured doc content</div>}>
<div
- className="slideButton"
- onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))}
- style={{ opacity: activeItem.config_pinData || activeItem.config_pinView ? 1 : 0.5, fontWeight: 700, display: 'flex' }}>
- C
+ className="slideButton"
+ style={{fontWeight: 700, display: 'flex'}}
+ >
+ <MultiToggle type={Type.PRIM} items={[
+ {icon: <FontAwesomeIcon icon="rotate-left" color="white" size='sm'/>, tooltip: "Save data to presentation", val: 'revert',
+ onPointerDown: e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.updateCapturedViewContents(targetDoc, activeItem))},
+ {icon: <FontAwesomeIcon icon="floppy-disk" color="white" size='sm'/>, tooltip: "Continously update content", val: "floppy-disk",
+ onPointerDown: e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.revertToPreviouslySaved(targetDoc, activeItem))},
+ ]} />
</div>
</Tooltip>
- );
+ )
items.push(
<Tooltip key="slash" title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
<div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}>
@@ -486,6 +539,22 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</Tooltip>
);
+ if (!Doc.noviceMode && hasChildren) {
+ // TODO: replace with if treeveiw, has childrenDocs
+ items.push(
+ <Tooltip key="children" title={<div className="dash-tooltip">Run child processes (tree only)</div>}>
+ <div
+ className="slideButton"
+ onClick={e => {
+ e.stopPropagation();
+ this.lfg(e);
+ }}
+ style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={'circle-play'} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>
+ );
+ }
items.push(
<Tooltip key="trash" title={<div className="dash-tooltip">Remove from presentation</div>}>
<div className={'slideButton'} onClick={this.removePresentationItem}>
@@ -532,7 +601,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
) : (
<div
ref={this._dragRef}
- className={`presItem-slide ${isCurrent ? 'active' : ''}`}
+ className={`presItem-slide ${isCurrent ? 'active' : ''}${this.rootDoc.runProcess ? ' testingv2' : ''}`}
style={{
display: 'infline-block',
backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),