aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json18
-rw-r--r--package.json1
-rw-r--r--src/client/Network.ts77
-rw-r--r--src/client/views/OverlayView.scss70
-rw-r--r--src/client/views/OverlayView.tsx387
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingBox.tsx37
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.scss5
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.tsx28
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx699
-rw-r--r--src/server/ApiManagers/UploadManager.ts534
10 files changed, 957 insertions, 899 deletions
diff --git a/package-lock.json b/package-lock.json
index 01763e9b6..0f045c546 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6535,6 +6535,14 @@
"pend": "~1.2.0"
}
},
+ "ffmpeg": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/ffmpeg/-/ffmpeg-0.0.4.tgz",
+ "integrity": "sha1-HEYN+OfaUSf2LO70v6BsWciWMMs=",
+ "requires": {
+ "when": ">= 0.0.1"
+ }
+ },
"file-loader": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz",
@@ -7961,13 +7969,14 @@
"resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz",
"integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=",
"requires": {
+ "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
"readable-stream": "^1.0.33",
"tryit": "^1.0.1"
},
"dependencies": {
"image-size": {
- "version": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1",
- "from": "git+https://github.com/netroy/image-size.git#da2c863807a3e9602617bdd357b0de3ab4a064c1"
+ "version": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1",
+ "from": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1"
},
"isarray": {
"version": "0.0.1",
@@ -19577,6 +19586,11 @@
"webidl-conversions": "^3.0.0"
}
},
+ "when": {
+ "version": "3.7.8",
+ "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz",
+ "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I="
+ },
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
diff --git a/package.json b/package.json
index 35aa2ef92..6185bc0d7 100644
--- a/package.json
+++ b/package.json
@@ -175,6 +175,7 @@
"express-session": "^1.17.2",
"express-validator": "^5.3.1",
"expressjs": "^1.0.1",
+ "ffmpeg": "0.0.4",
"file-saver": "^2.0.5",
"find-in-files": "^0.5.0",
"fit-curve": "^0.1.7",
diff --git a/src/client/Network.ts b/src/client/Network.ts
index bf2918734..58f356c90 100644
--- a/src/client/Network.ts
+++ b/src/client/Network.ts
@@ -4,46 +4,49 @@ import { Upload } from "../server/SharedMediaTypes";
export namespace Networking {
- export async function FetchFromServer(relativeRoute: string) {
- return (await fetch(relativeRoute)).text();
- }
+ export async function FetchFromServer(relativeRoute: string) {
+ return (await fetch(relativeRoute)).text();
+ }
- export async function PostToServer(relativeRoute: string, body?: any) {
- const options = {
- uri: Utils.prepend(relativeRoute),
- method: "POST",
- body,
- json: true
- };
- return requestPromise.post(options);
- }
+ export async function PostToServer(relativeRoute: string, body?: any) {
+ const options = {
+ uri: Utils.prepend(relativeRoute),
+ method: "POST",
+ body,
+ json: true
+ };
+ return requestPromise.post(options);
+ }
- export async function UploadFilesToServer<T extends Upload.FileInformation = Upload.FileInformation>(files: File | File[]): Promise<Upload.FileResponse<T>[]> {
- const formData = new FormData();
- if (Array.isArray(files)) {
- if (!files.length) {
- return [];
+ export async function UploadFilesToServer<T extends Upload.FileInformation = Upload.FileInformation>(files: File | File[]): Promise<Upload.FileResponse<T>[]> {
+ console.log(files)
+ const formData = new FormData();
+ if (Array.isArray(files)) {
+ if (!files.length) {
+ return [];
+ }
+ files.forEach(file => formData.append(Utils.GenerateGuid(), file));
+ } else {
+ formData.append(Utils.GenerateGuid(), files);
}
- files.forEach(file => formData.append(Utils.GenerateGuid(), file));
- } else {
- formData.append(Utils.GenerateGuid(), files);
- }
- const parameters = {
- method: 'POST',
- body: formData
- };
- const response = await fetch("/uploadFormData", parameters);
- return response.json();
- }
+ const parameters = {
+ method: 'POST',
+ body: formData
+ };
+ const response = await fetch("/uploadFormData", parameters);
+ console.log(response)
+ // console.log(response.json())
+ return response.json();
+ }
- export async function UploadYoutubeToServer<T extends Upload.FileInformation = Upload.FileInformation>(videoId: string): Promise<Upload.FileResponse<T>[]> {
- const parameters = {
- method: 'POST',
- body: JSON.stringify({ videoId }),
- json: true
- };
- const response = await fetch("/uploadYoutubeVideo", parameters);
- return response.json();
- }
+ export async function UploadYoutubeToServer<T extends Upload.FileInformation = Upload.FileInformation>(videoId: string): Promise<Upload.FileResponse<T>[]> {
+ const parameters = {
+ method: 'POST',
+ body: JSON.stringify({ videoId }),
+ json: true
+ };
+ const response = await fetch("/uploadYoutubeVideo", parameters);
+ return response.json();
+ }
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index 02ea5e53b..d6a6e4301 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -1,59 +1,59 @@
.overlayView {
- position: absolute;
- pointer-events: none;
- top: 0;
- width: 100vw;
- height: 100vh;
- /* background-color: pink; */
- z-index: 100000;
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ /* background-color: pink; */
+ z-index: 100000;
}
.overlayWindow-outerDiv {
- border-radius: 5px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- top: 0;
- left: 0;
+ border-radius: 5px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ top: 0;
+ left: 0;
}
.overlayWindow-outerDiv,
.overlayView-wrapperDiv {
- position: absolute;
- z-index: 1;
+ position: absolute;
+ z-index: 1;
}
.overlayWindow-titleBar {
- flex: 0 1 30px;
- background: darkslategray;
- color: whitesmoke;
- text-align: center;
- cursor: move;
+ flex: 0 1 30px;
+ background: darkslategray;
+ color: whitesmoke;
+ text-align: center;
+ cursor: move;
}
.overlayWindow-content {
- flex: 1 1 auto;
- display: flex;
- flex-direction: column;
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
}
.overlayWindow-closeButton {
- float: right;
- height: 30px;
- width: 30px;
+ float: right;
+ height: 30px;
+ width: 30px;
}
.overlayWindow-resizeDragger {
- background-color: rgb(0, 0, 0);
- position: absolute;
- right: 0px;
- bottom: 0px;
- width: 10px;
- height: 10px;
- cursor: nwse-resize;
+ background-color: rgb(0, 0, 0);
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ width: 10px;
+ height: 10px;
+ cursor: nwse-resize;
}
.overlayView-doc {
- z-index: 9002; //so that it appears above chroma
- position: absolute;
+ z-index: 9002; //so that it appears above chroma
+ position: absolute;
} \ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 0f51cf9b2..806abb990 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -20,212 +20,213 @@ import { DefaultStyleProvider } from "./StyleProvider";
export type OverlayDisposer = () => void;
export type OverlayElementOptions = {
- x: number;
- y: number;
- width?: number;
- height?: number;
- title?: string;
+ x: number;
+ y: number;
+ width?: number;
+ height?: number;
+ title?: string;
};
export interface OverlayWindowProps {
- children: JSX.Element;
- overlayOptions: OverlayElementOptions;
- onClick: () => void;
+ children: JSX.Element;
+ overlayOptions: OverlayElementOptions;
+ onClick: () => void;
}
@observer
export class OverlayWindow extends React.Component<OverlayWindowProps> {
- @observable x: number;
- @observable y: number;
- @observable width: number;
- @observable height: number;
- constructor(props: OverlayWindowProps) {
- super(props);
-
- const opts = props.overlayOptions;
- this.x = opts.x;
- this.y = opts.y;
- this.width = opts.width || 200;
- this.height = opts.height || 200;
- }
-
- onPointerDown = (_: React.PointerEvent) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- document.addEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointerup", this.onPointerUp);
- }
-
- onResizerPointerDown = (_: React.PointerEvent) => {
- document.removeEventListener("pointermove", this.onResizerPointerMove);
- document.removeEventListener("pointerup", this.onResizerPointerUp);
- document.addEventListener("pointermove", this.onResizerPointerMove);
- document.addEventListener("pointerup", this.onResizerPointerUp);
- }
-
- @action
- onPointerMove = (e: PointerEvent) => {
- this.x += e.movementX;
- this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0);
- this.y += e.movementY;
- this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0);
- }
-
- @action
- onResizerPointerMove = (e: PointerEvent) => {
- this.width += e.movementX;
- this.width = Math.max(this.width, 30);
- this.height += e.movementY;
- this.height = Math.max(this.height, 30);
- }
-
- onPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.removeEventListener("pointerup", this.onPointerUp);
- }
-
- onResizerPointerUp = (e: PointerEvent) => {
- document.removeEventListener("pointermove", this.onResizerPointerMove);
- document.removeEventListener("pointerup", this.onResizerPointerUp);
- }
-
- render() {
- return (
- <div className="overlayWindow-outerDiv" style={{ transform: `translate(${this.x}px, ${this.y}px)`, width: this.width, height: this.height }}>
- <div className="overlayWindow-titleBar" onPointerDown={this.onPointerDown} >
- {this.props.overlayOptions.title || "Untitled"}
- <button onClick={this.props.onClick} className="overlayWindow-closeButton">X</button>
- </div>
- <div className="overlayWindow-content">
- {this.props.children}
- </div>
- <div className="overlayWindow-resizeDragger" onPointerDown={this.onResizerPointerDown}></div>
- </div>
- );
- }
+ @observable x: number;
+ @observable y: number;
+ @observable width: number;
+ @observable height: number;
+ constructor(props: OverlayWindowProps) {
+ super(props);
+
+ const opts = props.overlayOptions;
+ this.x = opts.x;
+ this.y = opts.y;
+ this.width = opts.width || 200;
+ this.height = opts.height || 200;
+ }
+
+ onPointerDown = (_: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointerup", this.onPointerUp);
+ }
+
+ onResizerPointerDown = (_: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.onResizerPointerMove);
+ document.removeEventListener("pointerup", this.onResizerPointerUp);
+ document.addEventListener("pointermove", this.onResizerPointerMove);
+ document.addEventListener("pointerup", this.onResizerPointerUp);
+ }
+
+ @action
+ onPointerMove = (e: PointerEvent) => {
+ this.x += e.movementX;
+ this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0);
+ this.y += e.movementY;
+ this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0);
+ }
+
+ @action
+ onResizerPointerMove = (e: PointerEvent) => {
+ this.width += e.movementX;
+ this.width = Math.max(this.width, 30);
+ this.height += e.movementY;
+ this.height = Math.max(this.height, 30);
+ }
+
+ onPointerUp = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ onResizerPointerUp = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.onResizerPointerMove);
+ document.removeEventListener("pointerup", this.onResizerPointerUp);
+ }
+
+ render() {
+ return (
+ <div className="overlayWindow-outerDiv" style={{ transform: `translate(${this.x}px, ${this.y}px)`, width: this.width, height: this.height }}>
+ <div className="overlayWindow-titleBar" onPointerDown={this.onPointerDown} >
+ {this.props.overlayOptions.title || "Untitled"}
+ <button onClick={this.props.onClick} className="overlayWindow-closeButton">X</button>
+ </div>
+ <div className="overlayWindow-content">
+ {this.props.children}
+ </div>
+ <div className="overlayWindow-resizeDragger" onPointerDown={this.onResizerPointerDown}></div>
+ </div>
+ );
+ }
}
@observer
export class OverlayView extends React.Component {
- public static Instance: OverlayView;
- @observable.shallow
- private _elements: JSX.Element[] = [];
-
- constructor(props: any) {
- super(props);
- if (!OverlayView.Instance) {
- OverlayView.Instance = this;
- }
- }
-
- @action
- addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
- const remove = action(() => {
- const index = this._elements.indexOf(ele);
- if (index !== -1) this._elements.splice(index, 1);
- });
- ele = <div key={Utils.GenerateGuid()} className="overlayView-wrapperDiv" style={{
- transform: `translate(${options.x}px, ${options.y}px)`,
- width: options.width,
- height: options.height,
- top: 0,
- left: 0
- }}>{ele}</div>;
- this._elements.push(ele);
- return remove;
- }
-
- @action
- addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
- const remove = action(() => {
- const index = this._elements.indexOf(contents);
- if (index !== -1) this._elements.splice(index, 1);
- });
- contents = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{contents}</OverlayWindow>;
- this._elements.push(contents);
- return remove;
- }
-
-
- @computed get overlayDocs() {
- return CurrentUserUtils.OverlayDocs?.map(d => {
- let offsetx = 0, offsety = 0;
- const dref = React.createRef<HTMLDivElement>();
- const onPointerMove = action((e: PointerEvent, down: number[]) => {
- if (e.buttons === 1) {
- d.x = e.clientX + offsetx;
- d.y = e.clientY + offsety;
- }
- if (e.metaKey) {
- const dragData = new DragManager.DocumentDragData([d]);
- dragData.offset = [-offsetx, -offsety];
- dragData.dropAction = "move";
- dragData.removeDocument = (doc: Doc | Doc[]) => {
- const docs = (doc instanceof Doc) ? [doc] : doc;
- docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d));
- return true;
- };
- dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
- return dragData.removeDocument!(doc) ? addDocument(doc) : false;
- };
- DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]);
- return true;
- }
- return false;
+ public static Instance: OverlayView;
+ @observable.shallow
+ private _elements: JSX.Element[] = [];
+
+ constructor(props: any) {
+ super(props);
+ if (!OverlayView.Instance) {
+ OverlayView.Instance = this;
+ }
+ }
+
+ @action
+ addElement(ele: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+ const remove = action(() => {
+ const index = this._elements.indexOf(ele);
+ if (index !== -1) this._elements.splice(index, 1);
});
-
- const onPointerDown = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction);
- offsetx = NumCast(d.x) - e.clientX;
- offsety = NumCast(d.y) - e.clientY;
- };
- return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
- <DocumentView
- Document={d}
- rootSelected={returnTrue}
- bringToFront={emptyFunction}
- addDocument={undefined}
- removeDocument={undefined}
- PanelWidth={returnOne}
- PanelHeight={returnOne}
- ScreenToLocalTransform={Transform.Identity}
- renderDepth={1}
- isDocumentActive={returnTrue}
- isContentActive={emptyFunction}
- whenChildContentsActiveChanged={emptyFunction}
- focus={DocUtils.DefaultFocus}
- styleProvider={DefaultStyleProvider}
- layerProvider={undefined}
- docViewPath={returnEmptyDoclist}
- addDocTab={returnFalse}
- pinToPres={emptyFunction}
- docFilters={returnEmptyFilter}
- docRangeFilters={returnEmptyFilter}
- searchFilterDocs={returnEmptyDoclist}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined} />
- </div>;
- });
- }
-
- public static ShowSpinner() {
- return OverlayView.Instance.addElement(<ReactLoading type="spinningBubbles" color="green" height={250} width={250} />, { x: 300, y: 200 });
- }
-
-
- render() {
- return (
- <div className="overlayView" id="overlayView">
- <div>
- {this._elements}
- </div>
- <CollectionFreeFormLinksView key="freeformLinks" />
- {this.overlayDocs}
- </div>
- );
- }
+ ele = <div key={Utils.GenerateGuid()} className="overlayView-wrapperDiv" style={{
+ transform: `translate(${options.x}px, ${options.y}px)`,
+ width: options.width,
+ height: options.height,
+ top: 0,
+ left: 0
+ }}>{ele}</div>;
+ this._elements.push(ele);
+ return remove;
+ }
+
+ @action
+ addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+ const remove = action(() => {
+ const index = this._elements.indexOf(contents);
+ if (index !== -1) this._elements.splice(index, 1);
+ });
+ contents = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{contents}</OverlayWindow>;
+ this._elements.push(contents);
+ return remove;
+ }
+
+
+ @computed get overlayDocs() {
+ return CurrentUserUtils.OverlayDocs?.map(d => {
+ let offsetx = 0, offsety = 0;
+ const dref = React.createRef<HTMLDivElement>();
+ const onPointerMove = action((e: PointerEvent, down: number[]) => {
+ if (e.buttons === 1) {
+ d.x = e.clientX + offsetx;
+ d.y = e.clientY + offsety;
+ }
+ if (e.metaKey) {
+ const dragData = new DragManager.DocumentDragData([d]);
+ dragData.offset = [-offsetx, -offsety];
+ dragData.dropAction = "move";
+ dragData.removeDocument = (doc: Doc | Doc[]) => {
+ const docs = (doc instanceof Doc) ? [doc] : doc;
+ docs.forEach(d => Doc.RemoveDocFromList(Cast(Doc.UserDoc().myOverlayDocs, Doc, null), "data", d));
+ return true;
+ };
+ dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
+ return dragData.removeDocument!(doc) ? addDocument(doc) : false;
+ };
+ DragManager.StartDocumentDrag([dref.current!], dragData, down[0], down[1]);
+ return true;
+ }
+ return false;
+ });
+
+ const onPointerDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, onPointerMove, emptyFunction, emptyFunction);
+ offsetx = NumCast(d.x) - e.clientX;
+ offsety = NumCast(d.y) - e.clientY;
+ };
+
+ return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
+ <DocumentView
+ Document={d}
+ rootSelected={returnTrue}
+ bringToFront={emptyFunction}
+ addDocument={undefined}
+ removeDocument={undefined}
+ PanelWidth={returnOne}
+ PanelHeight={returnOne}
+ ScreenToLocalTransform={Transform.Identity}
+ renderDepth={1}
+ isDocumentActive={returnTrue}
+ isContentActive={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={DocUtils.DefaultFocus}
+ styleProvider={DefaultStyleProvider}
+ layerProvider={undefined}
+ docViewPath={returnEmptyDoclist}
+ addDocTab={returnFalse}
+ pinToPres={emptyFunction}
+ docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined} />
+ </div>;
+ });
+ }
+
+ public static ShowSpinner() {
+ return OverlayView.Instance.addElement(<ReactLoading type="spinningBubbles" color="green" height={250} width={250} />, { x: 300, y: 200 });
+ }
+
+
+ render() {
+ return (
+ <div className="overlayView" id="overlayView">
+ <div>
+ {this._elements}
+ </div>
+ <CollectionFreeFormLinksView key="freeformLinks" />
+ {this.overlayDocs}
+ </div>
+ );
+ }
}
// bcz: ugh ... want to be able to pass ScriptingRepl as tag argument, but that doesn't seem to work.. runtime error
ScriptingGlobals.add(function addOverlayWindow(type: string, options: OverlayElementOptions) {
- OverlayView.Instance.addWindow(<ScriptingRepl />, options);
+ OverlayView.Instance.addWindow(<ScriptingRepl />, options);
}); \ No newline at end of file
diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
index 6d444d324..1e17e2ddd 100644
--- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx
@@ -1,24 +1,39 @@
+import { action, observable } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
+import { AudioField } from "../../../../fields/URLField";
+import { Upload } from "../../../../server/SharedMediaTypes";
import { ViewBoxBaseComponent } from "../../DocComponent";
import { FieldView } from "../FieldView";
+import { VideoBox } from "../VideoBox";
import { RecordingView } from './RecordingView';
@observer
-export class RecordingBox extends ViewBoxBaseComponent(){
+export class RecordingBox extends ViewBoxBaseComponent() {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecordingBox, fieldKey); }
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecordingBox, fieldKey); }
- private _ref: React.RefObject<HTMLDivElement> = React.createRef();
+ private _ref: React.RefObject<HTMLDivElement> = React.createRef();
- constructor(props: any) {
- super(props);
- }
+ constructor(props: any) {
+ super(props);
+ }
- render() {
- return <div className="recordingBox" ref={this._ref}>
- <RecordingView/>
- </div>;
- }
+ @observable result: Upload.FileInformation | undefined = undefined
+
+ @action
+ setResult = (info: Upload.FileInformation) => {
+ console.log("Setting result to " + info)
+ this.result = info
+ console.log(this.result.accessPaths.agnostic.client)
+ this.props.Document[this.fieldKey] = new AudioField(this.result.accessPaths.agnostic.client);
+ }
+
+ render() {
+ return <div className="recordingBox" ref={this._ref}>
+ {!this.result ? <RecordingView setResult={this.setResult} /> :
+ <p>video box</p>}
+ </div>;
+ }
}
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss
index e4d971d51..1fea231b7 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.scss
+++ b/src/client/views/nodes/RecordingBox/RecordingView.scss
@@ -15,6 +15,7 @@ button {
height: 100%;
width: 100%;
display: flex;
+ pointer-events: all;
}
.video-wrapper {
@@ -157,8 +158,8 @@ button {
background-color: red;
border: 0px;
border-radius: 10%;
- height: 80%;
- width: 80%;
+ height: 70%;
+ width: 70%;
align-self: center;
margin: 0;
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx
index 905f87a1a..0d24f3c74 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.tsx
+++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx
@@ -5,6 +5,8 @@ import { ProgressBar } from "./ProgressBar"
import { MdBackspace } from 'react-icons/md';
import { FaCheckCircle } from 'react-icons/fa';
import { IconContext } from "react-icons";
+import { Networking } from '../../../Network';
+import { Upload } from '../../../../server/SharedMediaTypes';
enum RecordingStatus {
@@ -18,9 +20,14 @@ interface VideoSegment {
endTime: number
}
+interface IRecordingViewProps {
+ setResult: (info: Upload.FileInformation) => void
+}
+
const MAXTIME = 1000;
-export function RecordingView() {
+export function RecordingView(props: IRecordingViewProps) {
+ const { setResult } = props
const [recording, setRecording] = useState(false);
const recordingTimerRef = useRef<number>(0);
@@ -68,18 +75,27 @@ export function RecordingView() {
type: 'video/webm'
})
const blobUrl = URL.createObjectURL(blob)
+ const videoFile = new File([blob], "video", { lastModified: new Date().getDate() });
videoElementRef.current!.srcObject = null
videoElementRef.current!.src = blobUrl
videoElementRef.current!.muted = false
- // upload data
- // const [{ result }] = await Networking.UploadFilesToServer(e.data);
- // console.log("Data result", result);
- // if (!(result instanceof Error)) {
- // this.props.Document[this.fieldKey] = new AudioField(result.accessPaths.agnostic.client);
+ // const uploadVideo = async () => {
+ // const [{ result }] = await Networking.UploadFilesToServer(videoFile);
+ // console.log("upload result", result);
+ // if (!(result instanceof Error)) {
+ // setResult(result)
+ // }
// }
+ Networking.UploadFilesToServer(allVideoChunks)
+ .then((data) => {
+ console.log(data)
+ })
+ // uploadVideo()
+
+
// change to one recording box
}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 766676e95..aa7622736 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -30,376 +30,383 @@ import { List } from "../../../../fields/List";
*/
@observer
export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
- _heightDisposer: IReactionDisposer | undefined;
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
+ _heightDisposer: IReactionDisposer | undefined;
- @observable _dragging = false;
- // these fields are conditionally computed fields on the layout document that take this document as a parameter
- @computed get indexInPres() { return Number(this.lookupField("indexInPres")); } // 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 collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
- @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
- @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
- @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
- @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
+ @observable _dragging = false;
+ // these fields are conditionally computed fields on the layout document that take this document as a parameter
+ @computed get indexInPres() { return Number(this.lookupField("indexInPres")); } // 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 collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
+ @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
+ @computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
+ @computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
+ @computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
- componentDidMount() {
- this.layoutDoc.hideLinkButton = true;
- this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
- params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
- }
- componentWillUnmount() {
- this._heightDisposer?.();
- }
+ @observable isShowingVideo = false;
+ @action setIsShowingVideo(shown: boolean) {
+ this.isShowingVideo = shown
+ }
- /**
- * Returns a local transformed coordinate array for given coordinates.
- */
- ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
+ componentDidMount() {
+ this.layoutDoc.hideLinkButton = true;
+ this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
+ params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+ }
+ componentWillUnmount() {
+ this._heightDisposer?.();
+ }
- @action
- presExpandDocumentClick = () => {
- this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
- }
+ /**
+ * Returns a local transformed coordinate array for given coordinates.
+ */
+ ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
- embedHeight = (): number => 97;
- // embedWidth = () => this.props.PanelWidth();
- // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
- embedWidth = (): number => this.props.PanelWidth() - 35;
- styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
- if (property === StyleProp.Opacity) return 1;
- return this.props.styleProvider?.(doc, props, property);
- }
- /**
- * The function that is responsible for rendering a preview or not for this
- * presentation element.
- */
- @computed get renderEmbeddedInline() {
- return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
- <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
- <DocumentView
- Document={this.targetDoc}
- DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
- styleProvider={this.styleProvider}
- layerProvider={this.props.layerProvider}
- docViewPath={returnEmptyDoclist}
- rootSelected={returnTrue}
- addDocument={returnFalse}
- removeDocument={returnFalse}
- isContentActive={this.props.isContentActive}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- PanelWidth={this.embedWidth}
- PanelHeight={this.embedHeight}
- ScreenToLocalTransform={Transform.Identity}
- moveDocument={this.props.moveDocument!}
- renderDepth={this.props.renderDepth + 1}
- focus={DocUtils.DefaultFocus}
- whenChildContentsActiveChanged={returnFalse}
- bringToFront={returnFalse}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- hideLinkButton={true}
- />
- <div className="presItem-embeddedMask" />
- </div>;
- }
+ @action
+ presExpandDocumentClick = () => {
+ this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
+ }
- @computed get duration() {
- let durationInS: number;
- if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
- else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
- else durationInS = 2;
- return "D: " + durationInS + "s";
- }
+ embedHeight = (): number => 97;
+ // embedWidth = () => this.props.PanelWidth();
+ // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
+ embedWidth = (): number => this.props.PanelWidth() - 35;
+ styleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+ if (property === StyleProp.Opacity) return 1;
+ return this.props.styleProvider?.(doc, props, property);
+ }
+ /**
+ * The function that is responsible for rendering a preview or not for this
+ * presentation element.
+ */
+ @computed get renderEmbeddedInline() {
+ return !this.rootDoc.presExpandInlineButton || !this.targetDoc ? (null) :
+ <div className="presItem-embedded" style={{ height: this.embedHeight(), width: this.embedWidth() }}>
+ <DocumentView
+ Document={this.targetDoc}
+ DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
+ styleProvider={this.styleProvider}
+ layerProvider={this.props.layerProvider}
+ docViewPath={returnEmptyDoclist}
+ rootSelected={returnTrue}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ isContentActive={this.props.isContentActive}
+ addDocTab={returnFalse}
+ pinToPres={returnFalse}
+ PanelWidth={this.embedWidth}
+ PanelHeight={this.embedHeight}
+ ScreenToLocalTransform={Transform.Identity}
+ moveDocument={this.props.moveDocument!}
+ renderDepth={this.props.renderDepth + 1}
+ focus={DocUtils.DefaultFocus}
+ whenChildContentsActiveChanged={returnFalse}
+ bringToFront={returnFalse}
+ docFilters={this.props.docFilters}
+ docRangeFilters={this.props.docRangeFilters}
+ searchFilterDocs={this.props.searchFilterDocs}
+ ContainingCollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ hideLinkButton={true}
+ />
+ <div className="presItem-embeddedMask" />
+ </div>;
+ }
- @computed get transition() {
- let transitionInS: number;
- if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
- else transitionInS = 0.5;
- return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
- }
+ @computed get duration() {
+ let durationInS: number;
+ if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10; }
+ else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
+ else durationInS = 2;
+ return "D: " + durationInS + "s";
+ }
- private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
- private _titleRef: React.RefObject<EditableView> = React.createRef();
+ @computed get transition() {
+ let transitionInS: number;
+ if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
+ else transitionInS = 0.5;
+ return this.rootDoc.presMovement === PresMovement.Jump || this.rootDoc.presMovement === PresMovement.None ? (null) : "M: " + transitionInS + "s";
+ }
+ private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+ private _titleRef: React.RefObject<EditableView> = React.createRef();
- @action
- headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
- const element = e.target as any;
- e.stopPropagation();
- e.preventDefault();
- if (element && !(e.ctrlKey || e.metaKey)) {
- if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
- PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
- setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
- } else {
- setupMoveUpEvents(this, e, ((e: PointerEvent) => {
- PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
- return this.startDrag(e);
- }), emptyFunction, emptyFunction);
+
+ @action
+ headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
+ const element = e.target as any;
+ e.stopPropagation();
+ e.preventDefault();
+ if (element && !(e.ctrlKey || e.metaKey)) {
+ if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
+ PresBox.Instance._selectedArray.size === 1 && PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+ setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+ } else {
+ setupMoveUpEvents(this, e, ((e: PointerEvent) => {
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+ return this.startDrag(e);
+ }), emptyFunction, emptyFunction);
+ }
+ }
+ }
+
+ headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ /**
+ * Function to drag and drop the pres element to a diferent location
+ */
+ startDrag = (e: PointerEvent) => {
+ const miniView: boolean = this.toolbarWidth <= 100;
+ const activeItem = this.rootDoc;
+ const dragArray = PresBox.Instance._dragArray;
+ const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
+ const dragItem: HTMLElement[] = [];
+ if (dragArray.length === 1) {
+ const doc = dragArray[0];
+ doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
+ dragItem.push(doc);
+ } else if (dragArray.length >= 1) {
+ const doc = document.createElement('div');
+ doc.className = "presItem-multiDrag";
+ doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
+ doc.style.position = 'absolute';
+ doc.style.top = (e.clientY) + 'px';
+ doc.style.left = (e.clientX - 50) + 'px';
+ dragItem.push(doc);
}
- }
- }
- headerUp = (e: React.PointerEvent<HTMLDivElement>) => {
- e.stopPropagation();
- e.preventDefault();
- }
+ // const dropEvent = () => runInAction(() => this._dragging = false);
+ if (activeItem) {
+ DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
+ // runInAction(() => this._dragging = true);
+ return true;
+ }
+ return false;
+ }
- /**
- * Function to drag and drop the pres element to a diferent location
- */
- startDrag = (e: PointerEvent) => {
- const miniView: boolean = this.toolbarWidth <= 100;
- const activeItem = this.rootDoc;
- const dragArray = PresBox.Instance._dragArray;
- const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
- const dragItem: HTMLElement[] = [];
- if (dragArray.length === 1) {
- const doc = dragArray[0];
- doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
- dragItem.push(doc);
- } else if (dragArray.length >= 1) {
- const doc = document.createElement('div');
- doc.className = "presItem-multiDrag";
- doc.innerText = "Move " + PresBox.Instance._selectedArray.size + " slides";
- doc.style.position = 'absolute';
- doc.style.top = (e.clientY) + 'px';
- doc.style.left = (e.clientX - 50) + 'px';
- dragItem.push(doc);
- }
+ onPointerOver = (e: any) => {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointermove", this.onPointerMove);
+ }
- // const dropEvent = () => runInAction(() => this._dragging = false);
- if (activeItem) {
- DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
- // runInAction(() => this._dragging = true);
- return true;
- }
- return false;
- }
+ onPointerMove = (e: PointerEvent) => {
+ const slide = this._itemRef.current!;
+ let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
+ for (const doc of DragManager.docsBeingDragged) {
+ if (!doc.presentationTargetDoc) dragIsPresItem = false;
+ }
+ if (slide && dragIsPresItem) {
+ const rect = slide.getBoundingClientRect();
+ const y = e.clientY - rect.top; //y position within the element.
+ const height = slide.clientHeight;
+ const halfLine = height / 2;
+ if (y <= halfLine) {
+ slide.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
+ slide.style.borderBottom = "0px";
+ } else if (y > halfLine) {
+ slide.style.borderTop = "0px";
+ slide.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+ }
+ }
+ document.removeEventListener("pointermove", this.onPointerMove);
+ }
- onPointerOver = (e: any) => {
- document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
- }
+ onPointerLeave = (e: any) => {
+ this._itemRef.current!.style.borderTop = "0px";
+ this._itemRef.current!.style.borderBottom = "0px";
+ document.removeEventListener("pointermove", this.onPointerMove);
+ }
- onPointerMove = (e: PointerEvent) => {
- const slide = this._itemRef.current!;
- let dragIsPresItem: boolean = DragManager.docsBeingDragged.length > 0 ? true : false;
- for (const doc of DragManager.docsBeingDragged) {
- if (!doc.presentationTargetDoc) dragIsPresItem = false;
- }
- if (slide && dragIsPresItem) {
- const rect = slide.getBoundingClientRect();
- const y = e.clientY - rect.top; //y position within the element.
- const height = slide.clientHeight;
- const halfLine = height / 2;
- if (y <= halfLine) {
- slide.style.borderTop = `solid 2px ${Colors.MEDIUM_BLUE}`;
- slide.style.borderBottom = "0px";
- } else if (y > halfLine) {
- slide.style.borderTop = "0px";
- slide.style.borderBottom = `solid 2px ${Colors.MEDIUM_BLUE}`;
+ @action
+ toggleProperties = () => {
+ if (CurrentUserUtils.propertiesWidth < 5) {
+ action(() => (CurrentUserUtils.propertiesWidth = 250));
}
- }
- document.removeEventListener("pointermove", this.onPointerMove);
- }
+ }
- onPointerLeave = (e: any) => {
- this._itemRef.current!.style.borderTop = "0px";
- this._itemRef.current!.style.borderBottom = "0px";
- document.removeEventListener("pointermove", this.onPointerMove);
- }
+ @undoBatch
+ removeItem = action((e: React.MouseEvent) => {
+ this.props.removeDocument?.(this.rootDoc);
+ if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
+ PresBox.Instance._selectedArray.delete(this.rootDoc);
+ }
+ e.stopPropagation();
+ });
+
+ // set the value/title of the individual pres element
+ @undoBatch
+ @action
+ onSetValue = (value: string) => {
+ this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
+ return true;
+ }
- @action
- toggleProperties = () => {
- if (CurrentUserUtils.propertiesWidth < 5) {
- action(() => (CurrentUserUtils.propertiesWidth = 250));
- }
- }
+ /**
+ * Method called for updating the view of the currently selected document
+ *
+ * @param targetDoc
+ * @param activeItem
+ */
+ @undoBatch
+ @action
+ updateView = (targetDoc: Doc, activeItem: Doc) => {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const clipWidth = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = clipWidth;
+ } else {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ }
+ }
- @undoBatch
- removeItem = action((e: React.MouseEvent) => {
- this.props.removeDocument?.(this.rootDoc);
- if (PresBox.Instance._selectedArray.has(this.rootDoc)) {
- PresBox.Instance._selectedArray.delete(this.rootDoc);
- }
- e.stopPropagation();
- });
+ @undoBatch
+ @action
+ startRecording = (targetDoc: Doc, activeItem: Doc) => {
- // set the value/title of the individual pres element
- @undoBatch
- @action
- onSetValue = (value: string) => {
- this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
- return true;
- }
+ // TODO: Remove everything that already exists
+ if (activeItem.recording) {
+ // if we already have an existing recording
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null));
- /**
- * Method called for updating the view of the currently selected document
- *
- * @param targetDoc
- * @param activeItem
- */
- @undoBatch
- @action
- updateView = (targetDoc: Doc, activeItem: Doc) => {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinViewScroll = scroll;
- } else if (targetDoc.type === DocumentType.VID) {
- activeItem.presPinTimecode = targetDoc._currentTimecode;
- } else if (targetDoc.type === DocumentType.COMPARISON) {
- const clipWidth = targetDoc._clipWidth;
- activeItem.presPinClipWidth = clipWidth;
- } else {
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
- }
- }
+ } else {
+ // if we dont have any recording
+ console.log(targetDoc.title, activeItem.title);
+ const recording = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
+ activeItem.recording = recording
+ // TODO: Figure out exactly where we want the video to appear
+ const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ console.log("x: ", pt[0], "y: ", pt[1]);
+ recording.x = pt[0];
+ recording.y = pt[1];
+ Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording);
+ }
- @undoBatch
- @action
- startRecording = (targetDoc: Doc, activeItem: Doc) => {
- // If we already have an existing recording
- // TODO: Remove everything that already exists
- if (activeItem.recording) {
- Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, Cast(activeItem.recording, Doc, null));
- // Recording has not yet been created
- } else {
- console.log(targetDoc.title, activeItem.title);
- const recording = Docs.Create.WebCamDocument("", { _width: 400, _height: 200, title: "recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
- activeItem.recording = recording
- // TODO: Figure out exactly where we want the video to appear
- const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- console.log("x: ", pt[0], "y: ", pt[1]);
- recording.x = pt[0];
- recording.y = pt[1];
- Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, recording);
- }
-
- }
+ }
- @computed
- get toolbarWidth(): number {
- const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
- let width: number = NumCast(this.presBox._width);
- if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
- if (width === 0) width = 300;
- return width;
- }
+ @computed
+ get toolbarWidth(): number {
+ const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
+ let width: number = NumCast(this.presBox._width);
+ if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
+ if (width === 0) width = 300;
+ return width;
+ }
- @computed get mainItem() {
- const isSelected: boolean = PresBox.Instance._selectedArray.has(this.rootDoc);
- const toolbarWidth: number = this.toolbarWidth;
- const showMore: boolean = this.toolbarWidth >= 300;
- const miniView: boolean = this.toolbarWidth <= 110;
- const presBox: Doc = 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;
- return (
- <div className={`presItem-container`}
- key={this.props.Document[Id] + this.indexInPres}
- ref={this._itemRef}
- style={{
- backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? Colors.LIGHT_BLUE : "transparent",
- opacity: this._dragging ? 0.3 : 1
- }}
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
- PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
- }}
- onDoubleClick={action(e => {
- this.toggleProperties();
- PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
- })}
- onPointerOver={this.onPointerOver}
- onPointerLeave={this.onPointerLeave}
- onPointerDown={this.headerDown}
- onPointerUp={this.headerUp}
- >
- {miniView ?
- // when width is LESS than 110 px
- <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
- {`${this.indexInPres + 1}.`}
- </div>
- :
- // when width is MORE than 110 px
- <div className="presItem-number">
- {`${this.indexInPres + 1}.`}
- </div>}
- {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
- style={{
- backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
- boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
- }}>
- <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
- <EditableView
- ref={this._titleRef}
- editing={!isSelected ? false : undefined}
- contents={activeItem.title}
- overflow={'ellipsis'}
- GetValue={() => StrCast(activeItem.title)}
- SetValue={this.onSetValue}
- />
- </div>
- <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
- <div className={"presItem-slideButtons"}>
- <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
- <div className="slideButton"
- onClick={() => this.updateView(targetDoc, activeItem)}
- style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
- </Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Start recording"}</div></>}>
- <div className="slideButton"
- onClick={() => this.startRecording(targetDoc, activeItem)}
- style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={"video"} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
- <div className="slideButton"
- onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
- style={{
- zIndex: 1000 - this.indexInPres,
- fontWeight: 700,
- backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined,
- height: activeItem.groupWithUp ? 53 : 18,
- transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
- }}>
- <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
- <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
- </div>
- </div>
- </Tooltip>}
- <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
- <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
- </div></Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
- className={"slideButton"}
- onClick={this.removeItem}>
- <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
- </div></Tooltip>
- </div>
- <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
- {this.renderEmbeddedInline}
- </div>}
- </div >);
- }
+ @computed get mainItem() {
+ const isSelected: boolean = PresBox.Instance._selectedArray.has(this.rootDoc);
+ const toolbarWidth: number = this.toolbarWidth;
+ const showMore: boolean = this.toolbarWidth >= 300;
+ const miniView: boolean = this.toolbarWidth <= 110;
+ const presBox: Doc = 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;
+ return (
+ <div className={`presItem-container`}
+ key={this.props.Document[Id] + this.indexInPres}
+ ref={this._itemRef}
+ style={{
+ backgroundColor: presColorBool ? isSelected ? "rgba(250,250,250,0.3)" : "transparent" : isSelected ? Colors.LIGHT_BLUE : "transparent",
+ opacity: this._dragging ? 0.3 : 1
+ }}
+ onClick={e => {
+ e.stopPropagation();
+ e.preventDefault();
+ PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
+ }}
+ onDoubleClick={action(e => {
+ this.toggleProperties();
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
+ })}
+ onPointerOver={this.onPointerOver}
+ onPointerLeave={this.onPointerLeave}
+ onPointerDown={this.headerDown}
+ onPointerUp={this.headerUp}
+ >
+ {miniView ?
+ // when width is LESS than 110 px
+ <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
+ {`${this.indexInPres + 1}.`}
+ </div>
+ :
+ // when width is MORE than 110 px
+ <div className="presItem-number">
+ {`${this.indexInPres + 1}.`}
+ </div>}
+ {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
+ style={{
+ backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+ boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
+ }}>
+ <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
+ <EditableView
+ ref={this._titleRef}
+ editing={!isSelected ? false : undefined}
+ contents={activeItem.title}
+ overflow={'ellipsis'}
+ GetValue={() => StrCast(activeItem.title)}
+ SetValue={this.onSetValue}
+ />
+ </div>
+ <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
+ <div className={"presItem-slideButtons"}>
+ <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
+ <div className="slideButton"
+ onClick={() => this.updateView(targetDoc, activeItem)}
+ style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
+ </Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Start recording"}</div></>}>
+ <div className="slideButton"
+ onClick={() => this.startRecording(targetDoc, activeItem)}
+ style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={"video"} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>
+ {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
+ <div className="slideButton"
+ onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
+ style={{
+ zIndex: 1000 - this.indexInPres,
+ fontWeight: 700,
+ backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : Colors.MEDIUM_BLUE : undefined,
+ height: activeItem.groupWithUp ? 53 : 18,
+ transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
+ }}>
+ <div style={{ transform: activeItem.groupWithUp ? "rotate(180deg) translate(0, -17.5px)" : "rotate(0deg)" }}>
+ <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </div>
+ </Tooltip>}
+ <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
+ <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
+ </div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
+ className={"slideButton"}
+ onClick={this.removeItem}>
+ <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
+ </div></Tooltip>
+ </div>
+ <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
+ {this.renderEmbeddedInline}
+ </div>}
+ </div >);
+ }
- render() {
- return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
- }
+ render() {
+ return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : this.mainItem;
+ }
} \ No newline at end of file
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index bfa07d47a..5a19477dd 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -19,288 +19,288 @@ import { SolrManager } from "./SearchManager";
import { StringDecoder } from "string_decoder";
export enum Directory {
- parsed_files = "parsed_files",
- images = "images",
- videos = "videos",
- pdfs = "pdfs",
- text = "text",
- pdf_thumbnails = "pdf_thumbnails",
- audio = "audio",
+ parsed_files = "parsed_files",
+ images = "images",
+ videos = "videos",
+ pdfs = "pdfs",
+ text = "text",
+ pdf_thumbnails = "pdf_thumbnails",
+ audio = "audio",
}
export function serverPathToFile(directory: Directory, filename: string) {
- return normalize(`${filesDirectory}/${directory}/${filename}`);
+ return normalize(`${filesDirectory}/${directory}/${filename}`);
}
export function pathToDirectory(directory: Directory) {
- return normalize(`${filesDirectory}/${directory}`);
+ return normalize(`${filesDirectory}/${directory}`);
}
export function clientPathToFile(directory: Directory, filename: string) {
- return `/files/${directory}/${filename}`;
+ return `/files/${directory}/${filename}`;
}
export default class UploadManager extends ApiManager {
- protected initialize(register: Registration): void {
+ protected initialize(register: Registration): void {
- register({
- method: Method.POST,
- subscription: "/uploadFormData",
- secureHandler: async ({ req, res }) => {
- const form = new formidable.IncomingForm();
- form.keepExtensions = true;
- form.uploadDir = pathToDirectory(Directory.parsed_files);
- return new Promise<void>(resolve => {
- form.parse(req, async (_err, _fields, files) => {
- const results: Upload.FileResponse[] = [];
- for (const key in files) {
- const f = files[key];
- if (!Array.isArray(f)) {
- const result = await DashUploadUtils.upload(f);
- result && !(result.result instanceof Error) && results.push(result);
- }
- }
- _success(res, results);
- resolve();
- });
- });
- }
- });
+ register({
+ method: Method.POST,
+ subscription: "/uploadFormData",
+ secureHandler: async ({ req, res }) => {
+ const form = new formidable.IncomingForm();
+ form.keepExtensions = true;
+ form.uploadDir = pathToDirectory(Directory.parsed_files);
+ return new Promise<void>(resolve => {
+ form.parse(req, async (_err, _fields, files) => {
+ const results: Upload.FileResponse[] = [];
+ for (const key in files) {
+ const f = files[key];
+ if (!Array.isArray(f)) {
+ const result = await DashUploadUtils.upload(f);
+ result && !(result.result instanceof Error) && results.push(result);
+ }
+ }
+ _success(res, results);
+ resolve();
+ });
+ });
+ }
+ });
- register({
- method: Method.POST,
- subscription: "/uploadYoutubeVideo",
- secureHandler: async ({ req, res }) => {
- //req.readableBuffer.head.data
- return new Promise<void>(async resolve => {
- req.addListener("data", async (args) => {
- console.log(args);
- const payload = String.fromCharCode.apply(String, args);
- const videoId = JSON.parse(payload).videoId;
- const results: Upload.FileResponse[] = [];
- const result = await DashUploadUtils.uploadYoutube(videoId);
- result && !(result.result instanceof Error) && results.push(result);
- _success(res, results);
- resolve();
- });
- });
- }
- });
+ register({
+ method: Method.POST,
+ subscription: "/uploadYoutubeVideo",
+ secureHandler: async ({ req, res }) => {
+ //req.readableBuffer.head.data
+ return new Promise<void>(async resolve => {
+ req.addListener("data", async (args) => {
+ console.log(args);
+ const payload = String.fromCharCode.apply(String, args);
+ const videoId = JSON.parse(payload).videoId;
+ const results: Upload.FileResponse[] = [];
+ const result = await DashUploadUtils.uploadYoutube(videoId);
+ result && !(result.result instanceof Error) && results.push(result);
+ _success(res, results);
+ resolve();
+ });
+ });
+ }
+ });
- register({
- method: Method.POST,
- subscription: new RouteSubscriber("youtubeScreenshot"),
- secureHandler: async ({ req, res }) => {
- const { id, timecode } = req.body;
- const convert = (raw: string) => {
- const number = Math.floor(Number(raw));
- const seconds = number % 60;
- const minutes = (number - seconds) / 60;
- return `${minutes}m${seconds}s`;
- };
- const suffix = timecode ? `&t=${convert(timecode)}` : ``;
- const targetUrl = `https://www.youtube.com/watch?v=${id}${suffix}`;
- const buffer = await captureYoutubeScreenshot(targetUrl);
- if (!buffer) {
- return res.send();
- }
- const resolvedName = `youtube_capture_${id}_${suffix}.png`;
- const resolvedPath = serverPathToFile(Directory.images, resolvedName);
- return new Promise<void>(resolve => {
- writeFile(resolvedPath, buffer, async error => {
- if (error) {
- return res.send();
+ register({
+ method: Method.POST,
+ subscription: new RouteSubscriber("youtubeScreenshot"),
+ secureHandler: async ({ req, res }) => {
+ const { id, timecode } = req.body;
+ const convert = (raw: string) => {
+ const number = Math.floor(Number(raw));
+ const seconds = number % 60;
+ const minutes = (number - seconds) / 60;
+ return `${minutes}m${seconds}s`;
+ };
+ const suffix = timecode ? `&t=${convert(timecode)}` : ``;
+ const targetUrl = `https://www.youtube.com/watch?v=${id}${suffix}`;
+ const buffer = await captureYoutubeScreenshot(targetUrl);
+ if (!buffer) {
+ return res.send();
}
- await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images));
- res.send({
- accessPaths: {
- agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName)
- }
- } as Upload.FileInformation);
- resolve();
- });
- });
- }
- });
+ const resolvedName = `youtube_capture_${id}_${suffix}.png`;
+ const resolvedPath = serverPathToFile(Directory.images, resolvedName);
+ return new Promise<void>(resolve => {
+ writeFile(resolvedPath, buffer, async error => {
+ if (error) {
+ return res.send();
+ }
+ await DashUploadUtils.outputResizedImages(() => createReadStream(resolvedPath), resolvedName, pathToDirectory(Directory.images));
+ res.send({
+ accessPaths: {
+ agnostic: DashUploadUtils.getAccessPaths(Directory.images, resolvedName)
+ }
+ } as Upload.FileInformation);
+ resolve();
+ });
+ });
+ }
+ });
- register({
- method: Method.POST,
- subscription: "/uploadRemoteImage",
- secureHandler: async ({ req, res }) => {
+ register({
+ method: Method.POST,
+ subscription: "/uploadRemoteImage",
+ secureHandler: async ({ req, res }) => {
- const { sources } = req.body;
- if (Array.isArray(sources)) {
- const results = await Promise.all(sources.map(source => DashUploadUtils.UploadImage(source)));
- return res.send(results);
- }
- res.send();
- }
- });
+ const { sources } = req.body;
+ if (Array.isArray(sources)) {
+ const results = await Promise.all(sources.map(source => DashUploadUtils.UploadImage(source)));
+ return res.send(results);
+ }
+ res.send();
+ }
+ });
- register({
- method: Method.POST,
- subscription: "/uploadDoc",
- secureHandler: ({ req, res }) => {
+ register({
+ method: Method.POST,
+ subscription: "/uploadDoc",
+ secureHandler: ({ req, res }) => {
- const form = new formidable.IncomingForm();
- form.keepExtensions = true;
- // let path = req.body.path;
- const ids: { [id: string]: string } = {};
- let remap = true;
- const getId = (id: string): string => {
- if (!remap) return id;
- if (id.endsWith("Proto")) return id;
- if (id in ids) {
- return ids[id];
- } else {
- return ids[id] = v4();
- }
- };
- const mapFn = (doc: any) => {
- if (doc.id) {
- doc.id = getId(doc.id);
- }
- for (const key in doc.fields) {
- if (!doc.fields.hasOwnProperty(key)) { continue; }
- const field = doc.fields[key];
- if (field === undefined || field === null) { continue; }
+ const form = new formidable.IncomingForm();
+ form.keepExtensions = true;
+ // let path = req.body.path;
+ const ids: { [id: string]: string } = {};
+ let remap = true;
+ const getId = (id: string): string => {
+ if (!remap) return id;
+ if (id.endsWith("Proto")) return id;
+ if (id in ids) {
+ return ids[id];
+ } else {
+ return ids[id] = v4();
+ }
+ };
+ const mapFn = (doc: any) => {
+ if (doc.id) {
+ doc.id = getId(doc.id);
+ }
+ for (const key in doc.fields) {
+ if (!doc.fields.hasOwnProperty(key)) { continue; }
+ const field = doc.fields[key];
+ if (field === undefined || field === null) { continue; }
- if (field.__type === "Doc") {
- mapFn(field);
- } else if (field.__type === "proxy" || field.__type === "prefetch_proxy") {
- field.fieldId = getId(field.fieldId);
- } else if (field.__type === "script" || field.__type === "computed") {
- if (field.captures) {
- field.captures.fieldId = getId(field.captures.fieldId);
- }
- } else if (field.__type === "list") {
- mapFn(field);
- } else if (typeof field === "string") {
- const re = /("(?:dataD|d)ocumentId"\s*:\s*")([\w\-]*)"/g;
- doc.fields[key] = (field as any).replace(re, (match: any, p1: string, p2: string) => {
- return `${p1}${getId(p2)}"`;
- });
- } else if (field.__type === "RichTextField") {
- const re = /("href"\s*:\s*")(.*?)"/g;
- field.Data = field.Data.replace(re, (match: any, p1: string, p2: string) => {
- return `${p1}${getId(p2)}"`;
- });
- }
- }
- };
- return new Promise<void>(resolve => {
- form.parse(req, async (_err, fields, files) => {
- remap = fields.remap !== "false";
- let id: string = "";
- try {
- for (const name in files) {
- const f = files[name];
- const path_2 = Array.isArray(f) ? "" : f.path;
- const zip = new AdmZip(path_2);
- zip.getEntries().forEach((entry: any) => {
- if (!entry.entryName.startsWith("files/")) return;
- let directory = dirname(entry.entryName) + "/";
- const extension = extname(entry.entryName);
- const base = basename(entry.entryName).split(".")[0];
+ if (field.__type === "Doc") {
+ mapFn(field);
+ } else if (field.__type === "proxy" || field.__type === "prefetch_proxy") {
+ field.fieldId = getId(field.fieldId);
+ } else if (field.__type === "script" || field.__type === "computed") {
+ if (field.captures) {
+ field.captures.fieldId = getId(field.captures.fieldId);
+ }
+ } else if (field.__type === "list") {
+ mapFn(field);
+ } else if (typeof field === "string") {
+ const re = /("(?:dataD|d)ocumentId"\s*:\s*")([\w\-]*)"/g;
+ doc.fields[key] = (field as any).replace(re, (match: any, p1: string, p2: string) => {
+ return `${p1}${getId(p2)}"`;
+ });
+ } else if (field.__type === "RichTextField") {
+ const re = /("href"\s*:\s*")(.*?)"/g;
+ field.Data = field.Data.replace(re, (match: any, p1: string, p2: string) => {
+ return `${p1}${getId(p2)}"`;
+ });
+ }
+ }
+ };
+ return new Promise<void>(resolve => {
+ form.parse(req, async (_err, fields, files) => {
+ remap = fields.remap !== "false";
+ let id: string = "";
try {
- zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
- directory = "/" + directory;
+ for (const name in files) {
+ const f = files[name];
+ const path_2 = Array.isArray(f) ? "" : f.path;
+ const zip = new AdmZip(path_2);
+ zip.getEntries().forEach((entry: any) => {
+ if (!entry.entryName.startsWith("files/")) return;
+ let directory = dirname(entry.entryName) + "/";
+ const extension = extname(entry.entryName);
+ const base = basename(entry.entryName).split(".")[0];
+ try {
+ zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
+ directory = "/" + directory;
- createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_o" + extension));
- createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_s" + extension));
- createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_m" + extension));
- createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_l" + extension));
- } catch (e) {
- console.log(e);
- }
- });
- const json = zip.getEntry("doc.json");
- try {
- const data = JSON.parse(json.getData().toString("utf8"));
- const datadocs = data.docs;
- id = getId(data.id);
- const docs = Object.keys(datadocs).map(key => datadocs[key]);
- docs.forEach(mapFn);
- await Promise.all(docs.map((doc: any) => new Promise<void>(res => {
- Database.Instance.replace(doc.id, doc, (err, r) => {
- err && console.log(err);
- res();
- }, true);
- })));
- } catch (e) { console.log(e); }
- unlink(path_2, () => { });
- }
- SolrManager.update();
- res.send(JSON.stringify(id || "error"));
- } catch (e) { console.log(e); }
- resolve();
- });
- });
- }
- });
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_o" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_s" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_m" + extension));
+ createReadStream(publicDirectory + directory + base + extension).pipe(createWriteStream(publicDirectory + directory + base + "_l" + extension));
+ } catch (e) {
+ console.log(e);
+ }
+ });
+ const json = zip.getEntry("doc.json");
+ try {
+ const data = JSON.parse(json.getData().toString("utf8"));
+ const datadocs = data.docs;
+ id = getId(data.id);
+ const docs = Object.keys(datadocs).map(key => datadocs[key]);
+ docs.forEach(mapFn);
+ await Promise.all(docs.map((doc: any) => new Promise<void>(res => {
+ Database.Instance.replace(doc.id, doc, (err, r) => {
+ err && console.log(err);
+ res();
+ }, true);
+ })));
+ } catch (e) { console.log(e); }
+ unlink(path_2, () => { });
+ }
+ SolrManager.update();
+ res.send(JSON.stringify(id || "error"));
+ } catch (e) { console.log(e); }
+ resolve();
+ });
+ });
+ }
+ });
- register({
- method: Method.POST,
- subscription: "/inspectImage",
- secureHandler: async ({ req, res }) => {
+ register({
+ method: Method.POST,
+ subscription: "/inspectImage",
+ secureHandler: async ({ req, res }) => {
- const { source } = req.body;
- if (typeof source === "string") {
- return res.send(await DashUploadUtils.InspectImage(source));
- }
- res.send({});
- }
- });
+ const { source } = req.body;
+ if (typeof source === "string") {
+ return res.send(await DashUploadUtils.InspectImage(source));
+ }
+ res.send({});
+ }
+ });
- register({
- method: Method.POST,
- subscription: "/uploadURI",
- secureHandler: ({ req, res }) => {
- const uri = req.body.uri;
- const filename = req.body.name;
- const origSuffix = req.body.nosuffix ? SizeSuffix.None : SizeSuffix.Original;
- if (!uri || !filename) {
- res.status(401).send("incorrect parameters specified");
- return;
- }
- return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
- const ext = extname(savedName).toLowerCase();
- const { pngs, jpgs } = AcceptableMedia;
- const resizers = !origSuffix ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" }] : [
- { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: "_s" },
- { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" },
- { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: "_l" },
- ];
- let isImage = false;
- if (pngs.includes(ext)) {
- resizers.forEach(element => {
- element.resizer = element.resizer.png();
- });
- isImage = true;
- } else if (jpgs.includes(ext)) {
- resizers.forEach(element => {
- element.resizer = element.resizer.jpeg();
- });
- isImage = true;
- }
- if (isImage) {
- resizers.forEach(resizer => {
- const path = serverPathToFile(Directory.images, filename + resizer.suffix + ext);
- createReadStream(savedName).pipe(resizer.resizer).pipe(createWriteStream(path));
- });
+ register({
+ method: Method.POST,
+ subscription: "/uploadURI",
+ secureHandler: ({ req, res }) => {
+ const uri = req.body.uri;
+ const filename = req.body.name;
+ const origSuffix = req.body.nosuffix ? SizeSuffix.None : SizeSuffix.Original;
+ if (!uri || !filename) {
+ res.status(401).send("incorrect parameters specified");
+ return;
+ }
+ return imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
+ const ext = extname(savedName).toLowerCase();
+ const { pngs, jpgs } = AcceptableMedia;
+ const resizers = !origSuffix ? [{ resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" }] : [
+ { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: "_s" },
+ { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" },
+ { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: "_l" },
+ ];
+ let isImage = false;
+ if (pngs.includes(ext)) {
+ resizers.forEach(element => {
+ element.resizer = element.resizer.png();
+ });
+ isImage = true;
+ } else if (jpgs.includes(ext)) {
+ resizers.forEach(element => {
+ element.resizer = element.resizer.jpeg();
+ });
+ isImage = true;
+ }
+ if (isImage) {
+ resizers.forEach(resizer => {
+ const path = serverPathToFile(Directory.images, filename + resizer.suffix + ext);
+ createReadStream(savedName).pipe(resizer.resizer).pipe(createWriteStream(path));
+ });
- }
- res.send(clientPathToFile(Directory.images, filename + ext));
- });
- }
- });
+ }
+ res.send(clientPathToFile(Directory.images, filename + ext));
+ });
+ }
+ });
- }
+ }
}
function delay(ms: number) {
- return new Promise(resolve => setTimeout(resolve, ms));
+ return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* On success, returns a buffer containing the bytes of a screenshot
@@ -309,25 +309,25 @@ function delay(ms: number) {
* On failure, returns undefined.
*/
async function captureYoutubeScreenshot(targetUrl: string) {
- // const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
- // const page = await browser.newPage();
- // // await page.setViewport({ width: 1920, height: 1080 });
+ // const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
+ // const page = await browser.newPage();
+ // // await page.setViewport({ width: 1920, height: 1080 });
- // // await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any });
+ // // await page.goto(targetUrl, { waitUntil: 'domcontentloaded' as any });
- // const videoPlayer = await page.$('.html5-video-player');
- // videoPlayer && await page.focus("video");
- // await delay(7000);
- // const ad = await page.$('.ytp-ad-skip-button-text');
- // await ad?.click();
- // await videoPlayer?.click();
- // await delay(1000);
- // // hide youtube player controls.
- // await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
+ // const videoPlayer = await page.$('.html5-video-player');
+ // videoPlayer && await page.focus("video");
+ // await delay(7000);
+ // const ad = await page.$('.ytp-ad-skip-button-text');
+ // await ad?.click();
+ // await videoPlayer?.click();
+ // await delay(1000);
+ // // hide youtube player controls.
+ // await page.evaluate(() => (document.querySelector('.ytp-chrome-bottom') as HTMLElement).style.display = 'none');
- // const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
- // await browser.close();
+ // const buffer = await videoPlayer?.screenshot({ encoding: "binary" });
+ // await browser.close();
- // return buffer;
- return null;
+ // return buffer;
+ return null;
} \ No newline at end of file