From 5c9f40006aa157c58ec40828ebd4845c16daa8af Mon Sep 17 00:00:00 2001 From: monikahedman Date: Wed, 21 Aug 2019 15:08:39 -0400 Subject: start of making link follow --- src/client/documents/DocumentTypes.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src/client/documents/DocumentTypes.ts') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 1578e49fe..381981e1b 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -19,4 +19,5 @@ export enum DocumentType { YOUTUBE = "youtube", DRAGBOX = "dragbox", PRES = "presentation", + LINKFOLLOW = "linkfollow", } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From d7f515f32de780884774e7bbdcc1cfe78733af45 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 30 Sep 2019 14:01:59 -0400 Subject: a bunch of changes to presentation view ... more coming. --- src/client/documents/DocumentTypes.ts | 2 +- src/client/documents/Documents.ts | 5 +- src/client/views/MainView.tsx | 1 - src/client/views/nodes/DocumentContentsView.tsx | 31 ++-- src/client/views/nodes/PresBox.tsx | 165 ++++++++------------- .../views/presentationview/PresentationElement.tsx | 19 +-- .../views/presentationview/PresentationList.tsx | 9 -- .../presentationview/PresentationModeMenu.scss | 30 ---- .../presentationview/PresentationModeMenu.tsx | 101 ------------- src/new_fields/Doc.ts | 22 ++- 10 files changed, 105 insertions(+), 280 deletions(-) delete mode 100644 src/client/views/presentationview/PresentationModeMenu.scss delete mode 100644 src/client/views/presentationview/PresentationModeMenu.tsx (limited to 'src/client/documents/DocumentTypes.ts') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 381981e1b..8ec6e9642 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -19,5 +19,5 @@ export enum DocumentType { YOUTUBE = "youtube", DRAGBOX = "dragbox", PRES = "presentation", - LINKFOLLOW = "linkfollow", + LINKFOLLOW = "linkfollow" } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index d1ec2ac39..01c36182f 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -46,8 +46,6 @@ import { ComputedField } from "../../new_fields/ScriptField"; import { ProxyField } from "../../new_fields/Proxy"; import { DocumentType } from "./DocumentTypes"; import { LinkFollowBox } from "../views/linking/LinkFollowBox"; -//import { PresBox } from "../views/nodes/PresBox"; -//import { PresField } from "../../new_fields/PresField"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -176,7 +174,7 @@ export namespace Docs { }], [DocumentType.LINKFOLLOW, { layout: { view: LinkFollowBox } - }] + }], ]); // All document prototypes are initialized with at least these values @@ -459,7 +457,6 @@ export namespace Docs { export function LinkFollowBoxDocument(options?: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LINKFOLLOW), undefined, { ...(options || {}) }); } - export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index dadff21a7..35d527c91 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -634,7 +634,6 @@ export class MainView extends React.Component { {this.mainContent} - {PresBox.miniPresentation} {this.nodesMenu()} diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 3c3cc0d91..d035cbe18 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,37 +1,34 @@ -import { computed, trace } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; +import { Doc } from "../../../new_fields/Doc"; +import { ScriptField } from "../../../new_fields/ScriptField"; +import { Cast } from "../../../new_fields/Types"; +import { OmitKeys, Without } from "../../../Utils"; +import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; +import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionSchemaView } from "../collections/CollectionSchemaView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; +import { LinkFollowBox } from "../linking/LinkFollowBox"; +import { YoutubeBox } from "./../../apis/youtube/YoutubeBox"; import { AudioBox } from "./AudioBox"; +import { ButtonBox } from "./ButtonBox"; import { DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; -import { FormattedTextBox } from "./FormattedTextBox"; -import { ImageBox } from "./ImageBox"; import { DragBox } from "./DragBox"; -import { ButtonBox } from "./ButtonBox"; -import { PresBox } from "./PresBox"; -import { LinkFollowBox } from "../linking/LinkFollowBox"; +import { FieldView, FieldViewProps } from "./FieldView"; +import { FormattedTextBox } from "./FormattedTextBox"; import { IconBox } from "./IconBox"; +import { ImageBox } from "./ImageBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; +import { PresBox } from "./PresBox"; import { VideoBox } from "./VideoBox"; -import { FieldView } from "./FieldView"; import { WebBox } from "./WebBox"; -import { YoutubeBox } from "./../../apis/youtube/YoutubeBox"; -import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox"; import React = require("react"); -import { FieldViewProps } from "./FieldView"; -import { Without, OmitKeys } from "../../../Utils"; -import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { Doc } from "../../../new_fields/Doc"; -import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { fromPromise } from "mobx-utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index d246da87a..e2dac4fd3 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2,20 +2,19 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable, runInAction, computed } from "mobx"; +import { action, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; import { BoolCast, Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; import { ContextMenu } from "../ContextMenu"; -import PresentationElement from "../presentationview/PresentationElement"; import PresentationViewList from "../presentationview/PresentationList"; import "../presentationview/PresentationView.scss"; import { FieldView, FieldViewProps } from './FieldView'; -import PresModeMenu from "../presentationview/PresentationModeMenu"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; library.add(faArrowLeft); library.add(faArrowRight); @@ -31,31 +30,13 @@ export class PresBox extends React.Component { public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(PresBox, fieldKey); } public static Instance: PresBox; - //mapping from docs to their rendered component - @observable _presElementsMappings: Map = new Map(); //variable that holds all the docs in the presentation @observable _childrenDocs: Doc[] = []; - @observable _opacity = 1; - @observable _persistOpacity = true; - @observable _labelOpacity = 0; // whether presentation view has been minimized @observable _presMode = false; @observable public static CurrentPresentation: PresBox; - @computed static get miniPresentation() { - let next = () => PresBox.CurrentPresentation.next(); - let back = () => PresBox.CurrentPresentation.back(); - let startOrResetPres = () => PresBox.CurrentPresentation.startOrResetPres(); - let closePresMode = action(() => { - PresBox.CurrentPresentation._presMode = false; - CollectionDockingView.AddRightSplit(PresBox.CurrentPresentation.props.Document, undefined); - }); - return !PresBox.CurrentPresentation || !PresBox.CurrentPresentation._presMode ? (null) : - ; - } - //initilize class variables constructor(props: FieldViewProps) { super(props); @@ -71,7 +52,7 @@ export class PresBox extends React.Component { let nextSelected = current + 1; for (; nextSelected < presDocs.length - 1; nextSelected++) { - if (!this._presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) { + if (!presDocs[nextSelected + 1].groupButton) { break; } } @@ -89,18 +70,16 @@ export class PresBox extends React.Component { let prevSelected = current; let zoomOut: boolean = false; - //checking if this presentation id is mapped to a group, if so chosing the first element in group - let presDocs = DocListCast(this.props.Document.data); + let presDocs = await DocListCastAsync(this.props.Document[this.props.fieldKey]); let currentsArray: Doc[] = []; - for (; prevSelected > 0 && presDocs[prevSelected].groupButton; prevSelected--) { + for (; presDocs && prevSelected > 0 && presDocs[prevSelected].groupButton; prevSelected--) { currentsArray.push(presDocs[prevSelected]); } prevSelected = Math.max(0, prevSelected - 1); //checking if any of the group members had used zooming in currentsArray.forEach((doc: Doc) => { - //let presElem: PresentationElement | undefined = this.presElementsMappings.get(doc); - if (this._presElementsMappings.get(doc)!.props.document.showButton) { + if (doc.showButton) { zoomOut = true; return; } @@ -109,7 +88,7 @@ export class PresBox extends React.Component { // if a group set that flag to zero or a single element //If so making sure to zoom out, which goes back to state before zooming action if (current > 0) { - if (zoomOut || this._presElementsMappings.get(docAtCurrent)!.showButton) { + if (zoomOut || docAtCurrent.showButton) { let prevScale = NumCast(this._childrenDocs[prevSelected].viewScale, null); let curScale = DocumentManager.Instance.getScaleOfDocView(this._childrenDocs[current]); if (prevScale !== undefined && prevScale !== curScale) { @@ -127,20 +106,20 @@ export class PresBox extends React.Component { * Hide Until Presented, Hide After Presented, Fade After Presented */ showAfterPresented = (index: number) => { - this._presElementsMappings.forEach((presElem, doc) => { + this._childrenDocs.forEach((doc, ind) => { //the order of cases is aligned based on priority - if (presElem.props.document.hideTillShownButton) { - if (this._childrenDocs.indexOf(doc) <= index) { + if (doc.hideTillShownButton) { + if (ind <= index) { doc.opacity = 1; } } - if (presElem.props.document.hideAfterButton) { - if (this._childrenDocs.indexOf(doc) < index) { + if (doc.hideAfterButton) { + if (ind < index) { doc.opacity = 0; } } - if (presElem.props.document.fadeButton) { - if (this._childrenDocs.indexOf(doc) < index) { + if (doc.fadeButton) { + if (ind < index) { doc.opacity = 0.5; } } @@ -153,21 +132,21 @@ export class PresBox extends React.Component { * Hide Until Presented, Hide After Presented, Fade After Presented */ hideIfNotPresented = (index: number) => { - this._presElementsMappings.forEach((presElem, key) => { + this._childrenDocs.forEach((key, ind) => { //the order of cases is aligned based on priority - if (presElem.props.document.hideAfterButton) { - if (this._childrenDocs.indexOf(key) >= index) { + if (key.hideAfterButton) { + if (ind >= index) { key.opacity = 1; } } - if (presElem.props.document.fadeButton) { - if (this._childrenDocs.indexOf(key) >= index) { + if (key.fadeButton) { + if (ind >= index) { key.opacity = 1; } } - if (presElem.props.document.hideTillShownButton) { - if (this._childrenDocs.indexOf(key) > index) { + if (key.hideTillShownButton) { + if (ind > index) { key.opacity = 0; } } @@ -187,18 +166,18 @@ export class PresBox extends React.Component { let nextSelected = presDocs.indexOf(curDoc); let currentDocGroups: Doc[] = []; for (; nextSelected < presDocs.length - 1; nextSelected++) { - if (!this._presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) { + if (!presDocs[nextSelected + 1].groupButton) { break; } currentDocGroups.push(presDocs[nextSelected]); } currentDocGroups.forEach((doc: Doc, index: number) => { - if (this._presElementsMappings.get(doc)!.navButton) { + if (doc.navButton) { docToJump = doc; willZoom = false; } - if (this._presElementsMappings.get(doc)!.showButton) { + if (doc.showButton) { docToJump = doc; willZoom = true; } @@ -207,9 +186,9 @@ export class PresBox extends React.Component { //docToJump stayed same meaning, it was not in the group or was the last element in the group if (docToJump === curDoc) { //checking if curDoc has navigation open - if (this._presElementsMappings.get(curDoc)!.navButton) { + if (curDoc.navButton) { DocumentManager.Instance.jumpToDocument(curDoc, false); - } else if (this._presElementsMappings.get(curDoc)!.showButton) { + } else if (curDoc.showButton) { 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); @@ -250,15 +229,13 @@ export class PresBox extends React.Component { } /** - * The function that removes a doc from a presentation. It also makes sure to - * do necessary updates to backUps and mappings stored locally. + * The function that removes a doc from a presentation. */ @action public RemoveDoc = async (index: number) => { const value = FieldValue(Cast(this.props.Document.data, listSpec(Doc))); // don't replace with DocListCast -- we need to modify the document's actual stored list if (value) { - //removing the Presentation Element from the document and update mappings - this._presElementsMappings.delete(await value.splice(index, 1)[0]); + value.splice(index, 1); } } @@ -302,14 +279,6 @@ export class PresBox extends React.Component { this._childrenDocs = docList; } - //The function that is called to render the play or pause button depending on - //if presentation is running or not. - renderPlayPauseButton = () => { - return ; - } - //The function that starts or resets presentaton functionally, depending on status flag. @action startOrResetPres = () => { @@ -340,18 +309,18 @@ export class PresBox extends React.Component { //The function that starts the presentation, also checking if actions should be applied //directly at start. startPresentation = (startIndex: number) => { - this._presElementsMappings.forEach((component, doc) => { - if (component.props.document.hideTillShownButton) { + this._childrenDocs.map(doc => { + if (doc.hideTillShownButton) { if (this._childrenDocs.indexOf(doc) > startIndex) { doc.opacity = 0; } } - if (component.props.document.hideAfterButton) { + if (doc.hideAfterButton) { if (this._childrenDocs.indexOf(doc) < startIndex) { doc.opacity = 0; } } - if (component.props.document.fadeButton) { + if (doc.fadeButton) { if (this._childrenDocs.indexOf(doc) < startIndex) { doc.opacity = 0.5; } @@ -359,13 +328,18 @@ export class PresBox extends React.Component { }); } - addPressElem = (keyDoc: Doc, elem: PresentationElement) => { - this._presElementsMappings.set(keyDoc, elem); - } - - minimize = undoBatch(action(() => { - this._presMode = true; - this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close"); + toggleMinimize = undoBatch(action((e: React.PointerEvent) => { + if (this.props.Document.minimizedView) { + this.props.Document.minimizedView = false; + Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), "data", this.props.Document); + CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc); + } else { + this.props.Document.minimizedView = true; + this.props.Document.x = e.clientX + 25; + this.props.Document.y = e.clientY - 25; + this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close"); + Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), "data", this.props.Document); + } })); specificContextMenu = (e: React.MouseEvent): void => { @@ -374,37 +348,24 @@ export class PresBox extends React.Component { render() { return ( -
!this._persistOpacity && (this._opacity = 1))} onContextMenu={this.specificContextMenu} - onPointerLeave={action(() => !this._persistOpacity && (this._opacity = 0.4))} - style={{ width: "100%", opacity: this._opacity, }}> -
- - {this.renderPlayPauseButton()} - - +
+
+ + + +
- ) => { - 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)} - /> -

opacity {this._persistOpacity ? "persistent" : "on focus"}

- this._presElementsMappings.clear()} - /> + {this.props.Document.minimizedView ? (null) : + }
); } diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 126d62c52..6e8c28d34 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 { faArrowRight, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed } from "mobx"; import { observer } from "mobx-react"; @@ -22,7 +22,7 @@ library.add(fileSolid); library.add(faLocationArrow); library.add(fileRegular as any); library.add(faSearch); -library.add(faArrowRight); +library.add(faArrowDown); interface PresentationElementProps { mainDocument: Doc; @@ -33,7 +33,6 @@ interface PresentationElementProps { allListElements: Doc[]; presStatus: boolean; removeDocByRef(doc: Doc): boolean; - PresElementsMappings: Map; } /** @@ -59,14 +58,14 @@ export default class PresentationElement extends React.Component { + onExpandTabClick = (e: React.MouseEvent) => { e.stopPropagation(); - - this.openRightButton = !this.openRightButton; + this.embedInline = !this.embedInline } /** @@ -416,7 +413,7 @@ export default class PresentationElement extends React.Component e.stopPropagation()} onClick={this.onFadeDocumentAfterPresentedClick}> - +
{this.renderEmbeddedInline()} diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx index da48a856a..483461e5a 100644 --- a/src/client/views/presentationview/PresentationList.tsx +++ b/src/client/views/presentationview/PresentationList.tsx @@ -12,11 +12,9 @@ interface PresListProps { mainDocument: Doc; deleteDocument(index: number): void; gotoDocument(index: number, fromDoc: number): Promise; - PresElementsMappings: Map; setChildrenDocs: (docList: Doc[]) => void; presStatus: boolean; removeDocByRef(doc: Doc): boolean; - clearElemMap(): void; } @@ -45,16 +43,10 @@ export default class PresentationViewList extends React.Component const children = DocListCast(this.props.mainDocument.data); this.initializeScaleViews(children); this.props.setChildrenDocs(children); - this.props.clearElemMap(); return (
{children.map((doc: Doc, index: number) => { - if (e && e !== null) { - this.props.PresElementsMappings.set(doc, e); - } - }} key={doc[Id]} mainDocument={this.props.mainDocument} document={doc} @@ -64,7 +56,6 @@ export default class PresentationViewList extends React.Component allListElements={children} presStatus={this.props.presStatus} removeDocByRef={this.props.removeDocByRef} - PresElementsMappings={this.props.PresElementsMappings} /> )}
diff --git a/src/client/views/presentationview/PresentationModeMenu.scss b/src/client/views/presentationview/PresentationModeMenu.scss deleted file mode 100644 index 336f43d20..000000000 --- a/src/client/views/presentationview/PresentationModeMenu.scss +++ /dev/null @@ -1,30 +0,0 @@ -.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 deleted file mode 100644 index e4123a1fe..000000000 --- a/src/client/views/presentationview/PresentationModeMenu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -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 { - - @observable private _top: number = 20; - @observable private _left: number = window.innerWidth - 160; - @observable private _opacity: number = 1; - @observable private _transition: string = "opacity 0.5s"; - @observable private _transitionDelay: string = ""; - private _offsetY: number = 0; - private _offsetX: number = 0; - - - private _mainCont: React.RefObject = 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._left = e.pageX - this._offsetX; - this._top = e.pageY - this._offsetY; - - 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); - - this._offsetX = this._mainCont.current!.getBoundingClientRect().width - e.nativeEvent.offsetX; - this._offsetY = e.nativeEvent.offsetY; - - 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 ; - } else { - return ; - } - } - - render() { - return ( -
- - {this.renderPlayPauseButton()} - - -
-
- ); - } -} \ No newline at end of file diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 79b73aba8..4a03fed08 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -337,11 +337,25 @@ export namespace Doc { export function IndexOf(toFind: Doc, list: Doc[]) { return list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); } - export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { - if (target[key] === undefined) { - Doc.GetProto(target)[key] = new List(); + export function RemoveDocFromList(listDoc: Doc, key: string, doc: Doc) { + if (listDoc[key] === undefined) { + Doc.GetProto(listDoc)[key] = new List(); } - let list = Cast(target[key], listSpec(Doc)); + let list = Cast(listDoc[key], listSpec(Doc)); + if (list) { + let ind = list.indexOf(doc); + if (ind !== -1) { + list.splice(ind, 1); + return true; + } + } + return false; + } + export function AddDocToList(listDoc: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { + if (listDoc[key] === undefined) { + Doc.GetProto(listDoc)[key] = new List(); + } + let list = Cast(listDoc[key], listSpec(Doc)); if (list) { if (allowDuplicates !== true) { let pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1); -- cgit v1.2.3-70-g09d2 From 65d9b92bcadbecb6e7dd55930f96f228c6a2f4f7 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 30 Sep 2019 17:12:28 -0400 Subject: simpliified presentations to be a PresBox with PresElementBoxes. --- src/client/documents/DocumentTypes.ts | 3 +- src/client/documents/Documents.ts | 10 +- .../views/collections/CollectionDockingView.tsx | 9 +- src/client/views/linking/LinkMenuItem.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/PresBox.scss | 33 ++ src/client/views/nodes/PresBox.tsx | 189 +++++---- .../views/presentationview/PresElementBox.scss | 75 ++++ .../views/presentationview/PresElementBox.tsx | 329 ++++++++++++++++ .../views/presentationview/PresentationElement.tsx | 423 --------------------- .../views/presentationview/PresentationList.tsx | 64 ---- .../views/presentationview/PresentationView.scss | 113 ------ 12 files changed, 545 insertions(+), 708 deletions(-) create mode 100644 src/client/views/nodes/PresBox.scss create mode 100644 src/client/views/presentationview/PresElementBox.scss create mode 100644 src/client/views/presentationview/PresElementBox.tsx delete mode 100644 src/client/views/presentationview/PresentationElement.tsx delete mode 100644 src/client/views/presentationview/PresentationList.tsx delete mode 100644 src/client/views/presentationview/PresentationView.scss (limited to 'src/client/documents/DocumentTypes.ts') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 8ec6e9642..e5d5885cd 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -19,5 +19,6 @@ export enum DocumentType { YOUTUBE = "youtube", DRAGBOX = "dragbox", PRES = "presentation", - LINKFOLLOW = "linkfollow" + LINKFOLLOW = "linkfollow", + PRESELEMENT = "preselement" } \ No newline at end of file diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 01c36182f..0d04d044e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,7 +1,6 @@ import { HistogramField } from "../northstar/dash-fields/HistogramField"; import { HistogramBox } from "../northstar/dash-nodes/HistogramBox"; import { HistogramOperation } from "../northstar/operations/HistogramOperation"; -import { CollectionPDFView } from "../views/collections/CollectionPDFView"; import { CollectionVideoView } from "../views/collections/CollectionVideoView"; import { CollectionView } from "../views/collections/CollectionView"; import { CollectionViewType } from "../views/collections/CollectionBaseView"; @@ -46,6 +45,7 @@ import { ComputedField } from "../../new_fields/ScriptField"; import { ProxyField } from "../../new_fields/Proxy"; import { DocumentType } from "./DocumentTypes"; import { LinkFollowBox } from "../views/linking/LinkFollowBox"; +import { PresElementBox } from "../views/presentationview/PresElementBox"; var requestImageSize = require('../util/request-image-size'); var path = require('path'); @@ -175,6 +175,9 @@ export namespace Docs { [DocumentType.LINKFOLLOW, { layout: { view: LinkFollowBox } }], + [DocumentType.PRESELEMENT, { + layout: { view: PresElementBox } + }], ]); // All document prototypes are initialized with at least these values @@ -457,6 +460,11 @@ export namespace Docs { export function LinkFollowBoxDocument(options?: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.LINKFOLLOW), undefined, { ...(options || {}) }); } + + export function PresElementBoxDocument(options?: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) }); + } + export function DockDocument(documents: Array, config: string, options: DocumentOptions, id?: string) { return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, viewType: CollectionViewType.Docking, dockingConfig: config }, id); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 963851a12..d83530d4f 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -31,6 +31,8 @@ import { SubCollectionViewProps } from "./CollectionSubView"; import React = require("react"); import { ButtonSelector } from './ParentDocumentSelector'; import { DocumentType } from '../../documents/DocumentTypes'; +import { compileFunction } from 'vm'; +import { ComputedField } from '../../../new_fields/ScriptField'; library.add(faFile); const _global = (window /* browser */ || global /* node */) as any; @@ -571,11 +573,14 @@ export class DockedFrameRenderer extends React.Component { //add this new doc to props.Document let curPres = Cast(CurrentUserUtils.UserDocument.curPresentation, Doc) as Doc; if (curPres) { + let pinDoc = Docs.Create.PresElementBoxDocument(); + Doc.GetProto(pinDoc).target = doc; + Doc.GetProto(pinDoc).title = ComputedField.MakeFunction('(this.target instanceof Doc) && this.target.title.toString()'); const data = Cast(curPres.data, listSpec(Doc)); if (data) { - data.push(doc); + data.push(pinDoc); } else { - curPres.data = new List([doc]); + curPres.data = new List([pinDoc]); } if (!DocumentManager.Instance.getDocumentView(curPres)) { this.addDocTab(curPres, undefined, "onRight"); diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index e5a4a68bf..a6ee9c2c6 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -95,7 +95,7 @@ export class LinkMenuItem extends React.Component { @action.bound async followDefault() { if (LinkFollowBox.Instance !== undefined) { - LinkFollowBox.setAddDocTab(this.props.addDocTab);; + LinkFollowBox.setAddDocTab(this.props.addDocTab); LinkFollowBox.Instance.setLinkDocs(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc); LinkFollowBox.Instance.defaultLinkBehavior(); } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index d035cbe18..75dd27f46 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -26,6 +26,7 @@ import { ImageBox } from "./ImageBox"; import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { PresBox } from "./PresBox"; +import { PresElementBox } from "../presentationview/PresElementBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import React = require("react"); @@ -100,7 +101,7 @@ export class DocumentContentsView extends React.Component { public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(PresBox, fieldKey); } - public static Instance: PresBox; - //variable that holds all the docs in the presentation - @observable _childrenDocs: Doc[] = []; - - // whether presentation view has been minimized - @observable _presMode = false; - @observable public static CurrentPresentation: PresBox; - - //initilize class variables - constructor(props: FieldViewProps) { - super(props); - runInAction(() => PresBox.CurrentPresentation = this); - } + @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); } next = async () => { const current = NumCast(this.props.Document.selectedDoc); @@ -89,8 +78,8 @@ export class PresBox extends React.Component { //If so making sure to zoom out, which goes back to state before zooming action if (current > 0) { if (zoomOut || docAtCurrent.showButton) { - let prevScale = NumCast(this._childrenDocs[prevSelected].viewScale, null); - let curScale = DocumentManager.Instance.getScaleOfDocView(this._childrenDocs[current]); + let prevScale = NumCast(this.childDocs[prevSelected].viewScale, null); + let curScale = DocumentManager.Instance.getScaleOfDocView(this.childDocs[current]); if (prevScale !== undefined && prevScale !== curScale) { DocumentManager.Instance.zoomIntoScale(docAtCurrent, prevScale); } @@ -106,22 +95,16 @@ export class PresBox extends React.Component { * Hide Until Presented, Hide After Presented, Fade After Presented */ showAfterPresented = (index: number) => { - this._childrenDocs.forEach((doc, ind) => { + this.childDocs.forEach((doc, ind) => { //the order of cases is aligned based on priority - if (doc.hideTillShownButton) { - if (ind <= index) { - doc.opacity = 1; - } + if (doc.hideTillShownButton && ind <= index) { + (doc.target as Doc).opacity = 1; } - if (doc.hideAfterButton) { - if (ind < index) { - doc.opacity = 0; - } + if (doc.hideAfterButton && ind < index) { + (doc.target as Doc).opacity = 0; } - if (doc.fadeButton) { - if (ind < index) { - doc.opacity = 0.5; - } + if (doc.fadeButton && ind < index) { + (doc.target as Doc).opacity = 0.5; } }); } @@ -132,23 +115,17 @@ export class PresBox extends React.Component { * Hide Until Presented, Hide After Presented, Fade After Presented */ hideIfNotPresented = (index: number) => { - this._childrenDocs.forEach((key, ind) => { + this.childDocs.forEach((key, ind) => { //the order of cases is aligned based on priority - if (key.hideAfterButton) { - if (ind >= index) { - key.opacity = 1; - } + if (key.hideAfterButton && ind >= index) { + (key.target as Doc).opacity = 1; } - if (key.fadeButton) { - if (ind >= index) { - key.opacity = 1; - } + if (key.fadeButton && ind >= index) { + (key.target as Doc).opacity = 1; } - if (key.hideTillShownButton) { - if (ind > index) { - key.opacity = 0; - } + if (key.hideTillShownButton && ind > index) { + (key.target as Doc).opacity = 0; } }); } @@ -158,11 +135,12 @@ export class PresBox extends React.Component { * has the option open and last in the group. If not in the group, and it has * te option open, navigates to that element. */ - navigateToElement = async (curDoc: Doc, fromDoc: number) => { + navigateToElement = async (curDoc: Doc, fromDocIndex: number) => { + let fromDoc = this.childDocs[fromDocIndex].target as Doc; let docToJump = curDoc; let willZoom = false; - let presDocs = DocListCast(this.props.Document.data); + let presDocs = DocListCast(this.props.Document[this.props.fieldKey]); let nextSelected = presDocs.indexOf(curDoc); let currentDocGroups: Doc[] = []; for (; nextSelected < presDocs.length - 1; nextSelected++) { @@ -186,31 +164,32 @@ export class PresBox extends React.Component { //docToJump stayed same meaning, it was not in the group or was the last element in the group if (docToJump === curDoc) { //checking if curDoc has navigation open + let target = await curDoc.target as Doc; if (curDoc.navButton) { - DocumentManager.Instance.jumpToDocument(curDoc, false); + DocumentManager.Instance.jumpToDocument(target, false); } else if (curDoc.showButton) { - let curScale = DocumentManager.Instance.getScaleOfDocView(this._childrenDocs[fromDoc]); + let curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(curDoc, true); - curDoc.viewScale = DocumentManager.Instance.getScaleOfDocView(curDoc); + await DocumentManager.Instance.jumpToDocument(target, true); + curDoc.viewScale = DocumentManager.Instance.getScaleOfDocView(target); //saving the scale user was on before zooming in if (curScale !== 1) { - this._childrenDocs[fromDoc].viewScale = curScale; + fromDoc.viewScale = curScale; } } return; } - let curScale = DocumentManager.Instance.getScaleOfDocView(this._childrenDocs[fromDoc]); + let curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(docToJump, willZoom); - let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); + await DocumentManager.Instance.jumpToDocument(await docToJump.target as Doc, willZoom); + let newScale = DocumentManager.Instance.getScaleOfDocView(await curDoc.target as Doc); curDoc.viewScale = newScale; //saving the scale that user was on if (curScale !== 1) { - this._childrenDocs[fromDoc].viewScale = curScale; + fromDoc.viewScale = curScale; } } @@ -219,34 +198,25 @@ export class PresBox extends React.Component { * Async function that supposedly return the doc that is located at given index. */ getDocAtIndex = async (index: number) => { - const list = FieldValue(Cast(this.props.Document.data, listSpec(Doc))); + const list = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); if (list && index >= 0 && index < list.length) { this.props.Document.selectedDoc = index; //awaiting async call to finish to get Doc instance - return await list[index]; + return list[index]; } - return undefined + return undefined; } - /** - * The function that removes a doc from a presentation. - */ - @action - public RemoveDoc = async (index: number) => { - const value = FieldValue(Cast(this.props.Document.data, listSpec(Doc))); // don't replace with DocListCast -- we need to modify the document's actual stored list - if (value) { - value.splice(index, 1); - } - } - public removeDocByRef = (doc: Doc) => { - let indexOfDoc = this._childrenDocs.indexOf(doc); + @undoBatch + public removeDocument = (doc: Doc) => { const value = FieldValue(Cast(this.props.Document.data, listSpec(Doc))); if (value) { - value.splice(indexOfDoc, 1)[0]; - } - if (indexOfDoc !== - 1) { - return true; + let indexOfDoc = value.indexOf(doc); + if (indexOfDoc !== - 1) { + value.splice(indexOfDoc, 1)[0]; + return true; + } } return false; } @@ -256,7 +226,7 @@ export class PresBox extends React.Component { @action public gotoDocument = async (index: number, fromDoc: number) => { Doc.UnBrushAllDocs(); - const list = FieldValue(Cast(this.props.Document.data, listSpec(Doc))); + const list = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); if (list && index >= 0 && index < list.length) { this.props.Document.selectedDoc = index; @@ -273,11 +243,6 @@ export class PresBox extends React.Component { } } } - //Function that sets the store of the children docs. - @action - setChildrenDocs = (docList: Doc[]) => { - this._childrenDocs = docList; - } //The function that starts or resets presentaton functionally, depending on status flag. @action @@ -295,33 +260,33 @@ export class PresBox extends React.Component { //stops the presentaton. @action resetPresentation = () => { - this._childrenDocs.forEach((doc: Doc) => { + this.childDocs.forEach((doc: Doc) => { doc.opacity = 1; doc.viewScale = 1; }); this.props.Document.selectedDoc = 0; this.props.Document.presStatus = false; - if (this._childrenDocs.length !== 0) { - DocumentManager.Instance.zoomIntoScale(this._childrenDocs[0], 1); + if (this.childDocs.length !== 0) { + DocumentManager.Instance.zoomIntoScale(this.childDocs[0], 1); } } //The function that starts the presentation, also checking if actions should be applied //directly at start. startPresentation = (startIndex: number) => { - this._childrenDocs.map(doc => { + this.childDocs.map(doc => { if (doc.hideTillShownButton) { - if (this._childrenDocs.indexOf(doc) > startIndex) { + if (this.childDocs.indexOf(doc) > startIndex) { doc.opacity = 0; } } if (doc.hideAfterButton) { - if (this._childrenDocs.indexOf(doc) < startIndex) { + if (this.childDocs.indexOf(doc) < startIndex) { doc.opacity = 0; } } if (doc.fadeButton) { - if (this._childrenDocs.indexOf(doc) < startIndex) { + if (this.childDocs.indexOf(doc) < startIndex) { doc.opacity = 0.5; } } @@ -346,26 +311,46 @@ export class PresBox extends React.Component { ContextMenu.Instance.addItem({ description: "Make Current Presentation", event: action(() => Doc.UserDoc().curPresentation = this.props.Document), icon: "asterisk" }); } + /** + * Initially every document starts with a viewScale 1, which means + * that they will be displayed in a canvas with scale 1. + */ + @action + initializeScaleViews = (docList: Doc[]) => { + docList.forEach((doc: Doc) => { + let curScale = NumCast(doc.viewScale, null); + if (curScale === undefined) { + doc.viewScale = 1; + } + }); + } + render() { + this.initializeScaleViews(this.childDocs); return ( -
-
- - + - - + +
{this.props.Document.minimizedView ? (null) : - } +
+ {this.childDocs.map((doc, index) => + + )} +
}
); } diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss new file mode 100644 index 000000000..c7d846718 --- /dev/null +++ b/src/client/views/presentationview/PresElementBox.scss @@ -0,0 +1,75 @@ +.presElementBox-item { + padding: 10px; + display: inline-block; + width: 100%; + outline-color: maroon; + outline-style: dashed; + -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; + + .documentView-node { + position: absolute; + z-index: 1; + } +} + +.presElementBox-item-above { + border-top: black 2px solid; +} + +.presElementBox-item-below { + border-bottom: black 2px solid; +} + +.presElementBox-item:hover { + transition: all .1s; + background: #AAAAAA; + border-radius: 12px; +} + +.presElementBox-selected { + background: gray; + color: black; + border-radius: 12px; + box-shadow: black 2px 2px 5px; +} + + +.presElementBox-icon { + float: right; +} + +.presElementBox-interaction { + color: gray; + float: left; +} + +.presElementBox-interaction-selected { + color: white; + float: left; +} + +.presElementBox-name { + font-size: 15px; + display: inline-block; +} + +.presElementBox-embedded { + position: relative; + margin-top: 15; +} + +.presElementBox-embeddedMask { + width:100%; + height:100%; + position: absolute; + left:0; + top:0; + background: transparent; + z-index:2; +} \ No newline at end of file diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx new file mode 100644 index 000000000..fe2aea27b --- /dev/null +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -0,0 +1,329 @@ +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons'; +import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Doc } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/FieldSymbols"; +import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types"; +import { emptyFunction, returnEmptyString, returnFalse, returnOne } from "../../../Utils"; +import { DocumentType } from "../../documents/DocumentTypes"; +import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; +import { SelectionManager } from "../../util/SelectionManager"; +import { Transform } from "../../util/Transform"; +import { DocumentView } from "../nodes/DocumentView"; +import React = require("react"); +import "./PresElementBox.scss"; +import { FieldViewProps, FieldView } from '../nodes/FieldView'; + + +library.add(faArrowUp); +library.add(fileSolid); +library.add(faLocationArrow); +library.add(fileRegular as any); +library.add(faSearch); +library.add(faArrowDown); + +interface PresElementProps { + presentationDoc: Doc; + index: number; + gotoDocument(index: number, fromDoc: number): Promise; +} + +/** + * This class models the view a document added to presentation will have in the presentation. + * It involves some functionality for its buttons and options. + */ +@observer +export class PresElementBox extends React.Component { + + public static LayoutString() { return FieldView.LayoutString(PresElementBox); } + private header?: HTMLDivElement | undefined; + private listdropDisposer?: DragManager.DragDropDisposer; + private presElRef: React.RefObject = React.createRef(); + + @computed get currentIndex() { return NumCast(this.props.presentationDoc.selectedDoc); } + @computed get showButton() { return BoolCast(this.props.Document.showButton); } + @computed get navButton() { return BoolCast(this.props.Document.navButton); } + @computed get hideTillShownButton() { return BoolCast(this.props.Document.hideTillShownButton); } + @computed get fadeButton() { return BoolCast(this.props.Document.fadeButton); } + @computed get hideAfterButton() { return BoolCast(this.props.Document.hideAfterButton); } + @computed get groupButton() { return BoolCast(this.props.Document.groupButton); } + @computed get embedInline() { return BoolCast(this.props.Document.embedOpen); } + + set embedInline(value: boolean) { this.props.Document.embedOpen = value; } + set showButton(val: boolean) { this.props.Document.showButton = val; } + set navButton(val: boolean) { this.props.Document.navButton = val; } + set hideTillShownButton(val: boolean) { this.props.Document.hideTillShownButton = val; } + set fadeButton(val: boolean) { this.props.Document.fadeButton = val; } + set hideAfterButton(val: boolean) { this.props.Document.hideAfterButton = val; } + set groupButton(val: boolean) { this.props.Document.groupButton = val; } + + //Lifecycle function that makes sure that button BackUp is received when mounted. + componentDidMount() { + if (this.presElRef.current) { + this.header = this.presElRef.current; + this.createListDropTarget(this.presElRef.current); + } + } + + componentWillUnmount() { + this.listdropDisposer && this.listdropDisposer(); + } + /** + * The function that is called on click to turn Hiding document till press option on/off. + * It also sets the beginning and end opacitys. + */ + @action + onHideDocumentUntilPressClick = (e: React.MouseEvent) => { + e.stopPropagation(); + this.hideTillShownButton = !this.hideTillShownButton; + if (!this.hideTillShownButton) { + if (this.props.index >= this.currentIndex) { + (this.props.Document.target as Doc).opacity = 1; + } + } else { + if (this.props.presentationDoc.presStatus) { + if (this.props.index > this.currentIndex) { + (this.props.Document.target as Doc).opacity = 0; + } + } + } + } + + /** + * The function that is called on click to turn Hiding document after presented option on/off. + * It also makes sure that the option swithches from fade-after to this one, since both + * can't coexist. + */ + @action + onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => { + e.stopPropagation(); + this.hideAfterButton = !this.hideAfterButton; + if (!this.hideAfterButton) { + if (this.props.index <= this.currentIndex) { + (this.props.Document.target as Doc).opacity = 1; + } + } else { + if (this.fadeButton) this.fadeButton = false; + if (this.props.presentationDoc.presStatus) { + if (this.props.index < this.currentIndex) { + (this.props.Document.target as Doc).opacity = 0; + } + } + } + } + + /** + * The function that is called on click to turn fading document after presented option on/off. + * It also makes sure that the option swithches from hide-after to this one, since both + * can't coexist. + */ + @action + onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => { + e.stopPropagation(); + this.fadeButton = !this.fadeButton; + if (!this.fadeButton) { + if (this.props.index <= this.currentIndex) { + (this.props.Document.target as Doc).opacity = 1; + } + } else { + this.hideAfterButton = false; + if (this.props.presentationDoc.presStatus) { + if (this.props.index < this.currentIndex) { + (this.props.Document.target as Doc).opacity = 0.5; + } + } + } + } + + /** + * The function that is called on click to turn navigation option of docs on/off. + */ + @action + onNavigateDocumentClick = (e: React.MouseEvent) => { + e.stopPropagation(); + this.navButton = !this.navButton; + if (this.navButton) { + this.showButton = false; + if (this.currentIndex === this.props.index) { + this.props.gotoDocument(this.props.index, this.props.index); + } + } + } + + /** + * The function that is called on click to turn zoom option of docs on/off. + */ + @action + onZoomDocumentClick = (e: React.MouseEvent) => { + e.stopPropagation(); + + this.showButton = !this.showButton; + if (!this.showButton) { + this.props.Document.viewScale = 1; + } else { + this.navButton = false; + if (this.currentIndex === this.props.index) { + this.props.gotoDocument(this.props.index, this.props.index); + } + } + } + + /** + * Creating a drop target for drag and drop when called. + */ + protected createListDropTarget = (ele: HTMLDivElement) => { + this.listdropDisposer && this.listdropDisposer(); + ele && (this.listdropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.listDrop.bind(this) } })); + } + + /** + * Returns a local transformed coordinate array for given coordinates. + */ + ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord]; + + /** + * This method is called when a element is dropped on a already esstablished target. + * It makes sure to do appropirate action depending on if the item is dropped before + * or after the target. + */ + listDrop = async (e: Event, de: DragManager.DropEvent) => { + let x = this.ScreenToLocalListTransform(de.x, de.y); + let rect = this.header!.getBoundingClientRect(); + let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2); + let before = x[1] < bounds[1]; + if (de.data instanceof DragManager.DocumentDragData) { + let addDoc = (doc: Doc) => Doc.AddDocToList(this.props.presentationDoc, "data", doc, this.props.Document, before); + e.stopPropagation(); + //where does treeViewId come from + let movedDocs = (de.data.options === this.props.presentationDoc[Id] ? de.data.draggedDocuments : de.data.droppedDocuments); + //console.log("How is this causing an issue"); + document.removeEventListener("pointermove", this.onDragMove, true); + return (de.data.dropAction || de.data.userDropAction) ? + de.data.droppedDocuments.reduce((added: boolean, d: Doc) => Doc.AddDocToList(this.props.presentationDoc, "data", d, this.props.Document, before) || added, false) + : (de.data.moveDocument) ? + movedDocs.reduce((added: boolean, d: Doc) => de.data.moveDocument(d, this.props.Document, addDoc) || added, false) + : de.data.droppedDocuments.reduce((added: boolean, d: Doc) => Doc.AddDocToList(this.props.presentationDoc, "data", d, this.props.Document, before), false); + } + document.removeEventListener("pointermove", this.onDragMove, true); + + return false; + } + + //This is used to add dragging as an event. + onPointerEnter = (e: React.PointerEvent): void => { + if (e.buttons === 1 && SelectionManager.GetIsDragging()) { + this.header!.className = "presElementBox-item" + (this.currentIndex === this.props.index ? "presElementBox-selected" : ""); + + document.addEventListener("pointermove", this.onDragMove, true); + } + } + + //This is used to remove the dragging when dropped. + onPointerLeave = (e: React.PointerEvent): void => { + this.header!.className = "presElementBox-item" + (this.currentIndex === this.props.index ? " presElementBox-selected" : ""); + + document.removeEventListener("pointermove", this.onDragMove, true); + } + + /** + * This method is passed in to be used when dragging a document. + * It makes it possible to show dropping lines on drop targets. + */ + onDragMove = (e: PointerEvent): void => { + Doc.UnBrushDoc(this.props.Document); + let x = this.ScreenToLocalListTransform(e.clientX, e.clientY); + let rect = this.header!.getBoundingClientRect(); + let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2); + this.header!.className = "presElementBox-item presElementBox-item-" + (x[1] < bounds[1] ? "above" : "below"); + e.stopPropagation(); + } + + /** + * This method is passed in to on down event of presElement, so that drag and + * drop can be completed with DragManager functionality. + */ + @action + move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => { + return this.props.Document !== target && (this.props.removeDocument ? this.props.removeDocument(doc) : false) && addDoc(doc); + } + + /** + * The function that is responsible for rendering the a preview or not for this + * presentation element. + */ + renderEmbeddedInline = () => { + if (!this.embedInline || !(this.props.Document.target instanceof Doc)) { + return (null); + } + + let propDocWidth = NumCast(this.props.Document.nativeWidth); + let propDocHeight = NumCast(this.props.Document.nativeHeight); + let scale = () => 175 / NumCast(this.props.Document.nativeWidth, 175); + return ( +
+ 350} + PanelHeight={() => 90} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnFalse} + whenActiveChanged={returnFalse} + bringToFront={emptyFunction} + zoomToScale={emptyFunction} + getScale={returnOne} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + ContentScaling={scale} + /> +
+
+ ); + } + + render() { + let p = this.props; + + let className = "presElementBox-item" + (this.currentIndex === p.index ? " presElementBox-selected" : ""); + let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; + let onItemDown = SetupDrag(this.presElRef, () => p.Document, this.move, dropAction, this.props.presentationDoc[Id], true); + return ( +
p.gotoDocument(p.index, this.currentIndex)}> + + {`${p.index + 1}. ${p.Document.title}`} + + +
+ + + + + + + + +
+ {this.renderEmbeddedInline()} +
+ ); + } +} \ No newline at end of file diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx deleted file mode 100644 index 6e8c28d34..000000000 --- a/src/client/views/presentationview/PresentationElement.tsx +++ /dev/null @@ -1,423 +0,0 @@ -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons'; -import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed } from "mobx"; -import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, returnOne } from "../../../Utils"; -import { DocumentType } from "../../documents/DocumentTypes"; -import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; -import { SelectionManager } from "../../util/SelectionManager"; -import { Transform } from "../../util/Transform"; -import { ContextMenu } from "../ContextMenu"; -import { DocumentView } from "../nodes/DocumentView"; -import React = require("react"); - - -library.add(faArrowUp); -library.add(fileSolid); -library.add(faLocationArrow); -library.add(fileRegular as any); -library.add(faSearch); -library.add(faArrowDown); - -interface PresentationElementProps { - mainDocument: Doc; - document: Doc; - index: number; - deleteDocument(index: number): void; - gotoDocument(index: number, fromDoc: number): Promise; - allListElements: Doc[]; - presStatus: boolean; - removeDocByRef(doc: Doc): boolean; -} - -/** - * This class models the view a document added to presentation will have in the presentation. - * It involves some functionality for its buttons and options. - */ -@observer -export default class PresentationElement extends React.Component { - - private header?: HTMLDivElement | undefined; - private listdropDisposer?: DragManager.DragDropDisposer; - private presElRef: React.RefObject = React.createRef(); - - componentWillUnmount() { - this.listdropDisposer && this.listdropDisposer(); - } - - @computed get currentIndex() { return NumCast(this.props.mainDocument.selectedDoc); } - - @computed get showButton() { return BoolCast(this.props.document.showButton); } - @computed get navButton() { return BoolCast(this.props.document.navButton); } - @computed get hideTillShownButton() { return BoolCast(this.props.document.hideTillShownButton); } - @computed get fadeButton() { return BoolCast(this.props.document.fadeButton); } - @computed get hideAfterButton() { return BoolCast(this.props.document.hideAfterButton); } - @computed get groupButton() { return BoolCast(this.props.document.groupButton); } - @computed get expandInlineButton() { return BoolCast(this.props.document.expandInlineButton); } - set showButton(val: boolean) { this.props.document.showButton = val; } - set navButton(val: boolean) { this.props.document.navButton = val; } - set hideTillShownButton(val: boolean) { this.props.document.hideTillShownButton = val; } - set fadeButton(val: boolean) { this.props.document.fadeButton = val; } - set hideAfterButton(val: boolean) { this.props.document.hideAfterButton = val; } - set groupButton(val: boolean) { this.props.document.groupButton = val; } - set expandInlineButton(val: boolean) { this.props.document.expandInlineButton = val; } - - //Lifecycle function that makes sure that button BackUp is received when mounted. - async componentDidMount() { - if (this.presElRef.current) { - this.header = this.presElRef.current; - this.createListDropTarget(this.presElRef.current); - } - } - - //Lifecycle function that makes sure button BackUp is received when not re-mounted bu re-rendered. - async componentDidUpdate() { - if (this.presElRef.current) { - this.header = this.presElRef.current; - this.createListDropTarget(this.presElRef.current); - } - } - - @action - onGroupClick = (e: React.MouseEvent) => { - this.groupButton = !this.groupButton; - } - - /** - * The function that is called on click to turn Hiding document till press option on/off. - * It also sets the beginning and end opacitys. - */ - @action - onHideDocumentUntilPressClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.hideTillShownButton = !this.hideTillShownButton; - if (!this.hideTillShownButton) { - if (this.props.index >= this.currentIndex) { - this.props.document.opacity = 1; - } - } else { - if (this.props.presStatus) { - if (this.props.index > this.currentIndex) { - this.props.document.opacity = 0; - } - } - } - } - - /** - * The function that is called on click to turn Hiding document after presented option on/off. - * It also makes sure that the option swithches from fade-after to this one, since both - * can't coexist. - */ - @action - onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.hideAfterButton = !this.hideAfterButton; - if (!this.hideAfterButton) { - if (this.props.index <= this.currentIndex) { - this.props.document.opacity = 1; - } - } else { - if (this.fadeButton) this.fadeButton = false; - if (this.props.presStatus) { - if (this.props.index < this.currentIndex) { - this.props.document.opacity = 0; - } - } - } - } - - /** - * The function that is called on click to turn fading document after presented option on/off. - * It also makes sure that the option swithches from hide-after to this one, since both - * can't coexist. - */ - @action - onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.fadeButton = !this.fadeButton; - if (!this.fadeButton) { - if (this.props.index <= this.currentIndex) { - this.props.document.opacity = 1; - } - } else { - this.hideAfterButton = false; - if (this.props.presStatus) { - if (this.props.index < this.currentIndex) { - this.props.document.opacity = 0.5; - } - } - } - } - - /** - * The function that is called on click to turn navigation option of docs on/off. - */ - @action - onNavigateDocumentClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.navButton = !this.navButton; - if (this.navButton) { - this.showButton = false; - if (this.currentIndex === this.props.index) { - this.props.gotoDocument(this.props.index, this.props.index); - } - } - } - - /** - * The function that is called on click to turn zoom option of docs on/off. - */ - @action - onZoomDocumentClick = (e: React.MouseEvent) => { - e.stopPropagation(); - - this.showButton = !this.showButton; - if (!this.showButton) { - this.props.document.viewScale = 1; - } else { - this.navButton = false; - if (this.currentIndex === this.props.index) { - this.props.gotoDocument(this.props.index, this.props.index); - } - } - } - - /** - * Function that expands the target inline - */ - @action - onExpandTabClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.embedInline = !this.embedInline - } - - /** - * Creating a drop target for drag and drop when called. - */ - protected createListDropTarget = (ele: HTMLDivElement) => { - this.listdropDisposer && this.listdropDisposer(); - if (ele) { - this.listdropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.listDrop.bind(this) } }); - } - } - - /** - * Returns a local transformed coordinate array for given coordinates. - */ - ScreenToLocalListTransform = (xCord: number, yCord: number) => { - return [xCord, yCord]; - } - - /** - * This method is called when a element is dropped on a already esstablished target. - * It makes sure to do appropirate action depending on if the item is dropped before - * or after the target. - */ - listDrop = async (e: Event, de: DragManager.DropEvent) => { - let x = this.ScreenToLocalListTransform(de.x, de.y); - let rect = this.header!.getBoundingClientRect(); - let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2); - let before = x[1] < bounds[1]; - if (de.data instanceof DragManager.DocumentDragData) { - let addDoc = (doc: Doc) => Doc.AddDocToList(this.props.mainDocument, "data", doc, this.props.document, before); - e.stopPropagation(); - //where does treeViewId come from - let movedDocs = (de.data.options === this.props.mainDocument[Id] ? de.data.draggedDocuments : de.data.droppedDocuments); - //console.log("How is this causing an issue"); - document.removeEventListener("pointermove", this.onDragMove, true); - return (de.data.dropAction || de.data.userDropAction) ? - de.data.droppedDocuments.reduce((added: boolean, d: Doc) => Doc.AddDocToList(this.props.mainDocument, "data", d, this.props.document, before) || added, false) - : (de.data.moveDocument) ? - movedDocs.reduce((added: boolean, d: Doc) => de.data.moveDocument(d, this.props.document, addDoc) || added, false) - : de.data.droppedDocuments.reduce((added: boolean, d: Doc) => Doc.AddDocToList(this.props.mainDocument, "data", d, this.props.document, before), false); - } - document.removeEventListener("pointermove", this.onDragMove, true); - - return false; - } - - //This is used to add dragging as an event. - onPointerEnter = (e: React.PointerEvent): void => { - if (e.buttons === 1 && SelectionManager.GetIsDragging()) { - - this.header!.className = "presentationView-item"; - - if (this.currentIndex === this.props.index) { - //this doc is selected - this.header!.className = "presentationView-item presentationView-selected"; - } - document.addEventListener("pointermove", this.onDragMove, true); - } - } - - //This is used to remove the dragging when dropped. - onPointerLeave = (e: React.PointerEvent): void => { - this.header!.className = "presentationView-item"; - - if (this.currentIndex === this.props.index) { - //this doc is selected - this.header!.className = "presentationView-item presentationView-selected"; - - } - document.removeEventListener("pointermove", this.onDragMove, true); - } - - /** - * This method is passed in to be used when dragging a document. - * It makes it possible to show dropping lines on drop targets. - */ - onDragMove = (e: PointerEvent): void => { - Doc.UnBrushDoc(this.props.document); - let x = this.ScreenToLocalListTransform(e.clientX, e.clientY); - let rect = this.header!.getBoundingClientRect(); - let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2); - let before = x[1] < bounds[1]; - this.header!.className = "presentationView-item"; - if (before) { - this.header!.className += " presentationView-item-above"; - } - else if (!before) { - this.header!.className += " presentationView-item-below"; - } - e.stopPropagation(); - } - - /** - * This method is passed in to on down event of presElement, so that drag and - * drop can be completed with DragManager functionality. - */ - @action - move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => { - return this.props.document !== target && this.props.removeDocByRef(doc) && addDoc(doc); - } - /** - * 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) => { - 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 ( -
- 350} - PanelHeight={() => 90} - focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnFalse} - whenActiveChanged={returnFalse} - bringToFront={emptyFunction} - zoomToScale={emptyFunction} - getScale={returnOne} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - ContentScaling={scale} - /> -
-
- ); - } - - render() { - let p = this.props; - let title = p.document.title; - - let className = " presentationView-item"; - if (this.currentIndex === p.index) { - //this doc is selected - className += " presentationView-selected"; - } - 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 ( -
{ p.gotoDocument(p.index, this.currentIndex); e.stopPropagation(); }}> - - {`${p.index + 1}. ${title}`} - - -

- - - - - - - - -
- {this.renderEmbeddedInline()} -
- ); - } -} \ No newline at end of file diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx deleted file mode 100644 index 483461e5a..000000000 --- a/src/client/views/presentationview/PresentationList.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { action } from "mobx"; -import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { NumCast } from "../../../new_fields/Types"; -import PresentationElement from "./PresentationElement"; -import "./PresentationView.scss"; -import React = require("react"); - - -interface PresListProps { - mainDocument: Doc; - deleteDocument(index: number): void; - gotoDocument(index: number, fromDoc: number): Promise; - setChildrenDocs: (docList: Doc[]) => void; - presStatus: boolean; - removeDocByRef(doc: Doc): boolean; -} - - -@observer -/** - * Component that takes in a document prop and a boolean whether it's collapsed or not. - */ -export default class PresentationViewList extends React.Component { - - - /** - * Initially every document starts with a viewScale 1, which means - * that they will be displayed in a canvas with scale 1. - */ - @action - initializeScaleViews = (docList: Doc[]) => { - docList.forEach((doc: Doc) => { - let curScale = NumCast(doc.viewScale, null); - if (curScale === undefined) { - doc.viewScale = 1; - } - }); - } - - render() { - const children = DocListCast(this.props.mainDocument.data); - this.initializeScaleViews(children); - this.props.setChildrenDocs(children); - return ( -
- {children.map((doc: Doc, index: number) => - - )} -
- ); - } -} diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss deleted file mode 100644 index 5c40a8808..000000000 --- a/src/client/views/presentationview/PresentationView.scss +++ /dev/null @@ -1,113 +0,0 @@ -.presentationView-cont { - position: absolute; - z-index: 2; - box-shadow: #AAAAAA .2vw .2vw .4vw; - right: 0; - top: 0; - bottom: 0; - letter-spacing: 2px; - overflow: hidden; - transition: 0.7s opacity ease; - pointer-events: all; -} - -.presentationView-item { - padding: 10px; - display: inline-block; - width: 100%; - -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; - - .documentView-node { - - position: absolute; - z-index: 1; - } -} - -.presentationView-item-above { - border-top: black 2px solid; -} - -.presentationView-item-below { - border-bottom: black 2px solid; -} - -.presentationView-listCont { - padding-left: 10px; - padding-right: 10px; -} - -.presentationView-item:hover { - transition: all .1s; - background: #AAAAAA; - border-radius: 12px; -} - -.presentationView-selected { - background: gray; - color: black; - border-radius: 12px; - box-shadow: black 2px 2px 5px; -} - -.presentationView-heading { - background: gray; - padding: 10px; - display: inline-block; - width: 100%; -} - -.presentationView-title { - padding-top: 3px; - padding-bottom: 3px; - font-size: 25px; - display: inline-block; - width: calc(100% - 200px); - letter-spacing: 2px; -} - -.presentation-icon { - float: right; -} - -.presentation-interaction { - color: gray; - float: left; -} - -.presentation-interaction-selected { - color: white; - float: left; -} - -.presentationView-name { - font-size: 15px; - display: inline-block; -} - -.presentation-button { - margin-right: 2.5%; - margin-left: 2.5%; - width: 20%; - border-radius: 5px; -} - -.presentation-buttons { - padding: 10px; -} - -.presentation-next:hover { - transition: all .1s; - background: #AAAAAA -} - -.presentation-back:hover { - transition: all .1s; - background: #AAAAAA -} \ No newline at end of file -- cgit v1.2.3-70-g09d2