aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/trails
diff options
context:
space:
mode:
authormehekj <mehek.jethani@gmail.com>2022-11-07 12:57:52 -0500
committermehekj <mehek.jethani@gmail.com>2022-11-07 12:57:52 -0500
commita73521cdbccf9bed1326d24522e133fad4a0de26 (patch)
treee01371f6f845318831cf45f0dbc1d04d0d18f34c /src/client/views/nodes/trails
parent213a92ba3aa39d144754029fde32b9d69b0f51cf (diff)
parent31a51e9dda07e48c88166bffbc8f1ad7166cd624 (diff)
Merge branch 'master' into schema-mehek
Diffstat (limited to 'src/client/views/nodes/trails')
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx192
-rw-r--r--src/client/views/nodes/trails/PresElementBox.scss14
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx236
3 files changed, 247 insertions, 195 deletions
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 0c4d514cd..4e8aed8a6 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -5,14 +5,15 @@ import { action, computed, IReactionDisposer, observable, ObservableSet, reactio
import { observer } from 'mobx-react';
import { ColorState, SketchPicker } from 'react-color';
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { Doc, DocListCast, DocListCastAsync, FieldResult, Opt } from '../../../../fields/Doc';
-import { Copy } from '../../../../fields/FieldSymbols';
+import { Doc, DocListCast, FieldResult, StrListCast } from '../../../../fields/Doc';
+import { Copy, Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils';
+import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
@@ -29,6 +30,7 @@ import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
+import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresMovement, PresStatus } from './PresEnums';
@@ -36,14 +38,9 @@ export interface PinProps {
audioRange?: boolean;
activeFrame?: number;
hidePresBox?: boolean;
- pinWithView?: PinViewProps;
- pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document
- panelWidth?: number; // panel width and height of the document (used to compute the bounds of the pinned view area)
- panelHeight?: number;
-}
-
-export interface PinViewProps {
- bounds: MarqueeViewBounds;
+ pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected)
+ pinDocLayout?: boolean; // pin layout info (width/height/x/y)
+ pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text)
}
@observer
@@ -268,6 +265,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
this.nextSlide(0);
}
+ return this.itemIndex;
};
// Called when the user activates 'back' - to move to the previous part of the pres. trail
@@ -298,6 +296,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Case 3: Pres loop is on so it should go to the last slide
this.gotoDocument(this.childDocs.length - 1, activeItem);
}
+ return this.itemIndex;
};
//The function that is called when a document is clicked or reached through next or back.
@@ -351,16 +350,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any);
const clippable = [DocumentType.COMPARISON].includes(target.type as any);
- const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined;
+ const dataview = [DocumentType.INK, DocumentType.COL].includes(target.type as any) && target.activeFrame === undefined;
+ const poslayoutview = [DocumentType.COL].includes(target.type as any) && target.activeFrame === undefined;
const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined;
- return { scrollable, pannable, temporal, clippable, dataview, textview };
+ return { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview };
}
@action
static restoreTargetDocView(bestTarget: Doc, activeItem: Doc) {
const transTime = NumCast(activeItem.presTransition, 500);
const presTransitionTime = `all ${transTime}ms`;
- const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget);
+ const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(bestTarget);
bestTarget._viewTransition = presTransitionTime;
if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
if (temporal) bestTarget._currentTimecode = activeItem.presStartTime;
@@ -372,8 +372,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] });
}
}
- if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
- if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ if (dataview) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ if (textview) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ if (poslayoutview) {
+ StrListCast(activeItem.presPinLayoutData)
+ .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number })
+ .forEach(data => {
+ const doc = DocServer.GetCachedRefField(data.id) as Doc;
+ doc._dataTransition = presTransitionTime;
+ doc.x = data.x;
+ doc.y = data.y;
+ doc._width = data.w;
+ doc._height = data.h;
+ });
+ setTimeout(
+ () =>
+ StrListCast(activeItem.presPinLayoutData)
+ .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number })
+ .forEach(
+ action(data => {
+ const doc = DocServer.GetCachedRefField(data.id) as Doc;
+ doc._dataTransition = undefined;
+ })
+ ),
+ transTime + 10
+ );
+ }
if (pannable) {
const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
if (contentBounds) {
@@ -383,7 +407,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const dv = DocumentManager.Instance.getDocumentView(bestTarget);
if (dv) {
const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height);
- activeItem.presMovement === 'zoom' && (bestTarget._viewScale = activeItem.presZoom !== undefined ? computedScale : Math.min(computedScale, NumCast(bestTarget._viewScale)));
+ activeItem.presMovement === 'zoom' && (bestTarget._viewScale = computedScale);
dv.ComponentView?.brushView?.(viewport);
}
} else {
@@ -400,47 +424,41 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
/// target doc when navigating to it.
@action
static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) {
- if (pinProps?.pinWithView) {
- // If pinWithView option set then update scale and x / y props of slide
- const bounds = pinProps.pinWithView.bounds;
- pinDoc.presPinView = true;
- pinDoc.presPinViewX = bounds.left + bounds.width / 2;
- pinDoc.presPinViewY = bounds.top + bounds.height / 2;
- pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
- }
- if (pinProps?.pinDocView) {
- const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc);
- pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined;
+ const { scrollable, pannable, temporal, clippable, dataview, textview, poslayoutview } = this.pinDataTypes(pinDoc);
+ if (pinProps?.pinDocLayout) {
+ pinDoc.presPinLayout = true;
pinDoc.presX = NumCast(targetDoc.x);
pinDoc.presY = NumCast(targetDoc.y);
- pinDoc.presRot = NumCast(targetDoc.jitterRotation);
+ pinDoc.presRot = NumCast(targetDoc.rotation);
pinDoc.presWidth = NumCast(targetDoc.width);
pinDoc.presHeight = NumCast(targetDoc.height);
-
- if (scrollable) {
- pinDoc.presPinViewScroll = pinDoc._scrollTop;
- }
+ }
+ if (pinProps?.pinDocContent) {
+ pinDoc.presPinData = scrollable || temporal || pannable || clippable || dataview || textview || poslayoutview || pinProps.activeFrame !== undefined;
+ if (dataview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.data;
+ if (textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text;
+ if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop;
if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth;
+ if (poslayoutview) pinDoc.presPinLayoutData = new List<string>(DocListCast(pinDoc.presData).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) })));
+ if (pannable) {
+ pinDoc.presPinViewX = NumCast(pinDoc._panX);
+ pinDoc.presPinViewY = NumCast(pinDoc._panY);
+ pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1);
+ }
if (temporal) {
pinDoc.presStartTime = pinDoc._currentTimecode;
const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(pinDoc.presStartTime) + 0.1);
pinDoc.presEndTime = NumCast(pinDoc.clipEnd, duration);
}
- if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text;
- if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data;
- if (pannable || scrollable) {
- const panX = NumCast(pinDoc._panX);
- const panY = NumCast(pinDoc._panY);
- const pw = NumCast(pinProps.panelWidth);
- const ph = NumCast(pinProps.panelHeight);
- const ps = NumCast(pinDoc._viewScale, 1);
- if (pw && ph && ps) {
- pinDoc.presPinViewBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
- }
- pinDoc.presPinViewX = panX;
- pinDoc.presPinViewY = panY;
- pinDoc.presPinViewScale = ps;
- }
+ }
+ if (pinProps?.pinViewport) {
+ // If pinWithView option set then update scale and x / y props of slide
+ const bounds = pinProps.pinViewport;
+ pinDoc.presPinView = true;
+ pinDoc.presPinViewScale = NumCast(pinDoc._viewScale, 1);
+ pinDoc.presPinViewX = bounds.left + bounds.width / 2;
+ pinDoc.presPinViewY = bounds.top + bounds.height / 2;
+ pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
}
}
@@ -497,13 +515,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) {
- if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) {
+ if ((activeItem.presPinLayout || activeItem.presPinView) && DocCast(targetDoc.context)?._currentFrame === undefined) {
const transTime = NumCast(activeItem.presTransition, 500);
const presTransitionTime = `all ${transTime}ms`;
targetDoc._dataTransition = presTransitionTime;
targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x));
targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y));
- targetDoc.jitterRotation = NumCast(activeItem.presRot, NumCast(targetDoc.jitterRotation));
+ targetDoc.rotation = NumCast(activeItem.presRot, NumCast(targetDoc.rotation));
targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width));
targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height));
setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10);
@@ -514,11 +532,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
} else if (targetDoc && activeItem.presMovement !== PresMovement.None) {
LightboxView.SetLightboxDoc(undefined);
const zooming = activeItem.presMovement !== PresMovement.Pan;
- DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom));
+ DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom, 1));
+ } else if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) {
+ (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
}
// After navigating to the document, if it is added as a presPinView then it will
// adjust the pan and scale to that of the pinView when it was added.
- if (activeItem.presPinView) {
+ if (activeItem.presPinData || activeItem.presPinView) {
clearTimeout(PresBox._navTimer);
// targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc
const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
@@ -615,42 +635,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
@action
startAutoPres = (startSlide: number) => {
- this.updateCurrentPresentation();
- let activeItem: Doc = this.activeItem;
- let targetDoc: Doc = this.targetDoc;
- let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
- const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms)));
- const load = async () => {
- // Wrap the loop into an async function for this to work
- for (var i = startSlide; i < this.childDocs.length; i++) {
- activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
- duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
- if (duration < 100) {
- duration = 2500;
- }
- if (NumCast(targetDoc.lastFrame) > 0) {
- for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
- await timer(duration / NumCast(targetDoc.lastFrame));
- this.next();
- }
- }
-
- await timer(duration);
- this.next(); // then the created Promise can be awaited
- if (i === this.childDocs.length - 1) {
- setTimeout(() => {
- clearTimeout(this._presTimer);
- if (this.layoutDoc.presStatus === 'auto' && !this.layoutDoc.presLoop) this.layoutDoc.presStatus = PresStatus.Manual;
- else if (this.layoutDoc.presLoop) this.startAutoPres(0);
- }, duration);
- }
- }
- };
this.layoutDoc.presStatus = PresStatus.Autoplay;
this.startPresentation(startSlide);
- this.gotoDocument(startSlide, activeItem);
- load();
+ clearTimeout(this._presTimer);
+ const func = (itemIndex: number) => {
+ if (itemIndex === this.next()) this.layoutDoc.presStatus = PresStatus.Manual;
+ else
+ this._presTimer = setTimeout(
+ () => this.layoutDoc.presStatus !== PresStatus.Manual && func(this.itemIndex),
+ NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition)
+ );
+ };
+
+ func(this.itemIndex);
};
// The function pauses the auto presentation
@@ -659,7 +656,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (this.layoutDoc.presStatus === PresStatus.Autoplay) {
if (this._presTimer) clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
- this.layoutDoc.presLoop = false;
this.childDocs.forEach(this.stopTempMedia);
}
};
@@ -667,7 +663,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//The function that resets the presentation by removing every action done by it. It also
//stops the presentaton.
resetPresentation = () => {
- this.rootDoc._itemIndex = 0;
this.childDocs
.map(doc => Cast(doc.presentationTargetDoc, Doc, null))
.filter(doc => doc instanceof Doc)
@@ -706,8 +701,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
* @param startIndex: index that the presentation will start at
*/
startPresentation = (startIndex: number) => {
- this.updateCurrentPresentation();
- this.childDocs.map(doc => {
+ this.childDocs.forEach(doc => {
const tagDoc = doc.presentationTargetDoc as Doc;
if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) {
tagDoc.opacity = 0;
@@ -716,6 +710,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
tagDoc.opacity = 0;
}
});
+ this.gotoDocument(startIndex, this.activeItem);
};
/**
@@ -996,7 +991,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
break;
case 'Spacebar':
case ' ':
- if (this.layoutDoc.presStatus === PresStatus.Manual) this.startAutoPres(this.itemIndex);
+ if (this.layoutDoc.presStatus === PresStatus.Manual) this.startOrPause(true);
else if (this.layoutDoc.presStatus === PresStatus.Autoplay) if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
break;
@@ -1254,7 +1249,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (activeItem && targetDoc) {
const type = targetDoc.type;
const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
- const zoom = activeItem.presZoom ? NumCast(activeItem.presZoom) * 100 : 75;
+ const zoom = NumCast(activeItem.presZoom, 1) * 100;
let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
const effect = this.activeItem.presEffect ? this.activeItem.presEffect : 'None';
@@ -1808,6 +1803,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
+ scrollFocus = () => {
+ this.startOrPause(false);
+ return undefined;
+ };
+
// Case in which the document has keyframes to navigate to next key frame
@action
nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
@@ -2480,7 +2480,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'arrow-left'} />
</div>
<Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
- <div className="presPanel-button" onClick={this.startOrPause}>
+ <div className="presPanel-button" onClick={e => this.startOrPause(true)}>
<FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
</div>
</Tooltip>
@@ -2529,7 +2529,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@action
- startOrPause = () => {
+ startOrPause = (makeActive = true) => {
+ makeActive && this.updateCurrentPresentation();
if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex);
else this.pauseAutoPres();
};
@@ -2613,7 +2614,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'arrow-left'} />
</div>
<Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
- <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
+ <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.startOrPause(true), false, false)}>
<FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} />
</div>
</Tooltip>
@@ -2651,9 +2652,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
PanelHeight={this.panelHeight}
childIgnoreNativeSize={true}
moveDocument={returnFalse}
- childFitWidth={returnTrue}
+ //childFitWidth={returnTrue}
childOpacity={returnOne}
childLayoutTemplate={this.childLayoutTemplate}
+ childXPadding={Doc.IsComicStyle(this.rootDoc) ? 20 : undefined}
filterAddDocument={this.addDocumentFilter}
removeDocument={returnFalse}
dontRegisterView={true}
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
index 8a6c2a6dc..415253af1 100644
--- a/src/client/views/nodes/trails/PresElementBox.scss
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -42,10 +42,7 @@ $slide-active: #5b9fdd;
width: 100%;
border-bottom: 0.5px solid grey;
display: flex;
- justify-content: space-between;
align-items: center;
- grid-template-rows: 16px 10px auto;
- grid-template-columns: max-content max-content max-content max-content auto;
.presItem-name {
display: flex;
@@ -102,13 +99,7 @@ $slide-active: #5b9fdd;
grid-row: 3;
grid-column: 1/8;
position: relative;
- display: flex;
- width: auto;
- justify-content: center;
- margin: auto;
- margin-bottom: 2px;
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
+ display: inline-block;
}
.presItem-embeddedMask {
@@ -124,8 +115,7 @@ $slide-active: #5b9fdd;
.presItem-slideButtons {
display: flex;
- grid-column: 7;
- grid-row: 1/3;
+ position: absolute;
width: max-content;
justify-self: right;
justify-content: flex-end;
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index e6d08cd53..5d14a0e9a 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -4,7 +4,9 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'
import { observer } from 'mobx-react';
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
import { Copy, Id } from '../../../../fields/FieldSymbols';
+import { InkField } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
+import { RichTextField } from '../../../../fields/RichTextField';
import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
import { Docs, DocUtils } from '../../../documents/Documents';
@@ -14,6 +16,7 @@ import { DragManager } from '../../../util/DragManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { Transform } from '../../../util/Transform';
import { undoBatch } from '../../../util/UndoManager';
+import { MarqueeView } from '../../collections/collectionFreeForm';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { Colors } from '../../global/globalEnums';
@@ -24,8 +27,6 @@ import { PresBox } from './PresBox';
import './PresElementBox.scss';
import { PresMovement } from './PresEnums';
import React = require('react');
-import { InkField } from '../../../../fields/InkField';
-import { RichTextField } from '../../../../fields/RichTextField';
/**
* This class models the view a document added to presentation will have in the presentation.
* It involves some functionality for its buttons and options.
@@ -43,8 +44,11 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get indexInPres() {
return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
} // 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 expandViewHeight() {
+ return 100;
+ }
@computed get collapsedHeight() {
- return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(this.presBox._viewType as any) ? 35 : 31;
+ return 35;
} // 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 this.presBox.presStatus;
@@ -57,7 +61,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined;
}
@computed get presBox() {
- return (this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc)!;
+ return this.props.ContainingCollectionDoc!;
}
@computed get targetDoc() {
return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc;
@@ -66,8 +70,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
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)),
+ () => ({ expand: this.rootDoc.presExpandInlineButton, height: this.collapsedHeight }),
+ ({ expand, height }) => (this.layoutDoc._height = height + (expand ? this.expandViewHeight : 0)),
{ fireImmediately: true }
);
}
@@ -83,10 +87,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton);
- embedHeight = (): number => 97;
+ embedHeight = (): number => this.collapsedHeight + this.expandViewHeight;
// embedWidth = () => this.props.PanelWidth();
// embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
- embedWidth = (): number => this.props.PanelWidth() - 35;
+ embedWidth = (): number => this.props.PanelWidth() / 2;
styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (property === StyleProp.Opacity) return 1;
return this.props.styleProvider?.(doc, props, property);
@@ -97,35 +101,35 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
@computed get renderEmbeddedInline() {
return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? null : (
- <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
+ <div className="presItem-embedded" style={{ height: this.embedHeight(), width: '50%' }}>
<DocumentView
Document={this.rootDoc}
DataDoc={undefined} //this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
+ PanelWidth={this.embedWidth}
+ PanelHeight={this.embedHeight}
+ isContentActive={this.props.isContentActive}
styleProvider={this.styleProvider}
+ hideLinkButton={true}
+ ScreenToLocalTransform={Transform.Identity}
+ renderDepth={this.props.renderDepth + 1}
docViewPath={returnEmptyDoclist}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
rootSelected={returnTrue}
addDocument={returnFalse}
removeDocument={returnFalse}
- isContentActive={this.props.isContentActive}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
fitContentsToBox={returnTrue}
- PanelWidth={this.embedWidth}
- PanelHeight={this.embedHeight}
- ScreenToLocalTransform={Transform.Identity}
moveDocument={this.props.moveDocument!}
- renderDepth={this.props.renderDepth + 1}
focus={DocUtils.DefaultFocus}
whenChildContentsActiveChanged={returnFalse}
+ addDocTab={returnFalse}
+ pinToPres={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 className="presItem-embeddedMask" /> */}
</div>
);
}
@@ -142,7 +146,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.presExpandDocumentClick();
}}>
<div className="presItem-groupNum">{`${ind + 1}.`}</div>
- {/* style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }} */}
<div className="presItem-name">
<EditableView
ref={this._titleRef}
@@ -206,8 +209,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const dragData = new DragManager.DocumentDragData(this.presBoxView?.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;
+ dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
+ dragData.moveDocument = this.props.moveDocument;
const dragItem: HTMLElement[] = [];
if (dragArray.length === 1) {
const doc = this._itemRef.current || dragArray[0];
@@ -304,7 +307,22 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
@undoBatch
@action
- updateView = (targetDoc: Doc, activeItem: Doc) => {
+ updateCapturedContainerLayout = (targetDoc: Doc, activeItem: Doc) => {
+ activeItem.presX = NumCast(targetDoc.x);
+ activeItem.presY = NumCast(targetDoc.y);
+ activeItem.presRot = NumCast(targetDoc.rotation);
+ activeItem.presWidth = NumCast(targetDoc.width);
+ activeItem.presHeight = NumCast(targetDoc.height);
+ };
+ /**
+ * Method called for updating the view of the currently selected document
+ *
+ * @param targetDoc
+ * @param activeItem
+ */
+ @undoBatch
+ @action
+ updateCapturedViewContents = (targetDoc: Doc, activeItem: Doc) => {
switch (targetDoc.type) {
case DocumentType.PDF:
case DocumentType.WEB:
@@ -312,11 +330,11 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const scroll = targetDoc._scrollTop;
activeItem.presPinViewScroll = scroll;
if (targetDoc.type === DocumentType.RTF) {
- activeItem.presData = targetDoc.text instanceof RichTextField ? targetDoc.text[Copy]() : targetDoc.text;
+ activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof RichTextField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as RichTextField)[Copy]() : targetDoc.text;
}
break;
case DocumentType.INK:
- activeItem.presData = targetDoc.data instanceof InkField ? targetDoc.data[Copy]() : targetDoc.data;
+ activeItem.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof InkField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as InkField)[Copy]() : targetDoc.data;
break;
case DocumentType.VID:
case DocumentType.AUDIO:
@@ -326,20 +344,23 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
const clipWidth = targetDoc._clipWidth;
activeItem.presPinClipWidth = clipWidth;
break;
+ case DocumentType.COL:
+ activeItem.presPinLayoutData = new List<string>(DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) })));
default:
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
+ const bestView = DocumentManager.Instance.getFirstDocumentView(targetDoc);
+ if (activeItem.presPinViewBounds && bestView) {
+ const bounds = MarqueeView.CurViewBounds(targetDoc, bestView.props.PanelWidth(), bestView.props.PanelHeight());
+ activeItem.presPinView = true;
+ activeItem.presPinViewScale = NumCast(targetDoc._viewScale, 1);
+ activeItem.presPinViewX = bounds.left + bounds.width / 2;
+ activeItem.presPinViewY = bounds.top + bounds.height / 2;
+ activeItem.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
+ } else {
+ activeItem.presPinViewX = targetDoc._panX;
+ activeItem.presPinViewY = targetDoc._panY;
+ activeItem.presPinViewScale = targetDoc._viewScale;
+ }
}
-
- activeItem.presX = NumCast(targetDoc.x);
- activeItem.presY = NumCast(targetDoc.y);
- activeItem.presRot = NumCast(targetDoc.jitterRotation);
- activeItem.presWidth = NumCast(targetDoc.width);
- activeItem.presHeight = NumCast(targetDoc.height);
};
@computed get recordingIsInOverlay() {
@@ -446,16 +467,90 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
return width;
}
+ @computed get presButtons() {
+ 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;
+
+ const items: JSX.Element[] = [];
+ if (activeItem.presPinLayout) {
+ items.push(
+ <Tooltip key="slide" title={<div className="dash-tooltip">Update captured doc layout</div>}>
+ <div className="slideButton" onClick={() => this.updateCapturedContainerLayout(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}>
+ L
+ </div>
+ </Tooltip>
+ );
+ }
+ if (activeItem.presPinData || activeItem.presPinView) {
+ items.push(
+ <Tooltip key="flex" title={<div className="dash-tooltip">Update captured doc content</div>}>
+ <div className="slideButton" onClick={() => this.updateCapturedViewContents(targetDoc, activeItem)} style={{ fontWeight: 700, display: 'flex' }}>
+ C
+ </div>
+ </Tooltip>
+ );
+ }
+ if (!Doc.noviceMode) {
+ items.push(
+ <Tooltip key="slash" title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
+ <div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={`video${this.recordingIsInOverlay ? '-slash' : ''}`} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>
+ );
+ }
+ if (this.indexInPres === 0) {
+ items.push(
+ <Tooltip key="arrow" 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>
+ );
+ }
+ items.push(
+ <Tooltip key="eye" 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>
+ );
+ items.push(
+ <Tooltip key="trash" title={<div className="dash-tooltip">Remove from presentation</div>}>
+ <div className={'slideButton'} onClick={this.removeItem}>
+ <FontAwesomeIcon icon={'trash'} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>
+ );
+ return items;
+ }
+
@computed get mainItem() {
const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres;
- 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 (
@@ -466,6 +561,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{
backgroundColor: presColorBool ? (isSelected ? 'rgba(250,250,250,0.3)' : 'transparent') : isSelected ? Colors.LIGHT_BLUE : 'transparent',
opacity: this._dragging ? 0.3 : 1,
+ paddingLeft: NumCast(this.layoutDoc._xPadding, this.props.xPadding),
+ paddingRight: NumCast(this.layoutDoc._xPadding, this.props.xPadding),
+ paddingTop: NumCast(this.layoutDoc._yPadding, this.props.yPadding),
+ paddingBottom: NumCast(this.layoutDoc._yPadding, this.props.yPadding),
}}
onClick={e => {
e.stopPropagation();
@@ -489,6 +588,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
ref={this._dragRef}
className={`presItem-slide ${isCurrent ? 'active' : ''}`}
style={{
+ display: 'infline-block',
backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
//boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined,
@@ -496,8 +596,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div
className="presItem-name"
style={{
+ display: 'inline-flex',
pointerEvents: isSelected ? undefined : 'none',
- maxWidth: showMore ? toolbarWidth - 195 : toolbarWidth - 105,
+ width: `calc(100% ${this.rootDoc.presExpandInlineButton ? '- 50%' : ''} - ${this.presButtons.length * 22}px`,
cursor: isSelected ? 'text' : 'grab',
}}>
<div>{`${this.indexInPres + 1}. `}</div>
@@ -505,49 +606,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
</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>
- {!Doc.noviceMode && <Tooltip title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
- <div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={`video${this.recordingIsInOverlay ? '-slash' : ''}`} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>}
- <Tooltip title={<div className="dash-tooltip">{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}</div>}>
- <div
- className="slideButton"
- onClick={() => (activeItem.groupWithUp = !activeItem.groupWithUp)}
- style={{
- display: this.indexInPres === 0 ? 'none' : '',
- 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 className="presItem-slideButtons" style={{ position: 'absolute', right: 0 }}>
+ {...this.presButtons}
</div>
{this.renderEmbeddedInline}
</div>