aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts44
-rw-r--r--src/client/views/UndoStack.scss29
-rw-r--r--src/client/views/UndoStack.tsx35
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx9
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx11
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
7 files changed, 96 insertions, 36 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 795d60b48..5aa69e499 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -355,7 +355,7 @@ export class DocumentOptions {
cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
filterBoolean?: string;
data_useCors?: boolean;
- icon?: string;
+ icon?: string; // icon used by fonticonbox to render button
target?: Doc; // available for use in scripts as the primary target document
sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b0a2c7d60..85ab66301 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -289,23 +289,24 @@ export class CurrentUserUtils {
emptyThings.forEach(thing => DocUtils.AssignDocField(doc, "empty"+thing.key, (opts) => thing.creator(opts), {...standardOps(thing.key), ...thing.opts}, undefined, undefined, thing.funcs));
return [
- { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
- { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)},
- { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)},
- { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)},
- { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc,clickFactory: DocCast(doc.emptyTab)},
- { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
- { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc,clickFactory: DocCast(doc.emptyComparison)},
- { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
- { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc,clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)},
- { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript)},
- { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "file", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)},
- { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay},
- { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize", dragFactory: doc.emptyHeader as Doc, clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true },
- { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", clickFactory: 'repl' as any, openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a note", title: "Note", icon: "sticky-note", dragFactory: doc.emptyNote as Doc, clickFactory: DocCast(doc.emptyNote)},
+ { toolTip: "Tap or drag to create a flashcard", title: "Flashcard", icon: "id-card", dragFactory: doc.emptyFlashcard as Doc, clickFactory: DocCast(doc.emptyFlashcard)},
+ { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, clickFactory: DocCast(doc.emptyEquation)},
+ { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, clickFactory: DocCast(doc.emptyNoteboard)},
+ { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab)},
+ { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, clickFactory: DocCast(doc.emptyWebpage)},
+ { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, clickFactory: DocCast(doc.emptyComparison)},
+ { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, clickFactory: DocCast(doc.emptyAudio), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a map", title: "Map", icon: "map-marker-alt", dragFactory: doc.emptyMap as Doc, clickFactory: DocCast(doc.emptyMap)},
+ { toolTip: "Tap or drag to create a screen grabber", title: "Grab", icon: "photo-video", dragFactory: doc.emptyScreengrab as Doc, clickFactory: DocCast(doc.emptyScreengrab), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a WebCam recorder", title: "WebCam", icon: "photo-video", dragFactory: doc.emptyWebCam as Doc, clickFactory: DocCast(doc.emptyWebCam), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a button", title: "Button", icon: "bolt", dragFactory: doc.emptyButton as Doc, clickFactory: DocCast(doc.emptyButton)},
+ { toolTip: "Tap or drag to create a scripting box", title: "Script", icon: "terminal", dragFactory: doc.emptyScript as Doc, clickFactory: DocCast(doc.emptyScript)},
+ { toolTip: "Tap or drag to create a data viz node", title: "DataViz", icon: "file", dragFactory: doc.emptyDataViz as Doc, clickFactory: DocCast(doc.emptyDataViz)},
+ { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay},
+ { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true },
+ { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
+ { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack>" as any, openFactoryLocation: OpenWhere.overlay},
].map(tuple => (
{ openFactoryLocation: OpenWhere.addRight,
scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)',
@@ -598,10 +599,11 @@ export class CurrentUserUtils {
CurrentUserUtils.createToolButton(opts), scripts, funcs);
const btnDescs = [// setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet
- { scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
- { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
- { scripts: { }, opts: { title: "linker", icon: "linkui", toolTip: "link started"}},
- { scripts: { }, opts: { title: "currently playing", icon: "currentlyplayingui", toolTip: "currently playing media"}},
+ { scripts: { onClick: "undo()"}, opts: { title: "undo", icon: "undo-alt", toolTip: "Click to undo" }},
+ { scripts: { onClick: "redo()"}, opts: { title: "redo", icon: "redo-alt", toolTip: "Click to redo" }},
+ { 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"}},
];
const btns = btnDescs.map(desc => dockBtn({_width: 30, _height: 30, defaultDoubleClick: 'ignore', dontUndo: true, _stayInCollection: true, ...desc.opts}, desc.scripts));
const dockBtnsReqdOpts:DocumentOptions = {
diff --git a/src/client/views/UndoStack.scss b/src/client/views/UndoStack.scss
new file mode 100644
index 000000000..ab21e6d7e
--- /dev/null
+++ b/src/client/views/UndoStack.scss
@@ -0,0 +1,29 @@
+.undoStack-outerContainer {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ pointer-events: all;
+ padding-left: 4px;
+}
+
+.undoStack-resultContainer {
+ border-radius: 5px;
+}
+
+.undoStack-commandInput {
+ width: 100%;
+}
+
+.undoStack-commandResult,
+.undoStack-commandString {
+ overflow-wrap: break-word;
+}
+
+.undoStack-commandsContainer {
+ background-color: whitesmoke;
+ flex: 1 1 auto;
+ overflow-y: scroll;
+ height: 30px;
+ border-radius: 5px;
+}
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index 01e184d6b..f5af09e5b 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -1,24 +1,41 @@
+import { action, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { UndoManager } from '../util/UndoManager';
-import './ScriptingRepl.scss';
+import './UndoStack.scss';
+interface UndoStackProps {
+ width?: number;
+ height?: number;
+ inline?: boolean;
+}
@observer
-export class UndoStack extends React.Component {
+export class UndoStack extends React.Component<UndoStackProps> {
+ @observable static HideInline: boolean;
+ @observable static Expand: boolean;
render() {
- return (
- <div className="scriptingRepl-outerContainer">
- <div className="scriptingRepl-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ background: UndoManager.batchCounter.get() ? 'yellow' : undefined }}>
+ return this.props.inline && UndoStack.HideInline ? null : (
+ <div
+ className="undoStack-outerContainer"
+ style={{ width: this.props.width, height: this.props.height ? (UndoStack.Expand ? 4 : 1) * this.props.height : undefined, top: UndoStack.Expand && this.props.height ? -this.props.height * 3 : undefined }}
+ onClick={action(e => (UndoStack.Expand = !UndoStack.Expand))}
+ onDoubleClick={action(e => (UndoStack.Expand = UndoStack.HideInline = false))}>
+ <div className="undoStack-commandsContainer" ref={r => r?.scroll({ behavior: 'auto', top: r?.scrollHeight + 20 })} style={{ background: UndoManager.batchCounter.get() ? 'yellow' : undefined }}>
+ <div className="undoStack-resultContainer" key={0}>
+ <div className="undoStack-commandString" style={{ fontWeight: 'bold', textAlign: 'center' }}>
+ Undo/Redo Stack
+ </div>
+ </div>
{UndoManager.undoStackNames.map((name, i) => (
- <div className="scriptingRepl-resultContainer" key={i}>
- <div className="scriptingRepl-commandString">{name.replace(/[^\.]*\./, '')}</div>
+ <div className="undoStack-resultContainer" key={i}>
+ <div className="undoStack-commandString">{name.replace(/[^\.]*\./, '')}</div>
</div>
))}
{Array.from(UndoManager.redoStackNames)
.reverse()
.map((name, i) => (
- <div className="scriptingRepl-resultContainer" key={i}>
- <div className="scriptingRepl-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
+ <div className="undoStack-resultContainer" key={i}>
+ <div className="undoStack-commandString" style={{ fontWeight: 'bold', color: 'red' }}>
{name.replace(/[^\.]*\./, '')}
</div>
</div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4ae24af60..76dadc76d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -23,6 +23,7 @@ import { LightboxView } from '../LightboxView';
import { OpenWhere, OpenWhereMod } from '../nodes/DocumentView';
import { OverlayView } from '../OverlayView';
import { ScriptingRepl } from '../ScriptingRepl';
+import { UndoStack } from '../UndoStack';
import './CollectionDockingView.scss';
import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
@@ -587,8 +588,12 @@ ScriptingGlobals.add(
case OpenWhere.addRight:
return CollectionDockingView.AddSplit(doc, OpenWhereMod.right);
case OpenWhere.overlay:
- if (doc === 'repl') OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
- else Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ // prettier-ignore
+ switch (doc) {
+ case '<ScriptingRepl />': return OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
+ case "<UndoStack>": return OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' });
+ }
+ Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
}
},
'opens up document in location specified',
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index 9d82e3198..e0c294da4 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -15,6 +15,7 @@ import { DocumentLinksButton } from '../../nodes/DocumentLinksButton';
import { DocumentView } from '../../nodes/DocumentView';
import { LinkDescriptionPopup } from '../../nodes/LinkDescriptionPopup';
import { StyleProp } from '../../StyleProvider';
+import { UndoStack } from '../../UndoStack';
import { CollectionStackedTimeline } from '../CollectionStackedTimeline';
import { CollectionSubView } from '../CollectionSubView';
import './CollectionLinearView.scss';
@@ -161,9 +162,15 @@ export class CollectionLinearView extends CollectionSubView() {
</span>
);
};
+
getDisplayDoc = (doc: Doc, preview: boolean = false) => {
- if (doc.icon === 'linkui') return this.getLinkUI();
- if (doc.icon === 'currentlyplayingui') return this.getCurrentlyPlayingUI();
+ // hack to avoid overhead of making UndoStack,etc into DocumentView style Boxes. If the UndoStack is ever intended to become part of the persisten state of the dashboard, then this would have to change.
+ // prettier-ignore
+ switch (doc.layout) {
+ case '<LinkingUI>': return this.getLinkUI();
+ case '<CurrentlyPlayingUI>': return this.getCurrentlyPlayingUI();
+ case '<UndoStack>': return <UndoStack width={200} height={40} inline={true} />;
+ }
const nested = doc._type_collection === CollectionViewType.Linear;
const hidden = doc.hidden === true;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 52eee84ac..10ef1e6af 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -506,7 +506,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
this._longPressSelector = setTimeout(() => {
if (DocumentView.LongPress) {
if (this.rootDoc.dontUndo) {
- OverlayView.Instance.addWindow(<UndoStack />, { x: 300, y: 100, width: 200, height: 200, title: 'Undo Stack' });
+ runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline));
} else {
this.props.select(false);
}