diff options
| author | Jenny Yu <jennyyu212@outlook.com> | 2022-09-12 21:57:15 -0400 |
|---|---|---|
| committer | Jenny Yu <jennyyu212@outlook.com> | 2022-09-12 21:57:15 -0400 |
| commit | 7da791491a588f2a2a177a4eb144311ba49f5782 (patch) | |
| tree | ec715830946f7e1329135ff12be2c1d66ac65149 /src/client/views/nodes/trails | |
| parent | 7f0eacf3fc0b54ceb4d574a719208861789581d3 (diff) | |
| parent | 4315a0378bc54ae9eaa684d416839f635c38e865 (diff) | |
Merge branch 'master' into sharing-jenny (break)
Diffstat (limited to 'src/client/views/nodes/trails')
| -rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 1731 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresElementBox.tsx | 208 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresEnums.ts | 42 |
3 files changed, 712 insertions, 1269 deletions
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index c95ece3da..82b8a8f90 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,16 +1,18 @@ 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 { Copy } from '../../../../fields/FieldSymbols'; import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; +import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils'; +import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; @@ -19,7 +21,7 @@ import { SelectionManager } from '../../../util/SelectionManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionView } from '../../collections/CollectionView'; import { TabDocView } from '../../collections/TabDocView'; import { ViewBoxBaseComponent } from '../../DocComponent'; @@ -32,7 +34,7 @@ import { PresEffect, PresMovement, PresStatus } from './PresEnums'; export interface PinProps { audioRange?: boolean; - setPosition?: boolean; + activeFrame?: number; hidePresBox?: boolean; pinWithView?: PinViewProps; pinDocView?: boolean; // whether the current view specs of the document should be saved the pinned document @@ -66,52 +68,51 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { delay: presDoc.presTransition, // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc, }; + //prettier-ignore 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; + default: + case PresEffect.None: return renderDoc; + 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>; } } 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>(); + + constructor(props: any) { + super(props); + if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this)); + } + @observable public static Instance: PresBox; + @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView @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 _progressivizeTools: boolean = false; + @observable _openMovementDropdown: boolean = false; + @observable _openEffectDropdown: 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); } @@ -124,15 +125,8 @@ 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); @@ -143,42 +137,33 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); } - @computed get scrollable(): boolean { + @computed get scrollable() { 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; + 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; } + clearSelectedArray = () => this.selectedArray.clear(); + addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc); + removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc); _unmounting = false; @action componentWillUnmount() { this._unmounting = true; document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); - this._presKeyEventsActive = false; this.resetPresentation(); // Turn of progressivize editors this.turnOffEdit(true); @@ -187,6 +172,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @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; @@ -204,11 +210,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @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; }; @@ -312,12 +314,25 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { //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. + @undoBatch public gotoDocument = action((index: number, from?: Doc, group?: boolean) => { Doc.UnBrushAllDocs(); + if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; + if (activeItem.presActiveFrame !== undefined) { + const transTime = NumCast(activeItem.presTransition, 500); + const context = DocCast(DocCast(activeItem.presentationTargetDoc).context); + if (context) { + const contextView = DocumentManager.Instance.getFirstDocumentView(context); + if (contextView?.ComponentView) { + CollectionFreeFormDocumentView.gotoKeyframe((contextView.ComponentView as CollectionFreeFormView).childDocs.slice(), transTime); + context._currentFrame = NumCast(activeItem.presActiveFrame); + } + } + } if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } @@ -330,62 +345,97 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } 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); + targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500))); + setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10); } if (targetDoc?.lastFrame !== undefined) { targetDoc._currentFrame = 0; } - if (!group) this._selectedArray.clear(); - this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array + if (!group) this.clearSelectedArray(); + this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list this.onHideDocument(); //Handles hide after/before } }); + static pinDataTypes(target: Doc) { + const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking; + const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform); + const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any); + const clippable = [DocumentType.COMPARISON].includes(target.type as any); + const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined; + const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined; + return { scrollable, pannable, temporal, clippable, dataview, textview }; + } - _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); - }; - - // 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'; + static restoreTargetDocView(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) { + const transTime = NumCast(activeItem.presTransition, 500); + const presTransitionTime = `all ${transTime}ms`; + const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget); + bestTarget._viewTransition = presTransitionTime; + if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth; + if (temporal) bestTarget._currentTimecode = activeItem.presStartTime; + if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll; + if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + if (pannable) { + bestTarget._panX = activeItem.presPinViewX; + bestTarget._panY = activeItem.presPinViewY; + bestTarget._viewScale = activeItem.presPinViewScale; + const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { - bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2; - bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2; 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])); + dv && (bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0]))); + } + } + return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10); + } + + /// 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 | undefined, targetDoc: Doc) { + if (pinProps?.pinWithView) { + // If pinWithView option set then update scale and x / y props of slide + const bounds = pinProps.pinWithView.bounds; + pinDoc.presPinView = true; + pinDoc.presPinViewX = bounds.left + bounds.width / 2; + pinDoc.presPinViewY = bounds.top + bounds.height / 2; + pinDoc.presPinViewScale = pinProps.pinWithView.scale; + pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); + } + if (pinProps?.pinDocView) { + const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc); + pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined; + pinDoc.presX = NumCast(targetDoc.x); + pinDoc.presY = NumCast(targetDoc.y); + pinDoc.presRot = NumCast(targetDoc.jitterRotation); + pinDoc.presWidth = NumCast(targetDoc.width); + pinDoc.presHeight = NumCast(targetDoc.height); + + if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop; + if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth; + if (temporal) pinDoc.presEndTime = NumCast((pinDoc.presStartTime = pinDoc._currentTimecode)) + 0.1; + if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text; + if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data; + if (pannable) { + const panX = NumCast(pinDoc._panX); + const panY = NumCast(pinDoc._panY); + const pw = NumCast(pinProps.panelWidth); + const ph = NumCast(pinProps.panelHeight); + const ps = NumCast(pinDoc._viewScale, 1); + if (pw && ph && ps) { + pinDoc.presPinViewBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]); } - } else { - bestTarget._panX = activeItem.presPinViewX; - bestTarget._panY = activeItem.presPinViewY; - bestTarget._viewScale = activeItem.presPinViewScale; + pinDoc.presPinViewX = panX; + pinDoc.presPinViewY = panY; + pinDoc.presPinViewScale = ps; } } - return setTimeout(() => (bestTarget._viewTransition = undefined), activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510); } + _navTimer!: NodeJS.Timeout; /** * This method makes sure that cursor navigates to the element that * has the option open and last in the group. @@ -401,7 +451,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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 = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext); + const tab = CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext); this.turnOffEdit(); // Handles the setting of presCollection if (includesDoc) { @@ -411,7 +461,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.layoutDoc.presCollection = srcContext; } const presStatus = this.rootDoc.presStatus; - const selViewCache = Array.from(this._selectedArray.keys()); + const selViewCache = Array.from(this.selectedArray); const dragViewCache = Array.from(this._dragArray); const eleViewCache = Array.from(this._eleArray); const self = this; @@ -419,8 +469,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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.clearSelectedArray(); + selViewCache.forEach(doc => self.addToSelectedArray(doc)); self._dragArray.splice(0, self._dragArray.length, ...dragViewCache); self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); @@ -435,25 +485,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { finished?.(); } }; + if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) { + const transTime = NumCast(activeItem.presTransition, 500); + const presTransitionTime = `all ${transTime}ms`; + targetDoc._dataTransition = presTransitionTime; + targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x)); + targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y)); + targetDoc.jitterRotation = NumCast(activeItem.presRot, NumCast(targetDoc.jitterRotation)); + targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width)); + targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height)); + setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10); + } // 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(targetDoc); // openInTab(targetDoc); + } else if (targetDoc && curDoc.presMovement !== PresMovement.None && 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 + const zooming = curDoc.presMovement !== PresMovement.Pan; + DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); } // 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); + clearTimeout(this._navTimer); + const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document; + if (bestTarget) this._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem, false); } }; @@ -511,26 +568,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.childDocs.forEach((doc, index) => { const curDoc = Cast(doc, Doc, null); const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); - if (tagDoc) tagDoc.opacity = 1; + //if (tagDoc) tagDoc.opacity = 1; 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 (!curDoc.presHideAfter) { + if (curDoc.presHideBefore) { + if (itemIndexes.length > 1 && curInd !== 0) { tagDoc.opacity = 1; + } else { + if (index > this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideAfter) { + tagDoc.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 (!curDoc.presHideBefore) { + if (curDoc.presHideAfter) { + if (itemIndexes.length > 1 && curInd !== itemIndexes.length - 1) { tagDoc.opacity = 1; + } else { + if (index < this.itemIndex) { + tagDoc.opacity = 0; + } else if (index === this.itemIndex || !curDoc.presHideBefore) { + tagDoc.opacity = 1; + } } } } @@ -707,27 +770,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } }); - 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.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) { + activeItem.presMovement = 'zoom'; } - return output; + return StrCast(activeItem.presMovement); }); whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive))); @@ -773,16 +820,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /** * 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) @@ -806,7 +850,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> ); }); - return list; } @action @@ -818,54 +861,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { //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.setPosition && this.activeItem.y !== undefined && this.activeItem.x !== undefined && this.targetDoc.x !== undefined && this.targetDoc.y !== undefined) { - const timer = (ms: number) => new Promise(res => (this._presTimer = setTimeout(res, ms))); - const time = 10; - const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y); - const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x); - - for (let i = 0; i < time; i++) { - this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time; - this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time; - await timer(0.1); - } - } + if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0); + else 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); } @@ -876,8 +899,8 @@ 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); + 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); @@ -890,9 +913,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { else this.regularSelect(doc, ref, drag, focus); }; - static keyEventsWrapper = (e: KeyboardEvent) => { - PresBox.Instance.keyEvents(e); - }; + static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance.keyEvents(e); // Key for when the presentaiton is active @action @@ -906,10 +927,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; }) @@ -921,7 +942,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc)) { this.updateMinimize(); } else if (this.layoutDoc.presStatus === 'edit') { - this._selectedArray.clear(); + this.clearSelectedArray(); this._eleArray.length = this._dragArray.length = 0; } else this.layoutDoc.presStatus = 'edit'; if (this._presTimer) clearTimeout(this._presTimer); @@ -934,7 +955,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) { @@ -951,7 +972,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) { @@ -969,8 +990,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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: @@ -993,13 +1014,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } }; - 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() { @@ -1118,7 +1133,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; - Array.from(this._selectedArray.keys()).forEach(doc => (doc.presTransition = timeInMS)); + this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)); }; // Converts seconds to ms and updates presTransition @@ -1127,7 +1142,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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)); + this.selectedArray.forEach(doc => (doc.presZoom = scale)); }; // Converts seconds to ms and updates presDuration @@ -1136,114 +1151,43 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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 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; - }); + this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument)); }; @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; - } - }); - }; + updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect)); @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; - } - }); - }; + updateEffect = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffect = effect)); _batch: UndoManager.Batch | undefined = undefined; @@ -1252,6 +1196,46 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { const targetDoc: Doc = this.targetDoc; const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection; const isPinWithView: boolean = BoolCast(activeItem.presPinView); + const presEffect = (effect: PresEffect) => ( + <div className={`presBox-dropdownOption ${this.activeItem.presEffect === effect || (effect === PresEffect.None && !this.activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect)}> + {effect} + </div> + ); + const presMovement = (movement: PresMovement) => ( + <div className={`presBox-dropdownOption ${activeItem.presMovement === movement ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateMovement(movement)}> + {movement} + </div> + ); + const presDirection = (diretion: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => { + const color = this.activeItem.presEffectDirection === diretion || (diretion === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black'; + return ( + <Tooltip title={<div className="dash-tooltip">{diretion}</div>}> + <div + style={{ ...opts, border: diretion === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }} + onClick={() => this.updateEffectDirection(diretion)}> + {icon ? <FontAwesomeIcon icon={icon as any} /> : null} + </div> + </Tooltip> + ); + }; + const inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => { + return ( + <input + type="range" + step={step} + min={min} + max={max} + value={value} + className={`toolbar-slider ${active ? '' : 'none'}`} + onPointerDown={() => (this._batch = UndoManager.StartBatch('pres slider'))} + onPointerUp={() => this._batch?.end()} + onChange={e => { + e.stopPropagation(); + change(e.target.value); + }} + /> + ); + }; if (activeItem && targetDoc) { const type = targetDoc.type; const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; @@ -1262,13 +1246,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom'; 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; })}> <div className="ribbon-box"> Movement @@ -1281,24 +1265,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); - this.openMovementDropdown = !this.openMovementDropdown; + 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> + 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.Zoom)} + {presMovement(PresMovement.Pan)} + {presMovement(PresMovement.Jump)} </div> </div> )} @@ -1316,21 +1292,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </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); - }} - /> + {inputter('0', '1', '150', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)} <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}> <div className="presBox-subheading">Movement Speed</div> <div className="ribbon-property"> @@ -1345,21 +1307,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </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); - }} - /> + {inputter('0.1', '0.1', '10', transitionSpeed, [PresMovement.Pan, PresMovement.Zoom].includes(activeItem.presMovement as any), this.setTransitionTime)} <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}> <div className="slider-text">Fast</div> <div className="slider-text">Medium</div> @@ -1370,35 +1318,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { Visibility {'&'} Duration <div className="ribbon-doubleButton"> {isPresCollection ? null : ( - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Hide before presented'}</div> - </> - }> + <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> )} {isPresCollection ? null : ( - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Hide after presented'}</div> - </> - }> + <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> - </> - }> + <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> @@ -1420,26 +1353,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> </div> </div> - <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'); - }} - onPointerUp={() => { - if (this._batch) this._batch.end(); - }} - onChange={(e: React.ChangeEvent<HTMLInputElement>) => { - e.stopPropagation(); - this.setDurationTime(e.target.value); - }} - /> + {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)} <div className={'slider-headers'} style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'grid' }}> <div className="slider-text">Short</div> <div className="slider-text">Medium</div> @@ -1455,98 +1369,30 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); - this.openEffectDropdown = !this.openEffectDropdown; + this._openEffectDropdown = !this._openEffectDropdown; })} - style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + 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> + <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 === 'None' ? 'none' : 'inline-flex' }}> <div className="presBox-subheading">Effect direction</div> - <div className="ribbon-property">{this.effectDirection}</div> + <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</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> + {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})} + {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})} + {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})} + {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})} + {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })} </div> </div> )} @@ -1560,243 +1406,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } } - @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; - } + this.updateMovement(this.activeItem.presMovement as PresMovement, true); + this.updateEffect(this.activeItem.presEffect as PresEffect, true); + this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true); + const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; + array.forEach(curDoc => { + curDoc.presTransition = presTransition; + curDoc.presDuration = presDuration; + curDoc.presHideBefore = presHideBefore; + curDoc.presHideAfter = 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); - })} - /> - </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> - </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> @@ -1967,55 +1597,53 @@ 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> @@ -2029,73 +1657,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> @@ -2122,48 +1748,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }; 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( @@ -2221,42 +1828,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /** * 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; + @computed get stringType() { + if (this.activeItem) { + // prettier-ignore + switch (this.targetDoc.type) { + case DocumentType.PDF: return 'PDF'; + case DocumentType.RTF: return 'Text node'; + case DocumentType.COL: return 'Collection'; + case DocumentType.AUDIO: return 'Audio'; + case DocumentType.VID: return 'Video'; + case DocumentType.IMG: return 'Image'; + case DocumentType.WEB: return 'Web page'; + case DocumentType.MAP: return 'Map'; + default: return 'Other node'; } } - return type; + return ''; } @observable private openActiveColorPicker: boolean = false; @@ -2269,115 +1856,109 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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 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> - {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 className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}> + Edit </div> - {this.viewedColorPicker} + </div> + <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}> + <div className="presBox-subheading">Active text color</div> <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> + 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-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 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-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 + 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-frameList"> - {this.frameListHeader} - {this.frameList} + <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}> + Edit </div> - <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}> - Play + </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> @@ -2388,42 +1969,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @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; + this.targetDoc['pres-text-color'] = String(color.hex); 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; + this.targetDoc['pres-text-viewed-color'] = String(color.hex); 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'])} + color={StrCast(this.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'])} + color={StrCast(this.targetDoc['pres-text-viewed-color'])} /> ); } @@ -2466,12 +2037,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { //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; + this.activeItem.scrollProgressivize = true; } targetDoc.editScrollProgressivize = true; } else { @@ -2483,8 +2053,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @action progressivizeScroll = (e: React.MouseEvent) => { e.stopPropagation(); - const activeItem: Doc = this.activeItem; - activeItem.scrollProgressivize = !activeItem.scrollProgressivize; + this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize; const targetDoc: Doc = this.targetDoc; targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize; // CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame)); @@ -2586,21 +2155,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }; @observable - toggleDisplayMovement = (doc: Doc) => { - if (doc.displayMovement) doc.displayMovement = false; - else doc.displayMovement = true; - }; + toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement); @action checkList = (doc: Doc, list: any): number => { const x: List<number> = list; - if (x && x.length >= NumCast(doc._currentFrame) + 1) { + if (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; + } + return 100; }; @computed get progressivizeChildDocs() { @@ -2654,26 +2221,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } @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; + nextAppearFrame = (doc: Doc, i: number) => { + doc.appearFrame = (Cast(doc.appearFrame, 'number', null) ?? 0) + 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); + prevAppearFrame = (doc: Doc, i: number) => { + doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1); this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame)); }; @@ -2702,31 +2257,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } }; - @computed get moreInfoDropdown() { - return <div></div>; - } - @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 activeColor = Colors.LIGHT_BLUE; const inactiveColor = Colors.WHITE; return mode === CollectionViewType.Carousel3D ? null : ( @@ -2735,12 +2278,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <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 }} className={'toolbar-button'} @@ -2759,22 +2297,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </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 }} /> + <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> - <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> @@ -2797,14 +2325,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <div className="presBox-buttons" style={{ 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> )} @@ -2825,11 +2353,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> )} @@ -2841,16 +2369,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } @action - getList = (list: any): List<number> => { - const x: List<number> = list; - return x; - }; + getList = (list: any): List<number> => list; @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; }; @@ -2858,17 +2382,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @action newFrame = () => { const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const type: string = StrCast(targetDoc.type); + const type: string = StrCast(this.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; } }; @@ -2877,12 +2396,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <div className="frameList-header"> 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> - </> - }> + <Tooltip title={<div className="dash-tooltip">{'Add frame by example'}</div>}> <div className={'headerButton'} onClick={e => { @@ -2892,12 +2406,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <FontAwesomeIcon icon={'plus'} onPointerDown={e => e.stopPropagation()} /> </div> </Tooltip> - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Edit in collection'}</div> - </> - }> + <Tooltip title={<div className="dash-tooltip">{'Edit in collection'}</div>}> <div className={'headerButton'} onClick={e => { @@ -2913,27 +2422,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } @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; + const frameList: List<number> = this.getList(this.activeItem.frameList); + return !frameList ? null : ( + <div className="frameList-container"> + {frameList.map(value => ( + <div className="framList-item" /> + ))} + </div> + ); } @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} - </> + const targetDoc = this.targetDoc; + return !this.targetDoc ? null : ( + <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> ); } @@ -2943,17 +2449,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { // 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> - </> - }> + <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)}> <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 }} @@ -2966,12 +2467,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }}> <FontAwesomeIcon icon={'arrow-left'} /> </div> - <Tooltip - title={ - <> - <div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div> - </> - }> + <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'} /> </div> @@ -2989,12 +2485,7 @@ 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' }} onClick={() => this.gotoDocument(0, this.activeItem)}> <b>1</b> </div> @@ -3056,9 +2547,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }; @action - startMarqueeCreateSlide = () => { - PresBox.startMarquee = true; - }; + startMarqueeCreateSlide = () => (PresBox.startMarquee = true); AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => { var indexNum = 0; @@ -3088,23 +2577,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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> - </> - }> + <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}> + <div className="presPanelOverlay" style={{ display: 'inline-flex', height: 30, background: '#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 }} @@ -3116,12 +2597,7 @@ 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> - </> - }> + <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)}> <FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} /> </div> @@ -3130,12 +2606,7 @@ 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> @@ -3201,5 +2672,17 @@ ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) { 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)); + DocumentManager.Instance.jumpToDocument( + bestTarget, + true, + openInTab, + srcContext ? [srcContext] : [], + undefined, + undefined, + undefined, + () => PresBox.restoreTargetDocView(bestTarget, activeItem, true), + undefined, + true, + NumCast(activeItem.presZoom) + ); }); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index 1a2054676..d88ff45fa 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -3,7 +3,7 @@ import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc'; -import { Id } from '../../../../fields/FieldSymbols'; +import { Copy, Id } from '../../../../fields/FieldSymbols'; import { List } from '../../../../fields/List'; import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils'; @@ -24,6 +24,8 @@ import { PresBox } from './PresBox'; import './PresElementBox.scss'; import { PresMovement } from './PresEnums'; import React = require('react'); +import { InkField } from '../../../../fields/InkField'; +import { RichTextField } from '../../../../fields/RichTextField'; /** * This class models the view a document added to presentation will have in the presentation. * It involves some functionality for its buttons and options. @@ -47,6 +49,13 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get presStatus() { return this.presBox.presStatus; } + @computed get selectedArray() { + return this.presBoxView?.selectedArray; + } + @computed get presBoxView() { + const vpath = this.props.docViewPath(); + return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined; + } @computed get presBox() { return (this.props.DocumentView?.().props.treeViewDoc ?? this.props.ContainingCollectionDoc)!; } @@ -72,9 +81,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord]; @action - presExpandDocumentClick = () => { - this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton; - }; + presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton); embedHeight = (): number => 97; // embedWidth = () => this.props.PanelWidth(); @@ -129,10 +136,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { <div className="presItem-groupSlide" onClick={e => { - console.log('Clicked on slide with index: ', ind); e.stopPropagation(); e.preventDefault(); - PresBox.Instance.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.modifierSelect(doc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); this.presExpandDocumentClick(); }}> <div className="presItem-groupNum">{`${ind + 1}.`}</div> @@ -154,15 +160,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { )); return groupSlides; } - @computed get duration() { - let durationInS: number; - if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { - durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); - durationInS = Math.round(durationInS * 10) / 10; - } else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000; - else durationInS = 2; - return 'D: ' + durationInS + 's'; - } @computed get transition() { let transitionInS: number; @@ -181,15 +178,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { e.stopPropagation(); e.preventDefault(); if (element && !(e.ctrlKey || e.metaKey)) { - if (PresBox.Instance._selectedArray.has(this.rootDoc)) { - PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); + if (this.selectedArray?.has(this.rootDoc)) { + this.selectedArray.size === 1 && this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); } else { setupMoveUpEvents( this, e, (e: PointerEvent) => { - PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false, false); return this.startDrag(e); }, emptyFunction, @@ -199,19 +196,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { } }; - headerUp = (e: React.PointerEvent<HTMLDivElement>) => { - e.stopPropagation(); - e.preventDefault(); - }; - /** * Function to drag and drop the pres element to a diferent location */ startDrag = (e: PointerEvent) => { const miniView: boolean = this.toolbarWidth <= 100; const activeItem = this.rootDoc; - const dragArray = PresBox.Instance._dragArray; - const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray()); + const dragArray = this.presBoxView?._dragArray ?? []; + const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); dragData.dropAction = 'move'; dragData.treeViewDoc = this.props.docViewPath().lastElement()?.props.treeViewDoc; @@ -219,12 +211,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { const dragItem: HTMLElement[] = []; if (dragArray.length === 1) { const doc = this._itemRef.current || dragArray[0]; - doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide'; - dragItem.push(doc); + if (doc) { + doc.className = miniView ? 'presItem-miniSlide' : 'presItem-slide'; + dragItem.push(doc); + } } else if (dragArray.length >= 1) { const doc = document.createElement('div'); doc.className = 'presItem-multiDrag'; - doc.innerText = 'Move ' + PresBox.Instance._selectedArray.size + ' slides'; + doc.innerText = 'Move ' + this.selectedArray?.size + ' slides'; doc.style.position = 'absolute'; doc.style.top = e.clientY + 'px'; doc.style.left = e.clientX - 50 + 'px'; @@ -253,10 +247,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { onPointerMove = (e: PointerEvent) => { const slide = this._itemRef.current!; - let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false; - for (const doc of DragManager.docsBeingDragged) { - if (!doc.presentationTargetDoc) dragIsPresItem = false; - } + const dragIsPresItem = DragManager.docsBeingDragged.some(d => d.presentationTargetDoc); if (slide && dragIsPresItem) { const rect = slide.getBoundingClientRect(); const y = e.clientY - rect.top; //y position within the element. @@ -289,10 +280,11 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @undoBatch removeItem = action((e: React.MouseEvent) => { e.stopPropagation(); - this.props.removeDocument?.(this.rootDoc); - if (PresBox.Instance._selectedArray.has(this.rootDoc)) { - PresBox.Instance._selectedArray.delete(this.rootDoc); + if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) { + this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1; } + this.props.removeDocument?.(this.rootDoc); + this.presBoxView?.removeFromSelectedArray(this.rootDoc); this.removeAllRecordingInOverlay(); }); @@ -319,6 +311,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { case DocumentType.RTF: const scroll = targetDoc._scrollTop; activeItem.presPinViewScroll = scroll; + if (targetDoc.type === DocumentType.RTF) { + activeItem.presData = targetDoc.text instanceof RichTextField ? targetDoc.text[Copy]() : targetDoc.text; + } + break; + case DocumentType.INK: + activeItem.presData = targetDoc.data instanceof InkField ? targetDoc.data[Copy]() : targetDoc.data; break; case DocumentType.VID: case DocumentType.AUDIO: @@ -336,6 +334,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { activeItem.presPinViewY = y; activeItem.presPinViewScale = scale; } + + activeItem.presX = NumCast(targetDoc.x); + activeItem.presY = NumCast(targetDoc.y); + activeItem.presRot = NumCast(targetDoc.jitterRotation); + activeItem.presWidth = NumCast(targetDoc.width); + activeItem.presHeight = NumCast(targetDoc.height); }; @computed get recordingIsInOverlay() { @@ -380,7 +384,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { hideRecording = (e: React.MouseEvent, iconClick: boolean = false) => { e.stopPropagation(); this.removeAllRecordingInOverlay(); - // if (iconClick) PresElementBox.showVideo = false; }; @@ -400,7 +403,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @undoBatch @action - startRecording = (activeItem: Doc) => { + startRecording = (e: React.MouseEvent, activeItem: Doc) => { + e.stopPropagation(); console.log('start recording', 'activeItem', activeItem); if (PresElementBox.videoIsRecorded(activeItem)) { // if we already have an existing recording @@ -444,7 +448,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { } @computed get mainItem() { - const isSelected: boolean = PresBox.Instance?._selectedArray.has(this.rootDoc); + const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false; const toolbarWidth: number = this.toolbarWidth; const showMore: boolean = this.toolbarWidth >= 300; const miniView: boolean = this.toolbarWidth <= 110; @@ -466,109 +470,71 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { onClick={e => { e.stopPropagation(); e.preventDefault(); - PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); + this.presBoxView?.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey); this.showRecording(activeItem); }} onDoubleClick={action(e => { this.toggleProperties(); - PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true); + this.presBoxView?.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true); })} onPointerOver={this.onPointerOver} onPointerLeave={this.onPointerLeave} - onPointerDown={this.headerDown} - onPointerUp={this.headerUp}> - {/* {miniView ? - // when width is LESS than 110 px - <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}> - {`${this.indexInPres + 1}.`} - </div> - : - // when width is MORE than 110 px - <div className="presItem-number"> - {`${this.indexInPres + 1}.`} - </div>} */} - {/* <div className="presItem-number"> - {`${this.indexInPres + 1}.`} - </div> */} - {miniView ? null : ( + onPointerDown={this.headerDown}> + {miniView ? ( + <div className={`presItem-miniSlide ${isSelected ? 'active' : ''}`} ref={this._dragRef}> + {`${this.indexInPres + 1}.`} + </div> + ) : ( <div - ref={miniView ? null : this._dragRef} + ref={this._dragRef} className={`presItem-slide ${isSelected ? 'active' : ''}`} style={{ backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor), boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isSelected ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined, }}> - <div className="presItem-name" style={{ maxWidth: showMore ? toolbarWidth - 195 : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}> + <div + className="presItem-name" + style={{ + pointerEvents: isSelected ? undefined : 'none', + maxWidth: showMore ? toolbarWidth - 195 : toolbarWidth - 105, + cursor: isSelected ? 'text' : 'grab', + }}> <div>{`${this.indexInPres + 1}. `}</div> <EditableView ref={this._titleRef} editing={!isSelected ? false : undefined} contents={activeItem.title} overflow={'ellipsis'} GetValue={() => StrCast(activeItem.title)} SetValue={this.onSetValue} /> </div> {/* <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip> */} {/* <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip> */} - <div className={'presItem-slideButtons'}> - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Update view'}</div> - </> - }> + <div className="presItem-slideButtons"> + <Tooltip title={<div className="dash-tooltip">Update view</div>}> <div className="slideButton" onClick={() => this.updateView(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinView ? 'flex' : 'none' }}> V </div> </Tooltip> - - {this.recordingIsInOverlay ? ( - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Hide Recording'}</div> - </> - }> - <div className="slideButton" onClick={e => this.hideRecording(e, true)} style={{ fontWeight: 700 }}> - <FontAwesomeIcon icon={'video-slash'} onPointerDown={e => e.stopPropagation()} /> - </div> - </Tooltip> - ) : ( - <Tooltip - title={ - <> - <div className="dash-tooltip">{`${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div> - </> - }> - <div - className="slideButton" - onClick={e => { - e.stopPropagation(); - this.startRecording(activeItem); - }} - style={{ fontWeight: 700 }}> - <FontAwesomeIcon icon={'video'} onPointerDown={e => e.stopPropagation()} /> + <Tooltip title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}> + <div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}> + <FontAwesomeIcon icon={`video${this.recordingIsInOverlay ? '-slash' : ''}`} onPointerDown={e => e.stopPropagation()} /> + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}</div>}> + <div + className="slideButton" + onClick={() => (activeItem.groupWithUp = !activeItem.groupWithUp)} + style={{ + display: this.indexInPres === 0 ? 'none' : '', + zIndex: 1000 - this.indexInPres, + fontWeight: 700, + backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined, + height: activeItem.groupWithUp ? 53 : 18, + transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined, + }}> + <div style={{ transform: activeItem.groupWithUp ? 'rotate(180deg) translate(0, -17.5px)' : 'rotate(0deg)' }}> + <FontAwesomeIcon icon={'arrow-up'} onPointerDown={e => e.stopPropagation()} /> </div> - </Tooltip> - )} - - {/* {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}> - <div className="slideButton" - onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp} - style={{ - zIndex: 1000 - this.indexInPres, - fontWeight: 700, - backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined, - height: activeItem.groupWithUp ? 53 : 18, - transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined - }}> - <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}> - <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} /> - </div> - </div> - </Tooltip>} */} - <Tooltip - title={ - <> - <div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}</div> - </> - }> + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}</div>}> <div - className={'slideButton'} + className="slideButton" onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); @@ -576,18 +542,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? 'eye-slash' : 'eye'} onPointerDown={e => e.stopPropagation()} /> </div> </Tooltip> - <Tooltip - title={ - <> - <div className="dash-tooltip">{'Remove from presentation'}</div> - </> - }> + <Tooltip title={<div className="dash-tooltip">Remove from presentation</div>}> <div className={'slideButton'} onClick={this.removeItem}> <FontAwesomeIcon icon={'trash'} onPointerDown={e => e.stopPropagation()} /> </div> </Tooltip> </div> - {/* <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div> */} {this.renderEmbeddedInline} </div> )} diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts index 93ab323fb..c6a222c3a 100644 --- a/src/client/views/nodes/trails/PresEnums.ts +++ b/src/client/views/nodes/trails/PresEnums.ts @@ -1,28 +1,28 @@ export enum PresMovement { - Zoom = "zoom", - Pan = "pan", - Jump = "jump", - None = "none", + Zoom = 'zoom', + Pan = 'pan', + Jump = 'jump', + None = 'none', } export enum PresEffect { - Zoom = "Zoom", - Lightspeed = "Lightspeed", - Fade = "Fade in", - Flip = "Flip", - Rotate = "Rotate", - Bounce = "Bounce", - Roll = "Roll", - None = "None", - Left = "left", - Right = "right", - Center = "center", - Top = "top", - Bottom = "bottom" + Zoom = 'Zoom', + Lightspeed = 'Lightspeed', + Fade = 'Fade in', + Flip = 'Flip', + Rotate = 'Rotate', + Bounce = 'Bounce', + Roll = 'Roll', + None = 'None', + Left = 'Enter from left', + Right = 'Enter from right', + Center = 'Enter from center', + Top = 'Enter from Top', + Bottom = 'Enter from bottom', } export enum PresStatus { - Autoplay = "auto", - Manual = "manual", - Edit = "edit" -}
\ No newline at end of file + Autoplay = 'auto', + Manual = 'manual', + Edit = 'edit', +} |
