diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 1 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 86 | ||||
-rw-r--r-- | src/client/views/PresentationView.scss | 41 | ||||
-rw-r--r-- | src/client/views/PresentationView.tsx | 143 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 2 | ||||
-rw-r--r-- | src/fields/KeyStore.ts | 1 |
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"); |