aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/views/Main.tsx86
-rw-r--r--src/client/views/PresentationView.scss41
-rw-r--r--src/client/views/PresentationView.tsx143
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx2
-rw-r--r--src/fields/KeyStore.ts1
7 files changed, 238 insertions, 37 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7b30dff98..0a972eaf0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -11,6 +11,7 @@ import { WebField } from "../../fields/WebField";
import { WebBox } from "../views/nodes/WebBox";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
import { HtmlField } from "../../fields/HtmlField";
+import { PresentationView } from "../views/PresentationView";
import { Key } from "../../fields/Key"
import { Field } from "../../fields/Field";
import { KeyValueBox } from "../views/nodes/KeyValueBox"
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index b78f59681..bc7338578 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -12,6 +12,8 @@ import { Server } from '../Server';
import { setupDrag } from '../util/DragManager';
import { Transform } from '../util/Transform';
import { UndoManager } from '../util/UndoManager';
+import { PresentationView } from './PresentationView';
+import { Field } from '../../fields/Field';
import { CollectionDockingView } from './collections/CollectionDockingView';
import { ContextMenu } from './ContextMenu';
import { DocumentDecorations } from './DocumentDecorations';
@@ -41,6 +43,9 @@ Documents.initProtos(mainDocId, (res?: Document) => {
else {
mainContainer = Documents.DockDocument(JSON.stringify({ content: [{ type: 'row', content: [] }] }), { title: "main container" }, mainDocId);
+ //save a document for the presentation view in Key Store - this is where title is set
+ mainContainer.Set(KeyStore.PresentationView, Documents.FreeformDocument([], { title: "Presentation Mode" }));
+
// bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
setTimeout(() => {
mainfreeform = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" });
@@ -78,40 +83,47 @@ Documents.initProtos(mainDocId, (res?: Document) => {
let audioRef = React.createRef<HTMLDivElement>();
let colRef = React.createRef<HTMLDivElement>();
- ReactDOM.render((
- <div style={{ position: "absolute", width: "100%", height: "100%" }}>
- <DocumentView Document={mainContainer}
- AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity}
- ContentScaling={() => 1}
- PanelWidth={() => 0}
- PanelHeight={() => 0}
- isTopMost={true}
- SelectOnLoad={false}
- focus={() => { }}
- ContainingCollectionView={undefined} />
- <DocumentDecorations />
- <ContextMenu />
- <div className="main-buttonDiv" style={{ bottom: '0px' }} ref={imgRef} >
- <button onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>Add Image</button></div>
- <div className="main-buttonDiv" style={{ bottom: '25px' }} ref={webRef} >
- <button onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>Add Web</button></div>
- <div className="main-buttonDiv" style={{ bottom: '50px' }} ref={textRef}>
- <button onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>Add Text</button></div>
- <div className="main-buttonDiv" style={{ bottom: '75px' }} ref={colRef}>
- <button onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>Add Collection</button></div>
- <div className="main-buttonDiv" style={{ bottom: '100px' }} ref={schemaRef}>
- <button onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>Add Schema</button></div>
- <div className="main-buttonDiv" style={{ bottom: '125px' }} >
- <button onClick={clearDatabase}>Clear Database</button></div>
- <div className="main-buttonDiv" style={{ bottom: '175px' }} ref={videoRef}>
- <button onPointerDown={setupDrag(videoRef, addVideoNode)} onClick={addClick(addVideoNode)}>Add Video</button></div>
- <div className="main-buttonDiv" style={{ bottom: '200px' }} ref={audioRef}>
- <button onPointerDown={setupDrag(audioRef, addAudioNode)} onClick={addClick(addAudioNode)}>Add Audio</button></div>
- <div className="main-buttonDiv" style={{ bottom: '150px' }} ref={pdfRef}>
- <button onPointerDown={setupDrag(pdfRef, addPDFNode)} onClick={addClick(addPDFNode)}>Add PDF</button></div>
- <button className="main-undoButtons" style={{ bottom: '25px' }} onClick={() => UndoManager.Undo()}>Undo</button>
- <button className="main-undoButtons" style={{ bottom: '0px' }} onClick={() => UndoManager.Redo()}>Redo</button>
- <InkingControl />
- </div>),
- document.getElementById('root'));
-})
+ let render = function (field: Field | undefined) {
+ ReactDOM.render((
+ <div style={{ position: "absolute", width: "100%", height: "100%" }}>
+ <DocumentView Document={mainContainer}
+ AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity}
+ ContentScaling={() => 1}
+ PanelWidth={() => 0}
+ PanelHeight={() => 0}
+ isTopMost={true}
+ SelectOnLoad={false}
+ focus={() => { }}
+ ContainingCollectionView={undefined} />
+ <DocumentDecorations />
+ <ContextMenu />
+ <PresentationView Document={field as Document} />
+ <div className="main-buttonDiv" style={{ bottom: '0px' }} ref={imgRef} >
+ <button onPointerDown={setupDrag(imgRef, addImageNode)} onClick={addClick(addImageNode)}>Add Image</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '25px' }} ref={webRef} >
+ <button onPointerDown={setupDrag(webRef, addWebNode)} onClick={addClick(addWebNode)}>Add Web</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '50px' }} ref={textRef}>
+ <button onPointerDown={setupDrag(textRef, addTextNode)} onClick={addClick(addTextNode)}>Add Text</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '75px' }} ref={colRef}>
+ <button onPointerDown={setupDrag(colRef, addColNode)} onClick={addClick(addColNode)}>Add Collection</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '100px' }} ref={schemaRef}>
+ <button onPointerDown={setupDrag(schemaRef, addSchemaNode)} onClick={addClick(addSchemaNode)}>Add Schema</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '125px' }} >
+ <button onClick={clearDatabase}>Clear Database</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '175px' }} ref={videoRef}>
+ <button onPointerDown={setupDrag(videoRef, addVideoNode)} onClick={addClick(addVideoNode)}>Add Video</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '200px' }} ref={audioRef}>
+ <button onPointerDown={setupDrag(audioRef, addAudioNode)} onClick={addClick(addAudioNode)}>Add Audio</button></div>
+ <div className="main-buttonDiv" style={{ bottom: '150px' }} ref={pdfRef}>
+ <button onPointerDown={setupDrag(pdfRef, addPDFNode)} onClick={addClick(addPDFNode)}>Add PDF</button></div>
+ <button className="main-undoButtons" style={{ bottom: '25px' }} onClick={() => UndoManager.Undo()}>Undo</button>
+ <button className="main-undoButtons" style={{ bottom: '0px' }} onClick={() => UndoManager.Redo()}>Redo</button>
+ <InkingControl />
+ </div>),
+ document.getElementById('root'));
+ }
+ //call render async passing in the doc saved in PresentationView key
+ mainContainer.GetAsync(KeyStore.PresentationView, render);
+});
+
+
diff --git a/src/client/views/PresentationView.scss b/src/client/views/PresentationView.scss
new file mode 100644
index 000000000..595cdb879
--- /dev/null
+++ b/src/client/views/PresentationView.scss
@@ -0,0 +1,41 @@
+.presentationView-cont {
+ position: absolute;
+ background: white;
+ z-index: 1;
+ box-shadow: #AAAAAA .2vw .2vw .4vw;
+ right: 0;
+ top:0;
+ bottom:0;
+}
+
+.presentationView-item {
+ width: 10vw;
+ 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-title {
+ margin-top: 0px;
+ padding-top: 3px;
+ padding-bottom: 3px;
+ height: 50px;
+ text-align: center;
+ background: lightseagreen;
+}
+
+.icon{
+ margin-right: 0px;
+} \ 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..76431dc9a
--- /dev/null
+++ b/src/client/views/PresentationView.tsx
@@ -0,0 +1,143 @@
+import { observer } from "mobx-react";
+import { Document } from "../../fields/Document";
+import { KeyStore } from "../../fields/KeyStore";
+import { ListField } from "../../fields/ListField";
+import React = require("react")
+import { TextField } from "../../fields/TextField";
+import { observable, action } from "mobx";
+import { Field } from "../../fields/Field";
+import { Documents } from '../documents/Documents';
+import "./PresentationView.scss"
+import { mobxPendingDecorators } from "mobx/lib/internal";
+import { NumberField } from "../../fields/NumberField";
+import "./Main.tsx";
+
+export interface PresViewProps {
+ Document: Document;
+}
+
+
+@observer
+/**
+ * Component that takes in a document prop and a boolean whether it's collapsed or not.
+ */
+class PresentationViewItem extends React.Component<PresViewProps> {
+
+
+ /**
+ * Renders a single child document. It will just append a list element.
+ * @param document The document to render.
+ */
+ renderChild(document: Document) {
+ let title = document.GetT<TextField>(KeyStore.Title, TextField);
+
+ // if the title hasn't loaded, immediately return the div
+ if (!title || title === "<Waiting>") {
+ return <div className="presentationView-item" key={document.Id}></div>;
+ }
+ // finally, if it's a normal document, then render it as such.
+ else {
+ //TODO: there is a zoom event that will be merged for on click
+ return <li className="presentationView-item" key={document.Id}>
+ {title.Data}</li>;
+ }
+ }
+
+ render() {
+ var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+
+ if (children && children !== "<Waiting>") {
+ return (<div>
+ {children.Data.map(value => this.renderChild(value))}
+ </div>)
+ } else {
+ return <div></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.SetNumber(KeyStore.Width, 0));
+
+ private ref: React.RefObject<HTMLDivElement>;
+
+ //initilize class variables
+ constructor(props: PresViewProps) {
+ super(props);
+ this.ref = React.createRef()
+ PresentationView.Instance = this;
+ }
+
+ /**
+ * Adds a document to the presentation view
+ **/
+ @action
+ public PinDoc(doc: Document) {
+ //add this new doc to props.Document
+ if (this.props.Document.Get(KeyStore.Data) instanceof Field) {
+ const value = this.props.Document.GetData(KeyStore.Data, ListField, new Array<Document>())
+ value.push(doc);
+ } else {
+ this.props.Document.SetData(KeyStore.Data, [doc], ListField);
+ }
+
+ //TODO: open presentation view if not already open
+ this.props.Document.SetData(KeyStore.Width, 300, NumberField);
+ }
+
+ /**
+ * Removes a document from the presentation view
+ **/
+ @action
+ public RemoveDoc(doc: Document) {
+ const value = this.props.Document.GetData(KeyStore.Data, ListField, new Array<Document>())
+ 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)
+
+ //TODO: do i need below lines??
+ // SelectionManager.DeselectAll()
+ // ContextMenu.Instance.clearItems()
+ // return true;
+ }
+ // return false
+
+ this.collapsed = true;
+ }
+
+
+
+ render() {
+ let titleStr = "Title";
+ let title = this.props.Document.GetT<TextField>(KeyStore.Title, TextField);
+ if (title && title !== "<Waiting>") {
+ titleStr = title.Data;
+ }
+ //TODO: programmatically change width
+ let width = this.props.Document.GetNumber(KeyStore.Width, 0);
+ return (
+ <div className="presentationView-cont" style={{ width: width }}>
+ <div className="presentationView-title"><h2>{titleStr}</h2>
+ <p className='icon' onClick={this.closePresentation}>X</p></div>
+ <ul>
+ <PresentationViewItem
+ Document={this.props.Document}
+ />
+ </ul>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8b06d9ac4..efc22cdc5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -29,6 +29,7 @@ export enum BulletType {
*/
class TreeView extends React.Component<TreeViewProps> {
+ //observable means render is re-called every time variable is changed
@observable
collapsed: boolean = false;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index dc793c16d..3ce4aab6f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -24,6 +24,7 @@ import { WebBox } from "../nodes/WebBox";
import { PDFBox } from "../nodes/PDFBox";
import "./DocumentView.scss";
import React = require("react");
+import { PresentationView } from "../PresentationView";
import { TextField } from "../../../fields/TextField";
import { DocumentManager } from "../../util/DocumentManager";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -272,6 +273,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
e.stopPropagation();
}
+ ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document) })
ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked })
ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
SelectionManager.SelectDoc(this, e.ctrlKey);
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index f93a68c85..d9ba251ae 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -27,6 +27,7 @@ export namespace KeyStore {
export const Caption = new Key("Caption");
export const ActiveFrame = new Key("ActiveFrame");
export const DocumentText = new Key("DocumentText");
+ export const PresentationView = new Key("PresentationView");
export const LinkedToDocs = new Key("LinkedToDocs");
export const LinkedFromDocs = new Key("LinkedFromDocs");
export const LinkDescription = new Key("LinkDescription");