aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/presentationview
diff options
context:
space:
mode:
authoryipstanley <stanley_yip@brown.edu>2019-07-30 16:34:05 -0400
committeryipstanley <stanley_yip@brown.edu>2019-07-30 16:34:05 -0400
commitbf5761377d375d5d7a2ff99caf0af0d332562197 (patch)
treefb9319c69a15a4e8f134b360f0858ccd60609f8c /src/client/views/presentationview
parent676534c7ad5fd5fa155f4b76856ff33a08d8ab49 (diff)
parentf3d82375cd2e7e1f658824081eda2a5c618b2198 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web
Diffstat (limited to 'src/client/views/presentationview')
-rw-r--r--src/client/views/presentationview/PresentationElement.tsx124
-rw-r--r--src/client/views/presentationview/PresentationList.tsx2
-rw-r--r--src/client/views/presentationview/PresentationModeMenu.scss30
-rw-r--r--src/client/views/presentationview/PresentationModeMenu.tsx100
-rw-r--r--src/client/views/presentationview/PresentationView.scss15
-rw-r--r--src/client/views/presentationview/PresentationView.tsx280
6 files changed, 464 insertions, 87 deletions
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index 36f1178f1..11f3eb846 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -1,6 +1,6 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
-import { faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons';
+import { faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch, faArrowRight } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
@@ -9,17 +9,22 @@ import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { Utils } from "../../../Utils";
+import { Utils, returnFalse, emptyFunction, returnOne } from "../../../Utils";
import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
import { SelectionManager } from "../../util/SelectionManager";
-import "./PresentationView.scss";
+import { ContextMenu } from "../ContextMenu";
+import { Transform } from "../../util/Transform";
+import { DocumentView } from "../nodes/DocumentView";
+import { DocumentType } from "../../documents/Documents";
import React = require("react");
+
library.add(faArrowUp);
library.add(fileSolid);
library.add(faLocationArrow);
library.add(fileRegular as any);
library.add(faSearch);
+library.add(faArrowRight);
interface PresentationElementProps {
mainDocument: Doc;
@@ -46,6 +51,7 @@ export enum buttonIndex {
FadeAfter = 3,
HideAfter = 4,
Group = 5,
+ OpenRight = 6
}
@@ -63,12 +69,9 @@ export default class PresentationElement extends React.Component<PresentationEle
private backUpDoc: Doc | undefined;
-
-
-
constructor(props: PresentationElementProps) {
super(props);
- this.selectedButtons = new Array(6);
+ this.selectedButtons = new Array(7);
this.presElRef = React.createRef();
}
@@ -104,6 +107,9 @@ export default class PresentationElement extends React.Component<PresentationEle
}
}
+ /**
+ * Function that will be called to receive stored backUp for buttons
+ */
receiveButtonBackUp = async () => {
//get the list that stores docs that keep track of buttons
@@ -132,7 +138,7 @@ export default class PresentationElement extends React.Component<PresentationEle
if (!foundDoc) {
let newDoc = new Doc();
- let defaultBooleanArray: boolean[] = new Array(6);
+ let defaultBooleanArray: boolean[] = new Array(7);
newDoc.selectedButtons = new List(defaultBooleanArray);
newDoc.docId = this.props.document[Id];
castedList.push(newDoc);
@@ -395,6 +401,22 @@ export default class PresentationElement extends React.Component<PresentationEle
}
/**
+ * Function that opens up the option to open a element on right when navigated,
+ * instead of openening it as tab as default.
+ */
+ @action
+ onRightTabClick = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ if (this.selectedButtons[buttonIndex.OpenRight]) {
+ this.selectedButtons[buttonIndex.OpenRight] = false;
+ // action maybe
+ } else {
+ this.selectedButtons[buttonIndex.OpenRight] = true;
+ }
+ this.autoSaveButtonChange(buttonIndex.OpenRight);
+ }
+
+ /**
* Creating a drop target for drag and drop when called.
*/
protected createListDropTarget = (ele: HTMLDivElement) => {
@@ -629,7 +651,7 @@ export default class PresentationElement extends React.Component<PresentationEle
*/
getSelectedButtonsOfDoc = async (paramDoc: Doc) => {
let castedList = Cast(this.props.presButtonBackUp.selectedButtonDocs, listSpec(Doc));
- let foundSelectedButtons: boolean[] = new Array(6);
+ let foundSelectedButtons: boolean[] = new Array(7);
//if this is the first time this doc mounts, push a doc for it to store
for (let doc of castedList!) {
@@ -649,7 +671,6 @@ export default class PresentationElement extends React.Component<PresentationEle
//This is used to add dragging as an event.
onPointerEnter = (e: React.PointerEvent): void => {
- this.props.document.libraryBrush = true;
if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
let selected = NumCast(this.props.mainDocument.selectedDoc, 0);
@@ -666,7 +687,6 @@ export default class PresentationElement extends React.Component<PresentationEle
//This is used to remove the dragging when dropped.
onPointerLeave = (e: React.PointerEvent): void => {
- this.props.document.libraryBrush = false;
//to get currently selected presentation doc
let selected = NumCast(this.props.mainDocument.selectedDoc, 0);
@@ -765,9 +785,86 @@ export default class PresentationElement extends React.Component<PresentationEle
groupArray.push(tempStack.pop()!);
}
}
+ /**
+ * This function is a getter to get if a document is in previewMode.
+ */
+ private get embedInline() {
+ return BoolCast(this.props.document.embedOpen);
+ }
+
+ /**
+ * This function sets document in presentation preview mode as the given value.
+ */
+ private set embedInline(value: boolean) {
+ this.props.document.embedOpen = value;
+ }
+ /**
+ * The function that recreates that context menu of presentation elements.
+ */
+ onContextMenu = (e: React.MouseEvent<HTMLDivElement>) => {
+ e.preventDefault();
+ e.stopPropagation();
+ ContextMenu.Instance.addItem({ description: this.embedInline ? "Collapse Inline" : "Expand Inline", event: () => this.embedInline = !this.embedInline, icon: "expand" });
+ ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
+ }
+ /**
+ * The function that is responsible for rendering the a preview or not for this
+ * presentation element.
+ */
+ renderEmbeddedInline = () => {
+ if (!this.embedInline) {
+ return (null);
+ }
+ let propDocWidth = NumCast(this.props.document.nativeWidth);
+ let propDocHeight = NumCast(this.props.document.nativeHeight);
+ let scale = () => {
+ let newScale = 175 / NumCast(this.props.document.nativeWidth, 175);
+ return newScale;
+ };
+ return (
+ <div style={{
+ position: "relative",
+ height: propDocHeight === 0 ? 100 : propDocHeight * scale(),
+ width: propDocWidth === 0 ? "auto" : propDocWidth * scale(),
+ marginTop: 15
+
+ }}>
+ <DocumentView
+ fitToBox={StrCast(this.props.document.type).indexOf(DocumentType.COL) !== -1}
+ Document={this.props.document}
+ addDocument={returnFalse}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ addDocTab={returnFalse}
+ renderDepth={1}
+ PanelWidth={() => 350}
+ PanelHeight={() => 90}
+ focus={emptyFunction}
+ selectOnLoad={false}
+ parentActive={returnFalse}
+ whenActiveChanged={returnFalse}
+ bringToFront={emptyFunction}
+ zoomToScale={emptyFunction}
+ getScale={returnOne}
+ ContainingCollectionView={undefined}
+ ContentScaling={scale}
+ />
+ <div style={{
+ width: " 100%",
+ height: " 100%",
+ position: "absolute",
+ left: 0,
+ top: 0,
+ background: "transparent",
+ zIndex: 2,
+
+ }}></div>
+ </div>
+ );
+ }
render() {
let p = this.props;
@@ -784,7 +881,7 @@ export default class PresentationElement extends React.Component<PresentationEle
let dropAction = StrCast(this.props.document.dropAction) as dropActionType;
let onItemDown = SetupDrag(this.presElRef, () => p.document, this.move, dropAction, this.props.mainDocument[Id], true);
return (
- <div className={className} key={p.document[Id] + p.index}
+ <div className={className} onContextMenu={this.onContextMenu} key={p.document[Id] + p.index}
ref={this.presElRef}
onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}
onPointerDown={onItemDown}
@@ -809,7 +906,10 @@ export default class PresentationElement extends React.Component<PresentationEle
this.changeGroupStatus();
this.onGroupClick(p.document, p.index, this.selectedButtons[buttonIndex.Group]);
}}> <FontAwesomeIcon icon={"arrow-up"} /> </button>
+ <button title="Open Right" className={this.selectedButtons[buttonIndex.OpenRight] ? "presentation-interaction-selected" : "presentation-interaction"} onPointerDown={(e) => e.stopPropagation()} onClick={this.onRightTabClick}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ <br />
+ {this.renderEmbeddedInline()}
</div>
);
}
diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx
index 2d63d41b5..e853c4070 100644
--- a/src/client/views/presentationview/PresentationList.tsx
+++ b/src/client/views/presentationview/PresentationList.tsx
@@ -7,8 +7,6 @@ import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
import { NumCast, StrCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
import PresentationElement, { buttonIndex } from "./PresentationElement";
-import { DragManager } from "../../util/DragManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
import "../../../new_fields/Doc";
diff --git a/src/client/views/presentationview/PresentationModeMenu.scss b/src/client/views/presentationview/PresentationModeMenu.scss
new file mode 100644
index 000000000..336f43d20
--- /dev/null
+++ b/src/client/views/presentationview/PresentationModeMenu.scss
@@ -0,0 +1,30 @@
+.presMenu-cont {
+ position: fixed;
+ z-index: 10000;
+ height: 35px;
+ background: #323232;
+ box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
+ border-radius: 0px 6px 6px 6px;
+ overflow: hidden;
+ display: flex;
+
+ .presMenu-button {
+ background-color: transparent;
+ width: 35px;
+ height: 35px;
+ }
+
+ .presMenu-button:hover {
+ background-color: #121212;
+ }
+
+ .presMenu-dragger {
+ height: 100%;
+ transition: width .2s;
+ background-image: url("https://logodix.com/logo/1020374.png");
+ background-size: 90% 100%;
+ background-repeat: no-repeat;
+ background-position: left center;
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/presentationview/PresentationModeMenu.tsx b/src/client/views/presentationview/PresentationModeMenu.tsx
new file mode 100644
index 000000000..4de8da587
--- /dev/null
+++ b/src/client/views/presentationview/PresentationModeMenu.tsx
@@ -0,0 +1,100 @@
+import React = require("react");
+import { observable, action, runInAction } from "mobx";
+import "./PresentationModeMenu.scss";
+import { observer } from "mobx-react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+
+export interface PresModeMenuProps {
+ next: () => void;
+ back: () => void;
+ presStatus: boolean;
+ startOrResetPres: () => void;
+ closePresMode: () => void;
+}
+
+/**
+ * This class is responsible for modeling of the Presentation Mode Menu. The menu allows
+ * user to navigate through presentation elements, and start/stop the presentation.
+ */
+@observer
+export default class PresModeMenu extends React.Component<PresModeMenuProps> {
+
+ @observable private _top: number = 20;
+ @observable private _right: number = 0;
+ @observable private _opacity: number = 1;
+ @observable private _transition: string = "opacity 0.5s";
+ @observable private _transitionDelay: string = "";
+
+
+ private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+
+ /**
+ * The function that changes the coordinates of the menu, depending on the
+ * movement of the mouse when it's being dragged.
+ */
+ @action
+ dragging = (e: PointerEvent) => {
+ this._right -= e.movementX;
+ this._top += e.movementY;
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ /**
+ * The function that removes the event listeners that are responsible for
+ * dragging of the menu.
+ */
+ dragEnd = (e: PointerEvent) => {
+ document.removeEventListener("pointermove", this.dragging);
+ document.removeEventListener("pointerup", this.dragEnd);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ /**
+ * The function that starts the dragging of the presentation mode menu. When
+ * the lines on further right are clicked on.
+ */
+ dragStart = (e: React.PointerEvent) => {
+ document.removeEventListener("pointermove", this.dragging);
+ document.addEventListener("pointermove", this.dragging);
+ document.removeEventListener("pointerup", this.dragEnd);
+ document.addEventListener("pointerup", this.dragEnd);
+
+ e.stopPropagation();
+ e.preventDefault();
+ }
+
+ /**
+ * The function that is responsible for rendering the play or pause button, depending on the
+ * status of the presentation.
+ */
+ renderPlayPauseButton = () => {
+ if (this.props.presStatus) {
+ return <button title="Reset Presentation" className="presMenu-button" onClick={this.props.startOrResetPres}><FontAwesomeIcon icon="stop" /></button>;
+ } else {
+ return <button title="Start Presentation From Start" className="presMenu-button" onClick={this.props.startOrResetPres}><FontAwesomeIcon icon="play" /></button>;
+ }
+ }
+
+ render() {
+ return (
+ <div className="presMenu-cont" ref={this._mainCont}
+ style={{ right: this._right, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
+ <button title="Back" className="presMenu-button" onClick={this.props.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
+ {this.renderPlayPauseButton()}
+ <button title="Next" className="presMenu-button" onClick={this.props.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ <button className="presMenu-button" title="Close Presentation Menu" onClick={this.props.closePresMode}>
+ <FontAwesomeIcon icon="times" size="lg" />
+ </button>
+ <div className="presMenu-dragger" onPointerDown={this.dragStart} style={{ width: "20px" }} />
+ </div >
+ );
+ }
+
+
+
+
+} \ No newline at end of file
diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss
index 2bb0ec8c8..97cbd4a24 100644
--- a/src/client/views/presentationview/PresentationView.scss
+++ b/src/client/views/presentationview/PresentationView.scss
@@ -1,7 +1,7 @@
.presentationView-cont {
position: absolute;
background: white;
- z-index: 1;
+ z-index: 2;
box-shadow: #AAAAAA .2vw .2vw .4vw;
right: 0;
top: 0;
@@ -19,6 +19,17 @@
-ms-user-select: none;
user-select: none;
transition: all .1s;
+ //max-height: 250px;
+
+
+
+ .documentView-node {
+ // height: auto !important;
+ // width: aut !important;
+ position: absolute;
+ z-index: 1;
+ }
+
}
.presentationView-item-above {
@@ -55,7 +66,7 @@
padding-bottom: 3px;
font-size: 25px;
display: inline-block;
- width: calc(100% - 160px);
+ width: calc(100% - 200px);
}
.presentation-icon {
diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx
index e25725275..4fe9d3a1b 100644
--- a/src/client/views/presentationview/PresentationView.tsx
+++ b/src/client/views/presentationview/PresentationView.tsx
@@ -4,7 +4,7 @@ import { observable, action, runInAction, reaction, autorun } from "mobx";
import "./PresentationView.scss";
import { DocumentManager } from "../../util/DocumentManager";
import { Utils } from "../../../Utils";
-import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
+import { Doc, DocListCast, DocListCastAsync, WidthSym } from "../../../new_fields/Doc";
import { listSpec } from "../../../new_fields/Schema";
import { Cast, NumCast, FieldValue, PromiseValue, StrCast, BoolCast } from "../../../new_fields/Types";
import { Id } from "../../../new_fields/FieldSymbols";
@@ -12,10 +12,12 @@ import { List } from "../../../new_fields/List";
import PresentationElement, { buttonIndex } from "./PresentationElement";
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faArrowRight, faArrowLeft, faPlay, faStop, faPlus, faTimes, faMinus, faEdit } from '@fortawesome/free-solid-svg-icons';
+import { faArrowRight, faArrowLeft, faPlay, faStop, faPlus, faTimes, faMinus, faEdit, faEye } from '@fortawesome/free-solid-svg-icons';
import { Docs } from "../../documents/Documents";
import { undoBatch, UndoManager } from "../../util/UndoManager";
import PresentationViewList from "./PresentationList";
+import PresModeMenu from "./PresentationModeMenu";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
library.add(faArrowLeft);
library.add(faArrowRight);
@@ -25,6 +27,7 @@ library.add(faPlus);
library.add(faTimes);
library.add(faMinus);
library.add(faEdit);
+library.add(faEye);
export interface PresViewProps {
@@ -32,6 +35,7 @@ export interface PresViewProps {
}
const expandedWidth = 400;
+const presMinWidth = 300;
@observer
export class PresentationView extends React.Component<PresViewProps> {
@@ -62,6 +66,8 @@ export class PresentationView extends React.Component<PresViewProps> {
//Variable that holds reference to title input, so that new presentations get titles assigned.
@observable titleInputElement: HTMLInputElement | undefined;
@observable PresTitleChangeOpen: boolean = false;
+ @observable presMode: boolean = false;
+
@observable opacity = 1;
@observable persistOpacity = true;
@@ -84,6 +90,7 @@ export class PresentationView extends React.Component<PresViewProps> {
//The first lifecycle function that gets called to set up the current presentation.
async componentWillMount() {
+
this.props.Documents.forEach(async (doc, index: number) => {
//For each presentation received from mainContainer, a mapping is created.
@@ -361,11 +368,16 @@ export class PresentationView extends React.Component<PresViewProps> {
//checking if curDoc has navigation open
let curDocButtons = this.presElementsMappings.get(curDoc)!.selected;
if (curDocButtons[buttonIndex.Navigate]) {
- DocumentManager.Instance.jumpToDocument(curDoc, false);
+ this.jumpToTabOrRight(curDocButtons, curDoc);
} else if (curDocButtons[buttonIndex.Show]) {
let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]);
- //awaiting jump so that new scale can be found, since jumping is async
- await DocumentManager.Instance.jumpToDocument(curDoc, true);
+ if (curDocButtons[buttonIndex.OpenRight]) {
+ //awaiting jump so that new scale can be found, since jumping is async
+ await DocumentManager.Instance.jumpToDocument(curDoc, true);
+ } else {
+ await DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined));
+ }
+
let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc);
curDoc.viewScale = newScale;
@@ -378,9 +390,15 @@ export class PresentationView extends React.Component<PresViewProps> {
return;
}
let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]);
+ let curDocButtons = this.presElementsMappings.get(docToJump)!.selected;
- //awaiting jump so that new scale can be found, since jumping is async
- await DocumentManager.Instance.jumpToDocument(docToJump, willZoom);
+
+ if (curDocButtons[buttonIndex.OpenRight]) {
+ //awaiting jump so that new scale can be found, since jumping is async
+ await DocumentManager.Instance.jumpToDocument(docToJump, willZoom);
+ } else {
+ await DocumentManager.Instance.jumpToDocument(docToJump, willZoom, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined));
+ }
let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc);
curDoc.viewScale = newScale;
//saving the scale that user was on
@@ -391,6 +409,18 @@ export class PresentationView extends React.Component<PresViewProps> {
}
/**
+ * This function checks if right option is clicked on a presentation element, if not it does open it as a tab
+ * with help of CollectionDockingView.
+ */
+ jumpToTabOrRight = (curDocButtons: boolean[], curDoc: Doc) => {
+ if (curDocButtons[buttonIndex.OpenRight]) {
+ DocumentManager.Instance.jumpToDocument(curDoc, false);
+ } else {
+ DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined));
+ }
+ }
+
+ /**
* Async function that supposedly return the doc that is located at given index.
*/
getDocAtIndex = async (index: number) => {
@@ -434,22 +464,6 @@ export class PresentationView extends React.Component<PresViewProps> {
}
}
- //removing it from the backUp of selected Buttons
- // let castedList = Cast(this.presButtonBackUp.selectedButtonDocs, listSpec(Doc));
- // if (castedList) {
- // castedList.forEach(async (doc, indexOfDoc) => {
- // let curDoc = await doc;
- // let curDocId = StrCast(curDoc.docId);
- // if (curDocId === removedDoc[Id]) {
- // if (castedList) {
- // castedList.splice(indexOfDoc, 1);
- // return;
- // }
- // }
- // });
-
- // }
- //removing it from the backUp of selected Buttons
let castedList = Cast(this.presButtonBackUp.selectedButtonDocs, listSpec(Doc));
if (castedList) {
@@ -487,13 +501,16 @@ export class PresentationView extends React.Component<PresViewProps> {
}
}
+ /**
+ * An alternative remove method that removes a doc from presentation by its actual
+ * reference.
+ */
public removeDocByRef = (doc: Doc) => {
let indexOfDoc = this.childrenDocs.indexOf(doc);
const value = FieldValue(Cast(this.curPresentation.data, listSpec(Doc)));
if (value) {
value.splice(indexOfDoc, 1)[0];
}
- //this.RemoveDoc(indexOfDoc, true);
if (indexOfDoc !== - 1) {
return true;
}
@@ -579,18 +596,40 @@ export class PresentationView extends React.Component<PresViewProps> {
//The function that starts or resets presentaton functionally, depending on status flag.
@action
- startOrResetPres = () => {
+ startOrResetPres = async () => {
if (this.presStatus) {
this.resetPresentation();
} else {
this.presStatus = true;
- this.startPresentation(0);
+ let startIndex = await this.findStartDocument();
+ this.startPresentation(startIndex);
const current = NumCast(this.curPresentation.selectedDoc);
- this.gotoDocument(0, current);
+ this.gotoDocument(startIndex, current);
}
this.curPresentation.presStatus = this.presStatus;
}
+ /**
+ * This method is called to find the start document of presentation. So
+ * that when user presses on play, the correct presentation element will be
+ * selected.
+ */
+ findStartDocument = async () => {
+ let docAtZero = await this.getDocAtIndex(0);
+ if (docAtZero === undefined) {
+ return 0;
+ }
+ let docAtZeroPresId = StrCast(docAtZero.presentId);
+
+ if (this.groupMappings.has(docAtZeroPresId)) {
+ let group = this.groupMappings.get(docAtZeroPresId)!;
+ let lastDoc = group[group.length - 1];
+ return this.childrenDocs.indexOf(lastDoc);
+ } else {
+ return 0;
+ }
+ }
+
//The function that resets the presentation by removing every action done by it. It also
//stops the presentaton.
@action
@@ -805,60 +844,159 @@ export class PresentationView extends React.Component<PresViewProps> {
this.curPresentation.title = newTitle;
}
- addPressElem = (keyDoc: Doc, elem: PresentationElement) => {
- this.presElementsMappings.set(keyDoc, elem);
+ /**
+ * On pointer down element that is catched on resizer of te
+ * presentation view. Sets up the event listeners to change the size with
+ * mouse move.
+ */
+ _downsize = 0;
+ onPointerDown = (e: React.PointerEvent) => {
+ this._downsize = e.clientX;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointermove", this.onPointerMove);
+ document.addEventListener("pointerup", this.onPointerUp);
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ /**
+ * Changes the size of the presentation view, with mouse move.
+ * Minimum size is set to 300, so that every button is visible.
+ */
+ @action
+ onPointerMove = (e: PointerEvent) => {
+
+ this.curPresentation.width = Math.max(window.innerWidth - e.clientX, presMinWidth);
+ }
+
+ /**
+ * The method that is called on pointer up event. It checks if the button is just
+ * clicked so that presentation view will be closed. The way it's done is to check
+ * for minimal pixel change like 4, and accept it as it's just a click on top of the dragger.
+ */
+ @action
+ onPointerUp = (e: PointerEvent) => {
+ if (Math.abs(e.clientX - this._downsize) < 4) {
+ let presWidth = NumCast(this.curPresentation.width);
+ if (presWidth - presMinWidth !== 0) {
+ this.curPresentation.width = 0;
+ }
+ }
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
}
+ /**
+ * This function gets triggered on click of the dragger. It opens up the
+ * presentation view, if it was closed beforehand.
+ */
+ togglePresView = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ let width = NumCast(this.curPresentation.width);
+ if (width === 0) {
+ this.curPresentation.width = presMinWidth;
+ }
+ }
+ /**
+ * This function is a setter that opens up the
+ * presentation mode, by setting it's render flag
+ * to true. It also closes the presentation view.
+ */
+ @action
+ openPresMode = () => {
+ if (!this.presMode) {
+ this.curPresentation.width = 0;
+ this.presMode = true;
+ }
+ }
+
+ /**
+ * This function closes the presentation mode by setting its
+ * render flag to false. It also opens up the presentation view.
+ * By setting it to it's minimum size.
+ */
+ @action
+ closePresMode = () => {
+ if (this.presMode) {
+ this.presMode = false;
+ this.curPresentation.width = presMinWidth;
+ }
+
+ }
+
+ /**
+ * Function that is called to render the presentation mode, depending on its flag.
+ */
+ renderPresMode = () => {
+ if (this.presMode) {
+ return <PresModeMenu next={this.next} back={this.back} startOrResetPres={this.startOrResetPres} presStatus={this.presStatus} closePresMode={this.closePresMode} />;
+ } else {
+ return (null);
+ }
+
+ }
render() {
let width = NumCast(this.curPresentation.width);
return (
- <div className="presentationView-cont" onPointerEnter={action(() => !this.persistOpacity && (this.opacity = 1))} onPointerLeave={action(() => !this.persistOpacity && (this.opacity = 0.4))} style={{ width: width, overflow: "hidden", opacity: this.opacity, transition: "0.7s opacity ease" }}>
- <div className="presentationView-heading">
- {this.renderSelectOrPresSelection()}
- <button title="Close Presentation" className='presentation-icon' onClick={this.closePresentation}><FontAwesomeIcon icon={"times"} /></button>
- <button title="Add Presentation" className="presentation-icon" style={{ marginRight: 10 }} onClick={() => {
- runInAction(() => { if (this.PresTitleChangeOpen) { this.PresTitleChangeOpen = false; } });
- runInAction(() => this.PresTitleInputOpen ? this.PresTitleInputOpen = false : this.PresTitleInputOpen = true);
- }}><FontAwesomeIcon icon={"plus"} /></button>
- <button title="Remove Presentation" className='presentation-icon' style={{ marginRight: 10 }} onClick={this.removePresentation}><FontAwesomeIcon icon={"minus"} /></button>
- <button title="Change Presentation Title" className="presentation-icon" style={{ marginRight: 10 }} onClick={() => {
- runInAction(() => { if (this.PresTitleInputOpen) { this.PresTitleInputOpen = false; } });
- runInAction(() => this.PresTitleChangeOpen ? this.PresTitleChangeOpen = false : this.PresTitleChangeOpen = true);
- }}><FontAwesomeIcon icon={"edit"} /></button>
+ <div>
+ <div className="presentationView-cont" onPointerEnter={action(() => !this.persistOpacity && (this.opacity = 1))} onPointerLeave={action(() => !this.persistOpacity && (this.opacity = 0.4))} style={{ width: width, overflowY: "scroll", overflowX: "hidden", opacity: this.opacity, transition: "0.7s opacity ease" }}>
+ <div className="presentationView-heading">
+ {this.renderSelectOrPresSelection()}
+ <button title="Close Presentation" className='presentation-icon' onClick={this.closePresentation}><FontAwesomeIcon icon={"times"} /></button>
+ <button title="Open Presentation Mode" className="presentation-icon" style={{ marginRight: 10 }} onClick={this.openPresMode}><FontAwesomeIcon icon={"eye"} /></button>
+ <button title="Add Presentation" className="presentation-icon" style={{ marginRight: 10 }} onClick={() => {
+ runInAction(() => { if (this.PresTitleChangeOpen) { this.PresTitleChangeOpen = false; } });
+ runInAction(() => this.PresTitleInputOpen ? this.PresTitleInputOpen = false : this.PresTitleInputOpen = true);
+ }}><FontAwesomeIcon icon={"plus"} /></button>
+ <button title="Remove Presentation" className='presentation-icon' style={{ marginRight: 10 }} onClick={this.removePresentation}><FontAwesomeIcon icon={"minus"} /></button>
+ <button title="Change Presentation Title" className="presentation-icon" style={{ marginRight: 10 }} onClick={() => {
+ runInAction(() => { if (this.PresTitleInputOpen) { this.PresTitleInputOpen = false; } });
+ runInAction(() => this.PresTitleChangeOpen ? this.PresTitleChangeOpen = false : this.PresTitleChangeOpen = true);
+ }}><FontAwesomeIcon icon={"edit"} /></button>
+ </div>
+ <div className="presentation-buttons">
+ <button title="Back" className="presentation-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
+ {this.renderPlayPauseButton()}
+ <button title="Next" className="presentation-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ </div>
+
+ <PresentationViewList
+ mainDocument={this.curPresentation}
+ deleteDocument={this.RemoveDoc}
+ gotoDocument={this.gotoDocument}
+ groupMappings={this.groupMappings}
+ PresElementsMappings={this.presElementsMappings}
+ setChildrenDocs={this.setChildrenDocs}
+ presStatus={this.presStatus}
+ presButtonBackUp={this.presButtonBackUp}
+ presGroupBackUp={this.presGroupBackUp}
+ removeDocByRef={this.removeDocByRef}
+ clearElemMap={() => this.presElementsMappings.clear()}
+ />
+ <input
+ type="checkbox"
+ onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
+ this.persistOpacity = e.target.checked;
+ this.opacity = this.persistOpacity ? 1 : 0.4;
+ })}
+ checked={this.persistOpacity}
+ style={{ position: "absolute", bottom: 5, left: 5 }}
+ onPointerEnter={action(() => this.labelOpacity = 1)}
+ onPointerLeave={action(() => this.labelOpacity = 0)}
+ />
+ <p style={{ position: "absolute", bottom: 1, left: 22, opacity: this.labelOpacity, transition: "0.7s opacity ease" }}>opacity {this.persistOpacity ? "persistent" : "on focus"}</p>
</div>
- <div className="presentation-buttons">
- <button title="Back" className="presentation-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></button>
- {this.renderPlayPauseButton()}
- <button title="Next" className="presentation-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></button>
+ <div className="mainView-libraryHandle"
+ style={{ cursor: "ew-resize", right: `${width - 10}px`, backgroundColor: "white", opacity: this.opacity, transition: "0.7s opacity ease" }}
+ onPointerDown={this.onPointerDown} onClick={this.togglePresView}>
+ <span title="library View Dragger" style={{ width: "100%", height: "100%", position: "absolute" }} />
</div>
- <input
- type="checkbox"
- onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
- this.persistOpacity = e.target.checked;
- this.opacity = this.persistOpacity ? 1 : 0.4;
- })}
- checked={this.persistOpacity}
- style={{ position: "absolute", bottom: 5, left: 5 }}
- onPointerEnter={action(() => this.labelOpacity = 1)}
- onPointerLeave={action(() => this.labelOpacity = 0)}
- />
- <p style={{ position: "absolute", bottom: 1, left: 22, opacity: this.labelOpacity, transition: "0.7s opacity ease" }}>opacity {this.persistOpacity ? "persistent" : "on focus"}</p>
- <PresentationViewList
- mainDocument={this.curPresentation}
- deleteDocument={this.RemoveDoc}
- gotoDocument={this.gotoDocument}
- groupMappings={this.groupMappings}
- PresElementsMappings={this.presElementsMappings}
- setChildrenDocs={this.setChildrenDocs}
- presStatus={this.presStatus}
- presButtonBackUp={this.presButtonBackUp}
- presGroupBackUp={this.presGroupBackUp}
- removeDocByRef={this.removeDocByRef}
- clearElemMap={() => this.presElementsMappings.clear()}
- />
+ {this.renderPresMode()}
+
</div>
);
}