aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Schicke <tyler_schicke@brown.edu>2019-05-03 20:47:40 -0400
committerTyler Schicke <tyler_schicke@brown.edu>2019-05-03 20:47:40 -0400
commit070787b6be93dca4a43ec7e893ae4ac4b4d80e59 (patch)
tree4b93ac202fe813033b6d07f7202ab217c0da79f8
parent9b33ac1cb790e88558edb3e4626f5a7b759ea3db (diff)
parent95d89a193b25d19faf6da0af1412480a36fc9ebe (diff)
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into newDocs
-rw-r--r--src/client/views/Main.tsx16
-rw-r--r--src/client/views/PresentationView.scss68
-rw-r--r--src/client/views/PresentationView.tsx173
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/new_fields/Doc.ts1
5 files changed, 265 insertions, 1 deletions
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 90339aea2..c3b48d20f 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -22,6 +22,7 @@ import '../northstar/utils/Extensions';
import { SetupDrag, DragManager } from '../util/DragManager';
import { Transform } from '../util/Transform';
import { UndoManager } from '../util/UndoManager';
+import { PresentationView } from './PresentationView';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { ContextMenu } from './ContextMenu';
import { DocumentDecorations } from './DocumentDecorations';
@@ -50,6 +51,9 @@ export class Main extends React.Component {
}
private set mainContainer(doc: Opt<Doc>) {
if (doc) {
+ if (!("presentationView" in doc)) {
+ doc.presentationView = new Doc();
+ }
CurrentUserUtils.UserDocument.activeWorkspace = doc;
}
}
@@ -175,11 +179,21 @@ export class Main extends React.Component {
}
@computed
+ get presentationView() {
+ if (this.mainContainer) {
+ let presentation = FieldValue(Cast(this.mainContainer.presentationView, Doc));
+ return presentation ? <PresentationView Document={presentation} key="presentation" /> : (null);
+ }
+ return (null);
+ }
+
+ @computed
get mainContent() {
let pwidthFunc = () => this.pwidth;
let pheightFunc = () => this.pheight;
let noScaling = () => 1;
let mainCont = this.mainContainer;
+ let pcontent = this.presentationView;
return <Measure onResize={action((r: any) => { this.pwidth = r.entry.width; this.pheight = r.entry.height; })}>
{({ measureRef }) =>
<div ref={measureRef} id="mainContent-div">
@@ -197,7 +211,9 @@ export class Main extends React.Component {
focus={emptyFunction}
parentActive={returnTrue}
whenActiveChanged={emptyFunction}
+ bringToFront={emptyFunction}
ContainingCollectionView={undefined} />}
+ {pcontent}
</div>
}
</Measure>;
diff --git a/src/client/views/PresentationView.scss b/src/client/views/PresentationView.scss
new file mode 100644
index 000000000..7c5677f0d
--- /dev/null
+++ b/src/client/views/PresentationView.scss
@@ -0,0 +1,68 @@
+.presentationView-cont {
+ position: absolute;
+ background: white;
+ z-index: 1;
+ box-shadow: #AAAAAA .2vw .2vw .4vw;
+ right: 0;
+ top:0;
+ bottom:0;
+}
+
+.presentationView-item {
+ width: 220px;
+ height: 40px;
+ vertical-align: center;
+ padding-top: 15px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ transition: all .1s;
+}
+
+.presentationView-item:hover {
+ transition: all .1s;
+ background: #AAAAAA
+}
+
+.presentationView-heading {
+ margin-top: 0px;
+ height: 40px;
+ background: lightseagreen;
+ padding: 30px;
+}
+.presentationView-title {
+ padding-top: 3px;
+ padding-bottom: 3px;
+ font-size: 25px;
+ float:left;
+}
+.presentation-icon{
+ float: right;
+ display: inline;
+ width: 10px;
+ margin-top: 7px;
+}
+.presentationView-header {
+ padding-top: 1px;
+ padding-bottom: 1px;
+ font-size: 15px;
+ float:left;
+ }
+
+ .presentation-next{
+ float: right;
+ }
+ .presentation-back{
+ float: left;
+ }
+ .presentation-next:hover{
+ transition: all .1s;
+ background: #AAAAAA
+}
+.presentation-back:hover{
+ transition: all .1s;
+ background: #AAAAAA
+} \ No newline at end of file
diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx
new file mode 100644
index 000000000..b4c12d057
--- /dev/null
+++ b/src/client/views/PresentationView.tsx
@@ -0,0 +1,173 @@
+import { observer } from "mobx-react";
+import React = require("react")
+import { observable, action } from "mobx";
+import "./PresentationView.scss"
+import "./Main.tsx";
+import { DocumentManager } from "../util/DocumentManager";
+import { Utils } from "../../Utils";
+import { Doc } from "../../new_fields/Doc";
+import { listSpec } from "../../new_fields/Schema";
+import { Cast, NumCast, FieldValue } from "../../new_fields/Types";
+import { Id } from "../../new_fields/RefField";
+import { List } from "../../new_fields/List";
+
+export interface PresViewProps {
+ Document: Doc;
+}
+
+
+@observer
+/**
+ * Component that takes in a document prop and a boolean whether it's collapsed or not.
+ */
+class PresentationViewItem extends React.Component<PresViewProps> {
+
+ //look at CollectionFreeformView.focusDocument(d)
+ @action
+ openDoc = (doc: Doc) => {
+ let docView = DocumentManager.Instance.getDocumentView(doc);
+ if (docView) {
+ docView.props.focus(docView.props.Document);
+ }
+ }
+
+ /**
+ * Removes a document from the presentation view
+ **/
+ @action
+ public RemoveDoc(doc: Doc) {
+ const value = Cast(this.props.Document.data, listSpec(Doc), []);
+ let index = -1;
+ for (let i = 0; i < value.length; i++) {
+ if (value[i][Id] === doc[Id]) {
+ index = i;
+ break;
+ }
+ }
+ if (index !== -1) {
+ value.splice(index, 1);
+ }
+ }
+
+ /**
+ * Renders a single child document. It will just append a list element.
+ * @param document The document to render.
+ */
+ renderChild(document: Doc) {
+ let title = document.title;
+
+ //to get currently selected presentation doc
+ let selected = NumCast(this.props.Document.selectedDoc, 0);
+
+ // finally, if it's a normal document, then render it as such.
+ const children = Cast(this.props.Document.data, listSpec(Doc));
+ const styles: any = {};
+ if (children && children[selected] === document) {
+ //this doc is selected
+ styles.background = "gray";
+ }
+ return (
+ <li className="presentationView-item" style={styles} key={Utils.GenerateGuid()}>
+ <div className="presentationView-header" onClick={() => this.openDoc(document)}>{title}</div>
+ <div className="presentation-icon" onClick={() => this.RemoveDoc(document)}>X</div>
+ </li>
+ );
+
+ }
+
+ render() {
+ const children = Cast(this.props.Document.data, listSpec(Doc), []);
+
+ return (
+ <div>
+ {children.map(value => this.renderChild(value))}
+ </div>
+ );
+ }
+}
+
+
+@observer
+export class PresentationView extends React.Component<PresViewProps> {
+ public static Instance: PresentationView;
+
+ //observable means render is re-called every time variable is changed
+ @observable
+ collapsed: boolean = false;
+ closePresentation = action(() => this.props.Document.width = 0);
+ next = () => {
+ const current = NumCast(this.props.Document.selectedDoc);
+ const allDocs = FieldValue(Cast(this.props.Document.data, listSpec(Doc)));
+ if (allDocs && current < allDocs.length + 1) {
+ //can move forwards
+ this.props.Document.selectedDoc = current + 1;
+ const doc = allDocs[current + 1];
+ let docView = DocumentManager.Instance.getDocumentView(doc);
+ if (docView) {
+ docView.props.focus(docView.props.Document);
+ }
+ }
+
+ }
+ back = () => {
+ const current = NumCast(this.props.Document.selectedDoc);
+ const allDocs = FieldValue(Cast(this.props.Document.data, listSpec(Doc)));
+ if (allDocs && current - 1 >= 0) {
+ //can move forwards
+ this.props.Document.selectedDoc = current - 1;
+ const doc = allDocs[current - 1];
+ let docView = DocumentManager.Instance.getDocumentView(doc);
+ if (docView) {
+ docView.props.focus(docView.props.Document);
+ }
+ }
+ }
+
+ private ref = React.createRef<HTMLDivElement>();
+
+ //initilize class variables
+ constructor(props: PresViewProps) {
+ super(props);
+ PresentationView.Instance = this;
+ }
+
+ /**
+ * Adds a document to the presentation view
+ **/
+ @action
+ public PinDoc(doc: Doc) {
+ //add this new doc to props.Document
+ const data = Cast(this.props.Document.data, listSpec(Doc));
+ if (data) {
+ data.push(doc);
+ } else {
+ this.props.Document.data = new List([doc]);
+ }
+
+ this.props.Document.width = 300;
+ }
+
+ render() {
+ let titleStr = this.props.Document.Title;
+ let width = NumCast(this.props.Document.width);
+
+ //TODO: next and back should be icons
+ return (
+ <div className="presentationView-cont" style={{ width: width, overflow: "hidden" }}>
+ <div className="presentationView-heading">
+ <div className="presentationView-title">{titleStr}</div>
+ <div className='presentation-icon' onClick={this.closePresentation}>X</div></div>
+ <div>
+ <div className="presentation-back" onClick={this.back}>back</div>
+ <div className="presentation-next" onClick={this.next}>next</div>
+
+ </div>
+ <ul>
+ <PresentationViewItem
+ Document={this.props.Document}
+ />
+ </ul>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c08e322c0..fd012e7ea 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -25,6 +25,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { DocServer } from "../../DocServer";
import { Id } from "../../../new_fields/RefField";
+import { PresentationView } from "../PresentationView";
const linkSchema = createSchema({
title: "string",
@@ -277,7 +278,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])) });
ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]) });
//ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
+ ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document) });
ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked });
+ if (!this.topMost) {
+ // DocumentViews should stop propagation of this event
+ e.stopPropagation();
+ }
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
if (!SelectionManager.IsSelected(this)) {
SelectionManager.SelectDoc(this, false);
@@ -313,4 +319,4 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
</div>
);
}
-}
+} \ No newline at end of file
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 3eea6d2b2..3055af1bf 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -36,6 +36,7 @@ export class Doc extends RefField {
const doc = new Proxy<this>(this, {
set: setter,
get: getter,
+ has: (target, key) => key in target.__fields,
ownKeys: target => Object.keys(target.__fields),
getOwnPropertyDescriptor: (target, prop) => {
if (prop in target.__fields) {