aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/views/DocumentDecorations.scss5
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx216
-rw-r--r--src/client/views/animationtimeline/Track.tsx5
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx5
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx138
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx18
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx14
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx21
-rw-r--r--src/client/views/webcam/WebCamLogic.js5
-rw-r--r--src/fields/Doc.ts25
-rw-r--r--src/fields/documentSchemas.ts8
19 files changed, 198 insertions, 281 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 9c807eff2..8d3e5a771 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -514,6 +514,7 @@ export namespace Docs {
const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey);
const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
+ viewDoc.author = Doc.CurrentUserEmail;
viewDoc.type !== DocumentType.LINK && DocUtils.MakeLinkToActiveAudio(viewDoc);
return Doc.assign(viewDoc, delegateProps, true);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 67f2f244c..78c05f572 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -168,7 +168,7 @@ export class DocumentManager {
highlight();
} else { // otherwise try to get a view of the context of the target
const targetDocContextView = getFirstDocView(targetDocContext);
- targetDocContext.scrollY = 0; // this will force PDFs to activate and load their annotations / allow scrolling
+ targetDocContext._scrollY = 0; // this will force PDFs to activate and load their annotations / allow scrolling
if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first..
targetDocContext.panTransformType = "Ease";
targetDocContextView.props.focus(targetDocContextView.props.Document, willZoom);
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index a4d4af2f0..0a96b058b 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -152,6 +152,11 @@ $linkGap : 3px;
text-align: center;
display: flex;
border-bottom: solid 1px;
+ margin-left:10px;
+ width: calc(100% - 10px);
+ }
+ .focus-visible {
+ margin-left:0px;
}
.publishBox {
width: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 04f02c683..e7a237e62 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -466,7 +466,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const titleArea = this._edtingTitle ?
<>
- <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle} style={{ width: minimal ? "100%" : "calc(100% - 20px)" }}
+ <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} />
{minimal ? (null) : <div className="publishBox" title="make document referenceable by its title"
onPointerDown={action(e => {
@@ -485,7 +485,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
<FontAwesomeIcon size="lg" icon="cog" />
</div>}
<div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
- <span style={{ width: "calc(100% - 25px)", display: "inline-block" }}>{`${this.selectionTitle}`}</span>
+ <span style={{ width: "100%", display: "inline-block" }}>{`${this.selectionTitle}`}</span>
</div>
</>;
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 30692944d..43f15a33f 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -1,19 +1,17 @@
-import * as React from "react";
-import "./Timeline.scss";
-import { listSpec } from "../../../fields/Schema";
+import { faBackward, faForward, faGripLines, faPauseCircle, faPlayCircle } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, observable, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
-import { Track } from "./Track";
-import { observable, action, computed, runInAction, IReactionDisposer, reaction, trace } from "mobx";
-import { Cast, NumCast, StrCast, BoolCast } from "../../../fields/Types";
-import { List } from "../../../fields/List";
+import * as React from "react";
import { Doc, DocListCast } from "../../../fields/Doc";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faPlayCircle, faBackward, faForward, faGripLines, faPauseCircle, faEyeSlash, faEye, faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
-import { ContextMenu } from "../ContextMenu";
-import { TimelineOverview } from "./TimelineOverview";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils";
import { FieldViewProps } from "../nodes/FieldView";
import { KeyframeFunc } from "./Keyframe";
-import { Utils } from "../../../Utils";
+import "./Timeline.scss";
+import { TimelineOverview } from "./TimelineOverview";
+import { Track } from "./Track";
+import clamp from "../../util/clamp";
/**
* Timeline class controls most of timeline functions besides individual keyframe and track mechanism. Main functions are
@@ -39,7 +37,6 @@ import { Utils } from "../../../Utils";
@observer
export class Timeline extends React.Component<FieldViewProps> {
-
//readonly constants
private readonly DEFAULT_TICK_SPACING: number = 50;
private readonly MAX_TITLE_HEIGHT = 75;
@@ -57,7 +54,7 @@ export class Timeline extends React.Component<FieldViewProps> {
@observable private _infoContainer = React.createRef<HTMLDivElement>();
@observable private _roundToggleRef = React.createRef<HTMLDivElement>();
@observable private _roundToggleContainerRef = React.createRef<HTMLDivElement>();
- @observable private _timeInputRef = React.createRef<HTMLInputElement>();
+
//boolean vars and instance vars
@observable private _currentBarX: number = 0;
@@ -71,27 +68,18 @@ export class Timeline extends React.Component<FieldViewProps> {
@observable private _tickIncrement = this.DEFAULT_TICK_INCREMENT;
@observable private _time = 100000; //DEFAULT
@observable private _playButton = faPlayCircle;
- @observable private _mouseToggled = false;
- @observable private _doubleClickEnabled = false;
@observable private _titleHeight = 0;
- // so a reaction can be made
- @observable public _isAuthoring = this.props.Document.isATOn;
-
/**
* collection get method. Basically defines what defines collection's children. These will be tracked in the timeline. Do not edit.
*/
@computed
- private get children(): List<Doc> {
- const extendedDocument = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type));
- if (extendedDocument) {
- if (this.props.Document.data_ext) {
- return Cast((Cast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + "-annotations"], Doc) as Doc).annotations, listSpec(Doc)) as List<Doc>;
- } else {
- return new List<Doc>();
- }
+ private get children(): Doc[] {
+ const annotatedDoc = ["image", "video", "pdf"].includes(StrCast(this.props.Document.type));
+ if (annotatedDoc) {
+ return DocListCast(this.props.Document[Doc.LayoutFieldKey(this.props.Document) + "-annotations"]);
}
- return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc)) as List<Doc>;
+ return DocListCast(this.props.Document[this.props.fieldKey]);
}
/////////lifecycle functions////////////
@@ -144,9 +132,7 @@ export class Timeline extends React.Component<FieldViewProps> {
}
//for playing
- @action
onPlay = (e: React.MouseEvent) => {
- e.preventDefault();
e.stopPropagation();
this.play();
}
@@ -156,24 +142,15 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@action
play = () => {
- if (this._isPlaying) {
- this._isPlaying = false;
- this._playButton = faPlayCircle;
- } else {
- this._isPlaying = true;
- this._playButton = faPauseCircle;
- const playTimeline = () => {
- if (this._isPlaying) {
- if (this._currentBarX >= this._totalLength) {
- this.changeCurrentBarX(0);
- } else {
- this.changeCurrentBarX(this._currentBarX + this._windSpeed);
- }
- setTimeout(playTimeline, 15);
- }
- };
- playTimeline();
- }
+ const playTimeline = () => {
+ if (this._isPlaying) {
+ this.changeCurrentBarX(this._currentBarX >= this._totalLength ? 0 : this._currentBarX + this._windSpeed);
+ setTimeout(playTimeline, 15);
+ }
+ };
+ this._isPlaying = !this._isPlaying;
+ this._playButton = this._isPlaying ? faPauseCircle : faPlayCircle;
+ this._isPlaying && playTimeline();
}
@@ -206,12 +183,7 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@action
onScrubberDown = (e: React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onScrubberMove);
- document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onScrubberMove);
- });
+ setupMoveUpEvents(this, e, this.onScrubberMove, emptyFunction, emptyFunction);
}
/**
@@ -219,12 +191,11 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@action
onScrubberMove = (e: PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
const scrubberbox = this._infoContainer.current!;
const left = scrubberbox.getBoundingClientRect().left;
const offsetX = Math.round(e.clientX - left) * this.props.ScreenToLocalTransform().Scale;
this.changeCurrentBarX(offsetX + this._visibleStart); //changes scrubber to clicked scrubber position
+ return false;
}
/**
@@ -232,27 +203,8 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@action
onPanDown = (e: React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- const clientX = e.clientX;
- if (this._doubleClickEnabled) {
- this._doubleClickEnabled = false;
- } else {
- setTimeout(() => {
- if (!this._mouseToggled && this._doubleClickEnabled) this.changeCurrentBarX(this._trackbox.current!.scrollLeft + clientX - this._trackbox.current!.getBoundingClientRect().left);
- this._mouseToggled = false;
- this._doubleClickEnabled = false;
- }, 200);
- this._doubleClickEnabled = true;
- document.addEventListener("pointermove", this.onPanMove);
- document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onPanMove);
- if (!this._doubleClickEnabled) {
- this._mouseToggled = false;
- }
- });
-
- }
+ setupMoveUpEvents(this, e, this.onPanMove, emptyFunction, (e) =>
+ this.changeCurrentBarX(this._trackbox.current!.scrollLeft + e.clientX - this._trackbox.current!.getBoundingClientRect().left));
}
/**
@@ -260,11 +212,6 @@ export class Timeline extends React.Component<FieldViewProps> {
*/
@action
onPanMove = (e: PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- if (e.movementX !== 0 || e.movementY !== 0) {
- this._mouseToggled = true;
- }
const trackbox = this._trackbox.current!;
const titleContainer = this._titleContainer.current!;
this.movePanX(this._visibleStart - e.movementX);
@@ -276,43 +223,25 @@ export class Timeline extends React.Component<FieldViewProps> {
this._time -= KeyframeFunc.convertPixelTime(e.movementX, "mili", "time", this._tickSpacing, this._tickIncrement);
this.props.Document.AnimationLength = this._time;
}
-
+ return false;
}
@action
movePanX = (pixel: number) => {
- const infoContainer = this._infoContainer.current!;
- infoContainer.scrollLeft = pixel;
- this._visibleStart = infoContainer.scrollLeft;
+ this._infoContainer.current!.scrollLeft = pixel;
+ this._visibleStart = this._infoContainer.current!.scrollLeft;
}
/**
* resizing timeline (in editing mode) (the hamburger drag icon)
*/
- @action
onResizeDown = (e: React.PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- document.addEventListener("pointermove", this.onResizeMove);
- document.addEventListener("pointerup", () => {
- document.removeEventListener("pointermove", this.onResizeMove);
- });
- }
-
- @action
- onResizeMove = (e: PointerEvent) => {
- e.preventDefault();
- e.stopPropagation();
- const offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom;
- // let offset = 0;
- if (this._containerHeight + offset <= this.MIN_CONTAINER_HEIGHT) {
- this._containerHeight = this.MIN_CONTAINER_HEIGHT;
- } else if (this._containerHeight + offset >= this.MAX_CONTAINER_HEIGHT) {
- this._containerHeight = this.MAX_CONTAINER_HEIGHT;
- } else {
- this._containerHeight += offset;
- }
+ setupMoveUpEvents(this, e, action((e) => {
+ const offset = e.clientY - this._timelineContainer.current!.getBoundingClientRect().bottom;
+ this._containerHeight = clamp(this.MIN_CONTAINER_HEIGHT, this._containerHeight + offset, this.MAX_CONTAINER_HEIGHT);
+ return false;
+ }), emptyFunction, emptyFunction);
}
/**
@@ -323,8 +252,8 @@ export class Timeline extends React.Component<FieldViewProps> {
time = time / 1000;
const inSeconds = Math.round(time * 100) / 100;
- const min: (string | number) = Math.floor(inSeconds / 60);
- const sec: (string | number) = (Math.round((inSeconds % 60) * 100) / 100);
+ const min = Math.floor(inSeconds / 60);
+ const sec = (Math.round((inSeconds % 60) * 100) / 100);
let secString = sec.toFixed(2);
if (Math.floor(sec / 10) === 0) {
@@ -346,7 +275,7 @@ export class Timeline extends React.Component<FieldViewProps> {
const offset = e.clientX - this._infoContainer.current!.getBoundingClientRect().left;
const prevTime = KeyframeFunc.convertPixelTime(this._visibleStart + offset, "mili", "time", this._tickSpacing, this._tickIncrement);
const prevCurrent = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement);
- e.deltaY < 0 ? this.zoom(true) : this.zoom(false);
+ this.zoom(e.deltaY < 0);
const currPixel = KeyframeFunc.convertPixelTime(prevTime, "mili", "pixel", this._tickSpacing, this._tickIncrement);
const currCurrent = KeyframeFunc.convertPixelTime(prevCurrent, "mili", "pixel", this._tickSpacing, this._tickIncrement);
this._infoContainer.current!.scrollLeft = currPixel - offset;
@@ -405,30 +334,17 @@ export class Timeline extends React.Component<FieldViewProps> {
private timelineToolBox = (scale: number, totalTime: number) => {
const size = 40 * scale; //50 is default
const iconSize = 25;
+ const width: number = this.props.PanelWidth();
+ const modeType = this.props.Document.isATOn ? "Author" : "Play";
//decides if information should be omitted because the timeline is very small
// if its less than 950 pixels then it's going to be overlapping
- let shouldCompress = false;
- const width: number = this.props.PanelWidth();
+ let modeString = modeType, overviewString = "", lengthString = "";
if (width < 850) {
- shouldCompress = true;
- }
-
- let modeString, overviewString, lengthString;
- const modeType = this.props.Document.isATOn ? "Author" : "Play";
-
- if (!shouldCompress) {
modeString = "Mode: " + modeType;
overviewString = "Overview:";
lengthString = "Length: ";
}
- else {
- modeString = modeType;
- overviewString = "";
- lengthString = "";
- }
-
- // let rightInfo = this.timeIndicator;
return (
<div key="timeline_toolbox" className="timeline-toolbox" style={{ height: `${size}px` }}>
@@ -451,8 +367,7 @@ export class Timeline extends React.Component<FieldViewProps> {
<div className="time-box overview-tool" style={{ display: "flex" }}>
{this.timeIndicator(lengthString, totalTime)}
<div className="resetView-tool" title="Return to Default View" onClick={() => this.resetView(this.props.Document)}><FontAwesomeIcon icon="compress-arrows-alt" size="lg" /></div>
- <div className="resetView-tool" style={{ display: this._isAuthoring ? "flex" : "none" }} title="Set Default View" onClick={() => this.setView(this.props.Document)}><FontAwesomeIcon icon="expand-arrows-alt" size="lg" /></div>
-
+ <div className="resetView-tool" style={{ display: this.props.Document.isATOn ? "flex" : "none" }} title="Set Default View" onClick={() => this.setView(this.props.Document)}><FontAwesomeIcon icon="expand-arrows-alt" size="lg" /></div>
</div>
</div>
</div>
@@ -498,15 +413,15 @@ export class Timeline extends React.Component<FieldViewProps> {
const roundToggle = this._roundToggleRef.current!;
const roundToggleContainer = this._roundToggleContainerRef.current!;
const timelineContainer = this._timelineContainer.current!;
- if (BoolCast(this.props.Document.isATOn)) {
+
+ this.props.Document.isATOn = !this.props.Document.isATOn;
+ if (!BoolCast(this.props.Document.isATOn)) {
//turning on playmode...
roundToggle.style.transform = "translate(0px, 0px)";
roundToggle.style.animationName = "turnoff";
roundToggleContainer.style.animationName = "turnoff";
roundToggleContainer.style.backgroundColor = "white";
timelineContainer.style.top = `${-this._containerHeight}px`;
- this.props.Document.isATOn = false;
- this._isAuthoring = false;
this.toPlay();
} else {
//turning on authoring mode...
@@ -515,8 +430,6 @@ export class Timeline extends React.Component<FieldViewProps> {
roundToggleContainer.style.animationName = "turnon";
roundToggleContainer.style.backgroundColor = "#9acedf";
timelineContainer.style.top = "0px";
- this.props.Document.isATOn = true;
- this._isAuthoring = true;
this.toAuthoring();
}
}
@@ -533,10 +446,7 @@ export class Timeline extends React.Component<FieldViewProps> {
// @computed
getCurrentTime = () => {
let current = KeyframeFunc.convertPixelTime(this._currentBarX, "mili", "time", this._tickSpacing, this._tickIncrement);
- if (current > this._time) {
- current = this._time;
- }
- return this.toReadTime(current);
+ return this.toReadTime(current > this._time ? this._time : current);
}
@observable private mapOfTracks: (Track | null)[] = [];
@@ -562,18 +472,13 @@ export class Timeline extends React.Component<FieldViewProps> {
@action
toAuthoring = () => {
- let longestTime = this.findLongestTime();
- if (longestTime === 0) longestTime = 1;
- const adjustedTime = Math.ceil(longestTime / 100000) * 100000;
- // console.log(adjustedTime);
- this._totalLength = KeyframeFunc.convertPixelTime(adjustedTime, "mili", "pixel", this._tickSpacing, this._tickIncrement);
- this._time = adjustedTime;
+ this._time = Math.ceil((this.findLongestTime() ?? 1) / 100000) * 100000;
+ this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement);
}
@action
toPlay = () => {
- const longestTime = this.findLongestTime();
- this._time = longestTime;
+ this._time = this.findLongestTime();
this._totalLength = KeyframeFunc.convertPixelTime(this._time, "mili", "pixel", this._tickSpacing, this._tickIncrement);
}
@@ -582,40 +487,35 @@ export class Timeline extends React.Component<FieldViewProps> {
* basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region)
*/
render() {
- setTimeout(() => {
- this.changeLengths();
- // this.toPlay();
- // this._time = longestTime;
- }, 0);
+ setTimeout(() => this.changeLengths(), 0);
- const longestTime = this.findLongestTime();
trace();
// change visible and total width
return (
<div style={{ visibility: "visible" }}>
- <div key="timeline_wrapper" style={{ visibility: BoolCast(this.props.Document.isATOn) ? "visible" : "hidden", left: "0px", top: "0px", position: "absolute", width: "100%", transform: "translate(0px, 0px)" }}>
+ <div key="timeline_wrapper" style={{ visibility: this.props.Document.isATOn ? "visible" : "hidden", left: "0px", top: "0px", position: "absolute", width: "100%", transform: "translate(0px, 0px)" }}>
<div key="timeline_container" className="timeline-container" ref={this._timelineContainer} style={{ height: `${this._containerHeight}px`, top: `0px` }}>
- <div key="timeline_info" className="info-container" ref={this._infoContainer} onWheel={this.onWheelZoom}>
+ <div key="timeline_info" className="info-container" onPointerDown={this.onPanDown} ref={this._infoContainer} onWheel={this.onWheelZoom}>
{this.drawTicks()}
<div key="timeline_scrubber" className="scrubber" style={{ transform: `translate(${this._currentBarX}px)` }}>
<div key="timeline_scrubberhead" className="scrubberhead" onPointerDown={this.onScrubberDown} ></div>
</div>
- <div key="timeline_trackbox" className="trackbox" ref={this._trackbox} onPointerDown={this.onPanDown} style={{ width: `${this._totalLength}px` }}>
- {DocListCast(this.children).map(doc =>
+ <div key="timeline_trackbox" className="trackbox" ref={this._trackbox} style={{ width: `${this._totalLength}px` }}>
+ {this.children.map(doc =>
<Track ref={ref => this.mapOfTracks.push(ref)} node={doc} currentBarX={this._currentBarX} changeCurrentBarX={this.changeCurrentBarX} transform={this.props.ScreenToLocalTransform()} time={this._time} tickSpacing={this._tickSpacing} tickIncrement={this._tickIncrement} collection={this.props.Document} timelineVisible={true} />
)}
</div>
</div>
<div className="currentTime">Current: {this.getCurrentTime()}</div>
<div key="timeline_title" className="title-container" ref={this._titleContainer}>
- {DocListCast(this.children).map(doc => <div style={{ height: `${(this._titleHeight)}px` }} className="datapane" onPointerOver={() => { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}><p>{doc.title}</p></div>)}
+ {this.children.map(doc => <div style={{ height: `${(this._titleHeight)}px` }} className="datapane" onPointerOver={() => { Doc.BrushDoc(doc); }} onPointerOut={() => { Doc.UnBrushDoc(doc); }}><p>{doc.title}</p></div>)}
</div>
<div key="timeline_resize" onPointerDown={this.onResizeDown}>
<FontAwesomeIcon className="resize" icon={faGripLines} />
</div>
</div>
</div>
- {this.timelineToolBox(1, longestTime)}
+ {this.timelineToolBox(1, this.findLongestTime())}
</div>
);
}
diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx
index fc96c320a..4987006e7 100644
--- a/src/client/views/animationtimeline/Track.tsx
+++ b/src/client/views/animationtimeline/Track.tsx
@@ -31,13 +31,14 @@ export class Track extends React.Component<IProps> {
@observable private _autoKfReaction: any;
@observable private _newKeyframe: boolean = false;
private readonly MAX_TITLE_HEIGHT = 75;
- private _trackHeight = 0;
+ @observable private _trackHeight = 0;
private primitiveWhitelist = [
"x",
"y",
"_width",
"_height",
"opacity",
+ "_scrollTop"
];
private objectWhitelist = [
"data"
@@ -51,7 +52,7 @@ export class Track extends React.Component<IProps> {
if (!regions) this.props.node.regions = new List<Doc>(); //if there is no region, then create new doc to store stuff
//these two lines are exactly same from timeline.tsx
const relativeHeight = window.innerHeight / 20;
- this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT; //for responsiveness
+ runInAction(() => this._trackHeight = relativeHeight < this.MAX_TITLE_HEIGHT ? relativeHeight : this.MAX_TITLE_HEIGHT); //for responsiveness
this._timelineVisibleReaction = this.timelineVisibleReaction();
this._currentBarXReaction = this.currentBarXReaction();
if (DocListCast(this.props.node.regions).length === 0) this.createRegion(this.time);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7fd19a23c..bd48d1727 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -474,7 +474,10 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
width: `${1 / this.scaling * 100}%`,
transformOrigin: "top left",
}}
- onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
+ onScroll={action(e => {
+ if (!this.props.isSelected()) e.currentTarget.scrollTop = this._scroll;
+ else this._scroll = e.currentTarget.scrollTop;
+ })}
onDrop={this.onExternalDrop.bind(this)}
onContextMenu={this.onContextMenu}
onWheel={e => this.props.active() && e.stopPropagation()} >
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index b60419258..167bce131 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -335,7 +335,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
if (focusNode) {
const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
const x = (rect?.x || 0);
- const y = NumCast(srcWeb.scrollTop) + (rect?.y || 0);
+ const y = NumCast(srcWeb._scrollTop) + (rect?.y || 0);
const anchor = Docs.Create.FreeformDocument([], { _LODdisable: true, _backgroundColor: "transparent", _width: 25, _height: 25, x, y, annotationOn: srcWeb });
anchor.context = srcWeb;
const key = Doc.LayoutFieldKey(srcWeb);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9c0e5e917..379156179 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -118,10 +118,12 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.Document.scale || 1)
@computed get cachedCenteringShiftX(): number {
- return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections
+ const scaling = this.fitToContent ? 1 : this.contentScaling;
+ return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
- return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections
+ const scaling = this.fitToContent ? 1 : this.contentScaling;
+ return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections
}
@computed get cachedGetLocalTransform(): Transform {
return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
@@ -187,79 +189,76 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
return this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
}
+ onExternalDrop = (e: React.DragEvent) => {
+ return (pt => super.onExternalDrop(e, { x: pt[0], y: pt[1] }))(this.getTransform().transformPoint(e.pageX, e.pageY));
+ }
+
+ @undoBatch
+ @action
+ internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
+ if (!super.onInternalDrop(e, de)) return false;
+ const [xpo, ypo] = this.getTransformOverlay().transformPoint(de.x, de.y);
+ const z = NumCast(docDragData.droppedDocuments[0].z);
+ const x = (z ? xpo : xp) - docDragData.offset[0];
+ const y = (z ? ypo : yp) - docDragData.offset[1];
+ const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
+ zsorted.forEach((doc, index) => doc.zIndex = index + 1);
+ const dropPos = [NumCast(docDragData.droppedDocuments[0].x), NumCast(docDragData.droppedDocuments[0].y)];
+ for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
+ const d = docDragData.droppedDocuments[i];
+ const layoutDoc = Doc.Layout(d);
+ if (this.Document.currentFrame !== undefined && !this.props.isAnnotationOverlay) {
+ const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
+ CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.opacity);
+ } else {
+ d.x = x + NumCast(d.x) - dropPos[0];
+ d.y = y + NumCast(d.y) - dropPos[1];
+ }
+ const nd = [NumCast(layoutDoc._nativeWidth), NumCast(layoutDoc._nativeHeight)];
+ layoutDoc._width = NumCast(layoutDoc._width, 300);
+ layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
+ d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+ }
+
+ (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
+ return true;
+ }
+
+ @undoBatch
@action
- onExternalDrop = (e: React.DragEvent): Promise<void> => {
- const pt = this.getTransform().transformPoint(e.pageX, e.pageY);
- return super.onExternalDrop(e, { x: pt[0], y: pt[1] });
+ internalPdfAnnoDrop(e: Event, annoDragData: DragManager.PdfAnnoDragData, xp: number, yp: number) {
+ const dragDoc = annoDragData.dropDocument;
+ const dropPos = [NumCast(dragDoc.x), NumCast(dragDoc.y)];
+ dragDoc.x = xp - annoDragData.offset[0] + (NumCast(dragDoc.x) - dropPos[0]);
+ dragDoc.y = yp - annoDragData.offset[1] + (NumCast(dragDoc.y) - dropPos[1]);
+ annoDragData.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation
+ this.bringToFront(dragDoc);
+ return true;
}
@undoBatch
@action
+ internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
+ if (linkDragData.linkSourceDocument === this.props.Document) return false;
+ const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
+ this.props.addDocument(source);
+ linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: linkDragData.linkSourceDocument }, "doc annotation"); // TODODO this is where in text links get passed
+ e.stopPropagation();
+ return true;
+ }
+
+ @action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
// if (this.props.Document.isBackground) return false;
- const xf = this.getTransform();
- const xfo = this.getTransformOverlay();
- const [xp, yp] = xf.transformPoint(de.x, de.y);
- const [xpo, ypo] = xfo.transformPoint(de.x, de.y);
- const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
- if (!this.isAnnotationOverlay && de.complete.linkDragData && de.complete.linkDragData.linkSourceDocument !== this.props.Document) {
- const source = Docs.Create.TextDocument("", { _width: 200, _height: 75, x: xp, y: yp, title: "dropped annotation" });
- this.props.addDocument(source);
- (de.complete.linkDragData.linkDocument = DocUtils.MakeLink({ doc: source }, { doc: de.complete.linkDragData.linkSourceDocument },
- "doc annotation")); // TODODO this is where in text links get passed
- e.stopPropagation();
+ const [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ if (this.isAnnotationOverlay !== true && de.complete.linkDragData)
+ return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp);
+ if (de.complete.annoDragData?.dropDocument && super.onInternalDrop(e, de))
+ return this.internalPdfAnnoDrop(e, de.complete.annoDragData, xp, yp);
+ if (de.complete.docDragData?.droppedDocuments.length && this.internalDocDrop(e, de, de.complete.docDragData, xp, yp)) {
return true;
- }
- if (super.onInternalDrop(e, de)) {
- if (de.complete.docDragData) {
- if (de.complete.docDragData.droppedDocuments.length) {
- const firstDoc = de.complete.docDragData.droppedDocuments[0];
- const z = NumCast(firstDoc.z);
- const x = (z ? xpo : xp) - de.complete.docDragData.offset[0];
- const y = (z ? ypo : yp) - de.complete.docDragData.offset[1];
- const dropX = NumCast(firstDoc.x);
- const dropY = NumCast(firstDoc.y);
- const droppedDocs = de.complete.docDragData.droppedDocuments;
- runInAction(() => {
- zsorted.forEach((doc, index) => doc.zIndex = index + 1);
- for (let i = 0; i < droppedDocs.length; i++) {
- const d = droppedDocs[i];
- const layoutDoc = Doc.Layout(d);
- if (this.Document.currentFrame !== undefined && !this.props.isAnnotationOverlay) {
- const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropX, y + vals.y - dropY, vals.opacity);
- } else {
- d.x = x + NumCast(d.x) - dropX;
- d.y = y + NumCast(d.y) - dropY;
- }
- if (!NumCast(layoutDoc._width)) {
- layoutDoc._width = 300;
- }
- if (!NumCast(layoutDoc._height)) {
- const nw = NumCast(layoutDoc._nativeWidth);
- const nh = NumCast(layoutDoc._nativeHeight);
- layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300;
- }
- d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); // bringToFront
- }
- });
-
- (de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments);
- }
- }
- else if (de.complete.annoDragData) {
- if (de.complete.annoDragData.dropDocument) {
- const dragDoc = de.complete.annoDragData.dropDocument;
- const x = xp - de.complete.annoDragData.offset[0];
- const y = yp - de.complete.annoDragData.offset[1];
- const dropX = NumCast(dragDoc.x);
- const dropY = NumCast(dragDoc.y);
- dragDoc.x = x + NumCast(dragDoc.x) - dropX;
- dragDoc.y = y + NumCast(dragDoc.y) - dropY;
- de.complete.annoDragData.targetContext = this.props.Document; // dropped a PDF annotation, so we need to set the targetContext on the dragData which the PDF view uses at the end of the drop operation
- this.bringToFront(dragDoc);
- }
- }
+ } else {
+ UndoManager.Undo();
}
return false;
}
@@ -887,7 +886,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
} else {
const contextHgt = Doc.AreProtosEqual(annotOn, this.props.Document) && this.props.VisibleHeight ? this.props.VisibleHeight() : NumCast(annotOn._height);
const offset = annotOn && (contextHgt / 2 * 96 / 72);
- this.props.Document.scrollY = NumCast(doc.y) - offset;
+ this.props.Document._scrollY = NumCast(doc.y) - offset;
}
afterFocus && setTimeout(afterFocus, 1000);
@@ -1345,7 +1344,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
<CollectionFreeFormViewPannableContents
centeringShiftX={this.centeringShiftX}
centeringShiftY={this.centeringShiftY}
- shifted={!this.nativeHeight && !this.isAnnotationOverlay}
easing={this.easing}
transition={Cast(this.layoutDoc.transition, "string", null)}
viewDefDivClick={this.props.viewDefDivClick}
@@ -1431,7 +1429,6 @@ interface CollectionFreeFormViewPannableContentsProps {
easing: () => boolean;
viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
- shifted: boolean;
transition?: string;
}
@@ -1446,7 +1443,6 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
const zoom = this.props.zoomScaling();
return <div className={freeformclass}
style={{
- width: this.props.shifted ? 0 : undefined, height: this.props.shifted ? 0 : undefined,
transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}) translate(${panx}px, ${pany}px)`,
transition: this.props.transition
}}>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 97244ed06..73dd41a15 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -684,7 +684,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@computed
get marqueeDiv() {
- const p: [number, number] = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0];
+ const p = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0];
const v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
/**
* @RE - The commented out span below
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 98be1adc0..077a4d0d7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,6 +43,7 @@ import "./DocumentView.scss";
import { LinkAnchorBox } from './LinkAnchorBox';
import { RadialMenu } from './RadialMenu';
import React = require("react");
+import { undo } from 'prosemirror-history';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -681,6 +682,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true;
}
+ @undoBatch
+ @action
+ setAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => {
+ this.layoutDoc.ACL = this.dataDoc.ACL = acl;
+ DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => {
+ if (d.author === Doc.CurrentUserEmail) d.ACL = acl;
+ const data = d[DataSym];
+ if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl;
+ });
+ }
+
@action
onContextMenu = async (e: React.MouseEvent | Touch): Promise<void> => {
// the touch onContextMenu is button 0, the pointer onContextMenu is button 2
@@ -741,9 +753,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
const more = cm.findByDescription("More...");
const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
- moreItems.push({ description: "Make Add Only", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "addOnly", icon: "concierge-bell" });
- moreItems.push({ description: "Make Read Only", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "readOnly", icon: "concierge-bell" });
- moreItems.push({ description: "Make Private", event: () => this.dataDoc.ACL = this.layoutDoc.ACL = "noAccess", icon: "concierge-bell" });
+ moreItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" });
+ moreItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" });
+ moreItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" });
moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 493f23dc4..fae216f17 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -248,7 +248,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
_pdfjsRequested = false;
render() {
const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null);
- if (this.props.isSelected() || this.props.renderDepth <= 1 || this.props.Document.scrollY !== undefined) this._everActive = true;
+ if (this.props.isSelected() || this.props.renderDepth <= 1 || this.props.Document._scrollY !== undefined) this._everActive = true;
if (pdfUrl && (this._everActive || this.props.Document._scrollTop || (this.dataDoc[this.props.fieldKey + "-nativeWidth"] && this.props.ScreenToLocalTransform().Scale < 2.5))) {
if (pdfUrl instanceof PdfField && this._pdf) {
return this.renderPdfView;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8fdde61e0..fb9e57b51 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -57,15 +57,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
iframe.contentDocument.addEventListener('pointerdown', this.iframedown, false);
iframe.contentDocument.addEventListener('scroll', this.iframeScrolled, false);
this.layoutDoc.scrollHeight = iframe.contentDocument.children?.[0].scrollHeight || 1000;
- iframe.contentDocument.children[0].scrollTop = NumCast(this.layoutDoc.scrollTop);
- iframe.contentDocument.children[0].scrollLeft = NumCast(this.layoutDoc.scrollLeft);
+ iframe.contentDocument.children[0].scrollTop = NumCast(this.layoutDoc._scrollTop);
+ iframe.contentDocument.children[0].scrollLeft = NumCast(this.layoutDoc._scrollLeft);
}
this._reactionDisposer?.();
- this._reactionDisposer = reaction(() => ({ y: this.layoutDoc.scrollY, x: this.layoutDoc.scrollX }),
+ this._reactionDisposer = reaction(() => ({ y: this.layoutDoc._scrollY, x: this.layoutDoc._scrollX }),
({ x, y }) => {
if (y !== undefined) {
this._outerRef.current!.scrollTop = y;
- this.layoutDoc.scrollY = undefined;
+ this.layoutDoc._scrollY = undefined;
}
if (x !== undefined) {
this._outerRef.current!.scrollLeft = x;
@@ -82,8 +82,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
iframeScrolled = (e: any) => {
const scrollTop = e.target?.children?.[0].scrollTop;
const scrollLeft = e.target?.children?.[0].scrollLeft;
- this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scrollTop;
- this.layoutDoc.scrollLeft = this._outerRef.current!.scrollLeft = scrollLeft;
+ this.layoutDoc._scrollTop = this._outerRef.current!.scrollTop = scrollTop;
+ this.layoutDoc._scrollLeft = this._outerRef.current!.scrollLeft = scrollLeft;
}
async componentDidMount() {
const urlField = Cast(this.dataDoc[this.props.fieldKey], WebField);
@@ -439,7 +439,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
{this.urlEditor()}
</>);
}
- scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc.scrollLeft), NumCast(this.layoutDoc.scrollTop));
+ scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop));
render() {
return (<div className={`webBox-container`}
style={{
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2c1d93222..e55588f8a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -719,7 +719,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
},
{ fireImmediately: true }
);
- this._disposers.scroll = reaction(() => NumCast(this.layoutDoc.scrollPos),
+ this._disposers.scroll = reaction(() => NumCast(this.layoutDoc._scrollTop),
pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true }
);
@@ -1172,7 +1172,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
onscrolled = (ev: React.UIEvent) => {
- this.layoutDoc.scrollPos = this._scrollRef.current!.scrollTop;
+ this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop;
}
@action
tryUpdateHeight(limitHeight?: number) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index d47ae63af..59a6045ab 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -183,7 +183,7 @@ export class FormattedTextBoxComment {
const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc);
const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
if (anchor !== target && anchor && target) {
- target.scrollY = NumCast(anchor?.y);
+ target._scrollY = NumCast(anchor?.y);
}
if (target) {
ReactDOM.render(<ContentFittingDocumentView
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 8cf5026c8..e39e96607 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -36,9 +36,7 @@ import { Networking } from "../../Network";
export const pageSchema = createSchema({
curPage: "number",
- fitWidth: "boolean",
rotation: "number",
- scrollY: "number",
scrollHeight: "number",
serachMatch: "boolean"
});
@@ -93,7 +91,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@observable private _showWaiting = true;
@observable private _showCover = false;
@observable private _zoomed = 1;
- @observable private _scrollTop = 0;
private _pdfViewer: any;
private _retries = 0; // number of times tried to create the PDF viewer
@@ -141,6 +138,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
this._coverPath = href.startsWith(window.location.origin) ? await Networking.PostToServer("/thumbnail", params) : { width: 100, height: 100, path: "" };
runInAction(() => this._showWaiting = this._showCover = true);
this.props.startupLive && this.setupPdfJsViewer();
+ this._mainCont.current!.scrollTop = this.layoutDoc._scrollTop || 0;
this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => {
if (search) {
this.search(Doc.SearchQuery(), true);
@@ -156,14 +154,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
() => (SelectionManager.SelectedDocuments().length === 1) && this.setupPdfJsViewer(),
{ fireImmediately: true });
this._reactionDisposer = reaction(
- () => this.Document.scrollY,
+ () => this.Document._scrollY,
(scrollY) => {
if (scrollY !== undefined) {
- if (this._showCover || this._showWaiting) {
- this.setupPdfJsViewer();
- }
- this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document.scrollY || 0));
- this.Document.scrollY = undefined;
+ (this._showCover || this._showWaiting) && this.setupPdfJsViewer();
+ this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document._scrollY || 0));
+ setTimeout(() => this.Document._scrollY = undefined, 1000);
}
},
{ fireImmediately: true }
@@ -218,7 +214,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
await this.initialLoad();
this._scrollTopReactionDisposer = reaction(() => Cast(this.layoutDoc._scrollTop, "number", null),
- (stop) => (stop !== undefined) && this._mainCont.current && smoothScroll(500, this._mainCont.current, stop), { fireImmediately: true });
+ (stop) => (stop !== undefined && this.layoutDoc._scrollY === undefined) && (this._mainCont.current!.scrollTop = stop), { fireImmediately: true });
+
this._annotationReactionDisposer = reaction(
() => DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]),
annotations => annotations?.length && (this._annotations = annotations),
@@ -350,7 +347,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
onScroll = (e: React.UIEvent<HTMLElement>) => {
- this._scrollTop = this._mainCont.current!.scrollTop;
+ this.Document._scrollY === undefined && (this.layoutDoc._scrollTop = this._mainCont.current!.scrollTop);
this._pdfViewer && (this.Document.curPage = this._pdfViewer.currentPageNumber);
}
@@ -602,7 +599,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
scrollXf = () => {
- return this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, this._scrollTop) : this.props.ScreenToLocalTransform();
+ return this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, this.layoutDoc._scrollTop || 0) : this.props.ScreenToLocalTransform();
}
onClick = (e: React.MouseEvent) => {
this._setPreviewCursor &&
diff --git a/src/client/views/webcam/WebCamLogic.js b/src/client/views/webcam/WebCamLogic.js
index a8a2f5fa4..5f6202bc8 100644
--- a/src/client/views/webcam/WebCamLogic.js
+++ b/src/client/views/webcam/WebCamLogic.js
@@ -1,8 +1,5 @@
'use strict';
import io from "socket.io-client";
-import {
- resolvedPorts
-} from "../Main";
var socket;
var isChannelReady = false;
@@ -32,7 +29,7 @@ export function initialize(roomName, handlerUI) {
room = roomName;
- socket = io.connect(`${window.location.protocol}//${window.location.hostname}:${resolvedPorts.socket}`);
+ socket = io.connect(`${window.location.protocol}//${window.location.hostname}:4321`);
if (room !== '') {
socket.emit('create or join', room);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 981025483..6f712f2ed 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -93,7 +93,7 @@ export const HeightSym = Symbol("Height");
export const DataSym = Symbol("Data");
export const LayoutSym = Symbol("Layout");
export const AclSym = Symbol("Acl");
-export const AclPrivate = Symbol("AclNoAccess");
+export const AclPrivate = Symbol("AclOwnerOnly");
export const AclReadonly = Symbol("AclReadOnly");
export const AclAddonly = Symbol("AclAddonly");
export const UpdatingFromServer = Symbol("UpdatingFromServer");
@@ -102,13 +102,17 @@ const CachedUpdates = Symbol("Cached updates");
function fetchProto(doc: Doc) {
if (doc.author !== Doc.CurrentUserEmail) {
- if (doc.ACL === "noAccess") {
- doc[AclSym] = AclPrivate;
- return undefined;
- } else if (doc.ACL === "readOnly") {
- doc[AclSym] = AclReadonly;
- } else if (doc.ACL === "addOnly") {
- doc[AclSym] = AclAddonly;
+ const acl = Doc.Get(doc, "ACL", true);
+ switch (acl) {
+ case "ownerOnly":
+ doc[AclSym] = AclPrivate;
+ return undefined;
+ case "readOnly":
+ doc[AclSym] = AclReadonly;
+ break;
+ case "addOnly":
+ doc[AclSym] = AclAddonly;
+ break;
}
}
@@ -116,7 +120,7 @@ function fetchProto(doc: Doc) {
if (proto instanceof Promise) {
proto.then(proto => {
if (proto.author !== Doc.CurrentUserEmail) {
- if (proto.ACL === "noAccess") {
+ if (proto.ACL === "ownerOnly") {
proto[AclSym] = doc[AclSym] = AclPrivate;
return undefined;
} else if (proto.ACL === "readOnly") {
@@ -483,6 +487,7 @@ export namespace Doc {
}
alias.aliasOf = doc;
alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`);
+ alias.author = Doc.CurrentUserEmail;
return alias;
}
@@ -685,7 +690,7 @@ export namespace Doc {
}
}
});
-
+ copy["author"] = Doc.CurrentUserEmail;
return copy;
}
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 31f589ec0..6474ed148 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -22,10 +22,10 @@ export const documentSchema = createSchema({
y: "number", // y coordinate when in a freeform view
z: "number", // z "coordinate" - non-zero specifies the overlay layer of a freeformview
zIndex: "number", // zIndex of a document in a freeform view
- scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that )
- scrollX: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that )
- scrollTop: "number", // scroll position of a scrollable document (pdf, text, web)
- scrollLeft: "number", // scroll position of a scrollable document (pdf, text, web)
+ _scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that )
+ _scrollX: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that )
+ _scrollTop: "number", // scroll position of a scrollable document (pdf, text, web)
+ _scrollLeft: "number", // scroll position of a scrollable document (pdf, text, web)
// appearance properties on the layout
_autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents