aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/views/InkingCanvas.tsx7
-rw-r--r--src/client/views/Main.scss9
-rw-r--r--src/client/views/MainView.tsx33
-rw-r--r--src/client/views/PreviewCursor.tsx7
-rw-r--r--src/client/views/collections/CollectionBaseView.scss3
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx6
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx8
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx5
-rw-r--r--src/client/views/collections/CollectionVideoView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.tsx128
-rw-r--r--src/client/views/nodes/WebBox.tsx35
-rw-r--r--src/server/authentication/models/current_user_utils.ts5
17 files changed, 159 insertions, 98 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 30e4637b0..2a3827782 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -118,7 +118,7 @@ export namespace Docs {
options: { nativeWidth: 600, curPage: 0 }
}],
[DocumentType.WEB, {
- layout: { view: WebBox },
+ layout: { view: WebBox, collectionView: [CollectionView, data, anno] as CollectionViewType },
options: { height: 300 }
}],
[DocumentType.COL, {
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 2c54054a5..37a6bbab7 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -13,6 +13,7 @@ import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
interface InkCanvasProps {
getScreenTransform: () => Transform;
+ AnnotationDocument: Doc;
Document: Doc;
inkFieldKey: string;
children: () => JSX.Element[];
@@ -41,7 +42,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
}
componentDidMount() {
- PromiseValue(Cast(this.props.Document[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => {
+ PromiseValue(Cast(this.props.AnnotationDocument[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => {
if (ink) {
let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) =>
strokeData.pathData.reduce(([mix, max, miy, may], p) =>
@@ -56,12 +57,12 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
@computed
get inkData(): Map<string, StrokeData> {
- let map = Cast(this.props.Document[this.props.inkFieldKey], InkField);
+ let map = Cast(this.props.AnnotationDocument[this.props.inkFieldKey], InkField);
return !map ? new Map : new Map(map.inkData);
}
set inkData(value: Map<string, StrokeData>) {
- this.props.Document[this.props.inkFieldKey] = new InkField(value);
+ this.props.AnnotationDocument[this.props.inkFieldKey] = new InkField(value);
}
@action
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index f52e3b658..a16123476 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -235,16 +235,17 @@ ul#add-options-list {
}
.mainView-libraryHandle {
- opacity: 0.6;
width: 20px;
height: 40px;
top: 50%;
- border-radius: 20px;
+ border: 1px solid black;
+ border-radius: 5px;
position: absolute;
z-index: 1;
- background: gray;
}
-
+.svg-inline--fa {
+ vertical-align: unset;
+}
.mainView-workspace {
height:200px;
position:relative;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 935f00332..f0e11a480 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowDown, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faArrowUp, faClone, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx';
import { observer } from 'mobx-react';
@@ -13,7 +13,7 @@ import { Id } from '../../new_fields/FieldSymbols';
import { InkTool } from '../../new_fields/InkField';
import { List } from '../../new_fields/List';
import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue, NumCast, BoolCast } from '../../new_fields/Types';
+import { Cast, FieldValue, NumCast, BoolCast, StrCast } from '../../new_fields/Types';
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
import { RouteStore } from '../../server/RouteStore';
import { emptyFunction, returnOne, returnTrue } from '../../Utils';
@@ -64,6 +64,11 @@ export class MainView extends React.Component {
}
componentWillMount() {
+ var tag = document.createElement('script');
+
+ tag.src = "https://www.youtube.com/iframe_api";
+ var firstScriptTag = document.getElementsByTagName('script')[0];
+ firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag);
window.removeEventListener("keydown", KeyManager.Instance.handle);
window.addEventListener("keydown", KeyManager.Instance.handle);
@@ -105,7 +110,7 @@ export class MainView extends React.Component {
library.add(faFont);
library.add(faExclamation);
- library.add(faImage);
+ library.add(faPortrait);
library.add(faFilePdf);
library.add(faObjectGroup);
library.add(faTable);
@@ -325,13 +330,15 @@ export class MainView extends React.Component {
}
@computed
get mainContent() {
+ let sidebar = CurrentUserUtils.UserDocument.sidebar;
+ if (!(sidebar instanceof Doc)) return (null);
return <div>
<div className="mainView-libraryHandle"
- style={{ left: `${this.flyoutWidth - 10}px` }}
+ style={{ left: `${this.flyoutWidth - 10}px`, backgroundColor: `${StrCast(sidebar.backgroundColor, "lightGray")}` }}
onPointerDown={this.onPointerDown}>
<span title="library View Dragger" style={{ width: "100%", height: "100%", position: "absolute" }} />
</div>
- <div className="mainView-libraryFlyout" style={{ width: `${this.flyoutWidth}px` }}>
+ <div className="mainView-libraryFlyout" style={{ width: `${this.flyoutWidth}px`, zIndex: 1 }}>
{this.flyout}
</div>
{this.dockingContent}
@@ -371,28 +378,21 @@ export class MainView extends React.Component {
let addImportCollectionNode = action(() => Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 }));
let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [
- [React.createRef<HTMLDivElement>(), "image", "Add Image", addImageNode],
+ [React.createRef<HTMLDivElement>(), "portrait", "Add Cat Image", addImageNode],
[React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode],
- [React.createRef<HTMLDivElement>(), "tree", "Add Tree", addTreeNode],
- [React.createRef<HTMLDivElement>(), "table", "Add Schema", addSchemaNode],
// [React.createRef<HTMLDivElement>(), "clone", "Add Docking Frame", addDockingNode],
[React.createRef<HTMLDivElement>(), "arrow-up", "Import Directory", addImportCollectionNode],
];
return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} >
<input type="checkbox" id="add-menu-toggle" ref={this.addMenuToggle} />
- <label htmlFor="add-menu-toggle" title="Add Node"><p>+</p></label>
+ <label htmlFor="add-menu-toggle" style={{ marginTop: 2 }} title="Add Node"><p>+</p></label>
<div id="add-options-content">
<ul id="add-options-list">
<li key="search"><button className="add-button round-button" title="Search" onClick={this.toggleSearch}><FontAwesomeIcon icon="search" size="sm" /></button></li>
<li key="undo"><button className="add-button round-button" title="Undo" style={{ opacity: UndoManager.CanUndo() ? 1 : 0.5, transition: "0.4s ease all" }} onClick={() => UndoManager.Undo()}><FontAwesomeIcon icon="undo-alt" size="sm" /></button></li>
<li key="redo"><button className="add-button round-button" title="Redo" style={{ opacity: UndoManager.CanRedo() ? 1 : 0.5, transition: "0.4s ease all" }} onClick={() => UndoManager.Redo()}><FontAwesomeIcon icon="redo-alt" size="sm" /></button></li>
- <li key="color"><button className="add-button round-button" title="Select Color" onClick={() => this.toggleColorPicker()}><div className="toolbar-color-button" style={{ backgroundColor: InkingControl.Instance.selectedColor }} >
- <div className="toolbar-color-picker" onClick={this.onColorClick} style={this._colorPickerDisplay ? { color: "black", display: "block" } : { color: "black", display: "none" }}>
- <SketchPicker color={InkingControl.Instance.selectedColor} onChange={InkingControl.Instance.switchColor} />
- </div>
- </div></button></li>
{btns.map(btn =>
<li key={btn[1]} ><div ref={btn[0]}>
<button className="round-button add-button" title={btn[2]} onPointerDown={SetupDrag(btn[0], btn[3])}>
@@ -400,6 +400,11 @@ export class MainView extends React.Component {
</button>
</div></li>)}
<li key="undoTest"><button className="add-button round-button" onClick={() => UndoManager.PrintBatches()}><FontAwesomeIcon icon="exclamation" size="sm" /></button></li>
+ <li key="color"><button className="add-button round-button" title="Select Color" onClick={() => this.toggleColorPicker()}><div className="toolbar-color-button" style={{ backgroundColor: InkingControl.Instance.selectedColor }} >
+ <div className="toolbar-color-picker" onClick={this.onColorClick} style={this._colorPickerDisplay ? { color: "black", display: "block" } : { color: "black", display: "none" }}>
+ <SketchPicker color={InkingControl.Instance.selectedColor} onChange={InkingControl.Instance.switchColor} />
+ </div>
+ </div></button></li>
<li key="ink" style={{ paddingRight: "6px" }}><button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /> </button></li>
<li key="pen"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Pen)} title="Pen" style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="lg" /></button></li>
<li key="marker"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Highlighter)} title="Highlighter" style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="lg" /></button></li>
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 7c1d00eb0..ef68c4489 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -35,9 +35,10 @@ export class PreviewCursor extends React.Component<{}> {
// DASHFormattedTextBoxHandled flag when a text box consumes a key press so that we can ignore
// the keyPress here.
//if not these keys, make a textbox if preview cursor is active!
- if (e.key.startsWith("F") && !e.key.endsWith("F")) {
- } else if (e.key !== "Escape" && e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) {
- if ((!e.ctrlKey && !e.metaKey) || (e.key >= "a" && e.key <= "z")) {
+ if (e.key !== "Escape" && e.key !== "Backspace" && e.key !== "Delete" &&
+ e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" &&
+ !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) {
+ if (!e.ctrlKey && !e.metaKey) {// /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) {
PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e);
PreviewCursor.Visible = false;
}
diff --git a/src/client/views/collections/CollectionBaseView.scss b/src/client/views/collections/CollectionBaseView.scss
index 1f5acb96a..34bcb705e 100644
--- a/src/client/views/collections/CollectionBaseView.scss
+++ b/src/client/views/collections/CollectionBaseView.scss
@@ -1,11 +1,12 @@
@import "../globalCssVariables";
#collectionBaseView {
border-width: 0;
- box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
border-color: $light-color-secondary;
border-style: solid;
border-radius: 0 0 $border-radius $border-radius;
box-sizing: border-box;
border-radius: inherit;
pointer-events: all;
+ width:100%;
+ height:100%;
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 2eb2a727c..eba69b448 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -5,7 +5,7 @@ import { Doc } from '../../../new_fields/Doc';
import { Id } from '../../../new_fields/FieldSymbols';
import { List } from '../../../new_fields/List';
import { listSpec } from '../../../new_fields/Schema';
-import { BoolCast, Cast, NumCast, PromiseValue } from '../../../new_fields/Types';
+import { BoolCast, Cast, NumCast, PromiseValue, StrCast } from '../../../new_fields/Types';
import { DocumentManager } from '../../util/DocumentManager';
import { SelectionManager } from '../../util/SelectionManager';
import { ContextMenu } from '../ContextMenu';
@@ -145,7 +145,9 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
};
const viewtype = this.collectionViewType;
return (
- <div id="collectionBaseView" className={this.props.className || "collectionView-cont"}
+ <div id="collectionBaseView"
+ style={{ boxShadow: `#9c9396 ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}` }}
+ className={this.props.className || "collectionView-cont"}
onContextMenu={this.props.onContextMenu} ref={this.props.contentRef}>
{viewtype !== undefined ? this.props.children(viewtype, props) : (null)}
</div>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 1a7ccffa5..e5cee188f 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -430,7 +430,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
stack.header.element[0].style.backgroundColor = DocServer.Control.isReadOnly() ? "#228540" : undefined;
stack.header.element.on('mousedown', (e: any) => {
if (e.target === stack.header.element[0] && e.button === 1) {
- this.AddTab(stack, Docs.FreeformDocument([], { width: this.props.PanelWidth(), height: this.props.PanelHeight(), title: "Untitled Collection" }), undefined);
+ this.AddTab(stack, Docs.Create.FreeformDocument([], { width: this.props.PanelWidth(), height: this.props.PanelHeight(), title: "Untitled Collection" }), undefined);
}
});
stack.header.controlsContainer.find('.lm_close') //get the close icon
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index c667b3f3c..a84fd9cfe 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -14,7 +14,6 @@ import { undoBatch } from "../../util/UndoManager";
import { DragManager } from "../../util/DragManager";
import { DocumentType } from "../../documents/Documents";
import { Transform } from "../../util/Transform";
-import { resolve } from "bluebird";
@observer
export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -56,7 +55,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) {
let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
- let dataDoc = d !== this.props.DataDoc ? this.props.DataDoc : undefined;
let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth;
let height = () => this.getDocHeight(layoutDoc);
let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7ac8aee4c..71f1908f0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -179,8 +179,8 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
}
}
if (text && text.indexOf("www.youtube.com/watch") !== -1) {
- const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
- this.props.addDocument(Docs.Create.WebDocument(url, { ...options, width: 300, height: 300 }));
+ const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");// + "?enablejsapi=1";
+ this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, width: 400, height: 315 }));
return;
}
@@ -197,7 +197,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
.then(result => {
let type = result["content-type"];
if (type) {
- Docs.Get.DocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 })
+ Docs.Get.DocumentFromType(type, str, { ...options, width: 300, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300 })
.then(doc => doc && this.props.addDocument(doc, false));
}
});
@@ -218,7 +218,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
body: formData
}).then(async (res: Response) => {
(await res.json()).map(action((file: any) => {
- let full = { ...options, nativeWidth: 300, width: 300, title: dropFileName };
+ let full = { ...options, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300, width: 300, title: dropFileName };
let path = DocServer.prepend(file);
Docs.Get.DocumentFromType(type, path, full).then(doc => doc && this.props.addDocument(doc));
}));
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 188b78d63..0196fecff 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -153,7 +153,8 @@ class TreeView extends React.Component<TreeViewProps> {
let docList = Cast(this.resolvedDataDoc[this.fieldKey], listSpec(Doc));
let doc = Cast(this.resolvedDataDoc[this.fieldKey], Doc);
let isDoc = doc instanceof Doc || docList;
- return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)}>
+ let c
+ return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
{<FontAwesomeIcon icon={this._collapsed ? (isDoc ? "caret-square-right" : "caret-right") : (isDoc ? "caret-square-down" : "caret-down")} />}
</div>;
}
@@ -532,7 +533,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
return !this.childDocs ? (null) : (
<div id="body" className="collectionTreeView-dropTarget"
- style={{ overflow: "auto" }}
+ style={{ overflow: "auto", background: StrCast(this.props.Document.backgroundColor, "lightgray") }}
onContextMenu={this.onContextMenu}
onWheel={(e: React.WheelEvent) => (e.target as any).scrollHeight > (e.target as any).clientHeight && e.stopPropagation()}
onDrop={this.onTreeDrop}
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index 2b6c272aa..8d519ff2b 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -43,7 +43,7 @@ export class CollectionVideoView extends React.Component<FieldViewProps> {
@action
onPlayDown = () => {
- if (this._videoBox && this._videoBox.player) {
+ if (this._videoBox) {
if (this._videoBox.Playing) {
this._videoBox.Pause();
} else {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index ec0e446e9..00407d39a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -36,7 +36,6 @@
// linear-gradient(to bottom, $light-color-secondary 1px, transparent 1px);
// background-size: 30px 30px;
// }
- box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
opacity: 0.99;
border: 0px solid $light-color-secondary;
border-radius: inherit;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f4e5c4384..e35546fec 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -524,7 +524,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
<CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
easing={easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
<CollectionFreeFormLinksView {...this.props} key="freeformLinks">
- <InkingCanvas getScreenTransform={this.getTransform} Document={this.fieldExtensionDoc} inkFieldKey={"ink"} >
+ <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} AnnotationDocument={this.fieldExtensionDoc} inkFieldKey={"ink"} >
{this.childViews}
</InkingCanvas>
</CollectionFreeFormLinksView>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index c65dfe0bd..1b9138cfd 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,7 +3,7 @@ import { action, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import * as rp from "request-promise";
import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, FieldValue } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
import { VideoField } from "../../../new_fields/URLField";
import { RouteStore } from "../../../server/RouteStore";
import { DocServer } from "../../DocServer";
@@ -15,6 +15,7 @@ import "./VideoBox.scss";
import { ContextMenu } from "../ContextMenu";
import { ContextMenuProps } from "../ContextMenuItem";
import { InkingControl } from "../InkingControl";
+import * as $ from "jquery";
type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -22,6 +23,7 @@ const VideoDocument = makeInterface(positionSchema, pageSchema);
@observer
export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
private _reactionDisposer?: IReactionDisposer;
+ private _youtubePlayer: any = undefined;
private _videoRef: HTMLVideoElement | null = null;
@observable _playTimer?: NodeJS.Timeout = undefined;
@observable _fullScreen = false;
@@ -45,16 +47,31 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
@action public Play() {
this.Playing = true;
- if (this.player) this.player.play();
- if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 500);
+ if (this.player) {
+ this.player.play();
+ if (!this._playTimer) this._playTimer = setInterval(this.updateTimecode, 500);
+ } else if (this._youtubePlayer) {
+ this._youtubePlayer.playVideo();
+ if (!this._playTimer) this._playTimer = setInterval(this.updateYoutubeTimecode, 1000);
+ }
}
@action public Pause() {
this.Playing = false;
- if (this.player) this.player.pause();
- if (this._playTimer) {
- clearInterval(this._playTimer);
- this._playTimer = undefined;
+ if (this.player) {
+ this.player.pause();
+ if (this._playTimer) {
+ clearInterval(this._playTimer);
+ this._playTimer = undefined;
+ }
+ } else if (this._youtubePlayer) {
+ // let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
+ // this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none";
+ this._youtubePlayer.pauseVideo();
+ if (this._playTimer) {
+ clearInterval(this._playTimer);
+ this._playTimer = undefined;
+ }
}
}
@@ -67,10 +84,46 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
updateTimecode = () => {
this.player && (this.props.Document.curPage = this.player.currentTime);
}
-
+ @action
+ updateYoutubeTimecode = () => {
+ this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime());
+ }
componentDidMount() {
if (this.props.setVideoBox) this.props.setVideoBox(this);
+
+ let field = Cast(this.Document[this.props.fieldKey], VideoField);
+ let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+ if (videoid) {
+ let youtubeaspect = 400 / 315;
+ var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
+ var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
+ if (!nativeWidth || !nativeHeight || Math.abs(nativeWidth / nativeHeight - youtubeaspect) > 0.05) {
+ if (!this.Document.nativeWidth) this.Document.nativeWidth = 600;
+ this.Document.nativeHeight = this.Document.nativeWidth / youtubeaspect;
+ this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect;
+ }
+ this._youtubePlayer = new YT.Player(`${videoid}-player`, {
+ height: `${NumCast(this.props.Document.height)}`,
+ width: `${NumCast(this.props.Document.width)}`,
+ videoId: videoid.toString(),
+ playerVars: { 'controls': VideoBox._showControls ? 1 : 0 },
+ events: {
+ 'onStateChange': this.onPlayerStateChange,
+ }
+ });
+ // let iframe = $(document.getElementById(`${videoid}-player`)!);
+ // iframe.on("load", function () {
+ // iframe.contents().find("head")
+ // .append($("<style type='text/css'> .ytp-pause-overlay, .ytp-scroll-min { opacity : 0 !important; } </style>"));
+ // })
+ }
+ }
+
+ @action
+ onPlayerStateChange = (event: any) => {
+ this.Playing = event.data == YT.PlayerState.PLAYING;
}
+
componentWillUnmount() {
this.Pause();
if (this._reactionDisposer) this._reactionDisposer();
@@ -88,42 +141,6 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
}
}
- getMp4ForVideo(videoId: string = "JN5beCVArMs") {
- return new Promise(async (resolve, reject) => {
- const videoInfoRequestConfig = {
- headers: {
- connection: 'keep-alive',
- "user-agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/46.0',
- },
- };
- try {
- let responseSchema: any = {};
- const videoInfoResponse = await rp.get(DocServer.prepend(RouteStore.corsProxy + "/" + `https://www.youtube.com/watch?v=${videoId}`), videoInfoRequestConfig);
- const dataHtml = videoInfoResponse;
- const start = dataHtml.indexOf('ytplayer.config = ') + 18;
- const end = dataHtml.indexOf(';ytplayer.load');
- const subString = dataHtml.substring(start, end);
- const subJson = JSON.parse(subString);
- const stringSub = subJson.args.player_response;
- const stringSubJson = JSON.parse(stringSub);
- const adaptiveFormats = stringSubJson.streamingData.adaptiveFormats;
- const videoDetails = stringSubJson.videoDetails;
- responseSchema.adaptiveFormats = adaptiveFormats;
- responseSchema.videoDetails = videoDetails;
- resolve(responseSchema);
- }
- catch (err) {
- console.log(`
- --- Youtube ---
- Function: getMp4ForVideo
- Error: `, err);
- reject(err);
- }
- });
- }
- onPointerDown = (e: React.PointerEvent) => {
- }
-
@observable static _showControls: boolean = false;
specificContextMenu = (e: React.MouseEvent): void => {
@@ -137,20 +154,17 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
render() {
let field = Cast(this.Document[this.props.fieldKey], VideoField);
-
- // this.getMp4ForVideo().then((mp4) => {
- // console.log(mp4);
- // }).catch(e => {
- // console.log("")
- // });
- // //
-
- let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
+ let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : interactive);
+ let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+
+ if (this._youtubePlayer) this._youtubePlayer.getIframe().style.pointerEvents = interactive ? "all" : "none";
return !field ? <div>Loading</div> :
- <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} onPointerDown={this.onPointerDown} onContextMenu={this.specificContextMenu} controls={VideoBox._showControls}>
- <source src={field.url.href} type="video/mp4" />
- Not supported.
- </video>;
+ videoid ?
+ <div id={`${videoid}-player`} className={`${style}`} style={{ height: "100%" }} /> :
+ <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} onContextMenu={this.specificContextMenu} controls={VideoBox._showControls}>
+ <source src={field.url.href} type="video/mp4" />
+ Not supported.
+ </video>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 98c57fc75..96b972a1c 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -6,12 +6,45 @@ import { InkingControl } from "../InkingControl";
import { FieldView, FieldViewProps } from './FieldView';
import "./WebBox.scss";
import React = require("react");
+import { InkTool } from "../../../new_fields/InkField";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
+export function onYouTubeIframeAPIReady() {
+ console.log("player");
+ return;
+ let player = new YT.Player('player', {
+ events: {
+ 'onReady': onPlayerReady
+ }
+ });
+}
+// must cast as any to set property on window
+const _global = (window /* browser */ || global /* node */) as any
+_global.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
+
+function onPlayerReady(event: any) {
+ event.target.playVideo();
+}
@observer
export class WebBox extends React.Component<FieldViewProps> {
public static LayoutString() { return FieldView.LayoutString(WebBox); }
+ componentWillMount() {
+
+ let field = Cast(this.props.Document[this.props.fieldKey], WebField);
+ if (field && field.url.href.indexOf("youtube") !== -1) {
+ let youtubeaspect = 400 / 315;
+ var nativeWidth = NumCast(this.props.Document.nativeWidth, 0);
+ var nativeHeight = NumCast(this.props.Document.nativeHeight, 0);
+ if (!nativeWidth || !nativeHeight || Math.abs(nativeWidth / nativeHeight - youtubeaspect) > 0.05) {
+ if (!nativeWidth) this.props.Document.nativeWidth = 600;
+ this.props.Document.nativeHeight = NumCast(this.props.Document.nativeWidth) / youtubeaspect;
+ this.props.Document.height = NumCast(this.props.Document.width) / youtubeaspect;
+ }
+ }
+ }
+
_ignore = 0;
onPreWheel = (e: React.WheelEvent) => {
this._ignore = e.timeStamp;
@@ -46,7 +79,7 @@ export class WebBox extends React.Component<FieldViewProps> {
let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
- let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+ let classname = "webBox-cont" + (this.props.isSelected() && InkingControl.Instance.selectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
return (
<>
<div className={classname} >
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 763693dd6..39a973e08 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -37,6 +37,7 @@ export class CurrentUserUtils {
doc.gridGap = 5;
doc.xMargin = 5;
doc.yMargin = 5;
+ doc.boxShadow = "0 0";
doc.excludeFromLibrary = true;
doc.optionalRightCollection = Docs.Create.StackingDocument([], { title: "New mobile uploads" });
// doc.library = Docs.Create.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` });
@@ -49,11 +50,13 @@ export class CurrentUserUtils {
const workspaces = Docs.Create.TreeDocument([], { title: "Workspaces", height: 100 });
workspaces.excludeFromLibrary = true;
workspaces.workspaceLibrary = true;
+ workspaces.boxShadow = "0 0";
doc.workspaces = workspaces;
}
if (doc.recentlyClosed === undefined) {
const recentlyClosed = Docs.Create.TreeDocument([], { title: "Recently Closed", height: 75 });
recentlyClosed.excludeFromLibrary = true;
+ recentlyClosed.boxShadow = "0 0";
doc.recentlyClosed = recentlyClosed;
}
if (doc.sidebar === undefined) {
@@ -62,6 +65,8 @@ export class CurrentUserUtils {
sidebar.gridGap = 5;
sidebar.xMargin = 5;
sidebar.yMargin = 5;
+ Doc.GetProto(sidebar).backgroundColor = "#aca3a6";
+ sidebar.boxShadow = "1 1 3";
doc.sidebar = sidebar;
}