diff options
author | anika <anika.ahluwalia@gmail.com> | 2021-01-28 09:21:12 -0500 |
---|---|---|
committer | anika <anika.ahluwalia@gmail.com> | 2021-01-28 09:21:12 -0500 |
commit | 35e1b844c23b0f78ead7ab00ffec16c8c6460229 (patch) | |
tree | d2d9dcd87ca62cca4a02db0b55a5fe307a2926b9 | |
parent | 5b0a4a154a6e68139d3d7e462ca421d3fbbdd224 (diff) | |
parent | 17bd18fd01d8b1f7fbef11d42651932d251cacc7 (diff) |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into filters
-rw-r--r-- | src/client/views/DocComponent.tsx | 5 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.scss | 38 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 8 | ||||
-rw-r--r-- | src/client/views/MainView.scss | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackedTimeline.tsx | 60 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 31 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.tsx | 7 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.scss | 7 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 45 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextSchema.tsx | 3 |
12 files changed, 132 insertions, 77 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 8d545c61b..99f13295d 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -131,7 +131,10 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T const docs = indocs.filter(doc => effectiveAcl === AclEdit || effectiveAcl === AclAdmin || GetEffectiveAcl(doc) === AclAdmin); if (docs.length) { const docs = doc instanceof Doc ? [doc] : doc; - docs.map(doc => doc.isPushpin = doc.annotationOn = undefined); + docs.map(doc => { + Doc.SetInPlace(doc, "isPushpin", undefined, true); + Doc.SetInPlace(doc, "annotationOn", undefined, true); + }); const targetDataDoc = this.dataDoc; const value = DocListCast(targetDataDoc[annotationKey ?? this.annotationKey]); const toRemove = value.filter(v => docs.includes(v)); diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index f9b8c1940..22e120167 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -79,7 +79,7 @@ $linkGap : 3px; grid-column: 5; grid-row: 4; border-radius: 100%; - background: dimgray; + background: black; height: 8; right: -12; top: 12; @@ -145,7 +145,7 @@ $linkGap : 3px; .documentDecorations-topRightResizer:hover, .documentDecorations-bottomLeftResizer:hover { cursor: nesw-resize; - background: dimGray; + background: black; opacity: 1; } @@ -169,6 +169,14 @@ $linkGap : 3px; cursor: pointer; } + .documentDecorations-titleBackground { + background: #ffffffcf; + border-radius: 8px; + width: 100%; + height: 100%; + position: absolute; + } + .documentDecorations-title { opacity: 1; grid-column-start: 2; @@ -177,26 +185,22 @@ $linkGap : 3px; overflow: hidden; text-align: center; display: flex; - border-bottom: solid 1px; - margin-left: 10px; - width: calc(100% - 10px); + margin-left: 5px; + height: 22px; + position: absolute; + .documentDecorations-titleSpan { + width: 100%; + border-radius: 8px; + background: #ffffffcf; + position: absolute; + display: inline-block; + cursor: move; + } } .focus-visible { margin-left: 0px; } - - .publishBox { - width: 20px; - height: 22px; - grid-column-start: 3; - grid-column-end: 4; - pointer-events: all; - background: darkgray; - display: inline-block; - position: absolute; - right: 0; - } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fb85684fb..8d8f4cd3b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -577,8 +577,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b const titleArea = this._edtingTitle ? <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle} onBlur={e => this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} /> : - <div className="documentDecorations-title" style={{ gridColumnEnd: 5 }} key="title" onPointerDown={this.onTitleDown} > - <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span> + <div className="documentDecorations-title" style={{ width: `calc(100% - ${seldoc.props.hideResizeHandles ? 0 : 20}px` }} key="title" onPointerDown={this.onTitleDown} > + <span className="documentDecorations-titleSpan">{`${this.selectionTitle}`}</span> </div>; let inMainMenuPanel = false; @@ -612,8 +612,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, }}> {closeIcon} - {bounds.r - bounds.x < 100 ? null : titleArea} - {seldoc.rootDoc.anchorStartTime !== undefined ? (null) : + {titleArea} + {seldoc.props.hideResizeHandles ? (null) : <> {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : <Tooltip key="i" title={<div className="dash-tooltip">{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}</div>} placement="top"> diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index d6a455a22..8ccb64744 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -61,7 +61,7 @@ } .mainView-container { - color: dimgray; + color: black; .lm_title { background: #cacaca; diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index 1775250fa..21fbef1ac 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -16,6 +16,7 @@ import { CollectionSubView } from "../collections/CollectionSubView"; import { DocumentView } from "../nodes/DocumentView"; import { LabelBox } from "../nodes/LabelBox"; import "./CollectionStackedTimeline.scss"; +import { undoBatch } from "../../util/UndoManager"; type PanZoomDocument = makeInterface<[]>; const PanZoomDocument = makeInterface(); @@ -58,10 +59,10 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument constructor(props: any) { super(props); // onClick play scripts - CollectionStackedTimeline.RangeScript = CollectionStackedTimeline.RangeScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this)`, { self: Doc.name, scriptContext: "any" })!; - CollectionStackedTimeline.LabelScript = CollectionStackedTimeline.LabelScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this)`, { self: Doc.name, scriptContext: "any" })!; - CollectionStackedTimeline.RangePlayScript = CollectionStackedTimeline.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this)`, { self: Doc.name, scriptContext: "any" })!; - CollectionStackedTimeline.LabelPlayScript = CollectionStackedTimeline.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this)`, { self: Doc.name, scriptContext: "any" })!; + CollectionStackedTimeline.RangeScript = CollectionStackedTimeline.RangeScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!; + CollectionStackedTimeline.LabelScript = CollectionStackedTimeline.LabelScript || ScriptField.MakeFunction(`scriptContext.clickAnchor(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!; + CollectionStackedTimeline.RangePlayScript = CollectionStackedTimeline.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!; + CollectionStackedTimeline.LabelPlayScript = CollectionStackedTimeline.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(this, clientX)`, { self: Doc.name, scriptContext: "any", clientX: "number" })!; } // for creating key anchors with key events @@ -84,8 +85,8 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument } } - anchorStart = (anchor: Doc) => NumCast(anchor.anchorStartTime, NumCast(anchor._timecodeToShow, NumCast(anchor.videoStart))); - anchorEnd = (anchor: Doc, defaultVal: any = null) => NumCast(anchor.anchorEndTime, NumCast(anchor._timecodeToHide, NumCast(anchor.videoEnd, defaultVal))); + anchorStart = (anchor: Doc) => NumCast(anchor.anchorStartTime, NumCast(anchor._timecodeToShow, NumCast(anchor.videoStart, NumCast(anchor.audioStart)))); + anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor.anchorEndTime, NumCast(anchor._timecodeToHide, NumCast(anchor.videoEnd, NumCast(anchor.audioEnd, val)))); getLinkData(l: Doc) { let la1 = l.anchor1 as Doc; @@ -106,7 +107,11 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument // updates the anchor with the new time @action changeAnchor = (anchor: Opt<Doc>, time: number) => { - anchor && (this._left ? anchor.anchorStartTime = time : anchor.anchorEndTime = time); + if (anchor) { + const timelineOnly = Cast(anchor.anchorStartTime, "number", null) !== undefined; + if (timelineOnly) this._left ? anchor.anchorStartTime = time : anchor.anchorEndTime = time; + else this._left ? anchor._timecodeToShow = time : anchor._timecodeToHide = time; + } } // checks if the two anchors are the same with start and end time @@ -160,6 +165,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument } } + @undoBatch @action createAnchor(anchorStartTime?: number, anchorEndTime?: number) { if (anchorStartTime === undefined) return this.props.Document; @@ -179,21 +185,46 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument return anchor; } - // play back the audio from time @action - playOnClick = (anchorDoc: Doc) => { - this.props.playFrom(this.anchorStart(anchorDoc), this.anchorEnd(anchorDoc, this.props.duration)); + playOnClick = (anchorDoc: Doc, clientX: number) => { + const seekTimeInSeconds = this.anchorStart(anchorDoc); + const endTime = this.anchorEnd(anchorDoc); + if (this.layoutDoc.autoPlay) { + if (this.props.playing()) this.props.Pause(); + else this.props.playFrom(seekTimeInSeconds, endTime); + } else { + if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) { + if (!this.layoutDoc.autoPlay && this.props.playing()) { + this.props.Pause(); + } else { + this.props.Play(); + } + } else { + this.props.playFrom(seekTimeInSeconds, endTime); + } + } return { select: true }; } - // play back the audio from time @action - clickAnchor = (anchorDoc: Doc) => { - if (this.props.Document.autoPlay) return this.playOnClick(anchorDoc); - this.props.setTime(this.anchorStart(anchorDoc)); + clickAnchor = (anchorDoc: Doc, clientX: number) => { + const seekTimeInSeconds = this.anchorStart(anchorDoc); + const endTime = this.anchorEnd(anchorDoc); + if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) { + if (this.props.playing()) this.props.Pause(); + else if (this.layoutDoc.autoPlay) this.props.Play(); + else if (!this.layoutDoc.autoPlay) { + const rect = this._timeline?.getBoundingClientRect(); + rect && this.props.setTime(this.toTimeline(clientX - rect.x, rect.width)); + } + } else { + if (this.layoutDoc.autoPlay) this.props.playFrom(seekTimeInSeconds, endTime); + else this.props.setTime(seekTimeInSeconds); + } return { select: true }; } + toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.props.duration, screen_delta / width * this.props.duration)); // starting the drag event for anchor resizing onPointerDown = (e: React.PointerEvent, m: Doc, left: boolean): void => { @@ -263,6 +294,7 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument onClick={script} onDoubleClick={this.props.Document.autoPlay ? undefined : doublescript} ignoreAutoHeight={false} + hideResizeHandles={true} bringToFront={emptyFunction} scriptContext={this} /> }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6619205af..8c3f0997f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -931,11 +931,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const layoutdoc = Doc.Layout(doc); const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document[this.scaleFieldKey], pt: this.Document._viewTransition }; - willZoom && this.setScaleToZoom(layoutdoc, scale); - const newPanX = (NumCast(doc.x) + doc[WidthSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeWidth(this.props.Document)) / 2 / this.zoomScaling() : 0); - const newPanY = (NumCast(doc.y) + doc[HeightSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeHeight(this.props.Document)) / 2 / this.zoomScaling() : 0); const newState = HistoryUtil.getState(); - newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; + if (!layoutdoc.annotationOn) { + willZoom && this.setScaleToZoom(layoutdoc, scale); + const newPanX = (NumCast(doc.x) + doc[WidthSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeWidth(this.props.Document)) / 2 / this.zoomScaling() : 0); + const newPanY = (NumCast(doc.y) + doc[HeightSym]() / 2) - (this.isAnnotationOverlay ? (Doc.NativeHeight(this.props.Document)) / 2 / this.zoomScaling() : 0); + newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; + } HistoryUtil.pushState(newState); if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { @@ -1651,18 +1653,15 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF const vfTop: number = NumCast(activeItem.presPinViewY); const vfWidth: number = 100; const vfHeight: number = 100; - return ( - <> - {!this.props.presPinView ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}> - <div className='resizers' key={'resizer' + activeItem.id}> - <div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerDown}></div> - <div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerDown}></div> - <div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerDown}></div> - <div id="resizer-br" className='resizer bottom-right' onPointerDown={this.onPointerDown}></div> - </div> - </div>} - </> - ); + return !this.props.presPinView ? (null) : + <div key="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}> + <div className='resizers' key={'resizer' + activeItem.id}> + <div className='resizer top-left' onPointerDown={this.onPointerDown}></div> + <div className='resizer top-right' onPointerDown={this.onPointerDown}></div> + <div className='resizer bottom-left' onPointerDown={this.onPointerDown}></div> + <div className='resizer bottom-right' onPointerDown={this.onPointerDown}></div> + </div> + </div>; } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6dc7a822c..b653b35bc 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -30,7 +30,6 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from "../DocComponent"; import { EditableView } from '../EditableView'; import { InkingStroke } from "../InkingStroke"; -import { InkStrokeProperties } from '../InkStrokeProperties'; import { StyleLayers, StyleProp } from "../StyleProvider"; import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; import { DocumentContentsView } from "./DocumentContentsView"; @@ -86,6 +85,7 @@ export interface DocumentViewSharedProps { export interface DocumentViewProps extends DocumentViewSharedProps { // properties specific to DocumentViews but not to FieldView freezeDimensions?: boolean; + hideResizeHandles?: boolean; // whether to suppress DocumentDecorations when this document is selected hideTitle?: boolean; // forces suppression of title. e.g, treeView document labels suppress titles in case they are globally active via settings treeViewDoc?: Doc; contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 62e497e18..8d0283a12 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -417,15 +417,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> self._dragArray.splice(0, self._dragArray.length, ...dragViewCache); self._eleArray.splice(0, self._eleArray.length, ...eleViewCache); }); - const openInTab = () => { - collectionDocView ? collectionDocView.props.addDocTab(targetDoc, "") : this.props.addDocTab(targetDoc, ":left"); + const openInTab = (doc: Doc, finished?: () => void) => { + collectionDocView ? collectionDocView.props.addDocTab(doc, "") : this.props.addDocTab(doc, ":left"); this.layoutDoc.presCollection = targetDoc; // this still needs some fixing setTimeout(resetSelection, 500); + doc !== targetDoc && setTimeout(() => finished?.(), 100); /// give it some time to create the targetDoc if we're opening up its context }; // If openDocument is selected then it should open the document for the user if (activeItem.openDocument) { - openInTab(); + openInTab(targetDoc); } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) { diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index 19f605278..ac4d64f12 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -183,14 +183,15 @@ pointer-events:all; } -.timeline-button { +.videoBox-timelineButton { position: absolute; display: flex; align-items: center; z-index: 1010; - bottom: 35px; - right: 235px; + bottom: 5px; + right: 5px; color: white; + cursor: pointer; background: dimgrey; width: 20px; height: 20px; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index bfac7dc1c..506ba8c49 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -55,16 +55,17 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD @observable _marqueeing: number[] | undefined; @observable _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>(); @observable _screenCapture = false; - @observable _visible: boolean = false; + @observable _clicking = false; @observable _forceCreateYouTubeIFrame = false; @observable _playTimer?: NodeJS.Timeout = undefined; @observable _fullScreen = false; @observable _playing = false; @computed get links() { return DocListCast(this.dataDoc.links); } - @computed get heightPercent() { return this.layoutDoc._timelineShow ? NumCast(this.layoutDoc._videoTimelineHeightPercent, VideoBox.heightPercent) : 100; } + @computed get heightPercent() { return NumCast(this.layoutDoc._timelineHeightPercent, 100); } @computed get duration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); } @computed get anchorDocs() { return DocListCast(this.dataDoc[this.annotationKey + "-timeline"]).concat(DocListCast(this.dataDoc[this.annotationKey])); } + private get transition() { return this._clicking ? "left 0.5s, width 0.5s, height 0.5s" : ""; } public get player(): HTMLVideoElement | null { return this._videoRef; } constructor(props: Readonly<FieldViewProps>) { @@ -310,8 +311,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD const field = Cast(this.dataDoc[this.fieldKey], VideoField); const interactive = Doc.GetSelectedTool() !== InkTool.None || !this.props.isSelected() ? "" : "-interactive"; const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive; - return !field ? <div>Loading</div> : - <div className="container" style={{ pointerEvents: this._isChildActive || this.active() ? "all" : "none" }}> + return !field ? <div key="loading">Loading</div> : + <div className="container" key="container" style={{ pointerEvents: this._isChildActive || this.active() ? "all" : "none" }}> <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}> <video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef} style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }} @@ -380,16 +381,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD <span>{"" + formatTime(curTime)}</span> <span style={{ fontSize: 8 }}>{" " + Math.round((curTime - Math.trunc(curTime)) * 100)}</span> </div>, - <div className="videoBox-snapshot" key="snap" onPointerDown={this.onSnapshot} > + <div className="videoBox-snapshot" key="snap" onClick={this.onSnapshot} > <FontAwesomeIcon icon="camera" size="lg" /> </div>, - <div className="timeline-button" key="timeline-button" onPointerDown={action(e => this.layoutDoc._timelineShow = !this.layoutDoc._timelineShow)} - style={{ - transform: `scale(${this.scaling()})`, - right: this.scaling() * 10 - 10, - bottom: this.scaling() * 10 - 10 - }}> - <FontAwesomeIcon icon={this.layoutDoc._timelineShow ? "eye-slash" : "eye"} style={{ width: "100%" }} /> + <div className="videoBox-timelineButton" key="timeline" onPointerDown={this.onTimelineHdlDown} style={{ bottom: `${100 - this.heightPercent}%` }}> + <FontAwesomeIcon icon={"eye"} size="lg" /> </div>, VideoBox._showControls ? (null) : [ // <div className="control-background"> @@ -411,12 +407,29 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD e.preventDefault(); } - onSnapshot = (e: React.PointerEvent) => { + onSnapshot = (e: React.MouseEvent) => { this.Snapshot(); e.stopPropagation(); e.preventDefault(); } + onTimelineHdlDown = action((e: React.PointerEvent) => { + this._clicking = true; + setupMoveUpEvents(this, e, + action((e: PointerEvent) => { + this._clicking = false; + if (this.active()) { + const local = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); + this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100)); + } + return false; + }), emptyFunction, + () => { + this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent; + setTimeout(action(() => this._clicking = false), 500); + }, this.active(), this.active()); + }); + onResetDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e: PointerEvent) => { this.Seek(Math.max(0, (this.layoutDoc._currentTimecode || 0) + Math.sign(e.movementX) * 0.0333)); @@ -483,7 +496,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD // returns the timeline @computed get renderTimeline() { - return <div style={{ width: "100%", height: `${100 - this.heightPercent}%`, position: "absolute" }}> + return <div style={{ width: "100%", transition: this.transition, height: `${100 - this.heightPercent}%`, position: "absolute" }}> <CollectionStackedTimeline ref={this._stackedTimeline} Document={this.props.Document} fieldKey={this.annotationKey} @@ -524,7 +537,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content]; @computed get annotationLayer() { - return <div className="imageBox-annotationLayer" style={{ height: `${this.heightPercent}%` }} ref={this._annotationLayer} />; + return <div className="imageBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />; } marqueeDown = action((e: React.PointerEvent) => { @@ -553,7 +566,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD borderRadius }} > <div className="videoBox-viewer" onPointerDown={this.marqueeDown} > - <div style={{ position: "absolute", width: this.panelWidth(), height: this.panelHeight(), top: 0, left: `${(100 - this.heightPercent) / 2}%` }}> + <div style={{ position: "absolute", transition: this.transition, width: this.panelWidth(), height: this.panelHeight(), top: 0, left: `${(100 - this.heightPercent) / 2}%` }}> <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit} fieldKey={this.annotationKey} isAnnotationOverlay={true} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index e06a324d2..36d268fe9 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1302,6 +1302,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this.endUndoTypingBatch(); this.unhighlightSearchTerms(); this._editorView?.destroy(); + RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined); FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none"); } diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index d272b6b8c..abbb89780 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -136,6 +136,8 @@ export class DashDocView { addDocument={returnFalse} rootSelected={this._textBox.props.isSelected} removeDocument={removeDoc} + layerProvider={this._textBox.props.layerProvider} + styleProvider={this._textBox.props.styleProvider} ScreenToLocalTransform={this.getDocTransform} addDocTab={this._textBox.props.addDocTab} pinToPres={returnFalse} @@ -143,7 +145,6 @@ export class DashDocView { PanelWidth={finalLayout[WidthSym]} PanelHeight={finalLayout[HeightSym]} focus={this.outerFocus} - styleProvider={DefaultStyleProvider} parentActive={returnFalse} whenActiveChanged={returnFalse} bringToFront={emptyFunction} |