aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/DocComponent.tsx396
-rw-r--r--src/client/views/OverlayView.scss71
-rw-r--r--src/client/views/OverlayView.tsx390
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx3
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.scss2
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx6
-rw-r--r--src/client/views/nodes/VideoBox.tsx2
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx834
8 files changed, 853 insertions, 851 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 79aaf2158..103560a2a 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -17,223 +17,223 @@ import { Touchable } from './Touchable';
/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
export interface DocComponentProps {
- Document: Doc;
- LayoutTemplate?: () => Opt<Doc>;
- LayoutTemplateString?: string;
+ Document: Doc;
+ LayoutTemplate?: () => Opt<Doc>;
+ LayoutTemplateString?: string;
}
export function DocComponent<P extends DocComponentProps>() {
- class Component extends Touchable<P> {
- //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- @computed get Document() { return this.props.Document; }
- // This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
- // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return this.props.LayoutTemplateString ? this.props.Document : Doc.Layout(this.props.Document, this.props.LayoutTemplate?.()); }
- // This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.Document[DataSym] as Doc; }
-
- protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- }
- return Component;
+ class Component extends Touchable<P> {
+ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
+ @computed get Document() { return this.props.Document; }
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
+ @computed get layoutDoc() { return this.props.LayoutTemplateString ? this.props.Document : Doc.Layout(this.props.Document, this.props.LayoutTemplate?.()); }
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
+ @computed get dataDoc() { return this.props.Document[DataSym] as Doc; }
+
+ protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+ }
+ return Component;
}
/// FieldViewBoxProps - a generic base class for field views that are not annotatable (e.g. InkingStroke, ColorBox)
interface ViewBoxBaseProps {
- Document: Doc;
- DataDoc?: Doc;
- ContainingCollectionDoc: Opt<Doc>;
- DocumentView?: () => DocumentView;
- fieldKey: string;
- layerProvider?: (doc: Doc, assign?: boolean) => boolean;
- isSelected: (outsideReaction?: boolean) => boolean;
- isContentActive: () => boolean | undefined;
- renderDepth: number;
- rootSelected: (outsideReaction?: boolean) => boolean;
+ Document: Doc;
+ DataDoc?: Doc;
+ ContainingCollectionDoc: Opt<Doc>;
+ DocumentView?: () => DocumentView;
+ fieldKey: string;
+ layerProvider?: (doc: Doc, assign?: boolean) => boolean;
+ isSelected: (outsideReaction?: boolean) => boolean;
+ isContentActive: () => boolean | undefined;
+ renderDepth: number;
+ rootSelected: (outsideReaction?: boolean) => boolean;
}
export function ViewBoxBaseComponent<P extends ViewBoxBaseProps>() {
- class Component extends Touchable<P> {
- //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- //@computed get Document(): T { return schemaCtor(this.props.Document); }
-
- // This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
- // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
- // This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
-
- // key where data is stored
- @computed get fieldKey() { return this.props.fieldKey; }
-
- lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc }).result;
-
- isContentActive = (outsideReaction?: boolean) => (
- this.props.isContentActive?.() === false ? false :
- (CurrentUserUtils.SelectedTool !== InkTool.None ||
- (this.props.isContentActive?.() || this.props.Document.forceActive ||
- this.props.isSelected(outsideReaction) ||
- this.props.rootSelected(outsideReaction)) ? true : undefined))
- protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
- }
- return Component;
+ class Component extends Touchable<P> {
+ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
+ //@computed get Document(): T { return schemaCtor(this.props.Document); }
+
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
+ @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
+ @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+
+ // key where data is stored
+ @computed get fieldKey() { return this.props.fieldKey; }
+
+ lookupField = (field: string) => ScriptCast(this.layoutDoc.lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field, container: this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc }).result;
+
+ isContentActive = (outsideReaction?: boolean) => (
+ this.props.isContentActive?.() === false ? false :
+ (CurrentUserUtils.SelectedTool !== InkTool.None ||
+ (this.props.isContentActive?.() || this.props.Document.forceActive ||
+ this.props.isSelected(outsideReaction) ||
+ this.props.rootSelected(outsideReaction)) ? true : undefined))
+ protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+ }
+ return Component;
}
/// DocAnnotatbleComponent -return a base class for React views of document fields that are annotatable *and* interactive when selected (e.g., pdf, image)
export interface ViewBoxAnnotatableProps {
- Document: Doc;
- DataDoc?: Doc;
- fieldKey: string;
- filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
- layerProvider?: (doc: Doc, assign?: boolean) => boolean;
- isContentActive: () => boolean | undefined;
- select: (isCtrlPressed: boolean) => void;
- whenChildContentsActiveChanged: (isActive: boolean) => void;
- isSelected: (outsideReaction?: boolean) => boolean;
- rootSelected: (outsideReaction?: boolean) => boolean;
- renderDepth: number;
- isAnnotationOverlay?: boolean;
+ Document: Doc;
+ DataDoc?: Doc;
+ fieldKey: string;
+ filterAddDocument?: (doc: Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
+ layerProvider?: (doc: Doc, assign?: boolean) => boolean;
+ isContentActive: () => boolean | undefined;
+ select: (isCtrlPressed: boolean) => void;
+ whenChildContentsActiveChanged: (isActive: boolean) => void;
+ isSelected: (outsideReaction?: boolean) => boolean;
+ rootSelected: (outsideReaction?: boolean) => boolean;
+ renderDepth: number;
+ isAnnotationOverlay?: boolean;
}
export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>() {
- class Component extends Touchable<P> {
- @observable _annotationKeySuffix = () => "annotations";
-
- @observable _isAnyChildContentActive = false;
- //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
- @computed get Document() { return this.props.Document; }
- // This is the "The Document" -- it encapsulates, data, layout, and any templates
- @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
- // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
- @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
- // This is the data part of a document -- ie, the data that is constant across all views of the document
- @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
-
- // key where data is stored
- @computed get fieldKey() { return this.props.fieldKey; }
-
- isAnyChildContentActive = () => this._isAnyChildContentActive;
-
- lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
-
- styleFromLayoutString = (scale: number) => {
- const style: { [key: string]: any } = {};
- const divKeys = ["width", "height", "fontSize", "transform", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"];
- const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a property expression string: { script } into a value
- return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result?.toString() ?? "";
- };
- divKeys.map((prop: string) => {
- const p = (this.props as any)[prop];
- typeof p === "string" && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
- });
- return style;
- }
-
- protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
-
- @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? "-" + this._annotationKeySuffix() : ""); }
-
- @action.bound
- removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean {
- const effectiveAcl = GetEffectiveAcl(this.dataDoc);
- const indocs = doc instanceof Doc ? [doc] : doc;
- const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin);
- if (docs.length) {
- setTimeout(() => docs.map(doc => { // this allows 'addDocument' to see the annotationOn field in order to create a pushin
- Doc.SetInPlace(doc, "isPushpin", undefined, true);
- doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, "annotationOn", undefined, true);
- }));
- const targetDataDoc = this.dataDoc;
- const value = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
- const toRemove = value.filter(v => docs.includes(v));
-
- if (toRemove.length !== 0) {
- const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc;
- toRemove.forEach(doc => {
- leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
- Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
- doc.context = undefined;
- if (recent) {
- Doc.RemoveDocFromList(recent, "data", doc);
- Doc.AddDocToList(recent, "data", doc, undefined, true, true);
- }
- });
- this.isAnyChildContentActive() && this.props.select(false);
- return true;
- }
+ class Component extends Touchable<P> {
+ @observable _annotationKeySuffix = () => "annotations";
+
+ @observable _isAnyChildContentActive = false;
+ //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
+ @computed get Document() { return this.props.Document; }
+ // This is the "The Document" -- it encapsulates, data, layout, and any templates
+ @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
+ // This is the rendering data of a document -- it may be "The Document", or it may be some template document that holds the rendering info
+ @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
+ // This is the data part of a document -- ie, the data that is constant across all views of the document
+ @computed get dataDoc() { return this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : this.props.Document[DataSym]; }
+
+ // key where data is stored
+ @computed get fieldKey() { return this.props.fieldKey; }
+
+ isAnyChildContentActive = () => this._isAnyChildContentActive;
+
+ lookupField = (field: string) => ScriptCast((this.layoutDoc as any).lookupField)?.script.run({ self: this.layoutDoc, data: this.rootDoc, field: field }).result;
+
+ styleFromLayoutString = (scale: number) => {
+ const style: { [key: string]: any } = {};
+ const divKeys = ["width", "height", "fontSize", "transform", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"];
+ const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a property expression string: { script } into a value
+ return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result?.toString() ?? "";
+ };
+ divKeys.map((prop: string) => {
+ const p = (this.props as any)[prop];
+ typeof p === "string" && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
+ });
+ return style;
}
- return false;
- }
- // this is called with the document that was dragged and the collection to move it into.
- // if the target collection is the same as this collection, then the move will be allowed.
- // otherwise, the document being moved must be able to be removed from its container before
- // moving it into the target.
- @action.bound
- moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => {
- if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
- return true;
- }
- const first = doc instanceof Doc ? doc : doc[0];
- if (!first?._stayInCollection && addDocument !== returnFalse) {
- return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey));
+ protected _multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
+
+ @computed public get annotationKey() { return this.fieldKey + (this._annotationKeySuffix() ? "-" + this._annotationKeySuffix() : ""); }
+
+ @action.bound
+ removeDocument(doc: Doc | Doc[], annotationKey?: string, leavePushpin?: boolean): boolean {
+ const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+ const indocs = doc instanceof Doc ? [doc] : doc;
+ const docs = indocs.filter(doc => [AclEdit, AclAdmin].includes(effectiveAcl) || GetEffectiveAcl(doc) === AclAdmin);
+ if (docs.length) {
+ setTimeout(() => docs.map(doc => { // this allows 'addDocument' to see the annotationOn field in order to create a pushin
+ Doc.SetInPlace(doc, "isPushpin", undefined, true);
+ doc.annotationOn === this.props.Document && Doc.SetInPlace(doc, "annotationOn", undefined, true);
+ }));
+ const targetDataDoc = this.dataDoc;
+ const value = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
+ const toRemove = value.filter(v => docs.includes(v));
+
+ if (toRemove.length !== 0) {
+ const recent = Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc) as Doc;
+ toRemove.forEach(doc => {
+ leavePushpin && DocUtils.LeavePushpin(doc, annotationKey ?? this.annotationKey);
+ Doc.RemoveDocFromList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+ doc.context = undefined;
+ if (recent) {
+ Doc.RemoveDocFromList(recent, "data", doc);
+ Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ }
+ });
+ this.isAnyChildContentActive() && this.props.select(false);
+ return true;
+ }
+ }
+
+ return false;
}
- return false;
- }
- @action.bound
- addDocument = (doc: Doc | Doc[], annotationKey?: string): boolean => {
- const docs = doc instanceof Doc ? [doc] : doc;
- if (this.props.filterAddDocument?.(docs) === false ||
- docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
- return false;
+ // this is called with the document that was dragged and the collection to move it into.
+ // if the target collection is the same as this collection, then the move will be allowed.
+ // otherwise, the document being moved must be able to be removed from its container before
+ // moving it into the target.
+ @action.bound
+ moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[], annotationKey?: string) => boolean, annotationKey?: string): boolean => {
+ if (Doc.AreProtosEqual(this.props.Document, targetCollection)) {
+ return true;
+ }
+ const first = doc instanceof Doc ? doc : doc[0];
+ if (!first?._stayInCollection && addDocument !== returnFalse) {
+ return UndoManager.RunInTempBatch(() => this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey));
+ }
+ return false;
}
- const targetDataDoc = this.props.Document[DataSym];
- const docList = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
- const added = docs.filter(d => !docList.includes(d));
- const effectiveAcl = GetEffectiveAcl(this.dataDoc);
-
- if (added.length) {
- if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
- return false;
- }
- else {
- if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym]).length) {
- added.forEach(d => {
- for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
- if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d);
- }
- });
- }
-
- if (effectiveAcl === AclAugment) {
- added.map(doc => {
- if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
- doc.context = this.props.Document;
- if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
- this.props.layerProvider?.(doc, true);
- Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
- });
- }
- else {
- added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document
- this.props.layerProvider?.(doc, true);
- //DocUtils.LeavePushpin(doc);
- doc._stayInCollection = undefined;
- doc.context = this.props.Document;
- if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
-
- inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
- });
- const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
- if (annoDocs instanceof List) annoDocs.push(...added);
- else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
- targetDataDoc[(annotationKey ?? this.annotationKey) + "-lastModified"] = new DateField(new Date(Date.now()));
- }
- }
+ @action.bound
+ addDocument = (doc: Doc | Doc[], annotationKey?: string): boolean => {
+ const docs = doc instanceof Doc ? [doc] : doc;
+ if (this.props.filterAddDocument?.(docs) === false ||
+ docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
+ return false;
+ }
+ const targetDataDoc = this.props.Document[DataSym];
+ const docList = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]);
+ const added = docs.filter(d => !docList.includes(d));
+ const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+
+ if (added.length) {
+ if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
+ return false;
+ }
+ else {
+ if (this.props.Document[AclSym] && Object.keys(this.props.Document[AclSym]).length) {
+ added.forEach(d => {
+ for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+ if (d.author === denormalizeEmail(key.substring(4)) && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d);
+ }
+ });
+ }
+
+ if (effectiveAcl === AclAugment) {
+ added.map(doc => {
+ if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
+ doc.context = this.props.Document;
+ if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
+ this.props.layerProvider?.(doc, true);
+ Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
+ });
+ }
+ else {
+ added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => { // only make a pushpin if we have acl's to edit the document
+ this.props.layerProvider?.(doc, true);
+ //DocUtils.LeavePushpin(doc);
+ doc._stayInCollection = undefined;
+ doc.context = this.props.Document;
+ if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
+
+ inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
+ });
+ const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
+ if (annoDocs instanceof List) annoDocs.push(...added);
+ else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
+ targetDataDoc[(annotationKey ?? this.annotationKey) + "-lastModified"] = new DateField(new Date(Date.now()));
+ }
+ }
+ }
+ return true;
}
- return true;
- }
- whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
- }
- return Component;
+ whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged(this._isAnyChildContentActive = isActive));
+ }
+ return Component;
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index d6a6e4301..42efecb98 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -1,59 +1,60 @@
.overlayView {
- position: absolute;
- pointer-events: none;
- top: 0;
- width: 100vw;
- height: 100vh;
- /* background-color: pink; */
- z-index: 100000;
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ /* background-color: pink; */
+ z-index: 100000;
}
.overlayWindow-outerDiv {
- border-radius: 5px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- top: 0;
- left: 0;
+ border-radius: 5px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ top: 0;
+ left: 0;
}
.overlayWindow-outerDiv,
.overlayView-wrapperDiv {
- position: absolute;
- z-index: 1;
+ position: absolute;
+ z-index: 1;
}
.overlayWindow-titleBar {
- flex: 0 1 30px;
- background: darkslategray;
- color: whitesmoke;
- text-align: center;
- cursor: move;
+ flex: 0 1 30px;
+ background: darkslategray;
+ color: whitesmoke;
+ text-align: center;
+ cursor: move;
}
.overlayWindow-content {
- flex: 1 1 auto;
- display: flex;
- flex-direction: column;
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
}
.overlayWindow-closeButton {
- float: right;
- height: 30px;
- width: 30px;
+ float: right;
+ height: 30px;
+ width: 30px;
}
.overlayWindow-resizeDragger {
- background-color: rgb(0, 0, 0);
- position: absolute;
- right: 0px;
- bottom: 0px;
- width: 10px;
- height: 10px;
- cursor: nwse-resize;
+ background-color: rgb(0, 0, 0);
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ width: 10px;
+ height: 10px;
+ cursor: nwse-resize;
}
.overlayView-doc {
- z-index: 9002; //so that it appears above chroma
- position: absolute;
+ z-index: 9002; //so that it appears above chroma
+ position: absolute;
+ pointer-events: all;
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index f86406997..4b8e87b0f 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -2,7 +2,7 @@ import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
import ReactLoading from 'react-loading';
-import { Doc } from "../../fields/Doc";
+import { Doc, WidthSym, HeightSym } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { Cast, NumCast } from "../../fields/Types";
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from "../../Utils";
@@ -20,213 +20,213 @@ import { DefaultStyleProvider } from "./StyleProvider";
export type OverlayDisposer = () => void;
export type OverlayElementOptions = {
- x: number;
- y: number;
- width?: number;
- height?: number;
- title?: string;
+ x: number;
+ y: number;
+ width?: number;
+ height?: number;
+ title?: string;
};
export interface OverlayWindowProps {
- children: JSX.Element;
- overlayOptions: OverlayElementOptions;
- onClick: () => void;
+ children: JSX.Element;
+ overlayOptions: OverlayElementOptions;
+ onClick: () => void;
}
@observer
export class OverlayWindow extends React.Component<OverlayWindowProps> {
- @observable x: number;
- @observable y: number;
- @observable width: number;
- @observable height: number;
- constructor(props: OverlayWindowProps) {
- super(props);
-
- const opts = props.overlayOptions;
- this.x = opts.x;
- this.y = opts.y;
- this.width = opts.width || 200;
- this.height = opts.height || 200;
- }
-
- onPointerDown = (_: React.PointerEvent) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- onResizerPointerDown = (_: React.PointerEvent) => {
- document.removeEventListener("pointermove", this.onResizerPointerMove);
- document.removeEventListener("pointerup", this.onResizerPointerUp);
- document.addEventListener("pointermove", this.onResizerPointerMove);
- document.addEventListener("pointerup", this.onResizerPointerUp);
- }
-
- @action
- onPointerMove = (e: PointerEvent) => {
- this.x += e.movementX;
- this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0);
- this.y += e.movementY;
- this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0);
- }
-
- @action
- onResizerPointerMove = (e: PointerEvent) => {
- this.width += e.movementX;
- this.width = Math.max(this.width, 30);
- this.height += e.movementY;
- this.height = Math.max(this.height, 30);
- }
-
- onPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- onResizerPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onResizerPointerMove);
- document.removeEventListener("pointerup", this.onResizerPointerUp);
- }
-
- render() {
- return (
- <div className="overlayWindow-outerDiv" style={{ transform: `translate(${this.x}px, ${this.y}px)`, width: this.width, height: this.height }}>
- <div className="overlayWindow-titleBar" onPointerDown={this.onPointerDown} >
- {this.props.overlayOptions.title || "Untitled"}
- <button onClick={this.props.onClick} className="overlayWindow-closeButton">X</button>
- </div>
- <div className="overlayWindow-content">
- {this.props.children}
- </div>
- <div className="overlayWindow-resizeDragger" onPointerDown={this.onResizerPointerDown}></div>
- </div>
- );
- }
+ @observable x: number;
+ @observable y: number;
+ @observable width: number;
+ @observable height: number;
+ constructor(props: OverlayWindowProps) {
+ super(props);
+
+ const opts = props.overlayOptions;
+ this.x = opts.x;
+ this.y = opts.y;
+ this.width = opts.width || 200;
+ this.height = opts.height || 200;
+ }
+
+ onPointerDown = (_: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+
+ onResizerPointerDown = (_: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.onResizerPointerMove);
+ document.removeEventListener("pointerup", this.onResizerPointerUp);
+ document.addEventListener("pointermove", this.onResizerPointerMove);
+ document.addEventListener("pointerup", this.onResizerPointerUp);
+ }
+
+ @action
+ onPointerMove = (e: PointerEvent) => {
+ this.x += e.movementX;
+ this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0);
+ this.y += e.movementY;
+ this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0);
+ }
+
+ @action
+ onResizerPointerMove = (e: PointerEvent) => {
+ this.width += e.movementX;
+ this.width = Math.max(this.width, 30);
+ this.height += e.movementY;
+ this.height = Math.max(this.height, 30);
+ }
+
+ onPointerUp = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ onResizerPointerUp = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.onResizerPointerMove);
+ document.removeEventListener("pointerup", this.onResizerPointerUp);
+ }
+
+ render() {
+ return (
+ <div className="overlayWindow-outerDiv" style={{ transform: `translate(${this.x}px, ${this.y}px)`, width: this.width, height: this.height }}>
+ <div className="overlayWindow-titleBar" onPointerDown={this.onPointerDown} >
+ {this.props.overlayOptions.title || "Untitled"}
+ <button onClick={this.props.onClick} className="overlayWindow-closeButton">X</button>
+ </div>
+ <div className="overlayWindow-content">
+ {this.props.children}
+ </div>
+ <div className="overlayWindow-resizeDragger" onPointerDown={this.onResizerPointerDown}></div>
+ </div>
+ );
+ }
}
@observer
export class OverlayView extends React.Component {
- public static Instance: OverlayView;
- @observable.shallow
- private _elements: JSX.Element[] = [];
-
- constructor(props: any) {
- super(props);
- if (!OverlayView.Instance) {
- OverlayView.Instance = this;
- }
- }
-
- @action
- addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
- const remove = action(() => {
- const index = this._elements.indexOf(ele);
- if (index !== -1) this._elements.splice(index, 1);
+ public static Instance: OverlayView;
+ @observable.shallow
+ private _elements: JSX.Element[] = [];
+
+ constructor(props: any) {
+ super(props);
+ if (!OverlayView.Instance) {
+ OverlayView.Instance = this;
+ }
+ }
+
+ @action
+ addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+ const remove = action(() => {
+ const index = this._elements.indexOf(ele);
+ if (index !== -1) this._elements.splice(index, 1);
+ });
+ ele = <div key={Utils.GenerateGuid()} className="overlayView-wrapperDiv" style={{
+ transform: `translate(${options.x}px, ${options.y}px)`,
+ width: options.width,
+ height: options.height,
+ top: 0,
+ left: 0
+ }}>{ele}</div>;
+ this._elements.push(ele);
+ return remove;
+ }
+
+ @action
+ addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+ const remove = action(() => {
+ const index = this._elements.indexOf(contents);
+ if (index !== -1) this._elements.splice(index, 1);
+ });
+ contents = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{contents}</OverlayWindow>;
+ this._elements.push(contents);
+ return remove;
+ }
+
+
+ @computed get overlayDocs() {
+ return CurrentUserUtils.OverlayDocs?.map(d => {
+ let offsetx = 0, offsety = 0;
+ const dref = React.createRef<HTMLDivElement>();
+ const onPointerMove = action((e: PointerEvent, down: number[]) => {
+ if (e.buttons === 1) {
+ d.x = e.clientX + offsetx;
+ d.y = e.clientY + offsety;
+ }
+ if (e.metaKey) {
+ const dragData = new DragManager.DocumentDragData([d]);
+ dragData.offset = [-offsetx, -offsety];
+ dragData.dropAction = "move";
+ dragData.removeDocument = (doc: Doc | Doc[]) => {
+ const docs = (doc instanceof Doc) ? [doc] : doc;
+ docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d));
+ return true;
+ };
+ dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
+ return dragData.removeDocument!(doc) ? addDocument(doc) : false;
+ };
+ DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]);
+ return true;
+ }
+ return false;
});
- ele = <div key={Utils.GenerateGuid()} className="overlayView-wrapperDiv" style={{
- transform: `translate(${options.x}px, ${options.y}px)`,
- width: options.width,
- height: options.height,
- top: 0,
- left: 0
- }}>{ele}</div>;
- this._elements.push(ele);
- return remove;
- }
-
- @action
- addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
- const remove = action(() => {
- const index = this._elements.indexOf(contents);
- if (index !== -1) this._elements.splice(index, 1);
- });
- contents = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{contents}</OverlayWindow>;
- this._elements.push(contents);
- return remove;
- }
-
-
- @computed get overlayDocs() {
- return CurrentUserUtils.OverlayDocs?.map(d => {
- let offsetx = 0, offsety = 0;
- const dref = React.createRef<HTMLDivElement>();
- const onPointerMove = action((e: PointerEvent, down: number[]) => {
- if (e.buttons === 1) {
- d.x = e.clientX + offsetx;
- d.y = e.clientY + offsety;
- }
- if (e.metaKey) {
- const dragData = new DragManager.DocumentDragData([d]);
- dragData.offset = [-offsetx, -offsety];
- dragData.dropAction = "move";
- dragData.removeDocument = (doc: Doc | Doc[]) => {
- const docs = (doc instanceof Doc) ? [doc] : doc;
- docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d));
- return true;
- };
- dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
- return dragData.removeDocument!(doc) ? addDocument(doc) : false;
- };
- DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]);
- return true;
- }
- return false;
- });
-
- const onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction);
- offsetx = NumCast(d.x) - e.clientX;
- offsety = NumCast(d.y) - e.clientY;
- };
-
- return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
- <DocumentView
- Document={d}
- rootSelected={returnTrue}
- bringToFront={emptyFunction}
- addDocument={undefined}
- removeDocument={undefined}
- PanelWidth={() => NumCast(d._width)}
- PanelHeight={() => NumCast(d._height)}
- ScreenToLocalTransform={Transform.Identity}
- renderDepth={1}
- isDocumentActive={returnTrue}
- isContentActive={emptyFunction}
- whenChildContentsActiveChanged={emptyFunction}
- focus={DocUtils.DefaultFocus}
- styleProvider={DefaultStyleProvider}
- layerProvider={undefined}
- docViewPath={returnEmptyDoclist}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />
- </div>;
- });
- }
-
- public static ShowSpinner() {
- return OverlayView.Instance.addElement(<ReactLoading type="spinningBubbles" color="green" height={250} width={250} />, { x: 300, y: 200 });
- }
-
-
- render() {
- return (
- <div className="overlayView" id="overlayView">
- <div>
- {this._elements}
- </div>
- <CollectionFreeFormLinksView key="freeformLinks" />
- {this.overlayDocs}
- </div>
- );
- }
+
+ const onPointerDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction);
+ offsetx = NumCast(d.x) - e.clientX;
+ offsety = NumCast(d.y) - e.clientY;
+ };
+
+ return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
+ <DocumentView
+ Document={d}
+ rootSelected={returnTrue}
+ bringToFront={emptyFunction}
+ addDocument={undefined}
+ removeDocument={doc => (doc instanceof Doc ? [doc] : doc).map(doc => Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), "data", doc)).length ? true : false}
+ PanelWidth={d[WidthSym]}
+ PanelHeight={d[HeightSym]}
+ ScreenToLocalTransform={() => new Transform(-NumCast(d.x), -NumCast(d.y), 1)}
+ renderDepth={1}
+ isDocumentActive={returnTrue}
+ isContentActive={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={DocUtils.DefaultFocus}
+ styleProvider={DefaultStyleProvider}
+ layerProvider={undefined}
+ docViewPath={returnEmptyDoclist}
+ addDocTab={returnFalse}
+ pinToPres={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined} />
+ </div>;
+ });
+ }
+
+ public static ShowSpinner() {
+ return OverlayView.Instance.addElement(<ReactLoading type="spinningBubbles" color="green" height={250} width={250} />, { x: 300, y: 200 });
+ }
+
+
+ render() {
+ return (
+ <div className="overlayView" id="overlayView">
+ <div>
+ {this._elements}
+ </div>
+ <CollectionFreeFormLinksView key="freeformLinks" />
+ {this.overlayDocs}
+ </div>
+ );
+ }
}
// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error
ScriptingGlobals.add(function addOverlayWindow(type: string, options: OverlayElementOptions) {
- OverlayView.Instance.addWindow(<ScriptingRepl />, options);
+ OverlayView.Instance.addWindow(<ScriptingRepl />, options);
}); \ No newline at end of file
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 1b17476f7..d00f05759 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -40,7 +40,8 @@ export class RecordingBox extends ViewBoxBaseComponent() {
// console.log(this.videoDuration)
this.dataDoc[this.fieldKey + "-duration"] = this.videoDuration;
- this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
+ // this.layoutDoc.layout = VideoBox.LayoutString(this.fieldKey);
+ this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey);
// this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = undefined;
// this.layoutDoc._fitWidth = undefined;
this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.agnostic.client);
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss
index d1a50a82e..c55af5952 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.scss
+++ b/src/client/views/nodes/RecordingBox/RecordingView.scss
@@ -46,7 +46,7 @@ button {
padding: 14px;
width: 100%;
max-width: 500px;
- max-height: 20%;
+ // max-height: 20%;
flex-wrap: wrap;
background: rgba(255, 255, 255, 0.25);
box-shadow: 0 8px 32px 0 rgba(255, 255, 255, 0.1);
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index e7e431b49..0a8294dcf 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -86,8 +86,6 @@ export function RecordingView(props: IRecordingViewProps) {
}
})
- // this.dataDoc[this.fieldKey + "-duration"] = (new Date().getTime() - this.recordingStart!) / 1000;
-
}
@@ -282,9 +280,9 @@ export function RecordingView(props: IRecordingViewProps) {
{!recording && videos.length > 0 ?
<div className="video-edit-wrapper">
- <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons" }}>
+ {/* <IconContext.Provider value={{ color: "grey", className: "video-edit-buttons" }}>
<MdBackspace onClick={clearPrevious} />
- </IconContext.Provider>
+ </IconContext.Provider> */}
<IconContext.Provider value={{ color: "#cc1c08", className: "video-edit-buttons" }}>
<FaCheckCircle onClick={stop} />
</IconContext.Provider>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 226c2b1ce..8aecc2483 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -328,7 +328,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
if (Number.isFinite(this.player!.duration)) {
this.rawDuration = this.player!.duration;
- }
+ } else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + "-duration"]);
});
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 23c80253c..cd7b09017 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -31,427 +31,429 @@ import { List } from "../../../../fields/List";
*/
@observer
export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
- _heightDisposer: IReactionDisposer | undefined;
-
- @observable _dragging = false;
- // these fields are conditionally computed fields on the layout document that take this document as a parameter
- @computed get indexInPres() { return Number(this.lookupField("indexInPres")); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
- @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
- @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
- @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
- @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
- @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
-
-
- @observable isShowingVideo = false;
- @action setIsShowingVideo(shown: boolean) {
- this.isShowingVideo = shown
- }
-
- componentDidMount() {
- this.layoutDoc.hideLinkButton = true;
- this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
- params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
- }
- componentWillUnmount() {
- this._heightDisposer?.();
- }
-
- /**
- * Returns a local transformed coordinate array for given coordinates.
- */
- ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
-
- embedHeight = (): number => 97;
- // embedWidth = () => this.props.PanelWidth();
- // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
- embedWidth = (): number => this.props.PanelWidth() - 35;
- styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
- if (property === StyleProp.Opacity) return 1;
- return this.props.styleProvider?.(doc, props, property);
- }
- /**
- * The function that is responsible for rendering a preview or not for this
- * presentation element.
- */
- @computed get renderEmbeddedInline() {
- return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
- <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
- <DocumentView
- Document={this.targetDoc}
- DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
- styleProvider={this.styleProvider}
- layerProvider={this.props.layerProvider}
- docViewPath={returnEmptyDoclist}
- rootSelected={returnTrue}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- isContentActive={this.props.isContentActive}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- fitContentsToDoc={returnTrue}
- PanelWidth={this.embedWidth}
- PanelHeight={this.embedHeight}
- ScreenToLocalTransform={Transform.Identity}
- moveDocument={this.props.moveDocument!}
- renderDepth={this.props.renderDepth + 1}
- focus={DocUtils.DefaultFocus}
- whenChildContentsActiveChanged={returnFalse}
- bringToFront={returnFalse}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- hideLinkButton={true}
- />
- <div className="presItem-embeddedMask" />
- </div>;
- }
- @computed get duration() {
- let durationInS: number;
- if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
- else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
- else durationInS = 2;
- return "D: " + durationInS + "s";
- }
-
- @computed get transition() {
- let transitionInS: number;
- if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
- else transitionInS = 0.5;
- return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
- }
-
- private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _titleRef: React.RefObject<EditableView> = React.createRef();
-
-
- @action
- headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- const element = e.target as any;
- e.stopPropagation();
- e.preventDefault();
- if (element && !(e.ctrlKey || e.metaKey)) {
- if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
- PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
- setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
- } else {
- setupMoveUpEvents(this, e, ((e: PointerEvent) => {
- PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
- return this.startDrag(e);
- }), emptyFunction, emptyFunction);
- }
- }
- }
-
- headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
- e.stopPropagation();
- e.preventDefault();
- }
-
- /**
- * Function to drag and drop the pres element to a diferent location
- */
- startDrag = (e: PointerEvent) => {
- const miniView: boolean = this.toolbarWidth <= 100;
- const activeItem = this.rootDoc;
- const dragArray = PresBox.Instance._dragArray;
- const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
- if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
- dragData.dropAction = "move";
- dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc;
- dragData.moveDocument = this.props.docViewPath().lastElement()?.props.moveDocument;
- const dragItem: HTMLElement[] = [];
- if (dragArray.length === 1) {
- const doc = dragArray[0];
- doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
- dragItem.push(doc);
- } else if (dragArray.length >= 1) {
- const doc = document.createElement('div');
- doc.className = "presItem-multiDrag";
- doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
- doc.style.position = 'absolute';
- doc.style.top = (e.clientY) + 'px';
- doc.style.left = (e.clientX - 50) + 'px';
- dragItem.push(doc);
- }
-
- // const dropEvent = () => runInAction(() => this._dragging = false);
- if (activeItem) {
- DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
- // runInAction(() => this._dragging = true);
- return true;
- }
- return false;
- }
-
- onPointerOver = (e: any) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- }
-
- onPointerMove = (e: PointerEvent) => {
- const slide = this._itemRef.current!;
- let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
- for (const doc of DragManager.docsBeingDragged) {
- if (!doc.presentationTargetDoc) dragIsPresItem = false;
- }
- if (slide && dragIsPresItem) {
- const rect = slide.getBoundingClientRect();
- const y = e.clientY - rect.top; //y position within the element.
- const height = slide.clientHeight;
- const halfLine = height / 2;
- if (y <= halfLine) {
- slide.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
- slide.style.borderBottom = "0px";
- } else if (y > halfLine) {
- slide.style.borderTop = "0px";
- slide.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
- }
- }
- document.removeEventListener("pointermove", this.onPointerMove);
- }
-
- onPointerLeave = (e: any) => {
- this._itemRef.current!.style.borderTop = "0px";
- this._itemRef.current!.style.borderBottom = "0px";
- document.removeEventListener("pointermove", this.onPointerMove);
- }
-
- @action
- toggleProperties = () => {
- if (CurrentUserUtils.propertiesWidth < 5) {
- action(() => (CurrentUserUtils.propertiesWidth = 250));
- }
- }
-
- @undoBatch
- removeItem = action((e: React.MouseEvent) => {
- this.props.removeDocument?.(this.rootDoc);
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
+ _heightDisposer: IReactionDisposer | undefined;
+
+ @observable _dragging = false;
+ // these fields are conditionally computed fields on the layout document that take this document as a parameter
+ @computed get indexInPres() { return Number(this.lookupField("indexInPres")); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
+ @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
+ @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
+ @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
+ @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
+ @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
+
+
+ @observable isShowingVideo = false;
+ @action setIsShowingVideo(shown: boolean) {
+ this.isShowingVideo = shown
+ }
+
+ componentDidMount() {
+ this.layoutDoc.hideLinkButton = true;
+ this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
+ params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+ }
+ componentWillUnmount() {
+ this._heightDisposer?.();
+ }
+
+ /**
+ * Returns a local transformed coordinate array for given coordinates.
+ */
+ ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
+
+ embedHeight = (): number => 97;
+ // embedWidth = () => this.props.PanelWidth();
+ // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
+ embedWidth = (): number => this.props.PanelWidth() - 35;
+ styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+ if (property === StyleProp.Opacity) return 1;
+ return this.props.styleProvider?.(doc, props, property);
+ }
+ /**
+ * The function that is responsible for rendering a preview or not for this
+ * presentation element.
+ */
+ @computed get renderEmbeddedInline() {
+ return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
+ <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
+ <DocumentView
+ Document={this.targetDoc}
+ DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
+ styleProvider={this.styleProvider}
+ layerProvider={this.props.layerProvider}
+ docViewPath={returnEmptyDoclist}
+ rootSelected={returnTrue}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ isContentActive={this.props.isContentActive}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ fitContentsToDoc={returnTrue}
+ PanelWidth={this.embedWidth}
+ PanelHeight={this.embedHeight}
+ ScreenToLocalTransform={Transform.Identity}
+ moveDocument={this.props.moveDocument!}
+ renderDepth={this.props.renderDepth + 1}
+ focus={DocUtils.DefaultFocus}
+ whenChildContentsActiveChanged={returnFalse}
+ bringToFront={returnFalse}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ hideLinkButton={true}
+ />
+ <div className="presItem-embeddedMask" />
+ </div>;
+ }
+ @computed get duration() {
+ let durationInS: number;
+ if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
+ else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
+ else durationInS = 2;
+ return "D: " + durationInS + "s";
+ }
+
+ @computed get transition() {
+ let transitionInS: number;
+ if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
+ else transitionInS = 0.5;
+ return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
+ }
+
+ private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _titleRef: React.RefObject<EditableView> = React.createRef();
+
+
+ @action
+ headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
+ const element = e.target as any;
+ e.stopPropagation();
+ e.preventDefault();
+ if (element && !(e.ctrlKey || e.metaKey)) {
if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
- PresBox.Instance._selectedArray.delete(this.rootDoc);
+ PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+ setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+ } else {
+ setupMoveUpEvents(this, e, ((e: PointerEvent) => {
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+ return this.startDrag(e);
+ }), emptyFunction, emptyFunction);
}
- this.hideRecording();
- e.stopPropagation();
- });
-
- // set the value/title of the individual pres element
- @undoBatch
- @action
- onSetValue = (value: string) => {
- this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
+ }
+ }
+
+ headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ /**
+ * Function to drag and drop the pres element to a diferent location
+ */
+ startDrag = (e: PointerEvent) => {
+ const miniView: boolean = this.toolbarWidth <= 100;
+ const activeItem = this.rootDoc;
+ const dragArray = PresBox.Instance._dragArray;
+ const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
+ if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
+ dragData.dropAction = "move";
+ dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc;
+ dragData.moveDocument = this.props.docViewPath().lastElement()?.props.moveDocument;
+ const dragItem: HTMLElement[] = [];
+ if (dragArray.length === 1) {
+ const doc = dragArray[0];
+ doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
+ dragItem.push(doc);
+ } else if (dragArray.length >= 1) {
+ const doc = document.createElement('div');
+ doc.className = "presItem-multiDrag";
+ doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
+ doc.style.position = 'absolute';
+ doc.style.top = (e.clientY) + 'px';
+ doc.style.left = (e.clientX - 50) + 'px';
+ dragItem.push(doc);
+ }
+
+ // const dropEvent = () => runInAction(() => this._dragging = false);
+ if (activeItem) {
+ DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
+ // runInAction(() => this._dragging = true);
return true;
- }
-
- /**
- * Method called for updating the view of the currently selected document
- *
- * @param targetDoc
- * @param activeItem
- */
- @undoBatch
- @action
- updateView = (targetDoc: Doc, activeItem: Doc) => {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinViewScroll = scroll;
- } else if (targetDoc.type === DocumentType.VID) {
- activeItem.presPinTimecode = targetDoc._currentTimecode;
- } else if (targetDoc.type === DocumentType.COMPARISON) {
- const clipWidth = targetDoc._clipWidth;
- activeItem.presPinClipWidth = clipWidth;
- } else {
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
+ }
+ return false;
+ }
+
+ onPointerOver = (e: any) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
+ }
+
+ onPointerMove = (e: PointerEvent) => {
+ const slide = this._itemRef.current!;
+ let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
+ for (const doc of DragManager.docsBeingDragged) {
+ if (!doc.presentationTargetDoc) dragIsPresItem = false;
+ }
+ if (slide && dragIsPresItem) {
+ const rect = slide.getBoundingClientRect();
+ const y = e.clientY - rect.top; //y position within the element.
+ const height = slide.clientHeight;
+ const halfLine = height / 2;
+ if (y <= halfLine) {
+ slide.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+ slide.style.borderBottom = "0px";
+ } else if (y > halfLine) {
+ slide.style.borderTop = "0px";
+ slide.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
}
- }
-
- @computed get recordingIsInOverlay() {
- let isInOverlay = false
- DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
- if (doc.slides === this.rootDoc) {
- isInOverlay = true
- return
- }
- })
- return isInOverlay
- }
-
- @undoBatch
- @action
- hideRecording = () => {
- console.log("hide recording")
- DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
- if (doc.slides === this.rootDoc) {
- Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc);
- }
- })
- }
-
- @undoBatch
- @action
- startRecording = (targetDoc: Doc, activeItem: Doc) => {
- // Remove every recording that already exists in overlay view
- DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
- if (doc.slides !== null) {
- Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc);
- }
- })
-
- if (activeItem.recording) {
- // if we already have an existing recording
- console.log("recording exists")
- Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null));
-
- } else {
- console.log("creating new recording")
- // if we dont have any recording
- const recording = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
-
- // attach the recording to the slide, and attach the slide to the recording
- recording.slides = activeItem
- activeItem.recording = recording
-
- // TODO: Figure out exactly where we want the video to appear
- const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- recording.x = pt[0];
- recording.y = pt[1];
- console.log(pt)
- Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording);
+ }
+ document.removeEventListener("pointermove", this.onPointerMove);
+ }
+
+ onPointerLeave = (e: any) => {
+ this._itemRef.current!.style.borderTop = "0px";
+ this._itemRef.current!.style.borderBottom = "0px";
+ document.removeEventListener("pointermove", this.onPointerMove);
+ }
+
+ @action
+ toggleProperties = () => {
+ if (CurrentUserUtils.propertiesWidth < 5) {
+ action(() => (CurrentUserUtils.propertiesWidth = 250));
+ }
+ }
+
+ @undoBatch
+ removeItem = action((e: React.MouseEvent) => {
+ this.props.removeDocument?.(this.rootDoc);
+ if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
+ PresBox.Instance._selectedArray.delete(this.rootDoc);
+ }
+ this.hideRecording();
+ e.stopPropagation();
+ });
+
+ // set the value/title of the individual pres element
+ @undoBatch
+ @action
+ onSetValue = (value: string) => {
+ this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
+ return true;
+ }
+
+ /**
+ * Method called for updating the view of the currently selected document
+ *
+ * @param targetDoc
+ * @param activeItem
+ */
+ @undoBatch
+ @action
+ updateView = (targetDoc: Doc, activeItem: Doc) => {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const clipWidth = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = clipWidth;
+ } else {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ }
+ }
+
+ @computed get recordingIsInOverlay() {
+ let isInOverlay = false
+ DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
+ if (doc.slides === this.rootDoc) {
+ isInOverlay = true
+ return
+ }
+ })
+ return isInOverlay
+ }
+
+ @undoBatch
+ @action
+ hideRecording = () => {
+ console.log("hide recording")
+ DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
+ if (doc.slides === this.rootDoc) {
+ Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc);
}
- }
-
- @computed
- get toolbarWidth(): number {
- const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
- let width: number = NumCast(this.presBox._width);
- if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
- if (width === 0) width = 300;
- return width;
- }
-
- @computed get mainItem() {
- const isSelected: boolean = PresBox.Instance._selectedArray.has(this.rootDoc);
- const toolbarWidth: number = this.toolbarWidth;
- const showMore: boolean = this.toolbarWidth >= 300;
- const miniView: boolean = this.toolbarWidth <= 110;
- const presBox: Doc = this.presBox; //presBox
- const presBoxColor: string = StrCast(presBox._backgroundColor);
- const presColorBool: boolean = presBoxColor ? (presBoxColor !== Colors.WHITE && presBoxColor !== "transparent") : false;
- const targetDoc: Doc = this.targetDoc;
- const activeItem: Doc = this.rootDoc;
- return (
- <div className={`presItem-container`}
- key={this.props.Document[Id] + this.indexInPres}
- ref={this._itemRef}
- style={{
- backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? Colors.LIGHT_BLUE : "transparent",
- opacity: this._dragging ? 0.3 : 1
- }}
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
- PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
- }}
- onDoubleClick={action(e => {
- this.toggleProperties();
- PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
- })}
- onPointerOver={this.onPointerOver}
- onPointerLeave={this.onPointerLeave}
- onPointerDown={this.headerDown}
- onPointerUp={this.headerUp}
- >
- {miniView ?
- // when width is LESS than 110 px
- <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
- {`${this.indexInPres + 1}.`}
- </div>
- :
- // when width is MORE than 110 px
- <div className="presItem-number">
- {`${this.indexInPres + 1}.`}
- </div>}
- {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
- style={{
- backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
- boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
- }}>
- <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
- <EditableView
- ref={this._titleRef}
- editing={!isSelected ? false : undefined}
- contents={activeItem.title}
- overflow={'ellipsis'}
- GetValue={() => StrCast(activeItem.title)}
- SetValue={this.onSetValue}
- />
- </div>
- <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
- <div className={"presItem-slideButtons"}>
- <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
- <div className="slideButton"
- onClick={() => this.updateView(targetDoc, activeItem)}
- style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
- </Tooltip>
-
- {this.recordingIsInOverlay ?
- <Tooltip title={<><div className="dash-tooltip">{"Hide Recording"}</div></>}>
- <div className="slideButton"
- onClick={this.hideRecording}
- style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={"video-slash"} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip> :
- <Tooltip title={<><div className="dash-tooltip">{"Start recording"}</div></>}>
- <div className="slideButton"
- onClick={() => this.startRecording(targetDoc, activeItem)}
- style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={"video"} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- }
-
-
- {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
- <div className="slideButton"
- onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
- style={{
- zIndex: 1000 - this.indexInPres,
- fontWeight: 700,
- backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined,
- height: activeItem.groupWithUp ? 53 : 18,
- transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
- }}>
- <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
- <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
- </div>
- </div>
- </Tooltip>}
- {/* <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
+ })
+ }
+
+ @undoBatch
+ @action
+ startRecording = (targetDoc: Doc, activeItem: Doc) => {
+ // Remove every recording that already exists in overlay view
+ DocListCast((Doc.UserDoc().myOverlayDocs as Doc).data).forEach((doc) => {
+ if (doc.slides !== null) {
+ Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, doc);
+ }
+ })
+
+ if (activeItem.recording) {
+ // if we already have an existing recording
+ console.log("recording exists")
+ console.log(activeItem.recording)
+ console.log(Cast(activeItem.recording, Doc, null))
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null));
+
+ } else {
+ console.log("creating new recording")
+ // if we dont have any recording
+ const recording = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", cloneFieldFilter: new List<string>(["system"]) });
+
+ // attach the recording to the slide, and attach the slide to the recording
+ recording.slides = activeItem
+ activeItem.recording = recording
+
+ // TODO: Figure out exactly where we want the video to appear
+ const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ recording.x = pt[0];
+ recording.y = pt[1];
+ console.log(pt)
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording);
+ }
+ }
+
+ @computed
+ get toolbarWidth(): number {
+ const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
+ let width: number = NumCast(this.presBox._width);
+ if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
+ if (width === 0) width = 300;
+ return width;
+ }
+
+ @computed get mainItem() {
+ const isSelected: boolean = PresBox.Instance?._selectedArray.has(this.rootDoc);
+ const toolbarWidth: number = this.toolbarWidth;
+ const showMore: boolean = this.toolbarWidth >= 300;
+ const miniView: boolean = this.toolbarWidth <= 110;
+ const presBox: Doc = this.presBox; //presBox
+ const presBoxColor: string = StrCast(presBox._backgroundColor);
+ const presColorBool: boolean = presBoxColor ? (presBoxColor !== Colors.WHITE && presBoxColor !== "transparent") : false;
+ const targetDoc: Doc = this.targetDoc;
+ const activeItem: Doc = this.rootDoc;
+ return (
+ <div className={`presItem-container`}
+ key={this.props.Document[Id] + this.indexInPres}
+ ref={this._itemRef}
+ style={{
+ backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? Colors.LIGHT_BLUE : "transparent",
+ opacity: this._dragging ? 0.3 : 1
+ }}
+ onClick={e => {
+ e.stopPropagation();
+ e.preventDefault();
+ PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
+ }}
+ onDoubleClick={action(e => {
+ this.toggleProperties();
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
+ })}
+ onPointerOver={this.onPointerOver}
+ onPointerLeave={this.onPointerLeave}
+ onPointerDown={this.headerDown}
+ onPointerUp={this.headerUp}
+ >
+ {miniView ?
+ // when width is LESS than 110 px
+ <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
+ {`${this.indexInPres + 1}.`}
+ </div>
+ :
+ // when width is MORE than 110 px
+ <div className="presItem-number">
+ {`${this.indexInPres + 1}.`}
+ </div>}
+ {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
+ style={{
+ backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+ boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
+ }}>
+ <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
+ <EditableView
+ ref={this._titleRef}
+ editing={!isSelected ? false : undefined}
+ contents={activeItem.title}
+ overflow={'ellipsis'}
+ GetValue={() => StrCast(activeItem.title)}
+ SetValue={this.onSetValue}
+ />
+ </div>
+ <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
+ <div className={"presItem-slideButtons"}>
+ <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
+ <div className="slideButton"
+ onClick={() => this.updateView(targetDoc, activeItem)}
+ style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
+ </Tooltip>
+
+ {this.recordingIsInOverlay ?
+ <Tooltip title={<><div className="dash-tooltip">{"Hide Recording"}</div></>}>
+ <div className="slideButton"
+ onClick={this.hideRecording}
+ style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={"video-slash"} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip> :
+ <Tooltip title={<><div className="dash-tooltip">{"Start recording"}</div></>}>
+ <div className="slideButton"
+ onClick={() => this.startRecording(targetDoc, activeItem)}
+ style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={"video"} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>
+ }
+
+
+ {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
+ <div className="slideButton"
+ onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
+ style={{
+ zIndex: 1000 - this.indexInPres,
+ fontWeight: 700,
+ backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined,
+ height: activeItem.groupWithUp ? 53 : 18,
+ transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
+ }}>
+ <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
+ <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </div>
+ </Tooltip>}
+ {/* <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
<FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
</div></Tooltip> */}
- <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
- className={"slideButton"}
- onClick={this.removeItem}>
- <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
- </div></Tooltip>
- </div>
- <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
- {this.renderEmbeddedInline}
- </div>}
- </div >);
- }
-
- render() {
- return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
- }
+ <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
+ className={"slideButton"}
+ onClick={this.removeItem}>
+ <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
+ </div></Tooltip>
+ </div>
+ <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
+ {this.renderEmbeddedInline}
+ </div>}
+ </div >);
+ }
+
+ render() {
+ return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
+ }
} \ No newline at end of file