aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/trails/PresBox.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-04-05 22:44:03 -0400
committerbobzel <zzzman@gmail.com>2023-04-05 22:44:03 -0400
commit9b41da1af16b982ee8ac2fc09f2f8b5d67eac9fb (patch)
treebc3f57cd5b31fd453d272c925f6d5b728ab63bae /src/client/views/nodes/trails/PresBox.tsx
parent9dae453967183b294bf4f7444b948023a1d52d39 (diff)
parent8f7e99641f84ad15f34ba9e4a60b664ac93d2e5d (diff)
Merge branch 'master' into data-visualization-view-naafi
Diffstat (limited to 'src/client/views/nodes/trails/PresBox.tsx')
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx3563
1 files changed, 1432 insertions, 2131 deletions
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3bbdce1e4..bfaae8069 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1,49 +1,66 @@
import React = require('react');
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx';
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 } from '../../../../fields/Doc';
-import { InkTool } from '../../../../fields/InkField';
+import { AnimationSym, Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc';
+import { Copy, Id } from '../../../../fields/FieldSymbols';
+import { InkField, InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
+import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
+import { ComputedField, ScriptField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils';
+import { AudioField } from '../../../../fields/URLField';
+import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils';
+import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { SelectionManager } from '../../../util/SelectionManager';
+import { SerializationHelper } from '../../../util/SerializationHelper';
import { SettingsManager } from '../../../util/SettingsManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
-import { MarqueeViewBounds } from '../../collections/collectionFreeForm';
+import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm';
+import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline';
import { CollectionView } from '../../collections/CollectionView';
import { TabDocView } from '../../collections/TabDocView';
import { ViewBoxBaseComponent } from '../../DocComponent';
import { Colors } from '../../global/globalEnums';
import { LightboxView } from '../../LightboxView';
-import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView';
+import { DocFocusOptions, DocumentView, OpenWhere, OpenWhereMod } from '../DocumentView';
import { FieldView, FieldViewProps } from '../FieldView';
+import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
-import { PresEffect, PresMovement, PresStatus } from './PresEnums';
-import { CollectionFreeFormViewChrome } from '../../collections/CollectionMenu';
-
+import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums';
+const { Howl } = require('howler');
+
+export interface pinDataTypes {
+ scrollable?: boolean;
+ pannable?: boolean;
+ viewType?: boolean;
+ inkable?: boolean;
+ filters?: boolean;
+ pivot?: boolean;
+ temporal?: boolean;
+ clippable?: boolean;
+ datarange?: boolean;
+ dataview?: boolean;
+ textview?: boolean;
+ poslayoutview?: boolean;
+ dataannos?: boolean;
+}
export interface PinProps {
audioRange?: boolean;
activeFrame?: number;
+ currentFrame?: 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;
- scale: number;
+ 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)
+ pinAudioPlay?: boolean; // pin audio annotation
+ pinData?: pinDataTypes;
}
@observer
@@ -51,68 +68,40 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(PresBox, fieldKey);
}
+ static navigateToDocScript: ScriptField;
- /**
- * transitions & effects for documents
- * @param renderDoc
- * @param layoutDoc
- */
- static renderEffectsDoc(renderDoc: any, layoutDoc: Doc, presDoc: Doc) {
- const effectProps = {
- left: presDoc.presEffectDirection === PresEffect.Left,
- right: presDoc.presEffectDirection === PresEffect.Right,
- top: presDoc.presEffectDirection === PresEffect.Top,
- bottom: presDoc.presEffectDirection === PresEffect.Bottom,
- opposite: true,
- delay: presDoc.presTransition,
- // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
- };
- switch (presDoc.presEffect) {
- case PresEffect.Zoom:
- return <Zoom {...effectProps}>{renderDoc}</Zoom>;
- case PresEffect.Fade:
- return <Fade {...effectProps}>{renderDoc}</Fade>;
- case PresEffect.Flip:
- return <Flip {...effectProps}>{renderDoc}</Flip>;
- case PresEffect.Rotate:
- return <Rotate {...effectProps}>{renderDoc}</Rotate>;
- case PresEffect.Bounce:
- return <Bounce {...effectProps}>{renderDoc}</Bounce>;
- case PresEffect.Roll:
- return <Roll {...effectProps}>{renderDoc}</Roll>;
- case PresEffect.Lightspeed:
- return <LightSpeed {...effectProps}>{renderDoc}</LightSpeed>;
- case PresEffect.None:
- default:
- return renderDoc;
+ constructor(props: any) {
+ super(props);
+ if (!PresBox.navigateToDocScript) {
+ PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)')!;
}
}
- public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
- return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc;
- }
+
+ private _disposers: { [name: string]: IReactionDisposer } = {};
+ public selectedArray = new ObservableSet<Doc>();
+ _batch: UndoManager.Batch | undefined = undefined; // undo batch for dragging sliders which generate multiple scene edit events as the cursor moves
+ _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation.
+ _unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things
@observable public static Instance: PresBox;
@observable _isChildActive = false;
@observable _moveOnFromAudio: boolean = true;
@observable _presTimer!: NodeJS.Timeout;
- @observable _presKeyEventsActive: boolean = false;
- @observable _selectedArray: ObservableMap = new ObservableMap<Doc, any>();
@observable _eleArray: HTMLElement[] = [];
@observable _dragArray: HTMLElement[] = [];
@observable _pathBoolean: boolean = false;
@observable _expandBoolean: boolean = false;
-
- private _disposers: { [name: string]: IReactionDisposer } = {};
-
- @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView
- @observable private transitionTools: boolean = false;
- @observable private newDocumentTools: boolean = false;
- @observable private progressivizeTools: boolean = false;
- @observable private openMovementDropdown: boolean = false;
- @observable private openEffectDropdown: boolean = false;
- @observable private presentTools: boolean = false;
+ @observable _transitionTools: boolean = false;
+ @observable _newDocumentTools: boolean = false;
+ @observable _openMovementDropdown: boolean = false;
+ @observable _openEffectDropdown: boolean = false;
+ @observable _openBulletEffectDropdown: boolean = false;
+ @observable _presentTools: boolean = false;
+ @observable _treeViewMap: Map<Doc, number> = new Map();
+ @observable _presKeyEvents: boolean = false;
+ @observable _forceKeyEvents: boolean = false;
@computed get isTreeOrStack() {
return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any);
}
@@ -125,103 +114,111 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get childDocs() {
return DocListCast(this.rootDoc[this.presFieldKey]);
}
- @observable _treeViewMap: Map<Doc, number> = new Map();
-
@computed get tagDocs() {
- const tagDocs: Doc[] = [];
- for (const doc of this.childDocs) {
- const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
- tagDocs.push(tagDoc);
- }
- return tagDocs;
+ return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null));
}
@computed get itemIndex() {
return NumCast(this.rootDoc._itemIndex);
}
@computed get activeItem() {
- return Cast(this.childDocs[NumCast(this.rootDoc._itemIndex)], Doc, null);
+ return DocCast(this.childDocs[NumCast(this.rootDoc._itemIndex)]);
}
@computed get targetDoc() {
return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
}
- @computed get scrollable(): boolean {
- if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
- else return false;
+ public static targetRenderedDoc = (doc: Doc) => {
+ const targetDoc = Cast(doc?.presentationTargetDoc, Doc, null);
+ return targetDoc?.unrendered ? DocCast(targetDoc.annotationOn) : targetDoc;
+ };
+ @computed get scrollable() {
+ if ([DocumentType.PDF, DocumentType.WEB, DocumentType.RTF].includes(this.targetDoc.type as DocumentType) || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
+ return false;
}
- @computed get panable(): boolean {
+ @computed get panable() {
if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
- else return false;
- }
- constructor(props: any) {
- super(props);
- if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this));
- this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
+ return false;
}
@computed get selectedDocumentView() {
if (SelectionManager.Views().length) return SelectionManager.Views()[0];
- if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
+ if (this.selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
}
- @computed get isPres(): boolean {
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- if (this.selectedDoc?.type === DocumentType.PRES) {
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
- return true;
- }
- return false;
+ @computed get isPres() {
+ return this.selectedDoc === this.rootDoc;
}
@computed get selectedDoc() {
return this.selectedDocumentView?.rootDoc;
}
+ isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc;
+ clearSelectedArray = () => this.selectedArray.clear();
+ addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc));
+ removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc));
- _unmounting = false;
@action
componentWillUnmount() {
this._unmounting = true;
+ if (this._presTimer) clearTimeout(this._presTimer);
document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- this._presKeyEventsActive = false;
this.resetPresentation();
- // Turn of progressivize editors
this.turnOffEdit(true);
Object.values(this._disposers).forEach(disposer => disposer?.());
}
- @action
componentDidMount() {
+ this._disposers.keyboard = reaction(
+ () => this.selectedDoc,
+ selected => {
+ document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
+ (this._presKeyEvents = selected === this.rootDoc) && document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
+ },
+ { fireImmediately: true }
+ );
+ this._disposers.forcekeyboard = reaction(
+ () => this._forceKeyEvents,
+ force => {
+ if (force) {
+ document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
+ document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
+ this._presKeyEvents = true;
+ }
+ this._forceKeyEvents = false;
+ },
+ { fireImmediately: true }
+ );
+ this.props.setContentView?.(this);
this._unmounting = false;
- this.rootDoc._forceRenderEngine = 'timeline';
- this.layoutDoc.presStatus = PresStatus.Edit;
- this.layoutDoc._gridGap = 0;
- this.layoutDoc._yMargin = 0;
+ if (this.props.renderDepth > 0) {
+ runInAction(() => {
+ this.rootDoc._forceRenderEngine = computeTimelineLayout.name;
+ this.layoutDoc._gridGap = 0;
+ this.layoutDoc._yMargin = 0;
+ });
+ }
this.turnOffEdit(true);
- DocListCastAsync(Doc.MyTrails.data).then(pres => !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.MyTrails, 'data', this.rootDoc));
this._disposers.selection = reaction(
() => SelectionManager.Views(),
views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()
);
+ this._disposers.editing = reaction(
+ () => this.layoutDoc.presStatus === PresStatus.Edit,
+ editing => {
+ if (editing) {
+ this.childDocs.forEach(doc => {
+ if (doc.presIndexed !== undefined) {
+ this.progressivizedItems(doc)?.forEach(indexedDoc => (indexedDoc.opacity = undefined));
+ doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1);
+ }
+ });
+ }
+ }
+ );
}
@action
updateCurrentPresentation = (pres?: Doc) => {
- if (pres) Doc.ActivePresentation = pres;
- else Doc.ActivePresentation = this.rootDoc;
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
- this._presKeyEventsActive = true;
+ Doc.ActivePresentation = pres ?? this.rootDoc;
PresBox.Instance = this;
};
- // There are still other internal frames and should go through all frames before going to next slide
- nextInternalFrame = (targetDoc: Doc, activeItem: Doc) => {
- const currentFrame = Cast(targetDoc?._currentFrame, 'number', null);
- const childDocs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
- targetDoc._viewTransition = 'all 1s';
- setTimeout(() => (targetDoc._viewTransition = undefined), 1010);
- this.nextKeyframe(targetDoc, activeItem);
- if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
- else targetDoc.keyFrameEditing = true;
- };
-
_mediaTimer!: [NodeJS.Timeout, Doc];
// 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
startTempMedia = (targetDoc: Doc, activeItem: Doc) => {
@@ -233,7 +230,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
stopTempMedia = (targetDocField: FieldResult) => {
- const targetDoc = Cast(targetDocField, Doc, null);
+ const targetDoc = DocCast(DocCast(targetDocField).annotationOn) ?? DocCast(targetDocField);
if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) {
const targMedia = DocumentManager.Instance.getDocumentView(targetDoc);
targMedia?.ComponentView?.Pause?.();
@@ -243,80 +240,122 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
// TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
// No more frames in current doc and next slide is defined, therefore move to next slide
- nextSlide = (activeNext: Doc) => {
- const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
- console.info('nextSlide', activeNext.title, targetNext?.title);
- let nextSelected = this.itemIndex + 1;
- this.gotoDocument(nextSelected, this.activeItem);
- for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
- if (!this.childDocs[nextSelected].groupWithUp) {
- break;
- } else {
- console.log('Title: ' + this.childDocs[nextSelected].title);
- this.gotoDocument(nextSelected, this.activeItem, true);
- }
- }
+ nextSlide = (slideNum?: number) => {
+ const nextSlideInd = slideNum ?? this.itemIndex + 1;
+ let curSlideInd = nextSlideInd;
+ //CollectionStackedTimeline.CurrentlyPlaying?.map(clipView => clipView?.ComponentView?.Pause?.());
+ this.clearSelectedArray();
+ const doGroupWithUp =
+ (nextSelected: number, force = false) =>
+ () => {
+ if (nextSelected < this.childDocs.length) {
+ if (force || this.childDocs[nextSelected].groupWithUp) {
+ this.addToSelectedArray(this.childDocs[nextSelected]);
+ const serial = nextSelected + 1 < this.childDocs.length && NumCast(this.childDocs[nextSelected + 1].groupWithUp) > 1;
+ if (serial) {
+ this.gotoDocument(nextSelected, this.activeItem, true, async () => {
+ const waitTime = NumCast(this.activeItem.presDuration) - NumCast(this.activeItem.presTransition);
+ await new Promise<void>(res => setTimeout(() => res(), Math.max(0, waitTime)));
+ doGroupWithUp(nextSelected + 1)();
+ });
+ } else {
+ this.gotoDocument(nextSelected, this.activeItem, true);
+ curSlideInd = this.itemIndex;
+ doGroupWithUp(nextSelected + 1)();
+ }
+ }
+ }
+ };
+ doGroupWithUp(curSlideInd, true)();
};
+ // docs within a slide target that will be progressively revealed
+ progressivizedItems = (doc: Doc) => {
+ const targetList = PresBox.targetRenderedDoc(doc);
+ if (doc.presIndexed !== undefined && targetList) {
+ const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '-annotations']);
+ return listItems.filter(doc => !doc.unrendered);
+ }
+ };
// Called when the user activates 'next' - to move to the next part of the pres. trail
@action
next = () => {
- const activeNext = Cast(this.childDocs[this.itemIndex + 1], Doc, null);
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const lastFrame = Cast(targetDoc?.lastFrame, 'number', null);
- const curFrame = NumCast(targetDoc?._currentFrame);
- let internalFrames: boolean = false;
- if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
- if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
- // Case 1: There are still other frames and should go through all frames before going to next slide
- this.nextInternalFrame(targetDoc, activeItem);
- } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
- // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
- this.nextSlide(activeNext);
- } else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
- // Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
- this.gotoDocument(0, this.activeItem);
+ const progressiveReveal = (first: boolean) => {
+ const presIndexed = Cast(this.activeItem?.presIndexed, 'number', null);
+ if (presIndexed !== undefined) {
+ const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem);
+ targetRenderedDoc._dataTransition = 'all 1s';
+ targetRenderedDoc.opacity = 1;
+ setTimeout(() => (targetRenderedDoc._dataTransition = 'inherit'), 1000);
+ const listItems = this.progressivizedItems(this.activeItem);
+ if (listItems && presIndexed < listItems.length) {
+ if (!first) {
+ const listItemDoc = listItems[presIndexed];
+ const targetView = listItems && DocumentManager.Instance.getFirstDocumentView(listItemDoc);
+ Doc.linkFollowUnhighlight();
+ Doc.HighlightDoc(listItemDoc);
+ listItemDoc.presEffect = this.activeItem.presBulletEffect;
+ listItemDoc.presTransition = 500;
+ targetView?.setAnimEffect(listItemDoc, 500);
+ if (targetView?.docView && this.activeItem.presBulletExpand) {
+ targetView.docView._animateScalingTo = 1.1;
+ Doc.AddUnHighlightWatcher(() => (targetView!.docView!._animateScalingTo = 0));
+ }
+ listItemDoc.opacity = undefined;
+ this.activeItem.presIndexed = presIndexed + 1;
+ }
+ return true;
+ }
+ }
+ };
+ if (progressiveReveal(false)) return true;
+ if (this.childDocs[this.itemIndex + 1] !== undefined) {
+ // Case 1: No more frames in current doc and next slide is defined, therefore move to next slide
+ const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]);
+ const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex;
+ this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1);
+ progressiveReveal(true); // shows first progressive document, but without a transition effect
+ } else {
+ if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
+ // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode
+ this.nextSlide(0);
+ progressiveReveal(true); // shows first progressive document, but without a transition effect
+ }
+ return 0;
}
+ return this.itemIndex;
};
// Called when the user activates 'back' - to move to the previous part of the pres. trail
@action
back = () => {
const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null);
- const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
- const lastFrame = Cast(targetDoc.lastFrame, 'number', null);
- const curFrame = NumCast(targetDoc._currentFrame);
let prevSelected = this.itemIndex;
// Functionality for group with up
let didZoom = activeItem.presMovement;
- for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
- didZoom = this.childDocs[prevSelected].presMovement;
+ for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].groupWithUp; prevSelected--) {
+ didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presMovement : didZoom;
}
- if (lastFrame !== undefined && curFrame >= 1) {
- // Case 1: There are still other frames and should go through all frames before going to previous slide
- this.prevKeyframe(targetDoc, activeItem);
- } else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
+ if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
// Case 2: There are no other frames so it should go to the previous slide
prevSelected = Math.max(0, prevSelected - 1);
- this.gotoDocument(prevSelected, activeItem);
- if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
+ this.nextSlide(prevSelected);
+ this.rootDoc._itemIndex = prevSelected;
} else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
// Case 3: Pres loop is on so it should go to the last slide
- this.gotoDocument(this.childDocs.length - 1, activeItem);
+ this.nextSlide(this.childDocs.length - 1);
}
+ return this.itemIndex;
};
//The function that is called when a document is clicked or reached through next or back.
//it'll also execute the necessary actions if presentation is playing.
- public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
+ @undoBatch
+ public gotoDocument = action((index: number, from?: Doc, group?: boolean, finished?: () => void) => {
Doc.UnBrushAllDocs();
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
}
@@ -324,67 +363,312 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.stopTempMedia(from.presentationTargetDoc);
}
// If next slide is audio / video 'Play automatically' then the next slide should be played
- if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') {
- this.startTempMedia(targetDoc, activeItem);
+ if (this.layoutDoc.presStatus !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') {
+ this.startTempMedia(this.targetDoc, this.activeItem);
}
- if (targetDoc) {
- Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc);
- targetDoc &&
- runInAction(() => {
- if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
- else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
- });
- setTimeout(() => (targetDoc.focusSpeed = 500), this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+ if (!group) this.clearSelectedArray();
+ this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array
+ this.turnOffEdit();
+ this.navigateToActiveItem(finished); //Handles movement to element only when presTrail is list
+ this.doHideBeforeAfter(); //Handles hide after/before
+ }
+ });
+ static pinDataTypes(target?: Doc): pinDataTypes {
+ const targetType = target?.type as any;
+ const inkable = [DocumentType.INK].includes(targetType);
+ const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._viewType === CollectionViewType.Stacking;
+ const pannable = [DocumentType.IMG, DocumentType.PDF].includes(targetType) || (targetType === DocumentType.COL && target?._viewType === CollectionViewType.Freeform);
+ const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(targetType);
+ const clippable = [DocumentType.COMPARISON].includes(targetType);
+ const datarange = [DocumentType.FUNCPLOT].includes(targetType);
+ const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG].includes(targetType) && target?.activeFrame === undefined;
+ const poslayoutview = [DocumentType.COL].includes(targetType) && target?.activeFrame === undefined;
+ const textview = [DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined;
+ const viewType = targetType === DocumentType.COL;
+ const filters = true;
+ const pivot = true;
+ const dataannos = false;
+ return { scrollable, pannable, inkable, viewType, pivot, filters, temporal, clippable, dataview, datarange, textview, poslayoutview, dataannos };
+ }
+
+ @action
+ playAnnotation = (anno: AudioField) => {};
+ @action
+ static restoreTargetDocView(bestTargetView: Opt<DocumentView>, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.presPinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) {
+ const bestTarget = bestTargetView?.rootDoc ?? (targetDoc?.unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc);
+ if (!bestTarget || activeItem === bestTarget) return;
+ let changed = false;
+ if (pinDocLayout) {
+ if (
+ bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) ||
+ bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) ||
+ bestTarget.rotation !== NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)) ||
+ bestTarget.width !== NumCast(activeItem.presWidth, NumCast(bestTarget.width)) ||
+ bestTarget.height !== NumCast(activeItem.presHeight, NumCast(bestTarget.height))
+ ) {
+ bestTarget._dataTransition = `all ${transTime}ms`;
+ bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x));
+ bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y));
+ bestTarget.rotation = NumCast(activeItem.presRotation, NumCast(bestTarget.rotation));
+ bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width));
+ bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height));
+ setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
+ changed = true;
}
- if (targetDoc?.lastFrame !== undefined) {
- targetDoc._currentFrame = 0;
+ }
+
+ const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame;
+ if (activeFrame !== undefined) {
+ const transTime = NumCast(activeItem.presTransition, 500);
+ const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc);
+ const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext;
+ if (context) {
+ const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ if (ffview?.childDocs) {
+ PresBox.Instance._keyTimer = CollectionFreeFormView.gotoKeyframe(PresBox.Instance._keyTimer, ffview.childDocs, transTime);
+ ffview.rootDoc._currentFrame = NumCast(activeFrame);
+ }
+ }
+ }
+ if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) {
+ if (bestTarget.xRange !== activeItem.presXRange) {
+ bestTarget.xRange = (activeItem.presXRange as ObjectField)?.[Copy]();
+ changed = true;
+ }
+ if (bestTarget.yRange !== activeItem.presYRange) {
+ bestTarget.yRange = (activeItem.presYRange as ObjectField)?.[Copy]();
+ changed = true;
+ }
+ }
+ if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presClipWidth !== undefined)) {
+ if (bestTarget._clipWidth !== activeItem.presClipWidth) {
+ bestTarget._clipWidth = activeItem.presClipWidth;
+ changed = true;
+ }
+ }
+ if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) {
+ if (bestTarget._currentTimecode !== activeItem.presStartTime) {
+ bestTarget._currentTimecode = activeItem.presStartTime;
+ changed = true;
+ }
+ }
+ if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.presFillColor !== undefined || activeItem.color !== undefined))) {
+ if (bestTarget.fillColor !== activeItem.presFillColor) {
+ Doc.GetProto(bestTarget).fillColor = activeItem.presFillColor;
+ changed = true;
+ }
+ if (bestTarget.color !== activeItem.presColor) {
+ Doc.GetProto(bestTarget).color = activeItem.presColor;
+ changed = true;
+ }
+ if (bestTarget.width !== activeItem.width) {
+ bestTarget._width = NumCast(activeItem.presWidth, NumCast(bestTarget.width));
+ changed = true;
+ }
+ if (bestTarget.height !== activeItem.height) {
+ bestTarget._height = NumCast(activeItem.presHeight, NumCast(bestTarget.height));
+ changed = true;
+ }
+ }
+ if ((pinDataTypes?.viewType && activeItem.presViewType !== undefined) || (!pinDataTypes && activeItem.presViewType !== undefined)) {
+ if (bestTarget._viewType !== activeItem.presViewType) {
+ bestTarget._viewType = activeItem.presViewType;
+ changed = true;
}
- if (!group) this._selectedArray.clear();
- this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
- this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
- this.onHideDocument(); //Handles hide after/before
}
- });
- _navTimer!: NodeJS.Timeout;
- navigateToView = (targetDoc: Doc, activeItem: Doc) => {
- clearTimeout(this._navTimer);
- const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
- if (bestTarget) console.log(bestTarget.title, bestTarget.type);
- else console.log('no best target');
- if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false);
- };
+ if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) {
+ if (bestTarget.docFilters !== activeItem.presDocFilters) {
+ bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]);
+ changed = true;
+ }
+ }
- // navigates to the bestTarget document by making sure it is on screen,
- // then it applies the view specs stored in activeItem to
- @action
- static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) {
- if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
- bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
- bestTarget._scrollTop = activeItem.presPinViewScroll;
- } else if (bestTarget.type === DocumentType.COMPARISON) {
- bestTarget._clipWidth = activeItem.presPinClipWidth;
- } else if ([DocumentType.AUDIO, DocumentType.VID].includes(bestTarget.type as any)) {
- bestTarget._currentTimecode = activeItem.presStartTime;
- } else {
- const contentBounds = Cast(activeItem.contentBounds, listSpec('number'));
- bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
+ if ((pinDataTypes?.pivot && activeItem.presPivotField !== undefined) || (!pinDataTypes && activeItem.presPivotField !== undefined)) {
+ if (bestTarget.pivotField !== activeItem.presPivotField) {
+ bestTarget.pivotField = activeItem.presPivotField;
+ bestTarget._prevFilterIndex = 1; // need to revisit this...see CollectionTimeView
+ changed = true;
+ }
+ }
+
+ if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presViewScroll !== undefined)) {
+ if (bestTarget._scrollTop !== activeItem.presViewScroll) {
+ bestTarget._scrollTop = activeItem.presViewScroll;
+ changed = true;
+ const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
+ if (contentBounds) {
+ const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView;
+ 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 (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) {
+ const fkey = Doc.LayoutFieldKey(bestTarget);
+ const oldItems = DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered);
+ const newItems = DocListCast(activeItem.presAnnotations).map(doc => {
+ doc.hidden = false;
+ return doc;
+ });
+ const hiddenItems = DocListCast(bestTarget[fkey + '-annotations'])
+ .filter(doc => !doc.unrendered && !newItems.includes(doc))
+ .map(doc => {
+ doc.hidden = true;
+ return doc;
+ });
+ const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]);
+ Doc.GetProto(bestTarget)[fkey + '-annotations'] = newList;
+ }
+ if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) {
+ bestTarget._dataTransition = `all ${transTime}ms`;
+ const fkey = Doc.LayoutFieldKey(bestTarget);
+ Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt;
+ setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10);
+ }
+ if ((pinDataTypes?.textview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) {
+ Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ }
+ if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) {
+ changed = true;
+ const layoutField = Doc.LayoutFieldKey(bestTarget);
+ const transitioned = new Set<Doc>();
+ StrListCast(activeItem.presPinLayoutData)
+ .map(str => JSON.parse(str) as { id: string; x: number; y: number; back: string; fill: string; w: number; h: number; data: string; text: string })
+ .forEach(async data => {
+ const doc = DocCast(DocServer.GetCachedRefField(data.id));
+ if (doc) {
+ transitioned.add(doc);
+ const field = !data.data ? undefined : await SerializationHelper.Deserialize(data.data);
+ const tfield = !data.text ? undefined : await SerializationHelper.Deserialize(data.text);
+ doc._dataTransition = `all ${transTime}ms`;
+ doc.x = data.x;
+ doc.y = data.y;
+ data.back && (doc._backgroundColor = data.back);
+ data.fill && (doc._fillColor = data.fill);
+ doc._width = data.w;
+ doc._height = data.h;
+ data.data && (Doc.GetProto(doc).data = field);
+ data.text && (Doc.GetProto(doc).text = tfield);
+ Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc);
+ }
+ });
+ setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10);
+ }
+ if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.presPinViewBounds !== undefined || activeItem.presPanX !== undefined || activeItem.presViewScale !== undefined))) && !bestTarget._isGroup) {
+ const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
if (contentBounds) {
- bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2;
- bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2;
+ const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] };
+ bestTarget._panX = viewport.panX;
+ bestTarget._panY = viewport.panY;
const dv = DocumentManager.Instance.getDocumentView(bestTarget);
if (dv) {
- bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0]));
+ const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height);
+ activeItem.presMovement === PresMovement.Zoom && (bestTarget._viewScale = computedScale);
+ dv.ComponentView?.brushView?.(viewport);
}
} else {
- bestTarget._panX = activeItem.presPinViewX;
- bestTarget._panY = activeItem.presPinViewY;
- bestTarget._viewScale = activeItem.presPinViewScale;
+ if (bestTarget._panX !== activeItem.presPanX || bestTarget._panY !== activeItem.presPanY || bestTarget._viewScale !== activeItem.presViewScale) {
+ bestTarget._panX = activeItem.presPanX ?? bestTarget._panX;
+ bestTarget._panY = activeItem.presPanY ?? bestTarget._panY;
+ bestTarget._viewScale = activeItem.presViewScale ?? bestTarget._viewScale;
+ changed = true;
+ }
}
}
- return setTimeout(() => (bestTarget._viewTransition = undefined), activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510);
+ if (changed) {
+ return bestTargetView?.setViewTransition('all', transTime);
+ }
}
+ /// copies values from the targetDoc (which is the prototype of the pinDoc) to
+ /// reserved fields on the pinDoc so that those values can be restored to the
+ /// target doc when navigating to it.
+ @action
+ static pinDocView(pinDoc: Doc, pinProps: PinProps, targetDoc: Doc) {
+ if (pinProps.pinDocLayout) {
+ pinDoc.presPinLayout = true;
+ pinDoc.presX = NumCast(targetDoc.x);
+ pinDoc.presY = NumCast(targetDoc.y);
+ pinDoc.presRotation = NumCast(targetDoc.rotation);
+ pinDoc.presWidth = NumCast(targetDoc.width);
+ pinDoc.presHeight = NumCast(targetDoc.height);
+ }
+ if (pinProps.pinAudioPlay) pinDoc.presPlayAudio = true;
+ if (pinProps.pinData) {
+ pinDoc.presPinData =
+ pinProps.pinData.scrollable ||
+ pinProps.pinData.temporal ||
+ pinProps.pinData.pannable ||
+ pinProps.pinData.viewType ||
+ pinProps.pinData.clippable ||
+ pinProps.pinData.datarange ||
+ pinProps.pinData.dataview ||
+ pinProps.pinData.textview ||
+ pinProps.pinData.poslayoutview ||
+ pinProps?.activeFrame !== undefined;
+ const fkey = Doc.LayoutFieldKey(targetDoc);
+ if (pinProps.pinData.dataview) {
+ pinDoc.presUseAlt = targetDoc[fkey + '-useAlt'];
+ pinDoc.presData = targetDoc[fkey] instanceof ObjectField ? (targetDoc[fkey] as ObjectField)[Copy]() : targetDoc.data;
+ }
+ if (pinProps.pinData.dataannos) {
+ const fkey = Doc.LayoutFieldKey(targetDoc);
+ pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered));
+ }
+ if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text;
+ if (pinProps.pinData.inkable) {
+ pinDoc.presFillColor = targetDoc.fillColor;
+ pinDoc.presColor = targetDoc.color;
+ pinDoc.presWidth = targetDoc._width;
+ pinDoc.presHeight = targetDoc._height;
+ }
+ if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._scrollTop;
+ if (pinProps.pinData.clippable) pinDoc.presClipWidth = targetDoc._clipWidth;
+ if (pinProps.pinData.datarange) {
+ pinDoc.presXRange = undefined; //targetDoc?.xrange;
+ pinDoc.presYRange = undefined; //targetDoc?.yrange;
+ }
+ if (pinProps.pinData.poslayoutview)
+ pinDoc.presPinLayoutData = new List<string>(
+ DocListCast(targetDoc[fkey] as ObjectField).map(d =>
+ JSON.stringify({
+ id: d[Id],
+ x: NumCast(d.x),
+ y: NumCast(d.y),
+ w: NumCast(d._width),
+ h: NumCast(d._height),
+ fill: StrCast(d._fillColor),
+ back: StrCast(d._backgroundColor),
+ data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''),
+ text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''),
+ })
+ )
+ );
+ if (pinProps.pinData.viewType) pinDoc.presViewType = targetDoc._viewType;
+ if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField);
+ if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField;
+ if (pinProps.pinData.pannable) {
+ pinDoc.presPanX = NumCast(targetDoc._panX);
+ pinDoc.presPanY = NumCast(targetDoc._panY);
+ pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1);
+ }
+ if (pinProps.pinData.temporal) {
+ pinDoc.presStartTime = targetDoc._currentTimecode;
+ const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(targetDoc.presStartTime) + 0.1);
+ pinDoc.presEndTime = NumCast(targetDoc.clipEnd, duration);
+ }
+ }
+ if (pinProps?.pinViewport) {
+ // If pinWithView option set then update scale and x / y props of slide
+ const bounds = pinProps.pinViewport;
+ pinDoc.presPinView = true;
+ pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1);
+ pinDoc.presPanX = bounds.left + bounds.width / 2;
+ pinDoc.presPanY = bounds.top + bounds.height / 2;
+ pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
+ }
+ }
/**
* This method makes sure that cursor navigates to the element that
* has the option open and last in the group.
@@ -393,188 +677,161 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
* a new tab. If presCollection is undefined it will open the document
* on the right.
*/
- navigateToElement = async (curDoc: Doc) => {
+ navigateToActiveItem = (afterNav?: () => void) => {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
- const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null);
- const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
- const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
- const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
- const tab = CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext);
- this.turnOffEdit();
- // Handles the setting of presCollection
- if (includesDoc) {
- //Case 1: Pres collection should not change as it is already the same
- } else if (tab !== undefined) {
- // Case 2: Pres collection should update
- this.layoutDoc.presCollection = srcContext;
- }
- const presStatus = this.rootDoc.presStatus;
- const selViewCache = Array.from(this._selectedArray.keys());
+ const finished = () => {
+ afterNav?.();
+ console.log('Finish Slide Nav: ' + targetDoc.title);
+ targetDoc[AnimationSym] = undefined;
+ };
+ const selViewCache = Array.from(this.selectedArray);
const dragViewCache = Array.from(this._dragArray);
const eleViewCache = Array.from(this._eleArray);
- const self = this;
const resetSelection = action(() => {
- const presDocView = DocumentManager.Instance.getDocumentView(self.rootDoc);
- if (presDocView) SelectionManager.SelectView(presDocView, false);
- self.rootDoc.presStatus = presStatus;
- self._selectedArray.clear();
- selViewCache.forEach(doc => self._selectedArray.set(doc, undefined));
- self._dragArray.splice(0, self._dragArray.length, ...dragViewCache);
- self._eleArray.splice(0, self._eleArray.length, ...eleViewCache);
- });
- const openInTab = (doc: Doc, finished?: () => void) => {
- collectionDocView ? collectionDocView.props.addDocTab(doc, '') : this.props.addDocTab(doc, '');
- this.layoutDoc.presCollection = targetDoc;
- // this still needs some fixing
- setTimeout(resetSelection, 500);
- if (doc !== targetDoc) {
- setTimeout(finished ?? emptyFunction, 100); /// give it some time to create the targetDoc if we're opening up its context
- } else {
- finished?.();
+ if (!this.props.isSelected()) {
+ const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
+ if (presDocView) SelectionManager.SelectView(presDocView, false);
+ this.clearSelectedArray();
+ selViewCache.forEach(doc => this.addToSelectedArray(doc));
+ this._dragArray.splice(0, this._dragArray.length, ...dragViewCache);
+ this._eleArray.splice(0, this._eleArray.length, ...eleViewCache);
}
- };
- // If openDocument is selected then it should open the document for the user
- if (activeItem.openDocument) {
- LightboxView.SetLightboxDoc(targetDoc);
- // openInTab(targetDoc);
- } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
- LightboxView.SetLightboxDoc(undefined);
- await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
- } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
- LightboxView.SetLightboxDoc(undefined);
- //awaiting jump so that new scale can be found, since jumping is async
- await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right
- }
- // 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) {
- console.log(targetDoc.title);
- console.log('presPinView in PresBox.tsx:420');
- // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
- this.navigateToView(targetDoc, activeItem);
- }
+ finished();
+ });
+ PresBox.NavigateToTarget(targetDoc, activeItem, resetSelection);
};
- /**
- * Uses the viewfinder to progressivize through the different views of a single collection.
- * @param activeItem: document for which internal zoom is used
- */
- zoomProgressivizeNext = (activeItem: Doc) => {
- const targetDoc: Doc = this.targetDoc;
- const srcContext = Cast(targetDoc?.context, Doc, null);
- const docView = DocumentManager.Instance.getDocumentView(targetDoc);
- const vfLeft = this.checkList(targetDoc, activeItem['viewfinder-left-indexed']);
- const vfWidth = this.checkList(targetDoc, activeItem['viewfinder-width-indexed']);
- const vfTop = this.checkList(targetDoc, activeItem['viewfinder-top-indexed']);
- const vfHeight = this.checkList(targetDoc, activeItem['viewfinder-height-indexed']);
- // Case 1: document that is not a Golden Layout tab
- if (srcContext) {
- const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
- if (srcDocView) {
- const layoutdoc = Doc.Layout(targetDoc);
- const panelWidth: number = srcDocView.props.PanelWidth();
- const panelHeight: number = srcDocView.props.PanelHeight();
- const newPanX = NumCast(targetDoc.x) + NumCast(layoutdoc._width) / 2;
- const newPanY = NumCast(targetDoc.y) + NumCast(layoutdoc._height) / 2;
- const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
- srcContext._panX = newPanX + (vfLeft + vfWidth / 2);
- srcContext._panY = newPanY + (vfTop + vfHeight / 2);
- srcContext._viewScale = newScale;
- }
- }
- // Case 2: document is the containing collection
- if (docView && !srcContext) {
- const panelWidth: number = docView.props.PanelWidth();
- const panelHeight: number = docView.props.PanelHeight();
- const newScale = 0.9 * Math.min(Number(panelWidth) / vfWidth, Number(panelHeight) / vfHeight);
- targetDoc._panX = vfLeft + vfWidth / 2;
- targetDoc._panY = vfTop + vfWidth / 2;
- targetDoc._viewScale = newScale;
+ static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) {
+ if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) {
+ (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.();
+ return;
}
- const resize = document.getElementById('resizable');
- if (resize) {
- resize.style.width = vfWidth + 'px';
- resize.style.height = vfHeight + 'px';
- resize.style.top = vfTop + 'px';
- resize.style.left = vfLeft + 'px';
+ const effect = activeItem.presEffect && activeItem.presEffect !== PresEffect.None ? activeItem.presEffect : undefined;
+ const presTime = NumCast(activeItem.presTransition, effect ? 750 : 500);
+ const options: DocFocusOptions = {
+ willPan: activeItem.presMovement !== PresMovement.None,
+ willZoomCentered: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center,
+ zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1),
+ zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime),
+ effect: activeItem,
+ noSelect: true,
+ openLocation: OpenWhere.addLeft,
+ anchorDoc: activeItem,
+ easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any,
+ zoomTextSelections: BoolCast(activeItem.presZoomText),
+ playAudio: BoolCast(activeItem.presPlayAudio),
+ };
+ if (activeItem.presOpenInLightbox) {
+ const context = DocCast(targetDoc.annotationOn) ?? targetDoc;
+ if (!DocumentManager.Instance.getLightboxDocumentView(context)) {
+ LightboxView.SetLightboxDoc(context);
+ }
}
- };
+ if (targetDoc) {
+ if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined;
+
+ DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => {
+ // if target or the doc it annotates is not in the lightbox, then close the lightbox
+ if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(targetDoc.annotationOn) ?? targetDoc)) {
+ LightboxView.SetLightboxDoc(undefined);
+ }
+ DocumentManager.Instance.showDocument(targetDoc, options, finished);
+ });
+ } else finished?.();
+ }
/**
* For 'Hide Before' and 'Hide After' buttons making sure that
* they are hidden each time the presentation is updated.
*/
@action
- onHideDocument = () => {
+ doHideBeforeAfter = () => {
this.childDocs.forEach((doc, index) => {
const curDoc = Cast(doc, Doc, null);
- const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
- //if (tagDoc) tagDoc.opacity = 1;
+ const tagDoc = PresBox.targetRenderedDoc(curDoc);
const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc);
- const curInd: number = itemIndexes.indexOf(index);
- if (tagDoc === this.layoutDoc.presCollection) {
- tagDoc.opacity = 1;
- } else {
- if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) {
- } else if (curDoc.presHideBefore) {
- if (index > this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideAfter) {
- tagDoc.opacity = 1;
- }
+ let opacity: Opt<number> = index === this.itemIndex ? 1 : undefined;
+ if (curDoc.presHide) {
+ if (index !== this.itemIndex) {
+ opacity = 1;
}
- if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== itemIndexes.length - 1) {
- } else if (curDoc.presHideAfter) {
- if (index < this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideBefore) {
- tagDoc.opacity = 1;
- }
+ }
+ const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement();
+ if (curDoc.presHideBefore && index === hidingIndBef) {
+ if (index > this.itemIndex) {
+ opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideAfter) {
+ opacity = 1;
+ setTimeout(() => (tagDoc._dataTransition = undefined), 1000);
+ }
+ }
+ const hidingIndAft =
+ itemIndexes
+ .slice()
+ .reverse()
+ .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement();
+ if (curDoc.presHideAfter && index === hidingIndAft) {
+ if (index < this.itemIndex) {
+ opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideBefore) {
+ opacity = 1;
}
}
+ const hidingInd = itemIndexes.find(item => item === this.itemIndex);
+ if (curDoc.presHide && index === hidingInd) {
+ if (index === this.itemIndex) {
+ opacity = 0;
+ }
+ }
+ opacity !== undefined && (tagDoc.opacity = opacity);
});
};
- //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();
+ _exitTrail: Opt<() => void>;
+ PlayTrail = (docs: Doc[]) => {
+ const savedStates = docs.map(doc => {
+ switch (doc.type) {
+ case DocumentType.COL:
+ if (doc._viewType === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) };
+ break;
+ case DocumentType.INK:
+ if (doc.data instanceof InkField) {
+ return { type: doc.type, doc, data: doc.data?.[Copy](), fillColor: doc.fillColor, color: doc.color, x: NumCast(doc.x), y: NumCast(doc.y) };
}
- }
-
- 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);
- }
}
+ return undefined;
+ });
+ this.startPresentation(0);
+ this._exitTrail = () => {
+ savedStates
+ .filter(savedState => savedState)
+ .map(savedState => {
+ switch (savedState?.type) {
+ case CollectionViewType.Freeform:
+ {
+ const { x, y, s, doc } = savedState!;
+ doc._panX = x;
+ doc._panY = y;
+ doc._viewScale = s;
+ }
+ break;
+ case DocumentType.INK:
+ {
+ const { data, fillColor, color, x, y, doc } = savedState!;
+ doc.x = x;
+ doc.y = y;
+ doc.data = data;
+ doc.fillColor = fillColor;
+ doc.color = color;
+ }
+ break;
+ }
+ });
+ LightboxView.SetLightboxDoc(undefined);
+ Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
+ return PresStatus.Edit;
};
- this.layoutDoc.presStatus = PresStatus.Autoplay;
- this.startPresentation(startSlide);
- this.gotoDocument(startSlide, activeItem);
- load();
};
// The function pauses the auto presentation
@@ -583,7 +840,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);
}
};
@@ -591,9 +847,8 @@ 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))
+ .map(doc => PresBox.targetRenderedDoc(doc))
.filter(doc => doc instanceof Doc)
.forEach(doc => {
try {
@@ -605,14 +860,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
// The function allows for viewing the pres path on toggle
- @action togglePath = (srcContext: Doc, off?: boolean) => {
- if (off) {
- this._pathBoolean = false;
- srcContext.presPathView = false;
- } else {
- runInAction(() => (this._pathBoolean = !this._pathBoolean));
- srcContext.presPathView = this._pathBoolean;
- }
+ @action togglePath = (off?: boolean) => {
+ this._pathBoolean = off ? false : !this._pathBoolean;
+ CollectionFreeFormView.ShowPresPaths = this._pathBoolean;
};
// The function allows for expanding the view of pres on toggle
@@ -624,45 +874,74 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
});
};
+ initializePresState = (startIndex: number) => {
+ this.childDocs.forEach((doc, index) => {
+ const tagDoc = PresBox.targetRenderedDoc(doc);
+ if (doc.presHideBefore && index > startIndex) tagDoc.opacity = 0;
+ if (doc.presHideAfter && index < startIndex) tagDoc.opacity = 0;
+ if (doc.presIndexed !== undefined && index >= startIndex) {
+ const startInd = NumCast(doc.presIndexedStart);
+ this.progressivizedItems(doc)
+ ?.slice(startInd)
+ .forEach(indexedDoc => (indexedDoc.opacity = 0));
+ doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd);
+ }
+ // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0;
+ });
+ };
+
/**
* The function that starts the presentation at the given index, also checking if actions should be applied
* directly at start.
* @param startIndex: index that the presentation will start at
*/
+ @action
startPresentation = (startIndex: number) => {
- this.updateCurrentPresentation();
- this.childDocs.map(doc => {
- const tagDoc = doc.presentationTargetDoc as Doc;
- if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) {
- tagDoc.opacity = 0;
- }
- if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) {
- tagDoc.opacity = 0;
- }
- });
+ PresBox.Instance = this;
+ clearTimeout(this._presTimer);
+ if (this.childDocs.length) {
+ this.layoutDoc.presStatus = PresStatus.Autoplay;
+ this.initializePresState(startIndex);
+ const func = () => {
+ const delay = NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition);
+ this._presTimer = setTimeout(() => {
+ if (!this.next()) this.layoutDoc.presStatus = this._exitTrail?.() ?? PresStatus.Manual;
+ this.layoutDoc.presStatus === PresStatus.Autoplay && func();
+ }, delay);
+ };
+ this.gotoDocument(startIndex, this.activeItem, undefined, func);
+ }
};
/**
* The method called to open the presentation as a minimized view
*/
@action
- updateMinimize = async () => {
+ enterMinimize = () => {
+ this.updateCurrentPresentation(this.rootDoc);
+ clearTimeout(this._presTimer);
+ const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ this.props.removeDocument?.(this.layoutDoc);
+ return PresBox.OpenPresMinimized(this.rootDoc, [pt[0] + (this.props.PanelWidth() - 250), pt[1] + 10]);
+ };
+ exitMinimize = () => {
if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
- this.layoutDoc.presStatus = PresStatus.Edit;
Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc);
- CollectionDockingView.AddSplit(this.rootDoc, 'right');
- } else {
- this.layoutDoc.presStatus = PresStatus.Edit;
- clearTimeout(this._presTimer);
- const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
- this.rootDoc.y = pt[1] + 10;
- this.rootDoc._height = 30;
- this.rootDoc._width = 248;
- Doc.AddDocToList(Doc.MyOverlayDocs, undefined, this.rootDoc);
- this.props.removeDocument?.(this.layoutDoc);
+ CollectionDockingView.AddSplit(this.rootDoc, OpenWhereMod.right);
}
- };
+ return PresStatus.Edit;
+ };
+
+ public static minimizedWidth = 198;
+ public static OpenPresMinimized(doc: Doc, pt: number[]) {
+ doc.overlayX = pt[0];
+ doc.overlayY = pt[1];
+ doc._height = 30;
+ doc._width = PresBox.minimizedWidth;
+ Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
+ PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex);
+ return (doc.presStatus = PresStatus.Manual);
+ }
/**
* Called when the user changes the view type
@@ -695,38 +974,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (this.childDocs[stopDocIndex - 1].mediaStopTriggerList) {
const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
list.push(activeItem);
- // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
- console.log(list);
+ // this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;\
} else {
this.childDocs[stopDocIndex - 1].mediaStopTriggerList = new List<Doc>();
const list = DocListCast(this.childDocs[stopDocIndex - 1].mediaStopTriggerList);
list.push(activeItem);
// this.childDocs[stopDocIndex - 1].mediaStopTriggerList = list;
- console.log(list);
}
});
- setMovementName = action((movement: any, activeItem: Doc): string => {
- let output: string = 'none';
- switch (movement) {
- case PresMovement.Zoom:
- output = 'Pan & Zoom';
- break; //Pan and zoom
- case PresMovement.Pan:
- output = 'Pan';
- break; //Pan
- case PresMovement.Jump:
- output = 'Jump cut';
- break; //Jump Cut
- case PresMovement.None:
- output = 'None';
- break; //None
- default:
- output = 'Zoom';
- activeItem.presMovement = 'zoom';
- break; //default set as zoom
+ movementName = action((activeItem: Doc) => {
+ if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Center, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) {
+ return PresMovement.Zoom;
}
- return output;
+ return StrCast(activeItem.presMovement);
});
whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive)));
@@ -749,7 +1010,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
} else {
if (!doc.aliasOf) {
const original = Doc.MakeAlias(doc);
- TabDocView.PinDoc(original);
+ TabDocView.PinDoc(original, {});
setTimeout(() => this.removeDocument(doc), 0);
return false;
} else {
@@ -766,22 +1027,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight
panelHeight = () => this.props.PanelHeight() - 40;
- isContentActive = (outsideReaction?: boolean) =>
- Doc.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;
+ isContentActive = (outsideReaction?: boolean) => this.props.isContentActive(outsideReaction);
+ //.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false;
/**
* For sorting the array so that the order is maintained when it is dropped.
*/
- @action
- sortArray = (): Doc[] => {
- return this.childDocs.filter(doc => this._selectedArray.has(doc));
- };
+ sortArray = () => this.childDocs.filter(doc => this.selectedArray.has(doc));
/**
* Method to get the list of selected items in the order in which they have been selected
*/
@computed get listOfSelected() {
- const list = Array.from(this._selectedArray.keys()).map((doc: Doc, index: any) => {
+ return Array.from(this.selectedArray).map((doc: Doc, index: any) => {
const curDoc = Cast(doc, Doc, null);
const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
if (curDoc && curDoc === this.activeItem)
@@ -805,7 +1063,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
);
});
- return list;
}
@action
@@ -814,49 +1071,47 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
presDocView && SelectionManager.SelectView(presDocView, false);
};
+ focusElement = (doc: Doc, options: DocFocusOptions) => {
+ this.selectElement(doc);
+ return undefined;
+ };
+
//Regular click
@action
- selectElement = async (doc: Doc) => {
- const context = Cast(doc.context, Doc, null);
- this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
- if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
- else this.updateCurrentPresentation(context);
-
- if (this.activeItem.presActiveFrame !== undefined) {
- const context = DocCast(DocCast(this.activeItem.presentationTargetDoc).context);
- context && CollectionFreeFormViewChrome.gotoKeyFrame(context, NumCast(this.activeItem.presActiveFrame));
- }
+ selectElement = (doc: Doc, noNav = false) => {
+ CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => clip?.ComponentView?.Pause?.());
+ if (noNav) {
+ const index = this.childDocs.indexOf(doc);
+ if (index >= 0 && index < this.childDocs.length) {
+ this.rootDoc._itemIndex = index;
+ }
+ } else this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
+ this.updateCurrentPresentation(DocCast(doc.context));
};
//Command click
@action
multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
- if (!this._selectedArray.has(doc)) {
- this._selectedArray.set(doc, undefined);
+ if (!this.selectedArray.has(doc)) {
+ this.addToSelectedArray(doc);
this._eleArray.push(ref);
this._dragArray.push(drag);
} else {
- this._selectedArray.delete(doc);
- this.removeFromArray(this._eleArray, doc);
- this.removeFromArray(this._dragArray, doc);
+ this.removeFromSelectedArray(doc);
+ this._eleArray.splice(this._eleArray.indexOf(ref));
+ this._dragArray.splice(this._dragArray.indexOf(drag));
}
this.selectPres();
};
- removeFromArray = (arr: any[], val: any) => {
- const index: number = arr.indexOf(val);
- const ret: any[] = arr.splice(index, 1);
- arr = ret;
- };
-
//Shift click
@action
shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
- this._selectedArray.clear();
+ this.clearSelectedArray();
// const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
if (this.activeItem) {
for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
- this._selectedArray.set(this.childDocs[i], undefined);
+ this.addToSelectedArray(this.childDocs[i]);
this._eleArray.push(ref);
this._dragArray.push(drag);
}
@@ -866,24 +1121,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//regular click
@action
- regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, selectPres = true) => {
- this._selectedArray.clear();
- this._selectedArray.set(doc, undefined);
+ regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, selectPres = true) => {
+ this.clearSelectedArray();
+ this.addToSelectedArray(doc);
this._eleArray.splice(0, this._eleArray.length, ref);
this._dragArray.splice(0, this._dragArray.length, drag);
- focus && this.selectElement(doc);
+ this.selectElement(doc, noNav);
selectPres && this.selectPres();
};
- modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => {
+ modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, noNav: boolean, cmdClick: boolean, shiftClick: boolean) => {
if (cmdClick) this.multiSelect(doc, ref, drag);
else if (shiftClick) this.shiftSelect(doc, ref, drag);
- else this.regularSelect(doc, ref, drag, focus);
+ else this.regularSelect(doc, ref, drag, noNav);
};
- static keyEventsWrapper = (e: KeyboardEvent) => {
- PresBox.Instance.keyEvents(e);
- };
+ static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance?.keyEvents(e);
// Key for when the presentaiton is active
@action
@@ -897,10 +1150,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (this.layoutDoc.presStatus === 'edit') {
undoBatch(
action(() => {
- for (const doc of Array.from(this._selectedArray.keys())) {
+ for (const doc of this.selectedArray) {
this.removeDocument(doc);
}
- this._selectedArray.clear();
+ this.clearSelectedArray();
this._eleArray.length = 0;
this._dragArray.length = 0;
})
@@ -910,11 +1163,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
break;
case 'Escape':
if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) {
- this.updateMinimize();
- } else if (this.layoutDoc.presStatus === 'edit') {
- this._selectedArray.clear();
+ this.exitClicked();
+ } else if (this.layoutDoc.presStatus === PresStatus.Edit) {
+ this.clearSelectedArray();
this._eleArray.length = this._dragArray.length = 0;
- } else this.layoutDoc.presStatus = 'edit';
+ } else {
+ this.layoutDoc.presStatus = PresStatus.Edit;
+ }
if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
break;
@@ -925,7 +1180,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (e.shiftKey && this.itemIndex < this.childDocs.length - 1) {
// TODO: update to work properly
this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1;
- this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
+ this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]);
} else {
this.next();
if (this._presTimer) {
@@ -942,7 +1197,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (e.shiftKey && this.itemIndex !== 0) {
// TODO: update to work properly
this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1;
- this._selectedArray.set(this.childDocs[this.rootDoc._itemIndex], undefined);
+ this.addToSelectedArray(this.childDocs[this.rootDoc._itemIndex]);
} else {
this.back();
if (this._presTimer) {
@@ -954,14 +1209,14 @@ 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;
case 'a':
if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === 'edit') {
- this._selectedArray.clear();
- this.childDocs.forEach(doc => this._selectedArray.set(doc, undefined));
+ this.clearSelectedArray();
+ this.childDocs.forEach(doc => this.addToSelectedArray(doc));
handled = true;
}
default:
@@ -973,30 +1228,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- /**
- *
- */
- @action
- viewPaths = () => {
- const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
- if (srcContext) {
- this.togglePath(srcContext);
- }
- };
-
- getAllIndexes = (arr: Doc[], val: Doc): number[] => {
- const indexes = [];
- for (let i = 0; i < arr.length; i++) {
- arr[i] === val && indexes.push(i);
- }
- return indexes;
- };
+ getAllIndexes = (arr: Doc[], val: Doc) => arr.map((doc, i) => (doc === val ? i : -1)).filter(i => i !== -1);
// Adds the index in the pres path graphically
@computed get order() {
const order: JSX.Element[] = [];
const docs: Doc[] = [];
- const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
+ const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement();
const dv = DocumentManager.Instance.getDocumentView(presCollection);
this.childDocs
.filter(doc => Cast(doc.presentationTargetDoc, Doc, null))
@@ -1036,15 +1274,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
} else if (doc.presPinView && presCollection === tagDoc && dv) {
// Case B: Document is presPinView and is presCollection
- const scale: number = 1 / NumCast(doc.presPinViewScale);
+ const scale: number = 1 / NumCast(doc.presViewScale);
const height: number = dv.props.PanelHeight() * scale;
const width: number = dv.props.PanelWidth() * scale;
const indWidth = width / 10;
const indHeight = Math.max(height / 10, 15);
const indEdge = Math.max(indWidth, indHeight);
const indFontSize = indEdge * 0.8;
- const xLoc: number = NumCast(doc.presPinViewX) - width / 2;
- const yLoc: number = NumCast(doc.presPinViewY) - height / 2;
+ const xLoc: number = NumCast(doc.presPanX) - width / 2;
+ const yLoc: number = NumCast(doc.presPanY) - height / 2;
docs.push(tagDoc);
order.push(
<>
@@ -1069,18 +1307,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
*/
@computed get paths() {
let pathPoints = '';
- const presCollection = Cast(this.rootDoc.presCollection, Doc, null);
this.childDocs.forEach((doc, index) => {
const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
- const srcContext = Cast(tagDoc?.context, Doc, null);
- if (tagDoc && presCollection === srcContext) {
+ if (tagDoc) {
const n1x = NumCast(tagDoc.x) + NumCast(tagDoc._width) / 2;
const n1y = NumCast(tagDoc.y) + NumCast(tagDoc._height) / 2;
if ((index = 0)) pathPoints = n1x + ',' + n1y;
else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
- } else if (doc.presPinView && presCollection === tagDoc) {
- const n1x = NumCast(doc.presPinViewX);
- const n1y = NumCast(doc.presPinViewY);
+ } else if (doc.presPinView) {
+ const n1x = NumCast(doc.presPanX);
+ const n1y = NumCast(doc.presPanY);
if ((index = 0)) pathPoints = n1x + ',' + n1y;
else pathPoints = pathPoints + ' ' + n1x + ',' + n1y;
}
@@ -1102,835 +1338,555 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
/>
);
}
+ getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection
// Converts seconds to ms and updates presTransition
- setTransitionTime = (number: String, change?: number) => {
+ public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => {
let timeInMS = Number(number) * 1000;
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
- if (timeInMS > 10000) timeInMS = 10000;
- Array.from(this._selectedArray.keys()).forEach(doc => (doc.presTransition = timeInMS));
+ if (timeInMS > 100000) timeInMS = 100000;
+ setter(timeInMS);
+ };
+
+ @undoBatch
+ updateTransitionTime = (number: String, change?: number) => {
+ PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change);
};
// Converts seconds to ms and updates presTransition
- setZoom = (number: String, change?: number) => {
+ @undoBatch
+ updateZoom = (number: String, change?: number) => {
let scale = Number(number) / 100;
if (change) scale += change;
if (scale < 0.01) scale = 0.01;
- if (scale > 1.5) scale = 1.5;
- Array.from(this._selectedArray.keys()).forEach(doc => (doc.presZoom = scale));
+ if (scale > 1) scale = 1;
+ this.selectedArray.forEach(doc => (doc.presZoom = scale));
};
- // Converts seconds to ms and updates presDuration
- setDurationTime = (number: String, change?: number) => {
+ /*
+ * Converts seconds to ms and updates presDuration
+ */
+ @undoBatch
+ updateDurationTime = (number: String, change?: number) => {
let timeInMS = Number(number) * 1000;
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 20000) timeInMS = 20000;
- Array.from(this._selectedArray.keys()).forEach(doc => (doc.presDuration = timeInMS));
+ this.selectedArray.forEach(doc => (doc.presDuration = timeInMS));
};
- /**
- * When the movement dropdown is changes
- */
@undoBatch
- updateMovement = action((movement: any, all?: boolean) => {
- const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
- array.forEach(doc => {
- switch (movement) {
- case PresMovement.Zoom: //Pan and zoom
- doc.presMovement = PresMovement.Zoom;
- break;
- case PresMovement.Pan: //Pan
- doc.presMovement = PresMovement.Pan;
- break;
- case PresMovement.Jump: //Jump Cut
- doc.presJump = true;
- doc.presMovement = PresMovement.Jump;
- break;
- case PresMovement.None:
- default:
- doc.presMovement = PresMovement.None;
- break;
- }
- });
- });
+ updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement)));
@undoBatch
@action
updateHideBefore = (activeItem: Doc) => {
activeItem.presHideBefore = !activeItem.presHideBefore;
- Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideBefore = activeItem.presHideBefore));
+ this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore));
+ };
+
+ @undoBatch
+ @action
+ updateHide = (activeItem: Doc) => {
+ activeItem.presHide = !activeItem.presHide;
+ this.selectedArray.forEach(doc => (doc.presHide = activeItem.presHide));
};
@undoBatch
@action
updateHideAfter = (activeItem: Doc) => {
activeItem.presHideAfter = !activeItem.presHideAfter;
- Array.from(this._selectedArray.keys()).forEach(doc => (doc.presHideAfter = activeItem.presHideAfter));
+ this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter));
};
@undoBatch
@action
updateOpenDoc = (activeItem: Doc) => {
- activeItem.openDocument = !activeItem.openDocument;
- Array.from(this._selectedArray.keys()).forEach(doc => {
- doc.openDocument = activeItem.openDocument;
- });
+ activeItem.presOpenInLightbox = !activeItem.presOpenInLightbox;
+ this.selectedArray.forEach(doc => (doc.presOpenInLightbox = activeItem.presOpenInLightbox));
};
@undoBatch
@action
- updateEffectDirection = (effect: any, all?: boolean) => {
- const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
- array.forEach(doc => {
- const tagDoc = doc; // Cast(doc.presentationTargetDoc, Doc, null);
- switch (effect) {
- case PresEffect.Left:
- tagDoc.presEffectDirection = PresEffect.Left;
- break;
- case PresEffect.Right:
- tagDoc.presEffectDirection = PresEffect.Right;
- break;
- case PresEffect.Top:
- tagDoc.presEffectDirection = PresEffect.Top;
- break;
- case PresEffect.Bottom:
- tagDoc.presEffectDirection = PresEffect.Bottom;
- break;
- case PresEffect.Center:
- default:
- tagDoc.presEffectDirection = PresEffect.Center;
- break;
- }
- });
+ updateEaseFunc = (activeItem: Doc) => {
+ activeItem.presEaseFunc = activeItem.presEaseFunc === 'linear' ? 'ease' : 'linear';
+ this.selectedArray.forEach(doc => (doc.presEaseFunc = activeItem.presEaseFunc));
};
@undoBatch
@action
- updateEffect = (effect: any, all?: boolean) => {
- const array: any[] = all ? this.childDocs : Array.from(this._selectedArray.keys());
- array.forEach(doc => {
- const tagDoc = doc; //Cast(doc.presentationTargetDoc, Doc, null);
- switch (effect) {
- case PresEffect.Bounce:
- tagDoc.presEffect = PresEffect.Bounce;
- break;
- case PresEffect.Fade:
- tagDoc.presEffect = PresEffect.Fade;
- break;
- case PresEffect.Flip:
- tagDoc.presEffect = PresEffect.Flip;
- break;
- case PresEffect.Roll:
- tagDoc.presEffect = PresEffect.Roll;
- break;
- case PresEffect.Rotate:
- tagDoc.presEffect = PresEffect.Rotate;
- break;
- case PresEffect.None:
- default:
- tagDoc.presEffect = PresEffect.None;
- break;
- }
+ updateEffectDirection = (effect: PresEffectDirection, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect));
+
+ @undoBatch
+ @action
+ updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presEffect = effect)));
+
+ static _sliderBatch: any;
+ public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => {
+ return (
+ <input
+ type="range"
+ step={step}
+ min={min}
+ max={max}
+ value={value}
+ style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)` }}
+ className={`toolbar-slider ${active ? '' : 'none'}`}
+ onPointerDown={e => {
+ PresBox._sliderBatch = UndoManager.StartBatch('pres slider');
+ e.stopPropagation();
+ }}
+ onPointerUp={() => PresBox._sliderBatch.end()}
+ onChange={e => {
+ e.stopPropagation();
+ change(e.target.value);
+ }}
+ />
+ );
+ };
+
+ @undoBatch
+ @action
+ applyTo = (array: Doc[]) => {
+ this.updateMovement(this.activeItem.presMovement as PresMovement, true);
+ this.updateEffect(this.activeItem.presEffect as PresEffect, false, true);
+ this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true);
+ this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true);
+ const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem;
+ array.forEach(curDoc => {
+ curDoc.presTransition = presTransition;
+ curDoc.presDuration = presDuration;
+ curDoc.presHideBefore = presHideBefore;
+ curDoc.presHideAfter = presHideAfter;
});
};
- _batch: UndoManager.Batch | undefined = undefined;
+ @computed get visibiltyDurationDropdown() {
+ const activeItem = this.activeItem;
+ if (activeItem && this.targetDoc) {
+ const targetType = this.targetDoc.type;
+ let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 0;
+ if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
+ return (
+ <div className="presBox-ribbon">
+ <div className="ribbon-doubleButton">
+ <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
+ Hide before
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHide ? 'active' : ''}`} onClick={() => this.updateHide(activeItem)}>
+ Hide
+ </div>
+ </Tooltip>
+
+ <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
+ <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
+ Hide after
+ </div>
+ </Tooltip>
+
+ <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
+ <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presOpenInLightbox ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
+ Lightbox
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{'Transition movement style'}</div>}>
+ <div className="ribbon-toggle" onClick={() => this.updateEaseFunc(activeItem)}>
+ {`${StrCast(activeItem.presEaseFunc, 'ease')}`}
+ </div>
+ </Tooltip>
+ </div>
+ {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : (
+ <>
+ <div className="ribbon-doubleButton">
+ <div className="presBox-subheading">Slide Duration</div>
+ <div className="ribbon-property">
+ <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s
+ </div>
+ <div className="ribbon-propertyUpDown">
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), 1000)}>
+ <FontAwesomeIcon icon={'caret-up'} />
+ </div>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), -1000)}>
+ <FontAwesomeIcon icon={'caret-down'} />
+ </div>
+ </div>
+ </div>
+ {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)}
+ <div className={'slider-headers'} style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}>
+ <div className="slider-text">Short</div>
+ <div className="slider-text">Medium</div>
+ <div className="slider-text">Long</div>
+ </div>
+ </>
+ )}
+ </div>
+ );
+ }
+ }
+ @computed get progressivizeDropdown() {
+ const activeItem = this.activeItem;
+ if (activeItem && this.targetDoc) {
+ const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None;
+ const bulletEffect = (effect: PresEffect) => (
+ <div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect, true)}>
+ {effect}
+ </div>
+ );
+ return (
+ <div className="presBox-ribbon">
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize Collection</div>
+ <input
+ className="presBox-checkbox"
+ style={{ margin: 10 }}
+ type="checkbox"
+ onChange={() => {
+ activeItem.presIndexed = activeItem.presIndexed === undefined ? 0 : undefined;
+ activeItem.presHideBefore = activeItem.presIndexed !== undefined;
+ const tagDoc = PresBox.targetRenderedDoc(this.activeItem);
+ const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type;
+ activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0;
+ // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized.
+ // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list.
+ let dataField = Doc.LayoutFieldKey(tagDoc);
+ if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '-annotations';
+
+ if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`);
+ else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`);
+ }}
+ checked={Cast(activeItem.presIndexed, 'number', null) !== undefined ? true : false}
+ />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Progressivize First Bullet</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presIndexedStart = activeItem.presIndexedStart ? 0 : 1)} checked={!NumCast(activeItem.presIndexedStart)} />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Expand Current Bullet</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)} checked={BoolCast(activeItem.presBulletExpand)} />
+ </div>
+ <div className="ribbon-box">
+ Bullet Effect
+ <div
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openBulletEffectDropdown = !this._openBulletEffectDropdown;
+ })}
+ style={{ borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5, border: this._openBulletEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ {effect?.toString()}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
+ {bulletEffect(PresEffect.None)}
+ {bulletEffect(PresEffect.Fade)}
+ {bulletEffect(PresEffect.Flip)}
+ {bulletEffect(PresEffect.Rotate)}
+ {bulletEffect(PresEffect.Bounce)}
+ {bulletEffect(PresEffect.Roll)}
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ return null;
+ }
@computed get transitionDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection;
- const isPinWithView: boolean = BoolCast(activeItem.presPinView);
- if (activeItem && targetDoc) {
- const type = targetDoc.type;
+ const activeItem = this.activeItem;
+ const presEffect = (effect: PresEffect) => (
+ <div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect, false)}>
+ {effect}
+ </div>
+ );
+ const presMovement = (movement: PresMovement) => (
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === movement ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateMovement(movement)}>
+ {movement}
+ </div>
+ );
+ const presDirection = (direction: PresEffectDirection, icon: string, gridColumn: number, gridRow: number, opts: object) => {
+ const color = activeItem.presEffectDirection === direction || (direction === PresEffectDirection.Center && !activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black';
+ return (
+ <Tooltip title={<div className="dash-tooltip">{direction}</div>}>
+ <div
+ style={{ ...opts, border: direction === PresEffectDirection.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }}
+ onClick={() => this.updateEffectDirection(direction)}>
+ {icon ? <FontAwesomeIcon icon={icon as any} /> : null}
+ </div>
+ </Tooltip>
+ );
+ };
+ if (activeItem && this.targetDoc) {
const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
- const zoom = activeItem.presZoom ? NumCast(activeItem.presZoom) * 100 : 75;
- 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';
- activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
+ const zoom = NumCast(activeItem.presZoom, 1) * 100;
+ const effect = activeItem.presEffect ? activeItem.presEffect : PresMovement.None;
return (
<div
- className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`}
- onPointerDown={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
+ className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`}
+ onPointerDown={StopEvent}
+ onPointerUp={StopEvent}
onClick={action(e => {
e.stopPropagation();
- this.openMovementDropdown = false;
- this.openEffectDropdown = false;
+ this._openMovementDropdown = false;
+ this._openEffectDropdown = false;
+ this._openBulletEffectDropdown = false;
})}>
<div className="ribbon-box">
Movement
- {isPresCollection || (isPresCollection && isPinWithView) ? (
- <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
- {this.scrollable ? 'Scroll to pinned view' : !isPinWithView ? 'No movement' : 'Pan & Zoom to pinned view'}
- </div>
- ) : (
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this.openMovementDropdown = !this.openMovementDropdown;
- })}
- style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
- {this.setMovementName(activeItem.presMovement, activeItem)}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this.openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? 'grid' : 'none' }}>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>
- None
- </div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>
- Pan {'&'} Zoom
- </div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>
- Pan
- </div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>
- Jump cut
- </div>
- </div>
+ <div
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openMovementDropdown = !this._openMovementDropdown;
+ })}
+ style={{ borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, border: this._openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ {this.movementName(activeItem)}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={StopEvent} style={{ display: this._openMovementDropdown ? 'grid' : 'none' }}>
+ {presMovement(PresMovement.None)}
+ {presMovement(PresMovement.Center)}
+ {presMovement(PresMovement.Zoom)}
+ {presMovement(PresMovement.Pan)}
+ {presMovement(PresMovement.Jump)}
</div>
- )}
+ </div>
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
<div className="presBox-subheading">Zoom (% screen filled)</div>
<div className="ribbon-property">
- <input className="presBox-input" type="number" value={zoom} onChange={action(e => this.setZoom(e.target.value))} />%
+ <input className="presBox-input" type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />%
</div>
<div className="ribbon-propertyUpDown">
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), 0.1)}>
<FontAwesomeIcon icon={'caret-up'} />
</div>
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), -0.1)}>
<FontAwesomeIcon icon={'caret-down'} />
</div>
</div>
</div>
- <input
- type="range"
- step="1"
- min="0"
- max="150"
- value={zoom}
- className={`toolbar-slider ${activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}
- id="toolbar-slider"
- onPointerDown={() => (this._batch = UndoManager.StartBatch('presZoom'))}
- onPointerUp={() => this._batch?.end()}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- this.setZoom(e.target.value);
- }}
- />
- <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Movement Speed</div>
+ {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.updateZoom)}
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Transition Time</div>
<div className="ribbon-property">
- <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setTransitionTime(e.target.value))} /> s
+ <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s
</div>
<div className="ribbon-propertyUpDown">
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), 1000)}>
<FontAwesomeIcon icon={'caret-up'} />
</div>
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
+ <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), -1000)}>
<FontAwesomeIcon icon={'caret-down'} />
</div>
</div>
</div>
- <input
- type="range"
- step="0.1"
- min="0.1"
- max="10"
- value={transitionSpeed}
- className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}
- id="toolbar-slider"
- onPointerDown={() => (this._batch = UndoManager.StartBatch('presTransition'))}
- onPointerUp={() => this._batch?.end()}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- this.setTransitionTime(e.target.value);
- }}
- />
- <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
+ {PresBox.inputter('0.1', '0.1', '100', transitionSpeed, true, this.updateTransitionTime)}
+ <div className={'slider-headers'}>
<div className="slider-text">Fast</div>
<div className="slider-text">Medium</div>
<div className="slider-text">Slow</div>
</div>
</div>
<div className="ribbon-box">
- Visibility {'&'} Duration
- <div className="ribbon-doubleButton">
- {isPresCollection ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Hide before presented'}</div>
- </>
- }>
- <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
- Hide before
+ Effects
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Play Audio Annotation</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presPlayAudio = !BoolCast(activeItem.presPlayAudio))} checked={BoolCast(activeItem.presPlayAudio)} />
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
+ <div className="presBox-subheading">Zoom Text Selections</div>
+ <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presZoomText = !BoolCast(activeItem.presZoomText))} checked={BoolCast(activeItem.presZoomText)} />
+ </div>
+ <div
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openEffectDropdown = !this._openEffectDropdown;
+ })}
+ style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ {effect?.toString()}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this._openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
+ {presEffect(PresEffect.None)}
+ {presEffect(PresEffect.Fade)}
+ {presEffect(PresEffect.Flip)}
+ {presEffect(PresEffect.Rotate)}
+ {presEffect(PresEffect.Bounce)}
+ {presEffect(PresEffect.Roll)}
+ </div>
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: effect === PresEffectDirection.None ? 'none' : 'inline-flex' }}>
+ <div className="presBox-subheading">Effect direction</div>
+ <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</div>
+ </div>
+ <div className="effectDirection" style={{ display: effect === PresEffectDirection.None ? 'none' : 'grid', width: 40 }}>
+ {presDirection(PresEffectDirection.Left, 'angle-right', 1, 2, {})}
+ {presDirection(PresEffectDirection.Right, 'angle-left', 3, 2, {})}
+ {presDirection(PresEffectDirection.Top, 'angle-down', 2, 1, {})}
+ {presDirection(PresEffectDirection.Bottom, 'angle-up', 2, 3, {})}
+ {presDirection(PresEffectDirection.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
+ Apply to all
+ </div>
+ </div>
+ </div>
+ );
+ }
+ }
+ @computed get mediaOptionsDropdown() {
+ const activeItem = this.activeItem;
+ if (activeItem && this.targetDoc) {
+ const clipStart = NumCast(activeItem.clipStart);
+ const clipEnd = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration']));
+ return (
+ <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div>
+ <div className="ribbon-box">
+ Start {'&'} End Time
+ <div className={'slider-headers'}>
+ <div className="slider-block">
+ <div className="slider-text" style={{ fontWeight: 500 }}>
+ Start time (s)
</div>
- </Tooltip>
- )}
- {isPresCollection ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Hide after presented'}</div>
- </>
- }>
- <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
- Hide after
+ <div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
+ <input
+ className="presBox-input"
+ style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
+ type="number"
+ value={NumCast(activeItem.presStartTime).toFixed(2)}
+ onKeyDown={e => e.stopPropagation()}
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
+ activeItem.presStartTime = Number(e.target.value);
+ })}
+ />
</div>
- </Tooltip>
- )}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Open in lightbox view'}</div>
- </>
- }>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
- Lightbox
</div>
- </Tooltip>
- </div>
- {type === DocumentType.AUDIO || type === DocumentType.VID ? null : (
- <>
- <div className="ribbon-doubleButton">
- <div className="presBox-subheading">Slide Duration</div>
- <div className="ribbon-property">
- <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setDurationTime(e.target.value))} /> s
+ <div className="slider-block">
+ <div className="slider-text" style={{ fontWeight: 500 }}>
+ Duration (s)
+ </div>
+ <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}>
+ {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10}
+ </div>
+ </div>
+ <div className="slider-block">
+ <div className="slider-text" style={{ fontWeight: 500 }}>
+ End time (s)
</div>
- <div className="ribbon-propertyUpDown">
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
- <FontAwesomeIcon icon={'caret-up'} />
- </div>
- <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
- <FontAwesomeIcon icon={'caret-down'} />
- </div>
+ <div id={'endTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
+ <input
+ className="presBox-input"
+ onKeyDown={e => e.stopPropagation()}
+ style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
+ type="number"
+ value={NumCast(activeItem.presEndTime).toFixed(2)}
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
+ activeItem.presEndTime = Number(e.target.value);
+ })}
+ />
</div>
</div>
+ </div>
+ <div className="multiThumb-slider">
<input
type="range"
step="0.1"
- min="0.1"
- max="20"
- value={duration}
- style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'block' }}
- className={'toolbar-slider'}
- id="duration-slider"
- onPointerDown={() => {
- this._batch = UndoManager.StartBatch('presDuration');
+ min={clipStart}
+ max={clipEnd}
+ value={NumCast(activeItem.presEndTime)}
+ style={{ gridColumn: 1, gridRow: 1 }}
+ className={`toolbar-slider ${'end'}`}
+ id="toolbar-slider"
+ onPointerDown={e => {
+ this._batch = UndoManager.StartBatch('presEndTime');
+ const endBlock = document.getElementById('endTime');
+ if (endBlock) {
+ endBlock.style.color = Colors.LIGHT_GRAY;
+ endBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
+ }
+ e.stopPropagation();
}}
onPointerUp={() => {
- if (this._batch) this._batch.end();
+ this._batch?.end();
+ const endBlock = document.getElementById('endTime');
+ if (endBlock) {
+ endBlock.style.color = Colors.BLACK;
+ endBlock.style.backgroundColor = Colors.LIGHT_GRAY;
+ }
}}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
- this.setDurationTime(e.target.value);
+ activeItem.presEndTime = Number(e.target.value);
}}
/>
- <div className={'slider-headers'} style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'grid' }}>
- <div className="slider-text">Short</div>
- <div className="slider-text">Medium</div>
- <div className="slider-text">Long</div>
- </div>
- </>
- )}
- </div>
- {isPresCollection ? null : (
- <div className="ribbon-box">
- Effects
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this.openEffectDropdown = !this.openEffectDropdown;
- })}
- style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
- {effect.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this.openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
- <div
- className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.None || !this.activeItem.presEffect ? 'active' : ''}`}
- onPointerDown={e => e.stopPropagation()}
- onClick={() => this.updateEffect(PresEffect.None)}>
- None
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Fade ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>
- Fade In
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Flip ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>
- Flip
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Rotate ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>
- Rotate
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Bounce ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>
- Bounce
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Roll ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>
- Roll
- </div>
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: effect === 'None' ? 'none' : 'inline-flex' }}>
- <div className="presBox-subheading">Effect direction</div>
- <div className="ribbon-property">{this.effectDirection}</div>
- </div>
- <div className="effectDirection" style={{ display: effect === 'None' ? 'none' : 'grid', width: 40 }}>
- <Tooltip title={<div className="dash-tooltip">{'Enter from left'}</div>}>
- <div
- style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Left ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Left)}>
- <FontAwesomeIcon icon={'angle-right'} />
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Enter from right'}</div>}>
- <div
- style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Right ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Right)}>
- <FontAwesomeIcon icon={'angle-left'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from top'}</div>
- </>
- }>
- <div
- style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Top ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Top)}>
- <FontAwesomeIcon icon={'angle-down'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from bottom'}</div>
- </>
- }>
- <div
- style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Bottom ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Bottom)}>
- <FontAwesomeIcon icon={'angle-up'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from center'}</div>
- </>
- }>
- <div
- style={{
- gridColumn: 2,
- gridRow: 2,
- width: 10,
- height: 10,
- alignSelf: 'center',
- justifySelf: 'center',
- border: this.activeItem.presEffectDirection === PresEffect.Center || !this.activeItem.presEffectDirection ? `solid 2px ${Colors.LIGHT_BLUE}` : 'solid 2px black',
- borderRadius: '100%',
- cursor: 'pointer',
- }}
- onClick={() => this.updateEffectDirection(PresEffect.Center)}></div>
- </Tooltip>
- </div>
- </div>
- )}
- <div className="ribbon-final-box">
- <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
- Apply to all
- </div>
- </div>
- </div>
- );
- }
- }
-
- @computed get effectDirection(): string {
- let effect = '';
- switch (this.activeItem.presEffectDirection) {
- case 'left':
- effect = 'Enter from left';
- break;
- case 'right':
- effect = 'Enter from right';
- break;
- case 'top':
- effect = 'Enter from top';
- break;
- case 'bottom':
- effect = 'Enter from bottom';
- break;
- default:
- effect = 'Enter from center';
- break;
- }
- return effect;
- }
-
- @undoBatch
- @action
- applyTo = (array: Doc[]) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- this.updateMovement(activeItem.presMovement, true);
- this.updateEffect(activeItem.presEffect, true);
- this.updateEffectDirection(activeItem.presEffectDirection, true);
- array.forEach(doc => {
- const curDoc = Cast(doc, Doc, null);
- const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
- if (tagDoc && targetDoc) {
- curDoc.presTransition = activeItem.presTransition;
- curDoc.presDuration = activeItem.presDuration;
- curDoc.presHideBefore = activeItem.presHideBefore;
- curDoc.presHideAfter = activeItem.presHideAfter;
- }
- });
- };
-
- @computed get presPinViewOptionsDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: 'auto', width: 16, filter: 'invert(1)' }} />;
- return (
- <>
- {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : null}
- <div className="ribbon-doubleButton">
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{activeItem.presPinView ? 'Turn off pin with view' : 'Turn on pin with view'}</div>
- </>
- }>
- <div
- className="ribbon-toggle"
- style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? Colors.LIGHT_BLUE : '' }}
- onClick={() => {
- activeItem.presPinView = !activeItem.presPinView;
- targetDoc.presPinView = activeItem.presPinView;
- if (activeItem.presPinView) {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinView = true;
- activeItem.presPinViewScroll = scroll;
- } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) {
- activeItem.presStartTime = targetDoc._currentTimecode;
- activeItem.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1;
- } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinView = true;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
- } else if (targetDoc.type === DocumentType.COMPARISON) {
- const width = targetDoc._clipWidth;
- activeItem.presPinClipWidth = width;
- activeItem.presPinView = true;
- }
- }
- }}>
- {presPinWithViewIcon}
- </div>
- </Tooltip>
- {activeItem.presPinView ? (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Update the pinned view with the view of the selected document'}</div>
- </>
- }>
- <div
- className="ribbon-button"
- onClick={() => {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinViewScroll = scroll;
- } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) {
- activeItem.presStartTime = targetDoc._currentTimecode;
- activeItem.presStartTime = NumCast(targetDoc._currentTimecode) + 0.1;
- } 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;
- }
- }}>
- Update
- </div>
- </Tooltip>
- ) : null}
- </div>
- </>
- );
- }
-
- @computed get panOptionsDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- return (
- <>
- {this.panable ? (
- <div style={{ display: activeItem.presPinView ? 'block' : 'none' }}>
- <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
- <div className="presBox-subheading">Pan X</div>
- <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
- <input
- className="presBox-input"
- style={{ textAlign: 'left', width: 50 }}
- type="number"
- value={NumCast(activeItem.presPinViewX)}
- onKeyDown={e => e.stopPropagation()}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- const val = e.target.value;
- activeItem.presPinViewX = Number(val);
- })}
- />
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
- <div className="presBox-subheading">Pan Y</div>
- <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
- <input
- className="presBox-input"
- style={{ textAlign: 'left', width: 50 }}
- type="number"
- value={NumCast(activeItem.presPinViewY)}
- onKeyDown={e => e.stopPropagation()}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- const val = e.target.value;
- activeItem.presPinViewY = Number(val);
- })}
- />
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
- <div className="presBox-subheading">Scale</div>
- <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
<input
- className="presBox-input"
- style={{ textAlign: 'left', width: 50 }}
- type="number"
- value={NumCast(activeItem.presPinViewScale)}
- onKeyDown={e => e.stopPropagation()}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- const val = e.target.value;
- activeItem.presPinViewScale = Number(val);
- })}
+ type="range"
+ step="0.1"
+ min={clipStart}
+ max={clipEnd}
+ value={NumCast(activeItem.presStartTime)}
+ style={{ gridColumn: 1, gridRow: 1 }}
+ className={`toolbar-slider ${'start'}`}
+ id="toolbar-slider"
+ onPointerDown={e => {
+ this._batch = UndoManager.StartBatch('presStartTime');
+ const startBlock = document.getElementById('startTime');
+ if (startBlock) {
+ startBlock.style.color = Colors.LIGHT_GRAY;
+ startBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
+ }
+ e.stopPropagation();
+ }}
+ onPointerUp={() => {
+ this._batch?.end();
+ const startBlock = document.getElementById('startTime');
+ if (startBlock) {
+ startBlock.style.color = Colors.BLACK;
+ startBlock.style.backgroundColor = Colors.LIGHT_GRAY;
+ }
+ }}
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+ e.stopPropagation();
+ activeItem.presStartTime = Number(e.target.value);
+ }}
/>
</div>
- </div>
- </div>
- ) : null}
- </>
- );
- }
-
- @computed get scrollOptionsDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- return (
- <>
- {this.scrollable ? (
- <div style={{ display: activeItem.presPinView ? 'block' : 'none' }}>
- <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
- <div className="presBox-subheading">Scroll</div>
- <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
- <input
- className="presBox-input"
- style={{ textAlign: 'left', width: 50 }}
- type="number"
- value={NumCast(activeItem.presPinViewScroll)}
- onKeyDown={e => e.stopPropagation()}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- const val = e.target.value;
- activeItem.presPinViewScroll = Number(val);
- })}
- />
+ <div className="slider-headers">
+ <div className="slider-text">{clipStart.toFixed(2)} s</div>
+ <div className="slider-text"></div>
+ <div className="slider-text">{clipEnd.toFixed(2)} s</div>
</div>
</div>
- </div>
- ) : null}
- </>
- );
- }
-
- @computed get mediaStopSlides() {
- const activeItem: Doc = this.activeItem;
- const list = this.childDocs.map((doc, i) => {
- if (i > this.itemIndex) {
- return (
- <option>
- {i + 1}. {StrCast(doc.title)}
- </option>
- );
- }
- });
- return list;
- }
-
- @computed get mediaOptionsDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const clipStart: number = NumCast(activeItem.clipStart);
- const clipEnd: number = NumCast(activeItem.clipEnd);
- const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10);
- const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
- const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + '. ' + this.childDocs[mediaStopDocInd - 1].title : '';
- if (activeItem && targetDoc) {
- return (
- <div>
- <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
- <div>
- <div className="ribbon-box">
- Start {'&'} End Time
- <div className={'slider-headers'}>
- <div className="slider-block">
- <div className="slider-text" style={{ fontWeight: 500 }}>
- Start time (s)
- </div>
- <div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
- <input
- className="presBox-input"
- style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
- type="number"
- value={NumCast(activeItem.presStartTime)}
- onKeyDown={e => e.stopPropagation()}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- activeItem.presStartTime = Number(e.target.value);
- })}
- />
- </div>
- </div>
- <div className="slider-block">
- <div className="slider-text" style={{ fontWeight: 500 }}>
- Duration (s)
- </div>
- <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}>
- {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10}
- </div>
- </div>
- <div className="slider-block">
- <div className="slider-text" style={{ fontWeight: 500 }}>
- End time (s)
- </div>
- <div id={'endTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
- <input
- className="presBox-input"
- onKeyDown={e => e.stopPropagation()}
- style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
- type="number"
- value={NumCast(activeItem.presEndTime)}
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- activeItem.presEndTime = Number(e.target.value);
- })}
- />
- </div>
- </div>
- </div>
- <div className="multiThumb-slider">
- <input
- type="range"
- step="0.1"
- min={clipStart}
- max={clipEnd}
- value={NumCast(activeItem.presEndTime)}
- style={{ gridColumn: 1, gridRow: 1 }}
- className={`toolbar-slider ${'end'}`}
- id="toolbar-slider"
- onPointerDown={() => {
- this._batch = UndoManager.StartBatch('presEndTime');
- const endBlock = document.getElementById('endTime');
- if (endBlock) {
- endBlock.style.color = Colors.LIGHT_GRAY;
- endBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
- }
- }}
- onPointerUp={() => {
- this._batch?.end();
- const endBlock = document.getElementById('endTime');
- if (endBlock) {
- endBlock.style.color = Colors.BLACK;
- endBlock.style.backgroundColor = Colors.LIGHT_GRAY;
- }
- }}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- activeItem.presEndTime = Number(e.target.value);
- }}
- />
- <input
- type="range"
- step="0.1"
- min={clipStart}
- max={clipEnd}
- value={NumCast(activeItem.presStartTime)}
- style={{ gridColumn: 1, gridRow: 1 }}
- className={`toolbar-slider ${'start'}`}
- id="toolbar-slider"
- onPointerDown={() => {
- this._batch = UndoManager.StartBatch('presStartTime');
- const startBlock = document.getElementById('startTime');
- if (startBlock) {
- startBlock.style.color = Colors.LIGHT_GRAY;
- startBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
- }
- }}
- onPointerUp={() => {
- this._batch?.end();
- const startBlock = document.getElementById('startTime');
- if (startBlock) {
- startBlock.style.color = Colors.BLACK;
- startBlock.style.backgroundColor = Colors.LIGHT_GRAY;
- }
- }}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- activeItem.presStartTime = Number(e.target.value);
- }}
- />
+ <div className="ribbon-final-box">
+ Playback
+ <div className="presBox-subheading">Start playing:</div>
+ <div className="presBox-radioButtons">
+ <div className="checkbox-container">
+ <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} />
+ <div>On click</div>
</div>
- <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
- <div className="slider-text">{clipStart} s</div>
- <div className="slider-text"></div>
- <div className="slider-text">{clipEnd} s</div>
+ <div className="checkbox-container">
+ <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} />
+ <div>Automatically</div>
</div>
</div>
- <div className="ribbon-final-box">
- Playback
- <div className="presBox-subheading">Start playing:</div>
- <div className="presBox-radioButtons">
- <div className="checkbox-container">
- <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} />
- <div>On click</div>
- </div>
- <div className="checkbox-container">
- <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} />
- <div>Automatically</div>
- </div>
+ <div className="presBox-subheading">Stop playing:</div>
+ <div className="presBox-radioButtons">
+ <div className="checkbox-container">
+ <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} />
+ <div>At audio end time</div>
</div>
- <div className="presBox-subheading">Stop playing:</div>
- <div className="presBox-radioButtons">
- <div className="checkbox-container">
- <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} />
- <div>At audio end time</div>
- </div>
- <div className="checkbox-container">
- <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} />
- <div>On slide change</div>
- </div>
- {/* <div className="checkbox-container">
+ <div className="checkbox-container">
+ <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} />
+ <div>On slide change</div>
+ </div>
+ {/* <div className="checkbox-container">
<input className="presBox-checkbox"
type="checkbox"
onChange={() => activeItem.mediaStop = "afterSlide"}
@@ -1947,7 +1903,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</select>
</div>
</div> */}
- </div>
</div>
</div>
</div>
@@ -1955,58 +1910,55 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
}
-
@computed get newDocumentToolbarDropdown() {
return (
- <div>
- <div
- className={'presBox-toolbar-dropdown'}
- style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
- onClick={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
- onPointerDown={e => e.stopPropagation()}>
- <div className="layout-container" style={{ height: 'max-content' }}>
- <div
- className="layout"
- style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'blank';
- this.createNewSlide(this.layout);
- })}
- />
- <div
- className="layout"
- style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'title';
- this.createNewSlide(this.layout);
- })}>
- <div className="title">Title</div>
- <div className="subtitle">Subtitle</div>
- </div>
- <div
- className="layout"
- style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'header';
- this.createNewSlide(this.layout);
- })}>
- <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
- Section header
- </div>
+ <div
+ className="presBox-toolbar-dropdown"
+ style={{ display: this._newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
+ onClick={e => e.stopPropagation()}
+ onPointerUp={e => e.stopPropagation()}
+ onPointerDown={e => e.stopPropagation()}>
+ <div className="layout-container" style={{ height: 'max-content' }}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'blank';
+ this.createNewSlide(this.layout);
+ })}
+ />
+ <div
+ className="layout"
+ style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'title';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title">Title</div>
+ <div className="subtitle">Subtitle</div>
+ </div>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'header';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+ Section header
</div>
- <div
- className="layout"
- style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'content';
- this.createNewSlide(this.layout);
- })}>
- <div className="title" style={{ alignSelf: 'center' }}>
- Title
- </div>
- <div className="content">Text goes here</div>
+ </div>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'content';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title" style={{ alignSelf: 'center' }}>
+ Title
</div>
+ <div className="content">Text goes here</div>
</div>
</div>
</div>
@@ -2020,73 +1972,71 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get newDocumentDropdown() {
return (
- <div>
- <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
- <div className="ribbon-box">
- Slide Title: <br></br>
- <input
- className="ribbon-textInput"
- placeholder="..."
- type="text"
- name="fname"
- onChange={e => {
- e.stopPropagation();
- e.preventDefault();
- runInAction(() => (this.title = e.target.value));
- }}></input>
+ <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="ribbon-box">
+ Slide Title: <br></br>
+ <input
+ className="ribbon-textInput"
+ placeholder="..."
+ type="text"
+ name="fname"
+ onChange={e => {
+ e.stopPropagation();
+ e.preventDefault();
+ runInAction(() => (this.title = e.target.value));
+ }}></input>
+ </div>
+ <div className="ribbon-box">
+ Choose type:
+ <div className="ribbon-doubleButton">
+ <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ Text
+ </div>
+ <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ Freeform
+ </div>
</div>
- <div className="ribbon-box">
- Choose type:
- <div className="ribbon-doubleButton">
- <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
- Text
- </div>
- <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
- Freeform
+ </div>
+ <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
+ Preset layouts:
+ <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
+ <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
+ <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
+ <div className="title">Title</div>
+ <div className="subtitle">Subtitle</div>
+ </div>
+ <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
+ <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+ Section header
</div>
</div>
- </div>
- <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
- Preset layouts:
- <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
- <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
- <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
- <div className="title">Title</div>
- <div className="subtitle">Subtitle</div>
+ <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
+ <div className="title" style={{ alignSelf: 'center' }}>
+ Title
</div>
- <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
- <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
- Section header
- </div>
+ <div className="content">Text goes here</div>
+ </div>
+ <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
+ <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
+ Title
</div>
- <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
- <div className="title" style={{ alignSelf: 'center' }}>
- Title
- </div>
- <div className="content">Text goes here</div>
+ <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
+ Column one text
</div>
- <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
- <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
- Title
- </div>
- <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
- Column one text
- </div>
- <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
- Column two text
- </div>
+ <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
+ Column two text
</div>
</div>
- <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
- <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
- </div>
</div>
- <div className="ribbon-final-box">
- <div
- className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
- onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
- Create New Slide
- </div>
+ <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
+ <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div
+ className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
+ onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
+ Create New Slide
</div>
</div>
</div>
@@ -2099,67 +2049,50 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (freeform && layout) doc = this.createTemplate(layout, title);
if (!freeform && !layout) doc = Docs.Create.TextDocument('', { _nativeWidth: 400, _width: 225, title: title });
if (doc) {
- const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
+ const tabMap = CollectionDockingView.Instance?.tabMap;
+ const tab = tabMap && Array.from(tabMap).find(tab => tab.DashDoc.type === DocumentType.COL)?.DashDoc;
+ const presCollection = DocumentManager.GetContextPath(this.activeItem).reverse().lastElement().presentationTargetDoc ?? tab;
const data = Cast(presCollection?.data, listSpec(Doc));
const presData = Cast(this.rootDoc.data, listSpec(Doc));
if (data && presData) {
data.push(doc);
- TabDocView.PinDoc(doc);
+ TabDocView.PinDoc(doc, {});
this.gotoDocument(this.childDocs.length, this.activeItem);
} else {
- this.props.addDocTab(doc, 'add:right');
+ this.props.addDocTab(doc, OpenWhere.addRight);
}
}
};
createTemplate = (layout: string, input?: string) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- let x = 0;
- let y = 0;
- if (activeItem && targetDoc) {
- x = NumCast(targetDoc.x);
- y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20;
- }
- let doc = undefined;
- const title = Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, _fontSize: '24pt' });
- const subtitle = Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, _fontSize: '16pt' });
- const header = Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, _fontSize: '20pt' });
- const contentTitle = Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, _fontSize: '24pt' });
- const content = Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, _fontSize: '14pt' });
- const content1 = Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, _fontSize: '14pt' });
- const content2 = Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _fontSize: '14pt' });
+ const x = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.x) : 0;
+ const y = this.activeItem && this.targetDoc ? NumCast(this.targetDoc.y) + NumCast(this.targetDoc._height) + 20 : 0;
+ const title = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 58, _fontSize: '24pt' });
+ const subtitle = () => Docs.Create.TextDocument('Click to change subtitle', { title: 'Slide subtitle', _width: 380, _height: 50, x: 10, y: 118, _fontSize: '16pt' });
+ const header = () => Docs.Create.TextDocument('Click to change header', { title: 'Slide header', _width: 380, _height: 65, x: 10, y: 80, _fontSize: '20pt' });
+ const contentTitle = () => Docs.Create.TextDocument('Click to change title', { title: 'Slide title', _width: 380, _height: 60, x: 10, y: 10, _fontSize: '24pt' });
+ const content = () => Docs.Create.TextDocument('Click to change text', { title: 'Slide text', _width: 380, _height: 145, x: 10, y: 70, _fontSize: '14pt' });
+ const content1 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 1', _width: 185, _height: 140, x: 10, y: 80, _fontSize: '14pt' });
+ const content2 = () => Docs.Create.TextDocument('Click to change text', { title: 'Column 2', _width: 185, _height: 140, x: 205, y: 80, _fontSize: '14pt' });
+ // prettier-ignore
switch (layout) {
- case 'blank':
- doc = Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x: x, y: y });
- break;
- case 'title':
- doc = Docs.Create.FreeformDocument([title, subtitle], { title: input ? input : 'Title slide', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y });
- break;
- case 'header':
- doc = Docs.Create.FreeformDocument([header], { title: input ? input : 'Section header', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y });
- break;
- case 'content':
- doc = Docs.Create.FreeformDocument([contentTitle, content], { title: input ? input : 'Title and content', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y });
- break;
- case 'twoColumns':
- doc = Docs.Create.FreeformDocument([contentTitle, content1, content2], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _fitContentsToBox: true, x: x, y: y });
- break;
- default:
- break;
+ case 'blank': return Docs.Create.FreeformDocument([], { title: input ? input : 'Blank slide', _width: 400, _height: 225, x, y });
+ case 'title': return Docs.Create.FreeformDocument([title(), subtitle()], { title: input ? input : 'Title slide', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
+ case 'header': return Docs.Create.FreeformDocument([header()], { title: input ? input : 'Section header', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
+ case 'content': return Docs.Create.FreeformDocument([contentTitle(), content()], { title: input ? input : 'Title and content', _width: 400, _height: 225, _fitContentsToBox: true, x, y });
+ case 'twoColumns': return Docs.Create.FreeformDocument([contentTitle(), content1(), content2()], { title: input ? input : 'Title and two columns', _width: 400, _height: 225, _fitContentsToBox: true, x, y })
}
- return doc;
};
// Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
@computed get presentDropdown() {
return (
- <div className={`dropdown-play ${this.presentTools ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className={`dropdown-play ${this._presentTools ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div
className="dropdown-play-button"
onClick={undoBatch(
action(() => {
- this.updateMinimize();
+ this.enterMinimize();
this.turnOffEdit(true);
this.gotoDocument(this.itemIndex, this.activeItem);
})
@@ -2171,6 +2104,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
onClick={undoBatch(
action(() => {
this.layoutDoc.presStatus = 'manual';
+ this.initializePresState(this.itemIndex);
this.turnOffEdit(true);
this.gotoDocument(this.itemIndex, this.activeItem);
})
@@ -2181,591 +2115,48 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
- // Case in which the document has keyframes to navigate to next key frame
@action
- nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
- const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
- const currentFrame = Cast(tagDoc._currentFrame, 'number', null);
- if (currentFrame === undefined) {
- tagDoc._currentFrame = 0;
- // CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
- // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
- }
- // if (tagDoc.editScrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
- CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
- tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1);
- tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
- };
-
- @action
- prevKeyframe = (tagDoc: Doc, actItem: Doc): void => {
- const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
- const currentFrame = Cast(tagDoc._currentFrame, 'number', null);
- if (currentFrame === undefined) {
- tagDoc._currentFrame = 0;
- // CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
- }
- CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
- tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1);
- };
-
- /**
- * Returns the collection type as a string for headers
- */
- @computed get stringType(): string {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- let type: string = '';
- if (activeItem) {
- switch (targetDoc.type) {
- case DocumentType.PDF:
- type = 'PDF';
- break;
- case DocumentType.RTF:
- type = 'Text node';
- break;
- case DocumentType.COL:
- type = 'Collection';
- break;
- case DocumentType.AUDIO:
- type = 'Audio';
- break;
- case DocumentType.VID:
- type = 'Video';
- break;
- case DocumentType.IMG:
- type = 'Image';
- break;
- case DocumentType.WEB:
- type = 'Web page';
- break;
- case DocumentType.MAP:
- type = 'Map';
- break;
- default:
- type = 'Other node';
- break;
- }
- }
- return type;
- }
-
- @observable private openActiveColorPicker: boolean = false;
- @observable private openViewedColorPicker: boolean = false;
-
- @computed get progressivizeDropdown() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- if (activeItem && targetDoc) {
- const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black';
- const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black';
- return (
- <div>
- <div
- className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`}
- onClick={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
- onPointerDown={e => e.stopPropagation()}>
- <div className="ribbon-box">
- {this.stringType} selected
- <div
- className="ribbon-doubleButton"
- style={{
- borderTop: 'solid 1px darkgrey',
- display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
- }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
- Contents
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
- Edit
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Active text color</div>
- <div
- className="ribbon-colorBox"
- style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
- onClick={action(() => {
- this.openActiveColorPicker = !this.openActiveColorPicker;
- })}></div>
- </div>
- {this.activeColorPicker}
- <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Viewed font color</div>
- <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
- </div>
- {this.viewedColorPicker}
- <div
- className="ribbon-doubleButton"
- style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
- Zoom
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
- Edit
- </div>
- </div>
- <div
- className="ribbon-doubleButton"
- style={{
- borderTop: 'solid 1px darkgrey',
- display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
- }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
- Scroll
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
- Edit
- </div>
- </div>
- </div>
- <div className="ribbon-final-box">
- Frames
- <div className="ribbon-doubleButton">
- <div className="ribbon-frameSelector">
- <div
- key="back"
- title="back frame"
- className="backKeyframe"
- onClick={e => {
- e.stopPropagation();
- this.prevKeyframe(targetDoc, activeItem);
- }}>
- <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
- </div>
- <div
- key="num"
- title="toggle view all"
- className="numKeyframe"
- style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
- onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
- {NumCast(targetDoc._currentFrame)}
- </div>
- <div
- key="fwd"
- title="forward frame"
- className="fwdKeyframe"
- onClick={e => {
- e.stopPropagation();
- this.nextKeyframe(targetDoc, activeItem);
- }}>
- <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
- </div>
- </div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Last frame'}</div>
- </>
- }>
- <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
- </Tooltip>
- </div>
- <div className="ribbon-frameList">
- {this.frameListHeader}
- {this.frameList}
- </div>
- <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
- Play
- </div>
- </div>
- </div>
- </div>
- );
- }
- }
-
- @undoBatch
- @action
- switchActive = (color: ColorState) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const val = String(color.hex);
- targetDoc['pres-text-color'] = val;
- return true;
- };
- @undoBatch
- @action
- switchPresented = (color: ColorState) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const val = String(color.hex);
- targetDoc['pres-text-viewed-color'] = val;
- return true;
- };
-
- @computed get activeColorPicker() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- return !this.openActiveColorPicker ? null : (
- <SketchPicker
- onChange={this.switchActive}
- presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={StrCast(targetDoc['pres-text-color'])}
- />
- );
- }
-
- @computed get viewedColorPicker() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- return !this.openViewedColorPicker ? null : (
- <SketchPicker
- onChange={this.switchPresented}
- presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={StrCast(targetDoc['pres-text-viewed-color'])}
- />
- );
- }
-
- @action
- turnOffEdit = (paths?: boolean) => {
- // Turn off paths
- if (paths) {
- const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
- if (srcContext) this.togglePath(srcContext, true);
- }
- // Turn off the progressivize editors for each document
- this.childDocs.forEach(doc => {
- doc.editSnapZoomProgressivize = false;
- doc.editZoomProgressivize = false;
- const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
- if (targetDoc) {
- targetDoc.editZoomProgressivize = false;
- // targetDoc.editScrollProgressivize = false;
- }
- });
- };
-
- //Toggle whether the user edits or not
- @action
- editZoomProgressivize = (e: React.MouseEvent) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- if (!targetDoc.editZoomProgressivize) {
- if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true;
- targetDoc.zoomProgressivize = true;
- targetDoc.editZoomProgressivize = true;
- activeItem.editZoomProgressivize = true;
- } else {
- targetDoc.editZoomProgressivize = false;
- activeItem.editZoomProgressivize = false;
- }
- };
-
- //Toggle whether the user edits or not
- @action
- editScrollProgressivize = (e: React.MouseEvent) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- if (!targetDoc.editScrollProgressivize) {
- if (!targetDoc.scrollProgressivize) {
- targetDoc.scrollProgressivize = true;
- activeItem.scrollProgressivize = true;
- }
- targetDoc.editScrollProgressivize = true;
- } else {
- targetDoc.editScrollProgressivize = false;
- }
- };
-
- //Progressivize Zoom
- @action
- progressivizeScroll = (e: React.MouseEvent) => {
- e.stopPropagation();
- const activeItem: Doc = this.activeItem;
- activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
- const targetDoc: Doc = this.targetDoc;
- targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
- // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame));
- if (targetDoc.editScrollProgressivize) {
- targetDoc.editScrollProgressivize = false;
- targetDoc._currentFrame = 0;
- targetDoc.lastFrame = 0;
- }
- };
-
- //Progressivize Zoom
- @action
- progressivizeZoom = (e: React.MouseEvent) => {
- e.stopPropagation();
- const activeItem: Doc = this.activeItem;
- activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
- const targetDoc: Doc = this.targetDoc;
- targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
- CollectionFreeFormDocumentView.setupZoom(activeItem, targetDoc);
- if (activeItem.editZoomProgressivize) {
- activeItem.editZoomProgressivize = false;
- targetDoc._currentFrame = 0;
- targetDoc.lastFrame = 0;
- }
- };
-
- //Progressivize Child Docs
- @action
- editProgressivize = (e: React.MouseEvent) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- targetDoc._currentFrame = targetDoc.lastFrame;
- if (!targetDoc.editProgressivize) {
- if (!activeItem.presProgressivize) {
- activeItem.presProgressivize = true;
- targetDoc.presProgressivize = true;
- }
- targetDoc.editProgressivize = true;
- } else {
- targetDoc.editProgressivize = false;
- }
- };
-
- @action
- progressivizeChild = (e: React.MouseEvent) => {
- e.stopPropagation();
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
- if (!activeItem.presProgressivize) {
- targetDoc.keyFrameEditing = false;
- activeItem.presProgressivize = true;
- targetDoc.presProgressivize = true;
- targetDoc._currentFrame = 0;
- docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
- targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1;
- } else {
- // targetDoc.editProgressivize = false;
- activeItem.presProgressivize = false;
- targetDoc.presProgressivize = false;
- targetDoc._currentFrame = 0;
- targetDoc.keyFrameEditing = true;
- }
- };
-
- @action
- checkMovementLists = (doc: Doc, xlist: any, ylist: any) => {
- const x: List<number> = xlist;
- const y: List<number> = ylist;
- const tags: JSX.Element[] = [];
- let pathPoints = ''; //List of all of the pathpoints that need to be added
- for (let i = 0; i < x.length - 1; i++) {
- if (y[i] || x[i]) {
- if (i === 0) pathPoints = x[i] - 11 + ',' + (y[i] + 33);
- else pathPoints = pathPoints + ' ' + (x[i] - 11) + ',' + (y[i] + 33);
- tags.push(
- <div className="progressivizeMove-frame" style={{ position: 'absolute', top: y[i], left: x[i] }}>
- {i}
- </div>
- );
- }
- }
- tags.push(
- <svg style={{ overflow: 'visible', position: 'absolute' }}>
- <polyline
- points={pathPoints}
- style={{
- position: 'absolute',
- opacity: 1,
- stroke: '#000000',
- strokeWidth: 2,
- strokeDasharray: '10 5',
- }}
- fill="none"
- />
- </svg>
- );
- return tags;
- };
-
- @observable
- toggleDisplayMovement = (doc: Doc) => {
- if (doc.displayMovement) doc.displayMovement = false;
- else doc.displayMovement = true;
- };
-
- @action
- checkList = (doc: Doc, list: any): number => {
- const x: List<number> = list;
- if (x && x.length >= NumCast(doc._currentFrame) + 1) {
- return x[NumCast(doc._currentFrame)];
- } else if (x) {
- x.length = NumCast(doc._currentFrame) + 1;
- x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1];
- return x[NumCast(doc._currentFrame)];
- } else return 100;
- };
-
- @computed get progressivizeChildDocs() {
- const targetDoc: Doc = this.targetDoc;
- const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
- const tags: JSX.Element[] = [];
- docs.forEach((doc, index) => {
- if (doc['x-indexed'] && doc['y-indexed']) {
- tags.push(<div style={{ position: 'absolute', display: doc.displayMovement ? 'block' : 'none' }}>{this.checkMovementLists(doc, doc['x-indexed'], doc['y-indexed'])}</div>);
- }
- tags.push(
- <div
- className="progressivizeButton"
- key={index}
- onPointerLeave={() => {
- if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0;
- }}
- onPointerOver={() => {
- if (NumCast(targetDoc._currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5;
- }}
- onClick={e => {
- this.toggleDisplayMovement(doc);
- e.stopPropagation();
- }}
- style={{ backgroundColor: doc.displayMovement ? Colors.LIGHT_BLUE : '#c8c8c8', top: NumCast(doc.y), left: NumCast(doc.x) }}>
- <div className="progressivizeButton-prev">
- <FontAwesomeIcon
- icon={'caret-left'}
- size={'lg'}
- onClick={e => {
- e.stopPropagation();
- this.prevAppearFrame(doc, index);
- }}
- />
- </div>
- <div className="progressivizeButton-frame">{NumCast(doc.appearFrame)}</div>
- <div className="progressivizeButton-next">
- <FontAwesomeIcon
- icon={'caret-right'}
- size={'lg'}
- onClick={e => {
- e.stopPropagation();
- this.nextAppearFrame(doc, index);
- }}
- />
- </div>
- </div>
- );
- });
- return tags;
- }
-
- @action
- nextAppearFrame = (doc: Doc, i: number): void => {
- // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- const appearFrame = Cast(doc.appearFrame, 'number', null);
- if (appearFrame === undefined) {
- doc.appearFrame = 0;
- }
- doc.appearFrame = appearFrame + 1;
- this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
- };
-
- @action
- prevAppearFrame = (doc: Doc, i: number): void => {
- // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- const appearFrame = Cast(doc.appearFrame, 'number', null);
- if (appearFrame === undefined) {
- doc.appearFrame = 0;
- }
- doc.appearFrame = Math.max(0, appearFrame - 1);
- this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
- };
-
- @action
- updateOpacityList = (list: any, frame: number) => {
- const x: List<number> = list;
- if (x && x.length >= frame) {
- for (let i = 0; i < x.length; i++) {
- if (i < frame) {
- x[i] = 0;
- } else if (i >= frame) {
- x[i] = 1;
- }
- }
- list = x;
- } else {
- x.length = frame + 1;
- for (let i = 0; i < x.length; i++) {
- if (i < frame) {
- x[i] = 0;
- } else if (i >= frame) {
- x[i] = 1;
- }
- }
- list = x;
- }
- };
-
- @computed get moreInfoDropdown() {
- return <div></div>;
- }
+ turnOffEdit = (paths?: boolean) => paths && this.togglePath(true); // Turn off paths
@computed
get toolbarWidth(): number {
- const width = this.props.PanelWidth();
- return width;
+ return this.props.PanelWidth();
}
@action
- toggleProperties = () => {
- if (SettingsManager.propertiesWidth > 0) {
- SettingsManager.propertiesWidth = 0;
- } else {
- SettingsManager.propertiesWidth = 250;
- }
- };
+ toggleProperties = () => (SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250);
@computed get toolbar() {
const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
const propTitle = SettingsManager.propertiesWidth > 0 ? 'Close Presentation Panel' : 'Open Presentation Panel';
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
const isMini: boolean = this.toolbarWidth <= 100;
- const presKeyEvents: boolean = this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.ActivePresentation;
+ const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
const activeColor = Colors.LIGHT_BLUE;
const inactiveColor = Colors.WHITE;
- return mode === CollectionViewType.Carousel3D ? null : (
+ return mode === CollectionViewType.Carousel3D || inOverlay ? null : (
<div id="toolbarContainer" className={'presBox-toolbar'}>
{/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
<FontAwesomeIcon icon={"plus"} />
<FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
</div></Tooltip> */}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'View paths'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">View paths</div>}>
<div
- style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }}
+ style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }}
className={'toolbar-button'}
- onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
+ onClick={this.childDocs.length > 1 ? () => this.togglePath() : undefined}>
<FontAwesomeIcon icon={'exchange-alt'} />
</div>
</Tooltip>
{isMini ? null : (
<>
<div className="toolbar-divider" />
- {/* <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
- <div className={"toolbar-button"}
- style={{ color: this._expandBoolean ? Colors.MEDIUM_BLUE : 'white' }}
- onClick={this.toggleExpandMode}>
- <FontAwesomeIcon icon={"eye"} />
+ <Tooltip title={<div className="dash-tooltip">{this._presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>}>
+ <div className="toolbar-button" style={{ cursor: this._presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
+ <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: this._presKeyEvents ? activeColor : inactiveColor }} />
</div>
</Tooltip>
- <div className="toolbar-divider" /> */}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>
- </>
- }>
- <div className="toolbar-button" style={{ cursor: presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
- <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: presKeyEvents ? activeColor : inactiveColor }} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{propTitle}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{propTitle}</div>}>
<div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
<FontAwesomeIcon className={'toolbar-thumbtack'} icon={propIcon} style={{ color: SettingsManager.propertiesWidth > 0 ? activeColor : inactiveColor }} />
</div>
@@ -2784,30 +2175,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get topPanel() {
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
const isMini: boolean = this.toolbarWidth <= 100;
+ const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
return (
- <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
+ <div className={`presBox-buttons${inOverlay ? ' inOverlay' : ''}`} style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
{isMini ? null : (
<select className="presBox-viewPicker" style={{ display: this.layoutDoc.presStatus === 'edit' ? 'block' : 'none' }} onPointerDown={e => e.stopPropagation()} onChange={this.viewChanged} value={mode}>
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Stacking}>
List
</option>
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Tree}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Tree}>
Tree
</option>
{Doc.noviceMode ? null : (
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Carousel3D}>
3D Carousel
</option>
)}
</select>
)}
<div className="presBox-presentPanel" style={{ opacity: this.childDocs.length ? 1 : 0.3 }}>
- <span className={`presBox-button ${this.layoutDoc.presStatus === 'edit' ? 'present' : ''}`}>
+ <span className={`presBox-button ${this.layoutDoc.presStatus === PresStatus.Edit ? 'present' : ''}`}>
<div
className="presBox-button-left"
onClick={undoBatch(() => {
if (this.childDocs.length) {
this.layoutDoc.presStatus = 'manual';
+ this.initializePresState(this.itemIndex);
this.gotoDocument(this.itemIndex, this.activeItem);
}
})}>
@@ -2816,11 +2209,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
{mode === CollectionViewType.Carousel3D || isMini ? null : (
<div
- className={`presBox-button-right ${this.presentTools ? 'active' : ''}`}
+ className={`presBox-button-right ${this._presentTools ? 'active' : ''}`}
onClick={action(() => {
- if (this.childDocs.length) this.presentTools = !this.presentTools;
+ if (this.childDocs.length) this._presentTools = !this._presentTools;
})}>
- <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
+ <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this._presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
{this.presentDropdown}
</div>
)}
@@ -2831,168 +2224,97 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
- @action
- getList = (list: any): List<number> => {
- const x: List<number> = list;
- return x;
- };
-
- @action
- updateList = (list: any): List<number> => {
- const targetDoc: Doc = this.targetDoc;
- const x: List<number> = list;
- x.length + 1;
- x[x.length - 1] = NumCast(targetDoc._scrollY);
- return x;
- };
-
- @action
- newFrame = () => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const type: string = StrCast(targetDoc.type);
- if (!activeItem.frameList) activeItem.frameList = new List<number>();
- switch (type) {
- case DocumentType.PDF || DocumentType.RTF || DocumentType.WEB:
- this.updateList(activeItem.frameList);
- break;
- case DocumentType.COL:
- break;
- default:
- break;
- }
- };
-
- @computed get frameListHeader() {
- return (
- <div className="frameList-header">
- &nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : null}
- <div className={'frameList-headerButtons'}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Add frame by example'}</div>
- </>
- }>
- <div
- className={'headerButton'}
- onClick={e => {
- e.stopPropagation();
- this.newFrame();
- }}>
- <FontAwesomeIcon icon={'plus'} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Edit in collection'}</div>
- </>
- }>
- <div
- className={'headerButton'}
- onClick={e => {
- e.stopPropagation();
- console.log('New frame');
- }}>
- <FontAwesomeIcon icon={'edit'} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- </div>
- </div>
- );
- }
-
- @computed get frameList() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const frameList: List<number> = this.getList(activeItem.frameList);
- if (frameList) {
- const frameItems = frameList.map(value => <div className="framList-item"></div>);
- return <div className="frameList-container">{frameItems}</div>;
- } else return null;
- }
-
- @computed get playButtonFrames() {
- const targetDoc: Doc = this.targetDoc;
- return (
- <>
- {this.targetDoc ? (
- <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
- <div>{NumCast(targetDoc._currentFrame)}</div>
- <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
- <div>{NumCast(targetDoc.lastFrame)}</div>
- </div>
- ) : null}
- </>
- );
- }
-
@computed get playButtons() {
- const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1;
+ const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0));
const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
+ const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
// Case 1: There are still other frames and should go through all frames before going to next slide
return (
<div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== 'edit' ? 'inline-flex' : 'none' }}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Loop'}</div>
- </>
- }>
- <div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }} onClick={() => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}>
+ <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
+ <div
+ className="presPanel-button"
+ style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }}
+ onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop), false, false)}>
<FontAwesomeIcon icon={'redo-alt'} />
</div>
</Tooltip>
- <div className="presPanel-divider"></div>
+ <div className="presPanel-divider" />
<div
className="presPanel-button"
style={{ opacity: presStart ? 0.4 : 1 }}
- onClick={() => {
- this.back();
- if (this._presTimer) {
- clearTimeout(this._presTimer);
- this.layoutDoc.presStatus = PresStatus.Manual;
- }
- }}>
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ () => {
+ this.back();
+ if (this._presTimer) {
+ clearTimeout(this._presTimer);
+ this.layoutDoc.presStatus = PresStatus.Manual;
+ }
+ e.stopPropagation();
+ },
+ false,
+ false
+ )
+ }>
<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}>
- <FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
+ <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
+ <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this.startOrPause(true), false, false)}>
+ <FontAwesomeIcon color={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'red' : undefined} icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
</div>
</Tooltip>
<div
className="presPanel-button"
style={{ opacity: presEnd ? 0.4 : 1 }}
- onClick={() => {
- this.next();
- if (this._presTimer) {
- clearTimeout(this._presTimer);
- this.layoutDoc.presStatus = PresStatus.Manual;
- }
- }}>
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ () => {
+ this.next();
+ if (this._presTimer) {
+ clearTimeout(this._presTimer);
+ this.layoutDoc.presStatus = PresStatus.Manual;
+ }
+ e.stopPropagation();
+ },
+ false,
+ false
+ )
+ }>
<FontAwesomeIcon icon={'arrow-right'} />
</div>
<div className="presPanel-divider"></div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
- </>
- }>
- <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}>
+ <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
+ <div
+ className="presPanel-button"
+ style={{ border: 'solid 1px white' }}
+ onPointerDown={e =>
+ setupMoveUpEvents(
+ this,
+ e,
+ returnFalse,
+ emptyFunction,
+ () => {
+ this.nextSlide(0);
+ },
+ false,
+ false
+ )
+ }>
<b>1</b>
</div>
</Tooltip>
- <div className="presPanel-button-text" onClick={() => this.gotoDocument(0, this.activeItem)} style={{ display: this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}>
- Slide {this.itemIndex + 1} / {this.childDocs.length}
- {this.playButtonFrames}
+ <div className="presPanel-button-text" onClick={() => this.gotoDocument(0, this.activeItem)} style={{ display: inOverlay || this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}>
+ {inOverlay ? '' : 'Slide'} {this.itemIndex + 1}
+ {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
</div>
<div className="presPanel-divider"></div>
{this.props.PanelWidth() > 250 ? (
@@ -3000,14 +2322,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
className="presPanel-button-text"
onClick={undoBatch(
action(() => {
- this.layoutDoc.presStatus = 'edit';
+ this.layoutDoc.presStatus = PresStatus.Edit;
clearTimeout(this._presTimer);
})
)}>
EXIT
</div>
) : (
- <div className="presPanel-button" onClick={undoBatch(action(() => (this.layoutDoc.presStatus = 'edit')))}>
+ <div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, this.exitClicked, false, false)}>
<FontAwesomeIcon icon={'times'} />
</div>
)}
@@ -3016,8 +2338,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@action
- startOrPause = () => {
- if (this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startAutoPres(this.itemIndex);
+ startOrPause = (makeActive = true) => {
+ makeActive && this.updateCurrentPresentation();
+ if (!this.layoutDoc.presStatus || this.layoutDoc.presStatus === PresStatus.Manual || this.layoutDoc.presStatus === PresStatus.Edit) this.startPresentation(this.itemIndex);
else this.pauseAutoPres();
};
@@ -3038,20 +2361,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc.presStatus = PresStatus.Manual;
}
};
+
@undoBatch
@action
- exitClicked = (e: PointerEvent) => {
- this.updateMinimize();
- this.layoutDoc.presStatus = PresStatus.Edit;
+ exitClicked = () => {
+ this.layoutDoc.presStatus = this._exitTrail?.() ?? this.exitMinimize();
clearTimeout(this._presTimer);
};
- @action
- startMarqueeCreateSlide = () => {
- PresBox.startMarquee = true;
- };
-
- AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
+ AddToMap = (treeViewDoc: Doc, index: number[]) => {
+ if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element.
var indexNum = 0;
for (let i = 0; i < index.length; i++) {
indexNum += index[i] * 10 ** -i;
@@ -3064,38 +2383,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.dataDoc[this.presFieldKey] = new List<Doc>(sorted); // this is a flat array of Docs
}
}
- return this.childDocs;
};
- RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
+ RemFromMap = (treeViewDoc: Doc, index: number[]) => {
+ if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element.
if (!this._unmounting && this.isTree) {
this._treeViewMap.delete(treeViewDoc);
this.dataDoc[this.presFieldKey] = new List<Doc>(this.sort(this._treeViewMap));
}
- return this.childDocs;
};
- // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
sort = (treeViewMap: Map<Doc, number>) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]);
render() {
- // calling this method for keyEvents
- this.isPres;
// needed to ensure that the childDocs are loaded for looking up fields
this.childDocs.slice();
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
- const presKeyEvents: boolean = this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.ActivePresentation;
- const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1;
- const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
- return DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc) ? (
- <div className="miniPres" onClick={e => e.stopPropagation()}>
- <div className="presPanelOverlay" style={{ display: 'inline-flex', height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Loop'}</div>
- </>
- }>
+ const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0));
+ const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0;
+ const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc);
+ return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
+ <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
+ <div
+ className="presPanelOverlay"
+ style={{ display: 'inline-flex', height: 30, background: Doc.ActivePresentation === this.rootDoc ? 'green' : '#323232', top: 0, zIndex: 3000000, boxShadow: this._presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
+ <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
<div
className="presPanel-button"
style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
@@ -3107,13 +2419,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
<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)}>
+ <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(true), false, false)}>
<FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} />
</div>
</Tooltip>
@@ -3121,19 +2428,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'arrow-right'} />
</div>
<div className="presPanel-divider"></div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
<div className="presPanel-button" style={{ border: 'solid 1px white' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>
<b>1</b>
</div>
</Tooltip>
<div className="presPanel-button-text">
- Slide {this.itemIndex + 1} / {this.childDocs.length}
- {this.playButtonFrames}
+ Slide {this.itemIndex + 1}
+ {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length}
</div>
<div className="presPanel-divider" />
<div className="presPanel-button-text" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}>
@@ -3142,12 +2444,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
) : (
- <div className="presBox-cont" style={{ minWidth: DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc) ? 240 : undefined }}>
+ <div className="presBox-cont" style={{ minWidth: inOverlay ? PresBox.minimizedWidth : undefined }}>
{this.topPanel}
{this.toolbar}
{this.newDocumentToolbarDropdown}
<div className="presBox-listCont">
- <div className="Slide" style={{ height: `calc(100% - 30px)` }}>
+ <div className="Slide">
{mode !== CollectionViewType.Invalid ? (
<CollectionView
{...this.props}
@@ -3156,30 +2458,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
PanelHeight={this.panelHeight}
childIgnoreNativeSize={true}
moveDocument={returnFalse}
- childFitWidth={returnTrue}
+ ignoreUnrendered={true}
+ //childFitWidth={returnTrue}
childOpacity={returnOne}
+ //childLayoutString={PresElementBox.LayoutString('data')}
+ childClickScript={PresBox.navigateToDocScript}
childLayoutTemplate={this.childLayoutTemplate}
+ childXPadding={Doc.IsComicStyle(this.rootDoc) ? 20 : undefined}
filterAddDocument={this.addDocumentFilter}
removeDocument={returnFalse}
dontRegisterView={true}
- focus={this.selectElement}
+ focus={this.focusElement}
scriptContext={this}
ScreenToLocalTransform={this.getTransform}
AddToMap={this.AddToMap}
RemFromMap={this.RemFromMap}
- hierarchyIndex={[]}
+ hierarchyIndex={emptyPath}
/>
) : null}
</div>
- {
+ {/* {
// if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack
<Tooltip title={<div className="dash-tooltip">{'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}</div>}>
<button className="add-slide-button" onPointerDown={this.startMarqueeCreateSlide}>
+ NEW SLIDE
</button>
</Tooltip>
- }
+ } */}
</div>
</div>
);
@@ -3187,10 +2493,5 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) {
- const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null);
- const openInTab = (doc: Doc, finished?: () => void) => {
- CollectionDockingView.AddSplit(doc, 'right');
- finished?.();
- };
- DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom));
+ PresBox.NavigateToTarget(bestTarget, activeItem);
});