diff options
author | Tyler Schicke <tyler_schicke@brown.edu> | 2019-05-03 20:47:40 -0400 |
---|---|---|
committer | Tyler Schicke <tyler_schicke@brown.edu> | 2019-05-03 20:47:40 -0400 |
commit | 070787b6be93dca4a43ec7e893ae4ac4b4d80e59 (patch) | |
tree | 4b93ac202fe813033b6d07f7202ab217c0da79f8 | |
parent | 9b33ac1cb790e88558edb3e4626f5a7b759ea3db (diff) | |
parent | 95d89a193b25d19faf6da0af1412480a36fc9ebe (diff) |
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into newDocs
-rw-r--r-- | src/client/views/Main.tsx | 16 | ||||
-rw-r--r-- | src/client/views/PresentationView.scss | 68 | ||||
-rw-r--r-- | src/client/views/PresentationView.tsx | 173 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 8 | ||||
-rw-r--r-- | src/new_fields/Doc.ts | 1 |
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) { |