diff options
| author | bobzel <zzzman@gmail.com> | 2023-04-17 09:37:16 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2023-04-17 09:37:16 -0400 |
| commit | 6a9e80de419af14bece7a48e55edc1543d69f20f (patch) | |
| tree | 71ae1b819bc4f7fdb699ae90c035eb86275c5006 /src/client/views/nodes/trails | |
| parent | 0a38e3f91f4f85f07fdbb7575ceb678032dcdfe9 (diff) | |
| parent | 8127616d06b4db2b29de0b13068810fd19e77b5e (diff) | |
Merge branch 'master' into james-server-stats
Diffstat (limited to 'src/client/views/nodes/trails')
| -rw-r--r-- | src/client/views/nodes/trails/PresBox.scss | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 1186 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresElementBox.tsx | 33 |
3 files changed, 696 insertions, 525 deletions
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss index fd202590e..eb91c82f3 100644 --- a/src/client/views/nodes/trails/PresBox.scss +++ b/src/client/views/nodes/trails/PresBox.scss @@ -12,7 +12,7 @@ height: 100%; min-height: 35px; letter-spacing: 2px; - overflow: hidden; + //overflow: hidden; transition: 0.7s opacity ease; .presBox-listCont { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 13cbd87eb..807a19771 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -3,13 +3,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { action, computed, IReactionDisposer, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { ColorState, SketchPicker } from 'react-color'; -import { AnimationSym, Doc, DocListCast, FieldResult, Opt, StrListCast } from '../../../../fields/Doc'; +import { AnimationSym, Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../../fields/Doc'; import { Copy, Id } from '../../../../fields/FieldSymbols'; -import { InkTool } from '../../../../fields/InkField'; +import { InkField, InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { ObjectField } from '../../../../fields/ObjectField'; import { listSpec } from '../../../../fields/Schema'; +import { ComputedField, ScriptField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types'; import { AudioField } from '../../../../fields/URLField'; import { emptyFunction, emptyPath, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; @@ -19,6 +19,7 @@ import { CollectionViewType, DocumentType } from '../../../documents/DocumentTyp import { DocumentManager } from '../../../util/DocumentManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { SelectionManager } from '../../../util/SelectionManager'; +import { SerializationHelper } from '../../../util/SerializationHelper'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; @@ -36,6 +37,22 @@ import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; const { Howl } = require('howler'); +export interface pinDataTypes { + scrollable?: boolean; + dataviz?: number[]; + pannable?: boolean; + viewType?: boolean; + inkable?: boolean; + filters?: boolean; + pivot?: boolean; + temporal?: boolean; + clippable?: boolean; + datarange?: boolean; + dataview?: boolean; + textview?: boolean; + poslayoutview?: boolean; + dataannos?: boolean; +} export interface PinProps { audioRange?: boolean; activeFrame?: number; @@ -43,20 +60,8 @@ export interface PinProps { hidePresBox?: boolean; pinViewport?: MarqueeViewBounds; // pin a specific viewport on a freeform view (use MarqueeView.CurViewBounds to compute if no region has been selected) pinDocLayout?: boolean; // pin layout info (width/height/x/y) - pinDocContent?: boolean; // pin data info (scroll/pan/zoom/text) pinAudioPlay?: boolean; // pin audio annotation - pinData?: { - scrollable?: boolean | undefined; - pannable?: boolean | undefined; - viewType?: boolean | undefined; - filters?: boolean | undefined; - temporal?: boolean | undefined; - clippable?: boolean | undefined; - dataview?: boolean | undefined; - textview?: boolean | undefined; - poslayoutview?: boolean | undefined; - dataannos?: boolean | undefined; - }; + pinData?: pinDataTypes; } @observer @@ -64,9 +69,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } + static navigateToDocScript: ScriptField; + + constructor(props: any) { + super(props); + if (!PresBox.navigateToDocScript) { + PresBox.navigateToDocScript = ScriptField.MakeFunction('navigateToDoc(self.presentationTargetDoc, self)')!; + } + } private _disposers: { [name: string]: IReactionDisposer } = {}; public selectedArray = new ObservableSet<Doc>(); + _batch: UndoManager.Batch | undefined = undefined; // undo batch for dragging sliders which generate multiple scene edit events as the cursor moves + _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation. + _unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things @observable public static Instance: PresBox; @@ -82,6 +98,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @observable _newDocumentTools: boolean = false; @observable _openMovementDropdown: boolean = false; @observable _openEffectDropdown: boolean = false; + @observable _openBulletEffectDropdown: boolean = false; @observable _presentTools: boolean = false; @observable _treeViewMap: Map<Doc, number> = new Map(); @observable _presKeyEvents: boolean = false; @@ -110,6 +127,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get targetDoc() { return Cast(this.activeItem?.presentationTargetDoc, Doc, null); } + public static targetRenderedDoc = (doc: Doc) => { + const targetDoc = Cast(doc?.presentationTargetDoc, Doc, null); + return targetDoc?.unrendered ? DocCast(targetDoc.annotationOn) : targetDoc; + }; @computed get scrollable() { if ([DocumentType.PDF, DocumentType.WEB, DocumentType.RTF].includes(this.targetDoc.type as DocumentType) || this.targetDoc._viewType === CollectionViewType.Stacking) return true; return false; @@ -133,14 +154,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { addToSelectedArray = action((doc: Doc) => this.selectedArray.add(doc)); removeFromSelectedArray = action((doc: Doc) => this.selectedArray.delete(doc)); - _unmounting = false; @action componentWillUnmount() { this._unmounting = true; if (this._presTimer) clearTimeout(this._presTimer); document.removeEventListener('keydown', PresBox.keyEventsWrapper, true); this.resetPresentation(); - // Turn of progressivize editors this.turnOffEdit(true); Object.values(this._disposers).forEach(disposer => disposer?.()); } @@ -180,6 +199,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { () => SelectionManager.Views(), views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation() ); + this._disposers.editing = reaction( + () => this.layoutDoc.presStatus === PresStatus.Edit, + editing => { + if (editing) { + this.childDocs.forEach(doc => { + if (doc.presIndexed !== undefined) { + this.progressivizedItems(doc)?.forEach(indexedDoc => (indexedDoc.opacity = undefined)); + doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, 1); + } + }); + } + } + ); } @action @@ -199,7 +231,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }; stopTempMedia = (targetDocField: FieldResult) => { - const targetDoc = Cast(targetDocField, Doc, null); + const targetDoc = DocCast(DocCast(targetDocField).annotationOn) ?? DocCast(targetDocField); if ([DocumentType.VID, DocumentType.AUDIO].includes(targetDoc.type as any)) { const targMedia = DocumentManager.Instance.getDocumentView(targetDoc); targMedia?.ComponentView?.Pause?.(); @@ -212,7 +244,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { nextSlide = (slideNum?: number) => { const nextSlideInd = slideNum ?? this.itemIndex + 1; let curSlideInd = nextSlideInd; - CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); + //CollectionStackedTimeline.CurrentlyPlaying?.map(clipView => clipView?.ComponentView?.Pause?.()); this.clearSelectedArray(); const doGroupWithUp = (nextSelected: number, force = false) => @@ -238,18 +270,57 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { doGroupWithUp(curSlideInd, true)(); }; + // docs within a slide target that will be progressively revealed + progressivizedItems = (doc: Doc) => { + const targetList = PresBox.targetRenderedDoc(doc); + if (doc.presIndexed !== undefined && targetList) { + const listItems = (Cast(targetList[Doc.LayoutFieldKey(targetList)], listSpec(Doc), null)?.filter(d => d instanceof Doc) as Doc[]) ?? DocListCast(targetList[Doc.LayoutFieldKey(targetList) + '-annotations']); + return listItems.filter(doc => !doc.unrendered); + } + }; // Called when the user activates 'next' - to move to the next part of the pres. trail @action next = () => { + const progressiveReveal = (first: boolean) => { + const presIndexed = Cast(this.activeItem?.presIndexed, 'number', null); + if (presIndexed !== undefined) { + const targetRenderedDoc = PresBox.targetRenderedDoc(this.activeItem); + targetRenderedDoc._dataTransition = 'all 1s'; + targetRenderedDoc.opacity = 1; + setTimeout(() => (targetRenderedDoc._dataTransition = 'inherit'), 1000); + const listItems = this.progressivizedItems(this.activeItem); + if (listItems && presIndexed < listItems.length) { + if (!first) { + const listItemDoc = listItems[presIndexed]; + const targetView = listItems && DocumentManager.Instance.getFirstDocumentView(listItemDoc); + Doc.linkFollowUnhighlight(); + Doc.HighlightDoc(listItemDoc); + listItemDoc.presEffect = this.activeItem.presBulletEffect; + listItemDoc.presTransition = 500; + targetView?.setAnimEffect(listItemDoc, 500); + if (targetView?.docView && this.activeItem.presBulletExpand) { + targetView.docView._animateScalingTo = 1.1; + Doc.AddUnHighlightWatcher(() => (targetView!.docView!._animateScalingTo = 0)); + } + listItemDoc.opacity = undefined; + this.activeItem.presIndexed = presIndexed + 1; + } + return true; + } + } + }; + if (progressiveReveal(false)) return true; if (this.childDocs[this.itemIndex + 1] !== undefined) { // Case 1: No more frames in current doc and next slide is defined, therefore move to next slide const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]); const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex; this.nextSlide(curLast + 1 === this.childDocs.length ? (this.layoutDoc.presLoop ? 0 : curLast) : curLast + 1); + progressiveReveal(true); // shows first progressive document, but without a transition effect } else { if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) { // Case 2: Last slide and presLoop is toggled ON or it is in Edit mode this.nextSlide(0); + progressiveReveal(true); // shows first progressive document, but without a transition effect } return 0; } @@ -286,21 +357,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; - const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; - if (activeFrame !== undefined) { - const transTime = NumCast(activeItem.presTransition, 500); - const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc); - const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; - if (context) { - const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.ComponentView as CollectionFreeFormView; - if (ffview?.childDocs) { - this._keyTimer = CollectionFreeFormView.gotoKeyframe(this._keyTimer, ffview.childDocs, transTime); - context._currentFrame = NumCast(activeFrame); - } - } - } if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) { DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia); } @@ -308,96 +364,141 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.stopTempMedia(from.presentationTargetDoc); } // If next slide is audio / video 'Play automatically' then the next slide should be played - if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') { - this.startTempMedia(targetDoc, activeItem); + if (this.layoutDoc.presStatus !== PresStatus.Edit && (this.targetDoc.type === DocumentType.AUDIO || this.targetDoc.type === DocumentType.VID) && this.activeItem.mediaStart === 'auto') { + this.startTempMedia(this.targetDoc, this.activeItem); } if (!group) this.clearSelectedArray(); this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array this.turnOffEdit(); this.navigateToActiveItem(finished); //Handles movement to element only when presTrail is list - this.onHideDocument(); //Handles hide after/before + this.doHideBeforeAfter(); //Handles hide after/before } }); - static pinDataTypes(target?: Doc): { - scrollable?: boolean; - pannable?: boolean; - viewType?: boolean; - filters?: boolean; - temporal?: boolean; - clippable?: boolean; - dataview?: boolean; - textview?: boolean; - poslayoutview?: boolean; - dataannos?: boolean; - } { + static pinDataTypes(target?: Doc): pinDataTypes { const targetType = target?.type as any; + const inkable = [DocumentType.INK].includes(targetType); const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetType) || target?._viewType === CollectionViewType.Stacking; const pannable = [DocumentType.IMG, DocumentType.PDF].includes(targetType) || (targetType === DocumentType.COL && target?._viewType === CollectionViewType.Freeform); const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(targetType); const clippable = [DocumentType.COMPARISON].includes(targetType); + const datarange = [DocumentType.FUNCPLOT].includes(targetType); const dataview = [DocumentType.INK, DocumentType.COL, DocumentType.IMG].includes(targetType) && target?.activeFrame === undefined; const poslayoutview = [DocumentType.COL].includes(targetType) && target?.activeFrame === undefined; const textview = [DocumentType.RTF].includes(targetType) && target?.activeFrame === undefined; const viewType = targetType === DocumentType.COL; const filters = true; + const pivot = true; const dataannos = false; - return { scrollable, pannable, viewType, filters, temporal, clippable, dataview, textview, poslayoutview, dataannos }; + return { scrollable, pannable, inkable, viewType, pivot, filters, temporal, clippable, dataview, datarange, textview, poslayoutview, dataannos }; } @action playAnnotation = (anno: AudioField) => {}; @action - static restoreTargetDocView(bestTargetView: Opt<DocumentView>, pinProps: PinProps | undefined, activeItem: Doc, transTime: number, pinDataTypes = this.pinDataTypes(bestTargetView?.rootDoc)) { - if (!bestTargetView) return; - const bestTarget = bestTargetView.rootDoc; + static restoreTargetDocView(bestTargetView: Opt<DocumentView>, activeItem: Doc, transTime: number, pinDocLayout: boolean = BoolCast(activeItem.presPinLayout), pinDataTypes?: pinDataTypes, targetDoc?: Doc) { + const bestTarget = bestTargetView?.rootDoc ?? (targetDoc?.unrendered ? DocCast(targetDoc?.annotationOn) : targetDoc); + if (!bestTarget || activeItem === bestTarget) return; let changed = false; - if (pinProps?.pinDocLayout) { + if (pinDocLayout) { if ( bestTarget.x !== NumCast(activeItem.presX, NumCast(bestTarget.x)) || bestTarget.y !== NumCast(activeItem.presY, NumCast(bestTarget.y)) || - bestTarget.rotation !== NumCast(activeItem.presRot, NumCast(bestTarget.rotation)) || + bestTarget.rotation !== NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)) || bestTarget.width !== NumCast(activeItem.presWidth, NumCast(bestTarget.width)) || bestTarget.height !== NumCast(activeItem.presHeight, NumCast(bestTarget.height)) ) { bestTarget._dataTransition = `all ${transTime}ms`; bestTarget.x = NumCast(activeItem.presX, NumCast(bestTarget.x)); bestTarget.y = NumCast(activeItem.presY, NumCast(bestTarget.y)); - bestTarget.rotation = NumCast(activeItem.presRot, NumCast(bestTarget.rotation)); + bestTarget.rotation = NumCast(activeItem.presRotation, NumCast(bestTarget.rotation)); bestTarget.width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); bestTarget.height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); changed = true; } } - if (pinDataTypes.clippable) { - if (bestTarget._clipWidth !== activeItem.presPinClipWidth) { - bestTarget._clipWidth = activeItem.presPinClipWidth; + + const activeFrame = activeItem.presActiveFrame ?? activeItem.presCurrentFrame; + if (activeFrame !== undefined) { + const transTime = NumCast(activeItem.presTransition, 500); + const acontext = activeItem.presActiveFrame !== undefined ? DocCast(DocCast(activeItem.presentationTargetDoc).context) : DocCast(activeItem.presentationTargetDoc); + const context = DocCast(acontext)?.annotationOn ? DocCast(DocCast(acontext).annotationOn) : acontext; + if (context) { + const ffview = DocumentManager.Instance.getFirstDocumentView(context)?.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView; + if (ffview?.childDocs) { + PresBox.Instance._keyTimer = CollectionFreeFormView.gotoKeyframe(PresBox.Instance._keyTimer, ffview.childDocs, transTime); + ffview.rootDoc._currentFrame = NumCast(activeFrame); + } + } + } + if (pinDataTypes?.datarange || (!pinDataTypes && activeItem.presXRange !== undefined)) { + if (bestTarget.xRange !== activeItem.presXRange) { + bestTarget.xRange = (activeItem.presXRange as ObjectField)?.[Copy](); + changed = true; + } + if (bestTarget.yRange !== activeItem.presYRange) { + bestTarget.yRange = (activeItem.presYRange as ObjectField)?.[Copy](); changed = true; } } - if (pinDataTypes.temporal) { + if (pinDataTypes?.clippable || (!pinDataTypes && activeItem.presClipWidth !== undefined)) { + if (bestTarget._clipWidth !== activeItem.presClipWidth) { + bestTarget._clipWidth = activeItem.presClipWidth; + changed = true; + } + } + if (pinDataTypes?.temporal || (!pinDataTypes && activeItem.presStartTime !== undefined)) { if (bestTarget._currentTimecode !== activeItem.presStartTime) { bestTarget._currentTimecode = activeItem.presStartTime; changed = true; } } - if (pinDataTypes.viewType && activeItem.presPinViewType !== undefined) { - if (bestTarget._viewType !== activeItem.presPinViewType) { - bestTarget._viewType = activeItem.presPinViewType; + if (pinDataTypes?.inkable || (!pinDataTypes && (activeItem.presFillColor !== undefined || activeItem.color !== undefined))) { + if (bestTarget.fillColor !== activeItem.presFillColor) { + Doc.GetProto(bestTarget).fillColor = activeItem.presFillColor; + changed = true; + } + if (bestTarget.color !== activeItem.presColor) { + Doc.GetProto(bestTarget).color = activeItem.presColor; + changed = true; + } + if (bestTarget.width !== activeItem.width) { + bestTarget._width = NumCast(activeItem.presWidth, NumCast(bestTarget.width)); + changed = true; + } + if (bestTarget.height !== activeItem.height) { + bestTarget._height = NumCast(activeItem.presHeight, NumCast(bestTarget.height)); + changed = true; + } + } + if ((pinDataTypes?.viewType && activeItem.presViewType !== undefined) || (!pinDataTypes && activeItem.presViewType !== undefined)) { + if (bestTarget._viewType !== activeItem.presViewType) { + bestTarget._viewType = activeItem.presViewType; changed = true; } } - if (pinDataTypes.filters && activeItem.presPinDocFilters !== undefined) { - if (bestTarget.docFilters !== activeItem.presPinDocFilters) { - bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presPinDocFilters as ObjectField) || new List<string>([]); + if ((pinDataTypes?.filters && activeItem.presDocFilters !== undefined) || (!pinDataTypes && activeItem.presDocFilters !== undefined)) { + if (bestTarget.docFilters !== activeItem.presDocFilters) { + bestTarget.docFilters = ObjectField.MakeCopy(activeItem.presDocFilters as ObjectField) || new List<string>([]); changed = true; } } - if (pinDataTypes.scrollable) { - if (bestTarget._scrollTop !== activeItem.presPinViewScroll) { - bestTarget._scrollTop = activeItem.presPinViewScroll; + if ((pinDataTypes?.pivot && activeItem.presPivotField !== undefined) || (!pinDataTypes && activeItem.presPivotField !== undefined)) { + if (bestTarget.pivotField !== activeItem.presPivotField) { + bestTarget.pivotField = activeItem.presPivotField; + bestTarget._prevFilterIndex = 1; // need to revisit this...see CollectionTimeView + changed = true; + } + } + if (bestTargetView?.ComponentView?.restoreView?.(activeItem)) { + changed = true; + } + + if (pinDataTypes?.scrollable || (!pinDataTypes && activeItem.presViewScroll !== undefined)) { + if (bestTarget._scrollTop !== activeItem.presViewScroll) { + bestTarget._scrollTop = activeItem.presViewScroll; changed = true; const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { @@ -406,39 +507,59 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } } } - if (pinDataTypes.dataannos) { + if (pinDataTypes?.dataannos || (!pinDataTypes && activeItem.presAnnotations !== undefined)) { const fkey = Doc.LayoutFieldKey(bestTarget); - Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List<Doc>([...DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered), ...DocListCast(activeItem.presAnnotations)]); + const oldItems = DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered); + const newItems = DocListCast(activeItem.presAnnotations).map(doc => { + doc.hidden = false; + return doc; + }); + const hiddenItems = DocListCast(bestTarget[fkey + '-annotations']) + .filter(doc => !doc.unrendered && !newItems.includes(doc)) + .map(doc => { + doc.hidden = true; + return doc; + }); + const newList = new List<Doc>([...oldItems, ...hiddenItems, ...newItems]); + Doc.GetProto(bestTarget)[fkey + '-annotations'] = newList; } - if (pinDataTypes.dataview && activeItem.presData !== undefined) { + if ((pinDataTypes?.dataview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { bestTarget._dataTransition = `all ${transTime}ms`; const fkey = Doc.LayoutFieldKey(bestTarget); Doc.GetProto(bestTarget)[fkey] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; bestTarget[fkey + '-useAlt'] = activeItem.presUseAlt; setTimeout(() => (bestTarget._dataTransition = undefined), transTime + 10); } - if (pinDataTypes.textview && activeItem.presData !== undefined) Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; - if (pinDataTypes.poslayoutview) { + if ((pinDataTypes?.textview && activeItem.presData !== undefined) || (!pinDataTypes && activeItem.presData !== undefined)) { + Doc.GetProto(bestTarget)[Doc.LayoutFieldKey(bestTarget)] = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData; + } + if (pinDataTypes?.poslayoutview || (!pinDataTypes && activeItem.presPinLayoutData !== undefined)) { changed = true; + const layoutField = Doc.LayoutFieldKey(bestTarget); + const transitioned = new Set<Doc>(); StrListCast(activeItem.presPinLayoutData) - .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) - .forEach(data => { - const doc = DocServer.GetCachedRefField(data.id) as Doc; - doc._dataTransition = `all ${transTime}ms`; - doc.x = data.x; - doc.y = data.y; - doc._width = data.w; - doc._height = data.h; + .map(str => JSON.parse(str) as { id: string; x: number; y: number; back: string; fill: string; w: number; h: number; data: string; text: string }) + .forEach(async data => { + const doc = DocCast(DocServer.GetCachedRefField(data.id)); + if (doc) { + transitioned.add(doc); + const field = !data.data ? undefined : await SerializationHelper.Deserialize(data.data); + const tfield = !data.text ? undefined : await SerializationHelper.Deserialize(data.text); + doc._dataTransition = `all ${transTime}ms`; + doc.x = data.x; + doc.y = data.y; + data.back && (doc._backgroundColor = data.back); + data.fill && (doc._fillColor = data.fill); + doc._width = data.w; + doc._height = data.h; + data.data && (Doc.GetProto(doc).data = field); + data.text && (Doc.GetProto(doc).text = tfield); + Doc.AddDocToList(Doc.GetProto(bestTarget), layoutField, doc); + } }); - setTimeout( - () => - StrListCast(activeItem.presPinLayoutData) - .map(str => JSON.parse(str) as { id: string; x: number; y: number; w: number; h: number }) - .forEach(action(data => ((DocServer.GetCachedRefField(data.id) as Doc)._dataTransition = undefined))), - transTime + 10 - ); + setTimeout(() => Array.from(transitioned).forEach(action(doc => (doc._dataTransition = undefined))), transTime + 10); } - if (pinDataTypes.pannable) { + if ((pinDataTypes?.pannable || (!pinDataTypes && (activeItem.presPinViewBounds !== undefined || activeItem.presPanX !== undefined || activeItem.presViewScale !== undefined))) && !bestTarget._isGroup) { const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number')); if (contentBounds) { const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] }; @@ -451,16 +572,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { dv.ComponentView?.brushView?.(viewport); } } else { - if (bestTarget._panX !== activeItem.presPinViewX || bestTarget._panY !== activeItem.presPinViewY || bestTarget._viewScale !== activeItem.presPinViewScale) { - bestTarget._panX = activeItem.presPinViewX; - bestTarget._panY = activeItem.presPinViewY; - bestTarget._viewScale = activeItem.presPinViewScale; + if (bestTarget._panX !== activeItem.presPanX || bestTarget._panY !== activeItem.presPanY || bestTarget._viewScale !== activeItem.presViewScale) { + bestTarget._panX = activeItem.presPanX ?? bestTarget._panX; + bestTarget._panY = activeItem.presPanY ?? bestTarget._panY; + bestTarget._viewScale = activeItem.presViewScale ?? bestTarget._viewScale; changed = true; } } } if (changed) { - return bestTargetView.setViewTransition('all', transTime); + return bestTargetView?.setViewTransition('all', transTime); } } @@ -473,7 +594,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { pinDoc.presPinLayout = true; pinDoc.presX = NumCast(targetDoc.x); pinDoc.presY = NumCast(targetDoc.y); - pinDoc.presRot = NumCast(targetDoc.rotation); + pinDoc.presRotation = NumCast(targetDoc.rotation); pinDoc.presWidth = NumCast(targetDoc.width); pinDoc.presHeight = NumCast(targetDoc.height); } @@ -485,6 +606,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { pinProps.pinData.pannable || pinProps.pinData.viewType || pinProps.pinData.clippable || + pinProps.pinData.datarange || pinProps.pinData.dataview || pinProps.pinData.textview || pinProps.pinData.poslayoutview || @@ -499,16 +621,41 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered)); } if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text; - if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop; - if (pinProps.pinData.clippable) pinDoc.presPinClipWidth = targetDoc._clipWidth; + if (pinProps.pinData.inkable) { + pinDoc.presFillColor = targetDoc.fillColor; + pinDoc.presColor = targetDoc.color; + pinDoc.presWidth = targetDoc._width; + pinDoc.presHeight = targetDoc._height; + } + if (pinProps.pinData.scrollable) pinDoc.presViewScroll = targetDoc._scrollTop; + if (pinProps.pinData.clippable) pinDoc.presClipWidth = targetDoc._clipWidth; + if (pinProps.pinData.datarange) { + pinDoc.presXRange = undefined; //targetDoc?.xrange; + pinDoc.presYRange = undefined; //targetDoc?.yrange; + } if (pinProps.pinData.poslayoutview) - pinDoc.presPinLayoutData = new List<string>(DocListCast(targetDoc[fkey] as ObjectField).map(d => JSON.stringify({ id: d[Id], x: NumCast(d.x), y: NumCast(d.y), w: NumCast(d._width), h: NumCast(d._height) }))); - if (pinProps.pinData.viewType) pinDoc.presPinViewType = targetDoc._viewType; - if (pinProps.pinData.filters) pinDoc.presPinDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField); + pinDoc.presPinLayoutData = new List<string>( + DocListCast(targetDoc[fkey] as ObjectField).map(d => + JSON.stringify({ + id: d[Id], + x: NumCast(d.x), + y: NumCast(d.y), + w: NumCast(d._width), + h: NumCast(d._height), + fill: StrCast(d._fillColor), + back: StrCast(d._backgroundColor), + data: SerializationHelper.Serialize(d.data instanceof ObjectField ? d.data[Copy]() : ''), + text: SerializationHelper.Serialize(d.text instanceof ObjectField ? d.text[Copy]() : ''), + }) + ) + ); + if (pinProps.pinData.viewType) pinDoc.presViewType = targetDoc._viewType; + if (pinProps.pinData.filters) pinDoc.presDocFilters = ObjectField.MakeCopy(targetDoc.docFilters as ObjectField); + if (pinProps.pinData.pivot) pinDoc.presPivotField = targetDoc._pivotField; if (pinProps.pinData.pannable) { - pinDoc.presPinViewX = NumCast(targetDoc._panX); - pinDoc.presPinViewY = NumCast(targetDoc._panY); - pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1); + pinDoc.presPanX = NumCast(targetDoc._panX); + pinDoc.presPanY = NumCast(targetDoc._panY); + pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1); } if (pinProps.pinData.temporal) { pinDoc.presStartTime = targetDoc._currentTimecode; @@ -520,9 +667,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { // If pinWithView option set then update scale and x / y props of slide const bounds = pinProps.pinViewport; pinDoc.presPinView = true; - pinDoc.presPinViewScale = NumCast(targetDoc._viewScale, 1); - pinDoc.presPinViewX = bounds.left + bounds.width / 2; - pinDoc.presPinViewY = bounds.top + bounds.height / 2; + pinDoc.presViewScale = NumCast(targetDoc._viewScale, 1); + pinDoc.presPanX = bounds.left + bounds.width / 2; + pinDoc.presPanY = bounds.top + bounds.height / 2; pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]); } } @@ -556,62 +703,46 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } finished(); }); - const createDocView = (doc: Doc, finished?: () => void) => { - DocumentManager.Instance.AddViewRenderedCb(doc, () => finished?.()); - LightboxView.AddDocTab(doc, OpenWhere.lightbox); - }; - PresBox.NavigateToTarget(targetDoc, activeItem, createDocView, resetSelection); + PresBox.NavigateToTarget(targetDoc, activeItem, resetSelection); }; - static NavigateToTarget(targetDoc: Doc, activeItem: Doc, createDocView: any, finished?: () => void) { + static NavigateToTarget(targetDoc: Doc, activeItem: Doc, finished?: () => void) { if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); return; } + const effect = activeItem.presEffect && activeItem.presEffect !== PresEffect.None ? activeItem.presEffect : undefined; + const presTime = NumCast(activeItem.presTransition, effect ? 750 : 500); const options: DocFocusOptions = { willPan: activeItem.presMovement !== PresMovement.None, - willPanZoom: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, + willZoomCentered: activeItem.presMovement === PresMovement.Zoom || activeItem.presMovement === PresMovement.Jump || activeItem.presMovement === PresMovement.Center, zoomScale: activeItem.presMovement === PresMovement.Center ? 0 : NumCast(activeItem.presZoom, 1), - zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), + zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime), effect: activeItem, noSelect: true, - originatingDoc: activeItem, + openLocation: OpenWhere.addLeft, + anchorDoc: activeItem, easeFunc: StrCast(activeItem.presEaseFunc, 'ease') as any, zoomTextSelections: BoolCast(activeItem.presZoomText), playAudio: BoolCast(activeItem.presPlayAudio), }; - const restoreLayout = () => { - // 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. - const pinDocLayout = (BoolCast(activeItem.presPinLayout) || BoolCast(activeItem.presPinView)) && DocCast(targetDoc.context)?._currentFrame === undefined; - if (activeItem.presPinData || activeItem.presPinView || pinDocLayout) { - // targetDoc may or may not be displayed. so get the first available document (or alias) view that matches targetDoc and use it - PresBox.restoreTargetDocView(DocumentManager.Instance.getFirstDocumentView(targetDoc), { pinDocLayout }, activeItem, NumCast(activeItem.presTransition, 500)); - } - }; - const finishAndRestoreLayout = () => { - finished?.(); - restoreLayout(); - }; - const containerDocContext = DocumentManager.GetContextPath(targetDoc); - - let context = containerDocContext.length ? containerDocContext[0] : targetDoc; if (activeItem.presOpenInLightbox) { - if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(DocCast(targetDoc.annotationOn) ?? targetDoc))) { - context = DocCast(targetDoc.annotationOn) ?? targetDoc; - LightboxView.SetLightboxDoc(context); // openInTab(targetDoc); + const context = DocCast(targetDoc.annotationOn) ?? targetDoc; + if (!DocumentManager.Instance.getLightboxDocumentView(context)) { + LightboxView.SetLightboxDoc(context); } } if (targetDoc) { if (activeItem.presentationTargetDoc instanceof Doc) activeItem.presentationTargetDoc[AnimationSym] = undefined; DocumentManager.Instance.AddViewRenderedCb(LightboxView.LightboxDoc, dv => { - if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(context.annotationOn) ?? context)) { + // if target or the doc it annotates is not in the lightbox, then close the lightbox + if (!DocumentManager.Instance.getLightboxDocumentView(DocCast(targetDoc.annotationOn) ?? targetDoc)) { LightboxView.SetLightboxDoc(undefined); } - DocumentManager.Instance.jumpToDocument(targetDoc, options, createDocView, containerDocContext, finishAndRestoreLayout); + DocumentManager.Instance.showDocument(targetDoc, options, finished); }); - } else finishAndRestoreLayout(); + } else finished?.(); } /** @@ -619,22 +750,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { * they are hidden each time the presentation is updated. */ @action - onHideDocument = () => { + doHideBeforeAfter = () => { this.childDocs.forEach((doc, index) => { const curDoc = Cast(doc, Doc, null); - const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + const tagDoc = PresBox.targetRenderedDoc(curDoc); const itemIndexes: number[] = this.getAllIndexes(this.tagDocs, tagDoc); + let opacity: Opt<number> = index === this.itemIndex ? 1 : undefined; if (curDoc.presHide) { if (index !== this.itemIndex) { - tagDoc.opacity = 1; + opacity = 1; } } const hidingIndBef = itemIndexes.find(item => item >= this.itemIndex) ?? itemIndexes.slice().reverse().lastElement(); if (curDoc.presHideBefore && index === hidingIndBef) { if (index > this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } else if (index === this.itemIndex || !curDoc.presHideAfter) { - tagDoc.opacity = 1; + opacity = 1; + setTimeout(() => (tagDoc._dataTransition = undefined), 1000); } } const hidingIndAft = @@ -644,32 +777,60 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { .find(item => item <= this.itemIndex) ?? itemIndexes.lastElement(); if (curDoc.presHideAfter && index === hidingIndAft) { if (index < this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } else if (index === this.itemIndex || !curDoc.presHideBefore) { - tagDoc.opacity = 1; + opacity = 1; } } const hidingInd = itemIndexes.find(item => item === this.itemIndex); if (curDoc.presHide && index === hidingInd) { if (index === this.itemIndex) { - tagDoc.opacity = 0; + opacity = 0; } } + opacity !== undefined && (tagDoc.opacity = opacity); }); }; _exitTrail: Opt<() => void>; PlayTrail = (docs: Doc[]) => { - const savedStates = docs.map(doc => (doc._viewType !== CollectionViewType.Freeform ? undefined : { c: doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) })); + const savedStates = docs.map(doc => { + switch (doc.type) { + case DocumentType.COL: + if (doc._viewType === CollectionViewType.Freeform) return { type: CollectionViewType.Freeform, doc, x: NumCast(doc.panX), y: NumCast(doc.panY), s: NumCast(doc.viewScale) }; + break; + case DocumentType.INK: + if (doc.data instanceof InkField) { + return { type: doc.type, doc, data: doc.data?.[Copy](), fillColor: doc.fillColor, color: doc.color, x: NumCast(doc.x), y: NumCast(doc.y) }; + } + } + return undefined; + }); this.startPresentation(0); this._exitTrail = () => { savedStates .filter(savedState => savedState) .map(savedState => { - const { x, y, s, c } = savedState!; - c._panX = x; - c._panY = y; - c._viewScale = s; + switch (savedState?.type) { + case CollectionViewType.Freeform: + { + const { x, y, s, doc } = savedState!; + doc._panX = x; + doc._panY = y; + doc._viewScale = s; + } + break; + case DocumentType.INK: + { + const { data, fillColor, color, x, y, doc } = savedState!; + doc.x = x; + doc.y = y; + doc.data = data; + doc.fillColor = fillColor; + doc.color = color; + } + break; + } }); LightboxView.SetLightboxDoc(undefined); Doc.RemoveDocFromList(Doc.MyOverlayDocs, undefined, this.rootDoc); @@ -691,7 +852,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { //stops the presentaton. resetPresentation = () => { this.childDocs - .map(doc => Cast(doc.presentationTargetDoc, Doc, null)) + .map(doc => PresBox.targetRenderedDoc(doc)) .filter(doc => doc instanceof Doc) .forEach(doc => { try { @@ -717,6 +878,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { }); }; + initializePresState = (startIndex: number) => { + this.childDocs.forEach((doc, index) => { + const tagDoc = PresBox.targetRenderedDoc(doc); + if (doc.presHideBefore && index > startIndex) tagDoc.opacity = 0; + if (doc.presHideAfter && index < startIndex) tagDoc.opacity = 0; + if (doc.presIndexed !== undefined && index >= startIndex) { + const startInd = NumCast(doc.presIndexedStart); + this.progressivizedItems(doc) + ?.slice(startInd) + .forEach(indexedDoc => (indexedDoc.opacity = 0)); + doc.presIndexed = Math.min(this.progressivizedItems(doc)?.length ?? 0, startInd); + } + // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; + }); + }; + /** * The function that starts the presentation at the given index, also checking if actions should be applied * directly at start. @@ -728,12 +905,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { clearTimeout(this._presTimer); if (this.childDocs.length) { this.layoutDoc.presStatus = PresStatus.Autoplay; - this.childDocs.forEach(doc => { - const tagDoc = doc.presentationTargetDoc as Doc; - if (doc.presHideBefore && this.childDocs.indexOf(doc) > startIndex) tagDoc.opacity = 0; - if (doc.presHideAfter && this.childDocs.indexOf(doc) < startIndex) tagDoc.opacity = 0; - // if (doc.presHide && this.childDocs.indexOf(doc) === startIndex) tagDoc.opacity = 0; - }); + this.initializePresState(startIndex); const func = () => { const delay = NumCast(this.activeItem.presDuration, this.activeItem.type === DocumentType.SCRIPTING ? 0 : 2500) + NumCast(this.activeItem.presTransition); this._presTimer = setTimeout(() => { @@ -750,6 +922,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { */ @action enterMinimize = () => { + this.updateCurrentPresentation(this.rootDoc); clearTimeout(this._presTimer); const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); this.props.removeDocument?.(this.layoutDoc); @@ -770,6 +943,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { doc._height = 30; doc._width = PresBox.minimizedWidth; Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc); + PresBox.Instance?.initializePresState(PresBox.Instance.itemIndex); return (doc.presStatus = PresStatus.Manual); } @@ -857,8 +1031,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 40; - isContentActive = (outsideReaction?: boolean) => - Doc.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false; + isContentActive = (outsideReaction?: boolean) => this.props.isContentActive(outsideReaction); + //.ActiveTool === InkTool.None && !this.layoutDoc._lockedPosition && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false; /** * For sorting the array so that the order is maintained when it is dropped. @@ -901,12 +1075,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { presDocView && SelectionManager.SelectView(presDocView, false); }; - focusElement = (doc: Doc, options: DocFocusOptions) => this.selectElement(doc); + focusElement = (doc: Doc, options: DocFocusOptions) => { + this.selectElement(doc); + return undefined; + }; //Regular click @action - selectElement = async (doc: Doc, noNav = false) => { - CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => DocumentManager.Instance.getDocumentView(clip)?.ComponentView?.Pause?.()); + selectElement = (doc: Doc, noNav = false) => { + CollectionStackedTimeline.CurrentlyPlaying?.map((clip, i) => clip?.ComponentView?.Pause?.()); if (noNav) { const index = this.childDocs.indexOf(doc); if (index >= 0 && index < this.childDocs.length) { @@ -1101,15 +1278,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } } else if (doc.presPinView && presCollection === tagDoc && dv) { // Case B: Document is presPinView and is presCollection - const scale: number = 1 / NumCast(doc.presPinViewScale); + const scale: number = 1 / NumCast(doc.presViewScale); const height: number = dv.props.PanelHeight() * scale; const width: number = dv.props.PanelWidth() * scale; const indWidth = width / 10; const indHeight = Math.max(height / 10, 15); const indEdge = Math.max(indWidth, indHeight); const indFontSize = indEdge * 0.8; - const xLoc: number = NumCast(doc.presPinViewX) - width / 2; - const yLoc: number = NumCast(doc.presPinViewY) - height / 2; + const xLoc: number = NumCast(doc.presPanX) - width / 2; + const yLoc: number = NumCast(doc.presPanY) - height / 2; docs.push(tagDoc); order.push( <> @@ -1142,8 +1319,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } else if (doc.presPinView) { - const n1x = NumCast(doc.presPinViewX); - const n1y = NumCast(doc.presPinViewY); + const n1x = NumCast(doc.presPanX); + const n1y = NumCast(doc.presPanY); if ((index = 0)) pathPoints = n1x + ',' + n1y; else pathPoints = pathPoints + ' ' + n1x + ',' + n1y; } @@ -1175,12 +1352,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (timeInMS > 100000) timeInMS = 100000; setter(timeInMS); }; - setTransitionTime = (number: String, change?: number) => { + + @undoBatch + updateTransitionTime = (number: String, change?: number) => { PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change); }; // Converts seconds to ms and updates presTransition - setZoom = (number: String, change?: number) => { + @undoBatch + updateZoom = (number: String, change?: number) => { let scale = Number(number) / 100; if (change) scale += change; if (scale < 0.01) scale = 0.01; @@ -1188,8 +1368,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.selectedArray.forEach(doc => (doc.presZoom = scale)); }; - // Converts seconds to ms and updates presDuration - setDurationTime = (number: String, change?: number) => { + /* + * Converts seconds to ms and updates presDuration + */ + @undoBatch + updateDurationTime = (number: String, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; if (timeInMS < 100) timeInMS = 100; @@ -1197,9 +1380,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.selectedArray.forEach(doc => (doc.presDuration = timeInMS)); }; - /** - * When the movement dropdown is changes - */ @undoBatch updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement))); @@ -1230,6 +1410,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { activeItem.presOpenInLightbox = !activeItem.presOpenInLightbox; this.selectedArray.forEach(doc => (doc.presOpenInLightbox = activeItem.presOpenInLightbox)); }; + @undoBatch @action updateEaseFunc = (activeItem: Doc) => { @@ -1243,12 +1424,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { @undoBatch @action - updateEffect = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffect = effect)); - - _batch: UndoManager.Batch | undefined = undefined; + updateEffect = (effect: PresEffect, bullet: boolean, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (bullet ? (doc.presBulletEffect = effect) : (doc.presEffect = effect))); + static _sliderBatch: any; public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => { - let batch: any; return ( <input type="range" @@ -1259,10 +1438,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)` }} className={`toolbar-slider ${active ? '' : 'none'}`} onPointerDown={e => { - batch = UndoManager.StartBatch('pres slider'); + PresBox._sliderBatch = UndoManager.StartBatch('pres slider'); e.stopPropagation(); }} - onPointerUp={() => batch?.end()} + onPointerUp={() => PresBox._sliderBatch.end()} onChange={e => { e.stopPropagation(); change(e.target.value); @@ -1270,11 +1449,161 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { /> ); }; + + @undoBatch + @action + applyTo = (array: Doc[]) => { + this.updateMovement(this.activeItem.presMovement as PresMovement, true); + this.updateEffect(this.activeItem.presEffect as PresEffect, false, true); + this.updateEffect(this.activeItem.presBulletEffect as PresEffect, true, true); + this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); + const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; + array.forEach(curDoc => { + curDoc.presTransition = presTransition; + curDoc.presDuration = presDuration; + curDoc.presHideBefore = presHideBefore; + curDoc.presHideAfter = presHideAfter; + }); + }; + + @computed get visibiltyDurationDropdown() { + const activeItem = this.activeItem; + if (activeItem && this.targetDoc) { + const targetType = this.targetDoc.type; + let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 0; + if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); + return ( + <div className="presBox-ribbon"> + <div className="ribbon-doubleButton"> + <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}> + <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}> + Hide before + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}> + <div className={`ribbon-toggle ${activeItem.presHide ? 'active' : ''}`} onClick={() => this.updateHide(activeItem)}> + Hide + </div> + </Tooltip> + + <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}> + <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}> + Hide after + </div> + </Tooltip> + + <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}> + <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presOpenInLightbox ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}> + Lightbox + </div> + </Tooltip> + <Tooltip title={<div className="dash-tooltip">{'Transition movement style'}</div>}> + <div className="ribbon-toggle" onClick={() => this.updateEaseFunc(activeItem)}> + {`${StrCast(activeItem.presEaseFunc, 'ease')}`} + </div> + </Tooltip> + </div> + {[DocumentType.AUDIO, DocumentType.VID].includes(targetType as any as DocumentType) ? null : ( + <> + <div className="ribbon-doubleButton"> + <div className="presBox-subheading">Slide Duration</div> + <div className="ribbon-property"> + <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={e => this.updateDurationTime(e.target.value)} /> s + </div> + <div className="ribbon-propertyUpDown"> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), 1000)}> + <FontAwesomeIcon icon={'caret-up'} /> + </div> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateDurationTime(String(duration), -1000)}> + <FontAwesomeIcon icon={'caret-down'} /> + </div> + </div> + </div> + {PresBox.inputter('0.1', '0.1', '20', duration, targetType !== DocumentType.AUDIO, this.updateDurationTime)} + <div className={'slider-headers'} style={{ display: targetType === DocumentType.AUDIO ? 'none' : 'grid' }}> + <div className="slider-text">Short</div> + <div className="slider-text">Medium</div> + <div className="slider-text">Long</div> + </div> + </> + )} + </div> + ); + } + } + @computed get progressivizeDropdown() { + const activeItem = this.activeItem; + if (activeItem && this.targetDoc) { + const effect = activeItem.presBulletEffect ? activeItem.presBulletEffect : PresMovement.None; + const bulletEffect = (effect: PresEffect) => ( + <div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect, true)}> + {effect} + </div> + ); + return ( + <div className="presBox-ribbon"> + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Progressivize Collection</div> + <input + className="presBox-checkbox" + style={{ margin: 10 }} + type="checkbox" + onChange={() => { + activeItem.presIndexed = activeItem.presIndexed === undefined ? 0 : undefined; + activeItem.presHideBefore = activeItem.presIndexed !== undefined; + const tagDoc = PresBox.targetRenderedDoc(this.activeItem); + const type = DocCast(tagDoc?.annotationOn)?.type ?? tagDoc.type; + activeItem.presIndexedStart = type === DocumentType.COL ? 1 : 0; + // a progressivized slide doesn't have sub-slides, but rather iterates over the data list of the target being progressivized. + // to avoid creating a new slide to correspond to each of the target's data list, we create a computedField to refernce the target's data list. + let dataField = Doc.LayoutFieldKey(tagDoc); + if (Cast(tagDoc[dataField], listSpec(Doc), null)?.filter(d => d instanceof Doc) === undefined) dataField = dataField + '-annotations'; + + if (DocCast(activeItem.presentationTargetDoc).annotationOn) activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc.annotationOn["${dataField}"]`); + else activeItem.data = ComputedField.MakeFunction(`self.presentationTargetDoc["${dataField}"]`); + }} + checked={Cast(activeItem.presIndexed, 'number', null) !== undefined ? true : false} + /> + </div> + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Progressivize First Bullet</div> + <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presIndexedStart = activeItem.presIndexedStart ? 0 : 1)} checked={!NumCast(activeItem.presIndexedStart)} /> + </div> + <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> + <div className="presBox-subheading">Expand Current Bullet</div> + <input className="presBox-checkbox" style={{ margin: 10 }} type="checkbox" onChange={() => (activeItem.presBulletExpand = !activeItem.presBulletExpand)} checked={BoolCast(activeItem.presBulletExpand)} /> + </div> + + <div className="ribbon-box"> + Bullet Effect + <div + className="presBox-dropdown" + onClick={action(e => { + e.stopPropagation(); + this._openBulletEffectDropdown = !this._openBulletEffectDropdown; + })} + style={{ borderBottomLeftRadius: this._openBulletEffectDropdown ? 0 : 5, border: this._openBulletEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}> + {effect?.toString()} + <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openBulletEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} /> + <div className={'presBox-dropdownOptions'} style={{ display: this._openBulletEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}> + {bulletEffect(PresEffect.None)} + {bulletEffect(PresEffect.Fade)} + {bulletEffect(PresEffect.Flip)} + {bulletEffect(PresEffect.Rotate)} + {bulletEffect(PresEffect.Bounce)} + {bulletEffect(PresEffect.Roll)} + </div> + </div> + </div> + </div> + ); + } + return null; + } @computed get transitionDropdown() { - const activeItem: Doc = this.activeItem; - const targetDoc: Doc = this.targetDoc; + const activeItem = this.activeItem; const presEffect = (effect: PresEffect) => ( - <div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect)}> + <div className={`presBox-dropdownOption ${activeItem.presEffect === effect || (effect === PresEffect.None && !activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect, false)}> {effect} </div> ); @@ -1295,14 +1624,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </Tooltip> ); }; - if (activeItem && targetDoc) { - const type = targetDoc.type; + if (activeItem && this.targetDoc) { const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5; const zoom = NumCast(activeItem.presZoom, 1) * 100; - let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 0; - if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration); const effect = activeItem.presEffect ? activeItem.presEffect : PresMovement.None; - // activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : PresMovement.Zoom; return ( <div className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`} @@ -1312,6 +1637,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { e.stopPropagation(); this._openMovementDropdown = false; this._openEffectDropdown = false; + this._openBulletEffectDropdown = false; })}> <div className="ribbon-box"> Movement @@ -1335,33 +1661,33 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}> <div className="presBox-subheading">Zoom (% screen filled)</div> <div className="ribbon-property"> - <input className="presBox-input" type="number" value={zoom} onChange={action(e => this.setZoom(e.target.value))} />% + <input className="presBox-input" type="number" value={zoom} onChange={e => this.updateZoom(e.target.value)} />% </div> <div className="ribbon-propertyUpDown"> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), 0.1))}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), 0.1)}> <FontAwesomeIcon icon={'caret-up'} /> </div> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setZoom(String(zoom), -0.1))}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateZoom(String(zoom), -0.1)}> <FontAwesomeIcon icon={'caret-down'} /> </div> </div> </div> - {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)} + {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.updateZoom)} <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> - <div className="presBox-subheading">Transition Speed</div> + <div className="presBox-subheading">Transition Time</div> <div className="ribbon-property"> - <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setTransitionTime(e.target.value))} /> s + <input className="presBox-input" type="number" value={transitionSpeed} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.updateTransitionTime(e.target.value))} /> s </div> <div className="ribbon-propertyUpDown"> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), 1000)}> <FontAwesomeIcon icon={'caret-up'} /> </div> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.updateTransitionTime(String(transitionSpeed), -1000)}> <FontAwesomeIcon icon={'caret-down'} /> </div> </div> </div> - {PresBox.inputter('0.1', '0.1', '100', transitionSpeed, true, this.setTransitionTime)} + {PresBox.inputter('0.1', '0.1', '100', transitionSpeed, true, this.updateTransitionTime)} <div className={'slider-headers'}> <div className="slider-text">Fast</div> <div className="slider-text">Medium</div> @@ -1369,62 +1695,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> </div> <div className="ribbon-box"> - Visibility {'&'} Duration - <div className="ribbon-doubleButton"> - <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}> - <div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}> - Hide before - </div> - </Tooltip> - <Tooltip title={<div className="dash-tooltip">{'Hide while presented'}</div>}> - <div className={`ribbon-toggle ${activeItem.presHide ? 'active' : ''}`} onClick={() => this.updateHide(activeItem)}> - Hide - </div> - </Tooltip> - - <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}> - <div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}> - Hide after - </div> - </Tooltip> - - <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}> - <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presOpenInLightbox ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}> - Lightbox - </div> - </Tooltip> - <Tooltip title={<div className="dash-tooltip">{'Transition movement style'}</div>}> - <div className="ribbon-toggle" onClick={() => this.updateEaseFunc(activeItem)}> - {`${StrCast(activeItem.presEaseFunc, 'ease')}`} - </div> - </Tooltip> - </div> - {type === DocumentType.AUDIO || type === DocumentType.VID ? null : ( - <> - <div className="ribbon-doubleButton"> - <div className="presBox-subheading">Slide Duration</div> - <div className="ribbon-property"> - <input className="presBox-input" type="number" value={duration} onKeyDown={e => e.stopPropagation()} onChange={action(e => this.setDurationTime(e.target.value))} /> s - </div> - <div className="ribbon-propertyUpDown"> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}> - <FontAwesomeIcon icon={'caret-up'} /> - </div> - <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}> - <FontAwesomeIcon icon={'caret-down'} /> - </div> - </div> - </div> - {PresBox.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> - <div className="slider-text">Long</div> - </div> - </> - )} - </div> - <div className="ribbon-box"> Effects <div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}> <div className="presBox-subheading">Play Audio Annotation</div> @@ -1473,173 +1743,154 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { ); } } - - @undoBatch - @action - applyTo = (array: Doc[]) => { - this.updateMovement(this.activeItem.presMovement as PresMovement, true); - this.updateEffect(this.activeItem.presEffect as PresEffect, true); - this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffectDirection, true); - const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem; - array.forEach(curDoc => { - curDoc.presTransition = presTransition; - curDoc.presDuration = presDuration; - curDoc.presHideBefore = presHideBefore; - curDoc.presHideAfter = presHideAfter; - }); - }; - @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, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration'])); - const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc); - if (activeItem && targetDoc) { + const activeItem = this.activeItem; + if (activeItem && this.targetDoc) { + const clipStart = NumCast(activeItem.clipStart); + const clipEnd = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration'])); return ( - <div> - <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> - <div> - <div className="ribbon-box"> - Start {'&'} End Time - <div className={'slider-headers'}> - <div className="slider-block"> - <div className="slider-text" style={{ fontWeight: 500 }}> - Start time (s) - </div> - <div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}> - <input - className="presBox-input" - style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} - type="number" - value={NumCast(activeItem.presStartTime).toFixed(2)} - onKeyDown={e => e.stopPropagation()} - onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { - activeItem.presStartTime = Number(e.target.value); - })} - /> - </div> + <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> + <div> + <div className="ribbon-box"> + Start {'&'} End Time + <div className={'slider-headers'}> + <div className="slider-block"> + <div className="slider-text" style={{ fontWeight: 500 }}> + Start time (s) </div> - <div className="slider-block"> - <div className="slider-text" style={{ fontWeight: 500 }}> - Duration (s) - </div> - <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}> - {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} - </div> - </div> - <div className="slider-block"> - <div className="slider-text" style={{ fontWeight: 500 }}> - End time (s) - </div> - <div id={'endTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}> - <input - className="presBox-input" - onKeyDown={e => e.stopPropagation()} - style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} - type="number" - value={NumCast(activeItem.presEndTime).toFixed(2)} - onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { - activeItem.presEndTime = Number(e.target.value); - })} - /> - </div> + <div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}> + <input + className="presBox-input" + style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} + type="number" + value={NumCast(activeItem.presStartTime).toFixed(2)} + onKeyDown={e => e.stopPropagation()} + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { + activeItem.presStartTime = Number(e.target.value); + })} + /> </div> </div> - <div className="multiThumb-slider"> - <input - type="range" - step="0.1" - min={clipStart} - max={clipEnd} - value={NumCast(activeItem.presEndTime)} - style={{ gridColumn: 1, gridRow: 1 }} - className={`toolbar-slider ${'end'}`} - id="toolbar-slider" - onPointerDown={e => { - this._batch = UndoManager.StartBatch('presEndTime'); - const endBlock = document.getElementById('endTime'); - if (endBlock) { - endBlock.style.color = Colors.LIGHT_GRAY; - endBlock.style.backgroundColor = Colors.MEDIUM_BLUE; - } - e.stopPropagation(); - }} - onPointerUp={() => { - this._batch?.end(); - const endBlock = document.getElementById('endTime'); - if (endBlock) { - endBlock.style.color = Colors.BLACK; - endBlock.style.backgroundColor = Colors.LIGHT_GRAY; - } - }} - onChange={(e: React.ChangeEvent<HTMLInputElement>) => { - e.stopPropagation(); - activeItem.presEndTime = Number(e.target.value); - }} - /> - <input - type="range" - step="0.1" - min={clipStart} - max={clipEnd} - value={NumCast(activeItem.presStartTime)} - style={{ gridColumn: 1, gridRow: 1 }} - className={`toolbar-slider ${'start'}`} - id="toolbar-slider" - onPointerDown={e => { - this._batch = UndoManager.StartBatch('presStartTime'); - const startBlock = document.getElementById('startTime'); - if (startBlock) { - startBlock.style.color = Colors.LIGHT_GRAY; - startBlock.style.backgroundColor = Colors.MEDIUM_BLUE; - } - e.stopPropagation(); - }} - onPointerUp={() => { - this._batch?.end(); - const startBlock = document.getElementById('startTime'); - if (startBlock) { - startBlock.style.color = Colors.BLACK; - startBlock.style.backgroundColor = Colors.LIGHT_GRAY; - } - }} - onChange={(e: React.ChangeEvent<HTMLInputElement>) => { - e.stopPropagation(); - activeItem.presStartTime = Number(e.target.value); - }} - /> - </div> - <div className="slider-headers"> - <div className="slider-text">{clipStart.toFixed(2)} s</div> - <div className="slider-text"></div> - <div className="slider-text">{clipEnd.toFixed(2)} s</div> - </div> - </div> - <div className="ribbon-final-box"> - Playback - <div className="presBox-subheading">Start playing:</div> - <div className="presBox-radioButtons"> - <div className="checkbox-container"> - <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} /> - <div>On click</div> + <div className="slider-block"> + <div className="slider-text" style={{ fontWeight: 500 }}> + Duration (s) </div> - <div className="checkbox-container"> - <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} /> - <div>Automatically</div> + <div className="slider-number" style={{ backgroundColor: Colors.LIGHT_BLUE }}> + {Math.round((NumCast(activeItem.presEndTime) - NumCast(activeItem.presStartTime)) * 10) / 10} </div> </div> - <div className="presBox-subheading">Stop playing:</div> - <div className="presBox-radioButtons"> - <div className="checkbox-container"> - <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} /> - <div>At audio end time</div> + <div className="slider-block"> + <div className="slider-text" style={{ fontWeight: 500 }}> + End time (s) </div> - <div className="checkbox-container"> - <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} /> - <div>On slide change</div> + <div id={'endTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}> + <input + className="presBox-input" + onKeyDown={e => e.stopPropagation()} + style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }} + type="number" + value={NumCast(activeItem.presEndTime).toFixed(2)} + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { + activeItem.presEndTime = Number(e.target.value); + })} + /> </div> - {/* <div className="checkbox-container"> + </div> + </div> + <div className="multiThumb-slider"> + <input + type="range" + step="0.1" + min={clipStart} + max={clipEnd} + value={NumCast(activeItem.presEndTime)} + style={{ gridColumn: 1, gridRow: 1 }} + className={`toolbar-slider ${'end'}`} + id="toolbar-slider" + onPointerDown={e => { + this._batch = UndoManager.StartBatch('presEndTime'); + const endBlock = document.getElementById('endTime'); + if (endBlock) { + endBlock.style.color = Colors.LIGHT_GRAY; + endBlock.style.backgroundColor = Colors.MEDIUM_BLUE; + } + e.stopPropagation(); + }} + onPointerUp={() => { + this._batch?.end(); + const endBlock = document.getElementById('endTime'); + if (endBlock) { + endBlock.style.color = Colors.BLACK; + endBlock.style.backgroundColor = Colors.LIGHT_GRAY; + } + }} + onChange={(e: React.ChangeEvent<HTMLInputElement>) => { + e.stopPropagation(); + activeItem.presEndTime = Number(e.target.value); + }} + /> + <input + type="range" + step="0.1" + min={clipStart} + max={clipEnd} + value={NumCast(activeItem.presStartTime)} + style={{ gridColumn: 1, gridRow: 1 }} + className={`toolbar-slider ${'start'}`} + id="toolbar-slider" + onPointerDown={e => { + this._batch = UndoManager.StartBatch('presStartTime'); + const startBlock = document.getElementById('startTime'); + if (startBlock) { + startBlock.style.color = Colors.LIGHT_GRAY; + startBlock.style.backgroundColor = Colors.MEDIUM_BLUE; + } + e.stopPropagation(); + }} + onPointerUp={() => { + this._batch?.end(); + const startBlock = document.getElementById('startTime'); + if (startBlock) { + startBlock.style.color = Colors.BLACK; + startBlock.style.backgroundColor = Colors.LIGHT_GRAY; + } + }} + onChange={(e: React.ChangeEvent<HTMLInputElement>) => { + e.stopPropagation(); + activeItem.presStartTime = Number(e.target.value); + }} + /> + </div> + <div className="slider-headers"> + <div className="slider-text">{clipStart.toFixed(2)} s</div> + <div className="slider-text"></div> + <div className="slider-text">{clipEnd.toFixed(2)} s</div> + </div> + </div> + <div className="ribbon-final-box"> + Playback + <div className="presBox-subheading">Start playing:</div> + <div className="presBox-radioButtons"> + <div className="checkbox-container"> + <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'manual')} checked={activeItem.mediaStart === 'manual'} /> + <div>On click</div> + </div> + <div className="checkbox-container"> + <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStart = 'auto')} checked={activeItem.mediaStart === 'auto'} /> + <div>Automatically</div> + </div> + </div> + <div className="presBox-subheading">Stop playing:</div> + <div className="presBox-radioButtons"> + <div className="checkbox-container"> + <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'manual')} checked={activeItem.mediaStop === 'manual'} /> + <div>At audio end time</div> + </div> + <div className="checkbox-container"> + <input className="presBox-checkbox" type="checkbox" onChange={() => (activeItem.mediaStop = 'auto')} checked={activeItem.mediaStop === 'auto'} /> + <div>On slide change</div> + </div> + {/* <div className="checkbox-container"> <input className="presBox-checkbox" type="checkbox" onChange={() => activeItem.mediaStop = "afterSlide"} @@ -1656,7 +1907,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </select> </div> </div> */} - </div> </div> </div> </div> @@ -1664,7 +1914,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { ); } } - @computed get newDocumentToolbarDropdown() { return ( <div @@ -1859,6 +2108,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { onClick={undoBatch( action(() => { this.layoutDoc.presStatus = 'manual'; + this.initializePresState(this.itemIndex); this.turnOffEdit(true); this.gotoDocument(this.itemIndex, this.activeItem); }) @@ -1869,71 +2119,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { ); } - scrollFocus = () => { - // this.gotoDocument(0); - // this.startOrPause(false); - return undefined; - }; - - _keyTimer: NodeJS.Timeout | undefined; - - /** - * Returns the collection type as a string for headers - */ - @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 ''; - } - - @observable private openActiveColorPicker: boolean = false; - @observable private openViewedColorPicker: boolean = false; - - @undoBatch - @action - switchActive = (color: ColorState) => { - this.targetDoc['pres-text-color'] = String(color.hex); - return true; - }; - @undoBatch - @action - switchPresented = (color: ColorState) => { - this.targetDoc['pres-text-viewed-color'] = String(color.hex); - return true; - }; - - @computed get activeColorPicker() { - 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(this.targetDoc['pres-text-color'])} - /> - ); - } - - @computed get viewedColorPicker() { - 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(this.targetDoc['pres-text-viewed-color'])} - /> - ); - } - @action turnOffEdit = (paths?: boolean) => paths && this.togglePath(true); // Turn off paths @@ -1950,9 +2135,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { 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 inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); const activeColor = Colors.LIGHT_BLUE; const inactiveColor = Colors.WHITE; - return mode === CollectionViewType.Carousel3D ? null : ( + return mode === CollectionViewType.Carousel3D || inOverlay ? null : ( <div id="toolbarContainer" className={'presBox-toolbar'}> {/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}> <FontAwesomeIcon icon={"plus"} /> @@ -1969,14 +2155,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { {isMini ? null : ( <> <div className="toolbar-divider" /> - {/* <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}> - <div className={"toolbar-button"} - style={{ color: this._expandBoolean ? Colors.MEDIUM_BLUE : 'white' }} - onClick={this.toggleExpandMode}> - <FontAwesomeIcon icon={"eye"} /> - </div> - </Tooltip> - <div className="toolbar-divider" /> */} <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 }} /> @@ -2026,6 +2204,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { onClick={undoBatch(() => { if (this.childDocs.length) { this.layoutDoc.presStatus = 'manual'; + this.initializePresState(this.itemIndex); this.gotoDocument(this.itemIndex, this.activeItem); } })}> @@ -2050,7 +2229,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { } @computed get playButtons() { - const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; + const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0; const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); // Case 1: There are still other frames and should go through all frames before going to next slide @@ -2138,7 +2317,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> </Tooltip> <div className="presPanel-button-text" onClick={() => this.gotoDocument(0, this.activeItem)} style={{ display: inOverlay || this.props.PanelWidth() > 250 ? 'inline-flex' : 'none' }}> - {`${inOverlay ? '' : 'Slide'} ${this.itemIndex + 1} / ${this.childDocs.length}`} + {inOverlay ? '' : 'Slide'} {this.itemIndex + 1} + {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} </div> <div className="presPanel-divider"></div> {this.props.PanelWidth() > 250 ? ( @@ -2185,6 +2365,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.layoutDoc.presStatus = PresStatus.Manual; } }; + @undoBatch @action exitClicked = () => { @@ -2192,7 +2373,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { clearTimeout(this._presTimer); }; - AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => { + AddToMap = (treeViewDoc: Doc, index: number[]) => { + if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. var indexNum = 0; for (let i = 0; i < index.length; i++) { indexNum += index[i] * 10 ** -i; @@ -2205,25 +2387,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.dataDoc[this.presFieldKey] = new List<Doc>(sorted); // this is a flat array of Docs } } - return this.childDocs; }; - RemFromMap = (treeViewDoc: Doc, index: number[]): Doc[] => { + RemFromMap = (treeViewDoc: Doc, index: number[]) => { + if (!treeViewDoc.presentationTargetDoc) return this.childDocs; // if treeViewDoc is not a pres elements, then it's a sub-bullet of a progressivized slide which isn't added to the linearized list of pres elements since it's not really a pres element. if (!this._unmounting && this.isTree) { this._treeViewMap.delete(treeViewDoc); this.dataDoc[this.presFieldKey] = new List<Doc>(this.sort(this._treeViewMap)); } - return this.childDocs; }; - // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1]) sort = (treeViewMap: Map<Doc, number>) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]); render() { // needed to ensure that the childDocs are loaded for looking up fields this.childDocs.slice(); const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; - const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1; + const presEnd = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1 && (this.activeItem.presIndexed === undefined || NumCast(this.activeItem.presIndexed) === (this.progressivizedItems(this.activeItem)?.length ?? 0)); const presStart = !this.layoutDoc.presLoop && this.itemIndex === 0; const inOverlay = DocListCast(Doc.MyOverlayDocs?.data).includes(this.layoutDoc); return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player @@ -2258,7 +2438,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> </Tooltip> <div className="presPanel-button-text"> - Slide {this.itemIndex + 1} / {this.childDocs.length} + Slide {this.itemIndex + 1} + {this.activeItem?.presIndexed !== undefined ? `(${this.activeItem.presIndexed}/${this.progressivizedItems(this.activeItem)?.length})` : ''} / {this.childDocs.length} </div> <div className="presPanel-divider" /> <div className="presPanel-button-text" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}> @@ -2276,7 +2457,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { {mode !== CollectionViewType.Invalid ? ( <CollectionView {...this.props} - ContainingCollectionDoc={this.props.Document} PanelWidth={this.props.PanelWidth} PanelHeight={this.panelHeight} childIgnoreNativeSize={true} @@ -2285,6 +2465,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { //childFitWidth={returnTrue} childOpacity={returnOne} //childLayoutString={PresElementBox.LayoutString('data')} + childClickScript={PresBox.navigateToDocScript} childLayoutTemplate={this.childLayoutTemplate} childXPadding={Doc.IsComicStyle(this.rootDoc) ? 20 : undefined} filterAddDocument={this.addDocumentFilter} @@ -2312,15 +2493,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { </div> ); } - static NavigateToDoc(bestTarget: Doc, activeItem: Doc) { - const openInTab = (doc: Doc, finished?: () => void) => { - CollectionDockingView.AddSplit(doc, OpenWhereMod.right); - finished?.(); - }; - PresBox.NavigateToTarget(bestTarget, activeItem, openInTab); - } } ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) { - PresBox.NavigateToDoc(bestTarget, activeItem); + PresBox.NavigateToTarget(bestTarget, activeItem); }); diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index d19b78dbc..502eef373 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -39,7 +39,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { // Idea: this boolean will determine whether to automatically show the video when this preselement is selected. // @observable static showVideo: boolean = false; @computed get indexInPres() { - return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc); + return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements) @computed get expandViewHeight() { return 100; @@ -51,11 +51,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { return this.presBoxView?.selectedArray; } @computed get presBoxView() { - const vpath = this.props.docViewPath(); - return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined; + return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox; } @computed get presBox() { - return this.props.ContainingCollectionDoc!; + return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc; } @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; @@ -97,7 +96,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? null : ( <div className="presItem-embedded" style={{ height: this.embedHeight(), width: '50%' }}> <DocumentView - Document={this.rootDoc} + Document={PresBox.targetRenderedDoc(this.rootDoc)} DataDoc={undefined} //this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]} PanelWidth={this.embedWidth} PanelHeight={this.embedHeight} @@ -110,14 +109,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { docFilters={this.props.docFilters} docRangeFilters={this.props.docRangeFilters} searchFilterDocs={this.props.searchFilterDocs} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} rootSelected={returnTrue} addDocument={returnFalse} removeDocument={returnFalse} fitContentsToBox={returnTrue} moveDocument={this.props.moveDocument!} - focus={DocUtils.DefaultFocus} + focus={emptyFunction} whenChildContentsActiveChanged={returnFalse} addDocTab={returnFalse} pinToPres={returnFalse} @@ -195,7 +192,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []); if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc); dragData.dropAction = 'move'; - dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; + dragData.treeViewDoc = this.presBox?._viewType === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc; dragData.moveDocument = this.props.moveDocument; const dragItem: HTMLElement[] = []; if (dragArray.length === 1) { @@ -269,7 +266,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @undoBatch removeItem = action((e: React.MouseEvent) => { e.stopPropagation(); - if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) { + if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) { this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1; } this.props.removeDocument?.(this.rootDoc); @@ -297,7 +294,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { const targetDoc = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; activeItem.presX = NumCast(targetDoc.x); activeItem.presY = NumCast(targetDoc.y); - activeItem.presRot = NumCast(targetDoc.rotation); + activeItem.presRotation = NumCast(targetDoc.rotation); activeItem.presWidth = NumCast(targetDoc.width); activeItem.presHeight = NumCast(targetDoc.height); activeItem.presPinLayout = true; @@ -312,7 +309,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @action updateCapturedViewContents = (presTargetDoc: Doc, activeItem: Doc) => { const target = DocCast(presTargetDoc.annotationOn) ?? presTargetDoc; - PresBox.pinDocView(activeItem, { pinDocContent: true, pinData: PresBox.pinDataTypes(target) }, target); + PresBox.pinDocView(activeItem, { pinData: PresBox.pinDataTypes(target) }, target); }; @computed get recordingIsInOverlay() { @@ -406,15 +403,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get toolbarWidth(): number { const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox); - let width: number = NumCast(this.presBox._width); + let width: number = NumCast(this.presBox?._width); if (presBoxDocView) width = presBoxDocView.props.PanelWidth(); if (width === 0) width = 300; return width; } @computed get presButtons() { - const presBox: Doc = this.presBox; //presBox - const presBoxColor: string = StrCast(presBox._backgroundColor); + const presBox = this.presBox; //presBox + const presBoxColor: string = StrCast(presBox?._backgroundColor); const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; const targetDoc: Doc = this.targetDoc; const activeItem: Doc = this.rootDoc; @@ -494,10 +491,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() { @computed get mainItem() { const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false; - const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres; + const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres; const miniView: boolean = this.toolbarWidth <= 110; - const presBox: Doc = this.presBox; //presBox - const presBoxColor: string = StrCast(presBox._backgroundColor); + const presBox = this.presBox; //presBox + const presBoxColor: string = StrCast(presBox?._backgroundColor); const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false; const activeItem: Doc = this.rootDoc; |
