From bcd8589f9319221dceb23f5c1aad35fd6373194b Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Mon, 1 Jul 2019 17:23:30 -0400 Subject: Still trying to figure out DragManager --- .../views/presentationview/PresentationElement.tsx | 6 +- .../views/presentationview/PresentationList.tsx | 87 +++++++++++++++++----- 2 files changed, 73 insertions(+), 20 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 4afc0210f..d8953a4ae 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -31,8 +31,7 @@ interface PresentationElementProps { presStatus: boolean; presButtonBackUp: Doc; presGroupBackUp: Doc; - - + setHeader: (header: React.RefObject) => void; } //enum for the all kinds of buttons a doc in presentation can have @@ -54,6 +53,8 @@ export enum buttonIndex { export default class PresentationElement extends React.Component { @observable private selectedButtons: boolean[]; + private headerTest?: React.RefObject = React.createRef(); + constructor(props: PresentationElementProps) { @@ -374,6 +375,7 @@ export default class PresentationElement extends React.Component { p.document.libraryBrush = false; }; return (
this.props.setHeader(e)} onPointerEnter={onEnter} onPointerLeave={onLeave} style={{ outlineColor: "maroon", diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx index 7abd3e366..f14602cb3 100644 --- a/src/client/views/presentationview/PresentationList.tsx +++ b/src/client/views/presentationview/PresentationList.tsx @@ -7,6 +7,9 @@ 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"; @@ -30,6 +33,17 @@ interface PresListProps { */ export default class PresentationViewList extends React.Component { + private listdropDisposer?: DragManager.DragDropDisposer; + private header?: React.RefObject = React.createRef(); + private listContainer: HTMLDivElement | undefined; + + + componentWillUnmount() { + this.listdropDisposer && this.listdropDisposer(); + } + + + /** * Method that initializes presentation ids for the * docs that is in the presentation, when presentation list @@ -74,30 +88,67 @@ export default class PresentationViewList extends React.Component }); } + protected createListDropTarget = (ele: HTMLDivElement) => { + this.listdropDisposer && this.listdropDisposer(); + if (ele) { + this.listdropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.listDrop.bind(this) } }); + } + } + + listDrop = (e: Event, de: DragManager.DropEvent) => { + let x = this.ScreenToLocalListTransform(de.x, de.y); + let rect = this.header!.current!.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(doc, "data", this.resolvedDataDoc, before); + e.stopPropagation(); + //where does treeViewId come from + let movedDocs = (de.data.options === this.props.mainDocument[Id] ? de.data.draggedDocuments : de.data.droppedDocuments); + return (de.data.dropAction || de.data.userDropAction) ? + de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before) || added, false) + : (de.data.moveDocument) ? + movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.resolvedDataDoc, addDoc) || added, false) + : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before), false); + } + return false; + } + + ScreenToLocalListTransform = (xCord: number, yCord: number) => { + let rect = this.listContainer!.getBoundingClientRect(), + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, + scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return [rect.top + scrollTop, rect.left + scrollLeft]; + } + + render() { const children = DocListCast(this.props.mainDocument.data); this.initializeGroupIds(children); this.initializeScaleViews(children); this.props.setChildrenDocs(children); return ( - -
- {children.map((doc: Doc, index: number) => - { if (e) { this.props.presElementsMappings.set(doc, e); } }} - key={doc[Id]} - mainDocument={this.props.mainDocument} - document={doc} - index={index} - deleteDocument={this.props.deleteDocument} - gotoDocument={this.props.gotoDocument} - groupMappings={this.props.groupMappings} - allListElements={children} - presStatus={this.props.presStatus} - presButtonBackUp={this.props.presButtonBackUp} - presGroupBackUp={this.props.presGroupBackUp} - /> - )} +
{ + this.createListDropTarget(e!); + this.listContainer = e!; + }}> + {children.map((doc: Doc, index: number) => + { if (e) { this.props.presElementsMappings.set(doc, e); } }} + key={doc[Id]} + mainDocument={this.props.mainDocument} + document={doc} + index={index} + deleteDocument={this.props.deleteDocument} + gotoDocument={this.props.gotoDocument} + groupMappings={this.props.groupMappings} + allListElements={children} + presStatus={this.props.presStatus} + presButtonBackUp={this.props.presButtonBackUp} + presGroupBackUp={this.props.presGroupBackUp} + setHeader={(header: React.RefObject) => this.header = header} + /> + )}
); } -- cgit v1.2.3-70-g09d2 From 66e4851757894dcb43fb9baada0fa21fbd43164a Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Tue, 2 Jul 2019 16:58:43 -0400 Subject: Some dragging implemented. Like dragging from pres to workspace --- .../views/presentationview/PresentationElement.tsx | 92 +++++++++++++++++++++- .../views/presentationview/PresentationList.tsx | 54 +------------ .../views/presentationview/PresentationView.tsx | 10 +++ 3 files changed, 103 insertions(+), 53 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index d8953a4ae..79a27b4e9 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -12,6 +12,8 @@ import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSear import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons'; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; +import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; +import { SelectionManager } from "../../util/SelectionManager"; library.add(faArrowUp); @@ -31,7 +33,8 @@ interface PresentationElementProps { presStatus: boolean; presButtonBackUp: Doc; presGroupBackUp: Doc; - setHeader: (header: React.RefObject) => void; + removeDocByRef(doc: Doc): boolean; + } //enum for the all kinds of buttons a doc in presentation can have @@ -53,15 +56,27 @@ export enum buttonIndex { export default class PresentationElement extends React.Component { @observable private selectedButtons: boolean[]; - private headerTest?: React.RefObject = React.createRef(); + private header?: HTMLDivElement | undefined; + private listdropDisposer?: DragManager.DragDropDisposer; + private presElRef: React.RefObject; + + constructor(props: PresentationElementProps) { super(props); this.selectedButtons = new Array(6); + + this.presElRef = React.createRef(); } + + componentWillUnmount() { + this.listdropDisposer && this.listdropDisposer(); + } + + /** * Getter to get the status of the buttons. */ @@ -74,6 +89,10 @@ export default class PresentationElement extends React.Component { + this.listdropDisposer && this.listdropDisposer(); + if (ele) { + this.listdropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.listDrop.bind(this) } }); + } + } + + ScreenToLocalListTransform = (xCord: number, yCord: number) => { + let scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; + let scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return [yCord + scrollTop, xCord + scrollLeft]; + } + + + listDrop = (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); + 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); + } + return false; + } + + onPointerEnter = (e: React.PointerEvent): void => { + //this.props.document.libraryBrush = true; + if (e.buttons === 1 && SelectionManager.GetIsDragging()) { + //this.header!.className = "treeViewItem-header"; + document.addEventListener("pointermove", this.onDragMove, true); + } + } + onPointerLeave = (e: React.PointerEvent): void => { + this.props.document.libraryBrush = false; + //this.header!.className = "treeViewItem-header"; + document.removeEventListener("pointermove", this.onDragMove, true); + } + + onDragMove = (e: PointerEvent): void => { + this.props.document.libraryBrush = false; + 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 = "treeViewItem-header"; + // if (before) this.header!.className += " treeViewItem-header-above"; + // else if (!before) this.header!.className += " treeViewItem-header-below"; + e.stopPropagation(); + } + + @action + move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => { + return this.props.document !== target && this.props.removeDocByRef(doc) && addDoc(doc); + } + + render() { let p = this.props; @@ -373,10 +456,13 @@ export default class PresentationElement extends React.Component { p.document.libraryBrush = true; }; let onLeave = (e: React.PointerEvent) => { p.document.libraryBrush = false; }; + 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 (
this.props.setHeader(e)} + ref={this.presElRef} onPointerEnter={onEnter} onPointerLeave={onLeave} + onPointerDown={onItemDown} style={{ outlineColor: "maroon", outlineStyle: "dashed", diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx index f14602cb3..760cc80f4 100644 --- a/src/client/views/presentationview/PresentationList.tsx +++ b/src/client/views/presentationview/PresentationList.tsx @@ -24,6 +24,8 @@ interface PresListProps { presStatus: boolean; presButtonBackUp: Doc; presGroupBackUp: Doc; + removeDocByRef(doc: Doc): boolean; + } @@ -33,17 +35,6 @@ interface PresListProps { */ export default class PresentationViewList extends React.Component { - private listdropDisposer?: DragManager.DragDropDisposer; - private header?: React.RefObject = React.createRef(); - private listContainer: HTMLDivElement | undefined; - - - componentWillUnmount() { - this.listdropDisposer && this.listdropDisposer(); - } - - - /** * Method that initializes presentation ids for the * docs that is in the presentation, when presentation list @@ -88,50 +79,13 @@ export default class PresentationViewList extends React.Component }); } - protected createListDropTarget = (ele: HTMLDivElement) => { - this.listdropDisposer && this.listdropDisposer(); - if (ele) { - this.listdropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.listDrop.bind(this) } }); - } - } - - listDrop = (e: Event, de: DragManager.DropEvent) => { - let x = this.ScreenToLocalListTransform(de.x, de.y); - let rect = this.header!.current!.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(doc, "data", this.resolvedDataDoc, before); - e.stopPropagation(); - //where does treeViewId come from - let movedDocs = (de.data.options === this.props.mainDocument[Id] ? de.data.draggedDocuments : de.data.droppedDocuments); - return (de.data.dropAction || de.data.userDropAction) ? - de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before) || added, false) - : (de.data.moveDocument) ? - movedDocs.reduce((added: boolean, d) => de.data.moveDocument(d, this.resolvedDataDoc, addDoc) || added, false) - : de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d, this.resolvedDataDoc, before), false); - } - return false; - } - - ScreenToLocalListTransform = (xCord: number, yCord: number) => { - let rect = this.listContainer!.getBoundingClientRect(), - scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, - scrollTop = window.pageYOffset || document.documentElement.scrollTop; - return [rect.top + scrollTop, rect.left + scrollLeft]; - } - - render() { const children = DocListCast(this.props.mainDocument.data); this.initializeGroupIds(children); this.initializeScaleViews(children); this.props.setChildrenDocs(children); return ( -
{ - this.createListDropTarget(e!); - this.listContainer = e!; - }}> +
{children.map((doc: Doc, index: number) => { if (e) { this.props.presElementsMappings.set(doc, e); } }} @@ -146,7 +100,7 @@ export default class PresentationViewList extends React.Component presStatus={this.props.presStatus} presButtonBackUp={this.props.presButtonBackUp} presGroupBackUp={this.props.presGroupBackUp} - setHeader={(header: React.RefObject) => this.header = header} + removeDocByRef={this.props.removeDocByRef} /> )}
diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 20d0e113a..cdd059cab 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -447,6 +447,15 @@ export class PresentationView extends React.Component { } } + public removeDocByRef = (doc: Doc) => { + let indexOfDoc = this.childrenDocs.indexOf(doc); + this.RemoveDoc(indexOfDoc); + if (indexOfDoc !== - 1) { + return true; + } + return false; + } + //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. @action @@ -786,6 +795,7 @@ export class PresentationView extends React.Component { presStatus={this.presStatus} presButtonBackUp={this.presButtonBackUp} presGroupBackUp={this.presGroupBackUp} + removeDocByRef={this.removeDocByRef} />
); -- cgit v1.2.3-70-g09d2 From 118ca303bb18648451fe9c349c79594833d95001 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Wed, 3 Jul 2019 18:30:09 -0400 Subject: Reordering Done, Back-up protecting should be added --- .../views/presentationview/PresentationElement.tsx | 51 +++++++++++++++++----- .../views/presentationview/PresentationView.scss | 8 ++++ 2 files changed, 48 insertions(+), 11 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 79a27b4e9..23031f02c 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -98,6 +98,10 @@ export default class PresentationElement extends React.Component { @@ -385,9 +389,9 @@ export default class PresentationElement extends React.Component { - let scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; - let scrollTop = window.pageYOffset || document.documentElement.scrollTop; - return [yCord + scrollTop, xCord + scrollLeft]; + // let scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; + // let scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return [xCord, yCord]; } @@ -401,25 +405,46 @@ export default class PresentationElement extends React.Component 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; } onPointerEnter = (e: React.PointerEvent): void => { - //this.props.document.libraryBrush = true; + this.props.document.libraryBrush = true; if (e.buttons === 1 && SelectionManager.GetIsDragging()) { - //this.header!.className = "treeViewItem-header"; + let selected = NumCast(this.props.mainDocument.selectedDoc, 0); + + this.header!.className = "presentationView-item"; + + + if (selected === this.props.index) { + //this doc is selected + this.header!.className = "presentationView-item presentationView-selected"; + } document.addEventListener("pointermove", this.onDragMove, true); } } onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; - //this.header!.className = "treeViewItem-header"; + //to get currently selected presentation doc + let selected = NumCast(this.props.mainDocument.selectedDoc, 0); + + this.header!.className = "presentationView-item"; + + + if (selected === this.props.index) { + //this doc is selected + this.header!.className = "presentationView-item presentationView-selected"; + + } document.removeEventListener("pointermove", this.onDragMove, true); } @@ -429,9 +454,13 @@ export default class PresentationElement extends React.Component Date: Fri, 5 Jul 2019 15:41:17 -0400 Subject: Reodering mostly done. Refactored button backUps, and wrote function to update groups. Gotta find where to call it! --- .../views/presentationview/PresentationElement.tsx | 74 ++++++++++++++++++---- .../views/presentationview/PresentationView.tsx | 12 +++- 2 files changed, 73 insertions(+), 13 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 23031f02c..656ec62a0 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -14,6 +14,7 @@ import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; +import { indexOf } from "typescript-collections/dist/lib/arrays"; library.add(faArrowUp); @@ -59,6 +60,7 @@ export default class PresentationElement extends React.Component; + private backUpDoc: Doc | undefined; @@ -97,7 +99,7 @@ export default class PresentationElement extends React.Component(); } + + let foundDoc: boolean = false; + //if this is the first time this doc mounts, push a doc for it to store - if (castedList.length <= this.props.index) { + await castedList.forEach(async (doc) => { + let curDoc = await doc; + let curDocId = StrCast(curDoc.docId); + if (curDocId === this.props.document[Id]) { + let selectedButtonOfDoc = Cast(curDoc.selectedButtons, listSpec("boolean"), null); + if (selectedButtonOfDoc !== undefined) { + runInAction(() => this.selectedButtons = selectedButtonOfDoc); + foundDoc = true; + this.backUpDoc = curDoc; + return; + } + } + }); + + if (!foundDoc) { let newDoc = new Doc(); let defaultBooleanArray: boolean[] = new Array(6); newDoc.selectedButtons = new List(defaultBooleanArray); + newDoc.docId = this.props.document[Id]; castedList.push(newDoc); - //otherwise update the selected buttons depending on storage. - } else { - let curDoc: Doc = await castedList[this.props.index]; - let selectedButtonOfDoc = Cast(curDoc.selectedButtons, listSpec("boolean"), null); - if (selectedButtonOfDoc !== undefined) { - runInAction(() => this.selectedButtons = selectedButtonOfDoc); - } + this.backUpDoc = newDoc; } + // if (castedList.length <= this.props.index) { + // let newDoc = new Doc(); + // let defaultBooleanArray: boolean[] = new Array(6); + // newDoc.selectedButtons = new List(defaultBooleanArray); + // castedList.push(newDoc); + // //otherwise update the selected buttons depending on storage. + // } else { + // let curDoc: Doc = await castedList[this.props.index]; + // let selectedButtonOfDoc = Cast(curDoc.selectedButtons, listSpec("boolean"), null); + // if (selectedButtonOfDoc !== undefined) { + // runInAction(() => this.selectedButtons = selectedButtonOfDoc); + // } + // } + } /** @@ -269,9 +297,18 @@ export default class PresentationElement extends React.Component { - let castedList = (await DocListCastAsync(this.props.presButtonBackUp.selectedButtonDocs))!; - castedList[this.props.index].selectedButtons = new List(this.selectedButtons); - + // let castedList = (await DocListCastAsync(this.props.presButtonBackUp.selectedButtonDocs))!; + // // let hasBackupDoc: boolean = false; + // castedList.forEach((doc: Doc) => { + // let docId = StrCast(doc.docId); + // if (docId === this.props.document[Id]) { + // doc.selectedButtons = new List(this.selectedButtons); + // } + // }); + // castedList[this.props.index].selectedButtons = new List(this.selectedButtons); + if (this.backUpDoc) { + this.backUpDoc.selectedButtons = new List(this.selectedButtons); + } } /** @@ -417,6 +454,19 @@ export default class PresentationElement extends React.Component { + let p = this.props; + let curDocGuid = StrCast(p.document.presentId, null); + if (curDocGuid) { + if (p.groupMappings.has(curDocGuid)) { + let groupArray = this.props.groupMappings.get(curDocGuid)!; + groupArray.splice(groupArray.indexOf(p.document), 1); + } + } + + this.onGroupClick(p.document, p.index, true); + } + onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; if (e.buttons === 1 && SelectionManager.GetIsDragging()) { diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index cdd059cab..ba248a8aa 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -421,7 +421,17 @@ export class PresentationView extends React.Component { //removing it from the backUp of selected Buttons let castedList = Cast(this.presButtonBackUp.selectedButtonDocs, listSpec(Doc)); if (castedList) { - castedList.splice(index, 1); + 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 groups -- cgit v1.2.3-70-g09d2 From edf530d1524cc1896ceeb0289f946ee31b16a938 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Fri, 5 Jul 2019 18:52:31 -0400 Subject: Some factorization and group building in drop fixed --- .../views/presentationview/PresentationElement.tsx | 61 +++++++++++++++++----- .../views/presentationview/PresentationList.tsx | 4 +- .../views/presentationview/PresentationView.tsx | 7 ++- 3 files changed, 55 insertions(+), 17 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 656ec62a0..fcddb2ad4 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -442,6 +442,8 @@ export default class PresentationElement extends React.Component Doc.AddDocToList(this.props.mainDocument, "data", d, this.props.document, before) || added, false) @@ -454,17 +456,48 @@ export default class PresentationElement extends React.Component { + updateGroupsOnDrop = async (droppedDoc: Doc) => { let p = this.props; - let curDocGuid = StrCast(p.document.presentId, null); - if (curDocGuid) { - if (p.groupMappings.has(curDocGuid)) { - let groupArray = this.props.groupMappings.get(curDocGuid)!; - groupArray.splice(groupArray.indexOf(p.document), 1); + let droppedDocSelectedButtons: boolean[] = await this.getSelectedButtonsOfDoc(droppedDoc); + if (droppedDocSelectedButtons[buttonIndex.Group]) { + let curDocGuid = StrCast(droppedDoc.presentId, null); + if (curDocGuid) { + if (p.groupMappings.has(curDocGuid)) { + let groupArray = this.props.groupMappings.get(curDocGuid)!; + groupArray.splice(groupArray.indexOf(droppedDoc), 1); + } + } + + let aboveDocGuid = StrCast(p.document.presentId, null); + if (p.groupMappings.has(aboveDocGuid)) { + p.groupMappings.get(aboveDocGuid)!.push(droppedDoc); + } else { + let newGroup: Doc[] = []; + newGroup.push(p.document); + newGroup.push(droppedDoc); + droppedDoc.presentId = aboveDocGuid; + p.groupMappings.set(aboveDocGuid, newGroup); } + } + } + + getSelectedButtonsOfDoc = async (paramDoc: Doc) => { + let p = this.props; + + let castedList = Cast(this.props.presButtonBackUp.selectedButtonDocs, listSpec(Doc)); + let foundSelectedButtons: boolean[] = new Array(6); + //if this is the first time this doc mounts, push a doc for it to store + await castedList!.forEach(async (doc) => { + let curDoc = await doc; + let curDocId = StrCast(curDoc.docId); + if (curDocId === paramDoc[Id]) { + foundSelectedButtons = Cast(curDoc.selectedButtons, listSpec("boolean"), null); + return; + } + }); + return foundSelectedButtons; - this.onGroupClick(p.document, p.index, true); } onPointerEnter = (e: React.PointerEvent): void => { @@ -551,14 +584,14 @@ export default class PresentationElement extends React.Component {`${p.index + 1}. ${title}`} - +

- - - - - - + + + + + +
  • {btns.map(btn => @@ -444,7 +445,6 @@ export class MainView extends React.Component { this.isSearchVisible = !this.isSearchVisible; } - render() { return (
    diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 703873681..3fd86e950 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -31,6 +31,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; +import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; export const panZoomSchema = createSchema({ @@ -51,6 +52,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private _lastY: number = 0; private get _pwidth() { return this.props.PanelWidth(); } private get _pheight() { return this.props.PanelHeight(); } + private inkKey = "ink"; @computed get contentBounds() { let bounds = this.props.fitToBox && !NumCast(this.nativeWidth) ? Doc.ComputeContentBounds(DocListCast(this.props.Document.data)) : undefined; @@ -477,6 +479,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }, "arrange contents"); } }); + ContextMenu.Instance.addItem({ + description: "Analyze Strokes", event: async () => { + let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField); + if (!data) { + return; + } + CognitiveServices.Inking.analyze(data.inkData, Doc.GetProto(this.props.Document)); + } + }); ContextMenu.Instance.addItem({ description: "Add freeform arrangement", event: () => { diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index f80840f96..966ade3de 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -31,6 +31,8 @@ export interface PresViewProps { Documents: List; } +const expandedWidth = 400; + @observer export class PresentationView extends React.Component { public static Instance: PresentationView; @@ -67,6 +69,14 @@ export class PresentationView extends React.Component { PresentationView.Instance = this; } + toggle = (forcedValue: boolean | undefined) => { + if (forcedValue !== undefined) { + this.curPresentation.width = forcedValue ? expandedWidth : 0; + } else { + this.curPresentation.width = this.curPresentation.width === expandedWidth ? 0 : expandedWidth; + } + } + //The first lifecycle function that gets called to set up the current presentation. async componentWillMount() { this.props.Documents.forEach(async (doc, index: number) => { @@ -543,7 +553,7 @@ export class PresentationView extends React.Component { this.curPresentation.data = new List([doc]); } - this.curPresentation.width = 400; + this.toggle(true); } //Function that sets the store of the children docs. diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts index a436dcf2b..b5b3aa588 100644 --- a/src/new_fields/FieldSymbols.ts +++ b/src/new_fields/FieldSymbols.ts @@ -7,4 +7,4 @@ export const Id = Symbol("Id"); export const OnUpdate = Symbol("OnUpdate"); export const Parent = Symbol("Parent"); export const Copy = Symbol("Copy"); -export const ToScriptString = Symbol("Copy"); \ No newline at end of file +export const ToScriptString = Symbol("ToScriptString"); \ No newline at end of file diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 39c6c8ce3..8f64c1c2e 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -19,6 +19,8 @@ export interface StrokeData { page: number; } +export type InkData = Map; + const pointSchema = createSimpleSchema({ x: true, y: true }); @@ -31,9 +33,9 @@ const strokeDataSchema = createSimpleSchema({ @Deserializable("ink") export class InkField extends ObjectField { @serializable(map(object(strokeDataSchema))) - readonly inkData: Map; + readonly inkData: InkData; - constructor(data?: Map) { + constructor(data?: InkData) { super(); this.inkData = data || new Map; } diff --git a/src/server/index.ts b/src/server/index.ts index 5b086a2cf..66c982adc 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -284,18 +284,15 @@ addSecureRoute( RouteStore.getCurrUser ); +const ServicesApiKeyMap = new Map([ + ["face", process.env.FACE], + ["vision", process.env.VISION], + ["handwriting", process.env.HANDWRITING] +]); + addSecureRoute(Method.GET, (user, res, req) => { - let requested = req.params.requestedservice; - switch (requested) { - case "face": - res.send(process.env.FACE); - break; - case "vision": - res.send(process.env.VISION); - break; - default: - res.send(undefined); - } + let service = req.params.requestedservice; + res.send(ServicesApiKeyMap.get(service)); }, undefined, `${RouteStore.cognitiveServices}/:requestedservice`); class NodeCanvasFactory { -- cgit v1.2.3-70-g09d2 From 99ebc483059f5637e0731c9d0b43ddd3d531f2e3 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Wed, 24 Jul 2019 10:43:55 -0400 Subject: wrapped presentation view toggle in an action, cognitive services cleanup --- src/client/cognitive_services/CognitiveServices.ts | 15 +++++++++------ src/client/views/presentationview/PresentationView.tsx | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index a778bd47b..dcd27f858 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -187,12 +187,15 @@ export namespace CognitiveServices { xhttp.send(body); }; - let results = (await new Promise(requestExecutor)).recognitionUnits; - - target.inkAnalysis = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis"); - let recognizedText = results.map((item: any) => item.recognizedText); - let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); - target.handwriting = individualWords.join(" "); + let results = await new Promise(requestExecutor); + + if (results) { + results.recognitionUnits && (results = results.recognitionUnits); + target.inkAnalysis = Docs.Get.DocumentHierarchyFromJson(results, "Ink Analysis"); + let recognizedText = results.map((item: any) => item.recognizedText); + let individualWords = recognizedText.filter((text: string) => text && text.split(" ").length === 1); + target.handwriting = individualWords.join(" "); + } }); }; diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 966ade3de..b318f0321 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -69,6 +69,7 @@ export class PresentationView extends React.Component { PresentationView.Instance = this; } + @action toggle = (forcedValue: boolean | undefined) => { if (forcedValue !== undefined) { this.curPresentation.width = forcedValue ? expandedWidth : 0; -- cgit v1.2.3-70-g09d2 From 7844debd9862b15d2b36bf9ce1efb3274616a313 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Wed, 24 Jul 2019 18:53:21 -0400 Subject: Context Menu and Some Preview --- .../views/collections/CollectionTreeView.tsx | 2 +- .../views/presentationview/PresentationElement.tsx | 58 ++++++++++++++++++++-- .../views/presentationview/PresentationView.scss | 4 ++ .../views/presentationview/PresentationView.tsx | 2 +- 4 files changed, 60 insertions(+), 6 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 006de0c70..c0347ad7d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -64,7 +64,7 @@ library.add(faArrowsAltH); /** * Component that takes in a document prop and a boolean whether it's collapsed or not. */ -class TreeView extends React.Component { +export class TreeView extends React.Component { private _header?: React.RefObject = React.createRef(); private _treedropDisposer?: DragManager.DragDropDisposer; private _dref = React.createRef(); diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 329630875..f354a14c2 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -1,11 +1,11 @@ import { observer } from "mobx-react"; import React = require("react"); import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { NumCast, BoolCast, StrCast, Cast } from "../../../new_fields/Types"; +import { NumCast, BoolCast, StrCast, Cast, FieldValue } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/FieldSymbols"; import { observable, action, computed, runInAction } from "mobx"; import "./PresentationView.scss"; -import { Utils } from "../../../Utils"; +import { Utils, emptyFunction, returnFalse } from "../../../Utils"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch } from '@fortawesome/free-solid-svg-icons'; @@ -16,6 +16,11 @@ import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { indexOf } from "typescript-collections/dist/lib/arrays"; import { map } from "bluebird"; +import { ContextMenu } from "../ContextMenu"; +import { DocumentContentsView } from "../nodes/DocumentContentsView"; +import { Transform } from "../../util/Transform"; +import { FieldView } from "../nodes/FieldView"; +import { DocumentView } from "../nodes/DocumentView"; library.add(faArrowUp); library.add(fileSolid); @@ -768,8 +773,51 @@ export default class PresentationElement extends React.Component) => { + 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); + } + renderEmbeddedInline = () => { + if (!this.embedInline) { + return (null); + } + + // return
      + // {TreeView.GetChildElements([this.props.document], "", new Doc(), undefined, "", (doc: Doc, relativeTo?: Doc, before?: boolean) => false, this.props.removeDocByRef, this.move, + // StrCast(this.props.document.dropAction) as dropActionType, (doc: Doc, dataDoc: Doc | undefined, where: string) => { }, Transform.Identity, () => ({ translateX: 0, translateY: 0 }), () => false, () => 400, 7)} + //
    ; + return ( + 1} + PanelWidth={() => 400} + PanelHeight={() => 400} + focus={(doc: Doc, willZoom: boolean) => { }} + selectOnLoad={false} + parentActive={returnFalse} + whenActiveChanged={(isActive: boolean) => { }} + bringToFront={(doc: Doc) => { }} + addDocTab={(doc: Doc, dataDoc: Doc | undefined, where: string) => { }} + zoomToScale={(scale: number) => { }} + getScale={() => 3.1415} + /> + ); + } render() { let p = this.props; @@ -786,7 +834,7 @@ export default class PresentationElement extends React.Component p.document, this.move, dropAction, this.props.mainDocument[Id], true); return ( -
    { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}> @@ -811,7 +860,8 @@ export default class PresentationElement extends React.Component - +
    + {this.renderEmbeddedInline()}
    ); } diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index 2bb0ec8c8..56c8beba5 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -19,6 +19,10 @@ -ms-user-select: none; user-select: none; transition: all .1s; + + .jsx-parser { + height: auto; + } } .presentationView-item-above { diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index b318f0321..95458b4ca 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -16,6 +16,7 @@ import { faArrowRight, faArrowLeft, faPlay, faStop, faPlus, faTimes, faMinus, fa import { Docs } from "../../documents/Documents"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import PresentationViewList from "./PresentationList"; +import { ContextMenu } from "../ContextMenu"; library.add(faArrowLeft); library.add(faArrowRight); @@ -805,7 +806,6 @@ export class PresentationView extends React.Component { this.presElementsMappings.set(keyDoc, elem); } - render() { let width = NumCast(this.curPresentation.width); -- cgit v1.2.3-70-g09d2 From 1bb4cc79000b6d7c3a3fc137926e754877bf1dce Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Wed, 24 Jul 2019 20:50:13 -0400 Subject: some style --- src/client/views/presentationview/PresentationView.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index 56c8beba5..392ec1fb7 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -21,7 +21,8 @@ transition: all .1s; .jsx-parser { - height: auto; + height: 300px; + width: 400px; } } -- cgit v1.2.3-70-g09d2 From 3d5884541db27dca38dac25b773a0eae7451a57f Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Wed, 24 Jul 2019 21:15:42 -0400 Subject: Ask Bob About sizing and scaling --- .../views/presentationview/PresentationElement.tsx | 44 ++++++++++++++++------ .../views/presentationview/PresentationView.scss | 1 + 2 files changed, 33 insertions(+), 12 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index f354a14c2..2091974ee 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -5,7 +5,7 @@ import { NumCast, BoolCast, StrCast, Cast, FieldValue } from "../../../new_field import { Id } from "../../../new_fields/FieldSymbols"; import { observable, action, computed, runInAction } from "mobx"; import "./PresentationView.scss"; -import { Utils, emptyFunction, returnFalse } from "../../../Utils"; +import { Utils, emptyFunction, returnFalse, returnOne } from "../../../Utils"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch } from '@fortawesome/free-solid-svg-icons'; @@ -799,22 +799,42 @@ export default class PresentationElement extends React.Component; return ( + // 1} + // PanelWidth={() => 400} + // PanelHeight={() => 400} + // focus={(doc: Doc, willZoom: boolean) => { }} + // selectOnLoad={false} + // parentActive={returnFalse} + // whenActiveChanged={(isActive: boolean) => { }} + // bringToFront={(doc: Doc) => { }} + // addDocTab={(doc: Doc, dataDoc: Doc | undefined, where: string) => { }} + // zoomToScale={(scale: number) => { }} + // getScale={() => 3.1415} + // /> 1} - PanelWidth={() => 400} - PanelHeight={() => 400} - focus={(doc: Doc, willZoom: boolean) => { }} + addDocTab={returnFalse} + renderDepth={1} + PanelWidth={returnXDimension} + PanelHeight={returnYDimension} + focus={emptyFunction} selectOnLoad={false} parentActive={returnFalse} - whenActiveChanged={(isActive: boolean) => { }} - bringToFront={(doc: Doc) => { }} - addDocTab={(doc: Doc, dataDoc: Doc | undefined, where: string) => { }} - zoomToScale={(scale: number) => { }} - getScale={() => 3.1415} + whenActiveChanged={returnFalse} + bringToFront={emptyFunction} + zoomToScale={emptyFunction} + getScale={returnOne} + ContainingCollectionView={undefined} + ContentScaling={scale} /> ); } diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index 392ec1fb7..b8b4f23c4 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -23,6 +23,7 @@ .jsx-parser { height: 300px; width: 400px; + margin-top: 20px; } } -- cgit v1.2.3-70-g09d2 From 7a750bcd925e6903f7b44da15a336081f28f5c29 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 25 Jul 2019 10:38:42 -0400 Subject: presentation view opacity behavior toggle --- src/client/views/presentationview/PresentationView.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index b318f0321..f2fef7f16 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -63,6 +63,10 @@ export class PresentationView extends React.Component { @observable titleInputElement: HTMLInputElement | undefined; @observable PresTitleChangeOpen: boolean = false; + @observable opacity = 1; + @observable persistOpacity = true; + @observable labelOpacity = 0; + //initilize class variables constructor(props: PresViewProps) { super(props); @@ -811,7 +815,7 @@ export class PresentationView extends React.Component { let width = NumCast(this.curPresentation.width); return ( -
    +
    !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" }}>
    {this.renderSelectOrPresSelection()} @@ -830,6 +834,18 @@ export class PresentationView extends React.Component { {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"}

    Date: Thu, 25 Jul 2019 12:51:59 -0400 Subject: Some Preview Shown. Css left --- src/client/views/presentationview/PresentationElement.tsx | 15 ++++++++------- src/client/views/presentationview/PresentationView.scss | 4 +++- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 2091974ee..859ab9862 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -21,6 +21,7 @@ import { DocumentContentsView } from "../nodes/DocumentContentsView"; import { Transform } from "../../util/Transform"; import { FieldView } from "../nodes/FieldView"; import { DocumentView } from "../nodes/DocumentView"; +import { DocumentType } from "../../documents/Documents"; library.add(faArrowUp); library.add(fileSolid); @@ -656,7 +657,7 @@ export default class PresentationElement extends React.Component { - this.props.document.libraryBrush = true; + // this.props.document.libraryBrush = true; if (e.buttons === 1 && SelectionManager.GetIsDragging()) { let selected = NumCast(this.props.mainDocument.selectedDoc, 0); @@ -673,7 +674,7 @@ export default class PresentationElement extends React.Component { - this.props.document.libraryBrush = false; + // this.props.document.libraryBrush = false; //to get currently selected presentation doc let selected = NumCast(this.props.mainDocument.selectedDoc, 0); @@ -797,7 +798,7 @@ export default class PresentationElement extends React.Component false, this.props.removeDocByRef, this.move, // StrCast(this.props.document.dropAction) as dropActionType, (doc: Doc, dataDoc: Doc | undefined, where: string) => { }, Transform.Identity, () => ({ translateX: 0, translateY: 0 }), () => false, () => 400, 7)} // ; - + let scale = () => 175 / NumCast(this.props.document.nativeWidth, 175); return ( // { }} // getScale={() => 3.1415} // /> + 175} + PanelHeight={() => 175} focus={emptyFunction} selectOnLoad={false} parentActive={returnFalse} @@ -861,8 +863,7 @@ export default class PresentationElement extends React.Component { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}> diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index b8b4f23c4..c2d064941 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -19,12 +19,14 @@ -ms-user-select: none; user-select: none; transition: all .1s; + max-height: 250px; .jsx-parser { height: 300px; - width: 400px; + //width: 400px; margin-top: 20px; } + } .presentationView-item-above { -- cgit v1.2.3-70-g09d2 From 24a73583847e6ab00c8b1a00859129665e6ac212 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Thu, 25 Jul 2019 19:03:04 -0400 Subject: Css Acting weird, fixes needed --- .../views/presentationview/PresentationElement.tsx | 66 ++++++++++++++-------- .../views/presentationview/PresentationView.scss | 14 ++++- 2 files changed, 55 insertions(+), 25 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 859ab9862..ff68f47ba 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -798,6 +798,8 @@ export default class PresentationElement extends React.Component false, this.props.removeDocByRef, this.move, // StrCast(this.props.document.dropAction) as dropActionType, (doc: Doc, dataDoc: Doc | undefined, where: string) => { }, Transform.Identity, () => ({ translateX: 0, translateY: 0 }), () => false, () => 400, 7)} // ; + let propDocWidth = NumCast(this.props.document.nativeWidth); + let propDocHeight = NumCast(this.props.document.nativeHeight); let scale = () => 175 / NumCast(this.props.document.nativeWidth, 175); return ( // { }} // getScale={() => 3.1415} // /> - - 175} - PanelHeight={() => 175} - focus={emptyFunction} - selectOnLoad={false} - parentActive={returnFalse} - whenActiveChanged={returnFalse} - bringToFront={emptyFunction} - zoomToScale={emptyFunction} - getScale={returnOne} - ContainingCollectionView={undefined} - ContentScaling={scale} - /> +
    + 20} + PanelHeight={() => 20} + focus={emptyFunction} + selectOnLoad={false} + parentActive={returnFalse} + whenActiveChanged={returnFalse} + bringToFront={emptyFunction} + zoomToScale={emptyFunction} + getScale={returnOne} + ContainingCollectionView={undefined} + ContentScaling={scale} + /> +
    +
    ); } @@ -863,7 +885,7 @@ export default class PresentationElement extends React.Component { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}> diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index c2d064941..93cf0b365 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -19,12 +19,20 @@ -ms-user-select: none; user-select: none; transition: all .1s; - max-height: 250px; + //max-height: 250px; .jsx-parser { - height: 300px; + // height: 300px; //width: 400px; - margin-top: 20px; + // margin-top: 20px; + // overflow-y: scroll; + } + + .documentView-node { + // height: auto !important; + // width: aut !important; + position: absolute; + z-index: 1; } } -- cgit v1.2.3-70-g09d2 From 4e73b2b844846ee39e743f69df6225fb4cbf4f2c Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Fri, 26 Jul 2019 17:24:27 -0400 Subject: Preview shown with right css --- src/client/views/presentationview/PresentationElement.tsx | 14 ++++++++++---- src/client/views/presentationview/PresentationView.tsx | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index ff68f47ba..3297acee9 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -800,7 +800,12 @@ export default class PresentationElement extends React.Component; let propDocWidth = NumCast(this.props.document.nativeWidth); let propDocHeight = NumCast(this.props.document.nativeHeight); - let scale = () => 175 / NumCast(this.props.document.nativeWidth, 175); + let previewWidth = NumCast(this.props.document.schemaPreviewWidth); + let scale = () => { + let newScale = 175 / NumCast(this.props.document.nativeWidth, 175); + console.log("New Scale: ", newScale); + return newScale; + }; return ( // { }} // getScale={() => 3.1415} // /> +
    20} - PanelHeight={() => 20} + PanelWidth={() => 350} + PanelHeight={() => 100} focus={emptyFunction} selectOnLoad={false} parentActive={returnFalse} diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 95458b4ca..718af1bf2 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -811,7 +811,7 @@ export class PresentationView extends React.Component { let width = NumCast(this.curPresentation.width); return ( -
    +
    {this.renderSelectOrPresSelection()} -- cgit v1.2.3-70-g09d2 From c6da9a2800037a951ea5070b4a77663401c4d00e Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Fri, 26 Jul 2019 18:52:30 -0400 Subject: resizable pres view --- .../views/presentationview/PresentationElement.tsx | 22 ----- .../views/presentationview/PresentationView.scss | 2 +- .../views/presentationview/PresentationView.tsx | 109 +++++++++++++++------ 3 files changed, 80 insertions(+), 53 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 3297acee9..fdddf0e41 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -800,36 +800,14 @@ export default class PresentationElement extends React.Component; let propDocWidth = NumCast(this.props.document.nativeWidth); let propDocHeight = NumCast(this.props.document.nativeHeight); - let previewWidth = NumCast(this.props.document.schemaPreviewWidth); let scale = () => { let newScale = 175 / NumCast(this.props.document.nativeWidth, 175); console.log("New Scale: ", newScale); return newScale; }; return ( - // 1} - // PanelWidth={() => 400} - // PanelHeight={() => 400} - // focus={(doc: Doc, willZoom: boolean) => { }} - // selectOnLoad={false} - // parentActive={returnFalse} - // whenActiveChanged={(isActive: boolean) => { }} - // bringToFront={(doc: Doc) => { }} - // addDocTab={(doc: Doc, dataDoc: Doc | undefined, where: string) => { }} - // zoomToScale={(scale: number) => { }} - // getScale={() => 3.1415} - // /> -
    { //Variable that holds reference to title input, so that new presentations get titles assigned. @observable titleInputElement: HTMLInputElement | undefined; @observable PresTitleChangeOpen: boolean = false; + @observable PresViewWidth: number | undefined; //initilize class variables constructor(props: PresViewProps) { @@ -81,6 +82,7 @@ export class PresentationView extends React.Component { //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. @@ -806,43 +808,90 @@ export class PresentationView extends React.Component { this.presElementsMappings.set(keyDoc, elem); } + //_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(); + } + @action + onPointerMove = (e: PointerEvent) => { + + this.curPresentation.width = Math.max(window.innerWidth - e.clientX, 255); + } + @action + onPointerUp = (e: PointerEvent) => { + //this.isPointerDown = false; + // if (Math.abs(e.clientX - this._downsize) < 4) { + // if (this.flyoutWidth < 5) this.flyoutWidth = 250; + // else this.flyoutWidth = 0; + // } + document.removeEventListener("pointermove", this.onPointerMove); + document.removeEventListener("pointerup", this.onPointerUp); + } + + togglePresView = (e) => { + e.stopPropagation(); + e.preventDefault(); + let width = NumCast(this.curPresentation.width); + if (width === 0) { + this.curPresentation.width = 255; + } else { + this.curPresentation.width = 0; + } + } + render() { let width = NumCast(this.curPresentation.width); + this.PresViewWidth = width; + return ( -
    -
    - {this.renderSelectOrPresSelection()} - - - - +
    +
    +
    + {this.renderSelectOrPresSelection()} + + + + +
    +
    + + {this.renderPlayPauseButton()} + +
    + + this.presElementsMappings.clear()} + />
    -
    - - {this.renderPlayPauseButton()} - +
    +
    - this.presElementsMappings.clear()} - />
    ); } -- cgit v1.2.3-70-g09d2 From 811cb72cdb04b316f19d02c609ad515d6ec0a1b1 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Fri, 26 Jul 2019 18:54:37 -0400 Subject: CleanUp --- src/client/views/presentationview/PresentationView.scss | 7 +------ src/client/views/presentationview/PresentationView.tsx | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index 5769a1a0a..ee413f379 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -21,12 +21,7 @@ transition: all .1s; //max-height: 250px; - .jsx-parser { - // height: 300px; - //width: 400px; - // margin-top: 20px; - // overflow-y: scroll; - } + .documentView-node { // height: auto !important; diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 273fa5e5f..de6c8ff82 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -834,7 +834,7 @@ export class PresentationView extends React.Component { document.removeEventListener("pointerup", this.onPointerUp); } - togglePresView = (e) => { + togglePresView = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); let width = NumCast(this.curPresentation.width); -- cgit v1.2.3-70-g09d2 From c360dc0adb468ae3aaa1c2d943606993d01a5a52 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 27 Jul 2019 11:08:44 -0400 Subject: fixed handling of keyboard events to avoid triggering global key events. made BoolCast default to false. fixed templating to deal with conflict between field fields and template fields --- src/client/util/DocumentManager.ts | 16 +++++++-------- src/client/views/EditableView.tsx | 3 +++ src/client/views/MainView.tsx | 1 - src/client/views/MetadataEntryMenu.tsx | 1 + .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionStackingView.tsx | 3 ++- .../CollectionFreeFormLinkView.tsx | 8 ++++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 8 ++++---- src/client/views/nodes/FormattedTextBox.tsx | 4 ++-- src/client/views/nodes/IconBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 3 ++- src/client/views/nodes/LinkMenuItem.tsx | 2 +- src/client/views/pdf/Page.tsx | 22 ++++++++------------ .../views/presentationview/PresentationElement.tsx | 24 ++++++++++------------ .../views/presentationview/PresentationView.tsx | 2 +- src/new_fields/Doc.ts | 19 +++++++++-------- src/new_fields/Types.ts | 2 +- 18 files changed, 62 insertions(+), 62 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 262194a40..32f728c71 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,16 +1,14 @@ -import { computed, observable, action } from 'mobx'; -import { DocumentView } from '../views/nodes/DocumentView'; -import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; -import { FieldValue, Cast, NumCast, BoolCast, StrCast } from '../../new_fields/Types'; -import { listSpec } from '../../new_fields/Schema'; -import { undoBatch, UndoManager } from './UndoManager'; +import { action, computed, observable } from 'mobx'; +import { Doc } from '../../new_fields/Doc'; +import { Id } from '../../new_fields/FieldSymbols'; +import { BoolCast, Cast, NumCast } from '../../new_fields/Types'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; -import { CollectionView } from '../views/collections/CollectionView'; import { CollectionPDFView } from '../views/collections/CollectionPDFView'; import { CollectionVideoView } from '../views/collections/CollectionVideoView'; -import { Id } from '../../new_fields/FieldSymbols'; +import { CollectionView } from '../views/collections/CollectionView'; +import { DocumentView } from '../views/nodes/DocumentView'; import { LinkManager } from './LinkManager'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; +import { undoBatch, UndoManager } from './UndoManager'; export class DocumentManager { diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index c66a92f48..7cabebddd 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -50,8 +50,10 @@ export class EditableView extends React.Component { @action onKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Tab") { + e.stopPropagation(); this.props.OnTab && this.props.OnTab(); } else if (e.key === "Enter") { + e.stopPropagation(); if (!e.ctrlKey) { if (this.props.SetValue(e.currentTarget.value, e.shiftKey)) { this._editing = false; @@ -61,6 +63,7 @@ export class EditableView extends React.Component { this._editing = false; } } else if (e.key === "Escape") { + e.stopPropagation(); this._editing = false; } } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index bfb50bc75..8b7eb8856 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -7,7 +7,6 @@ import "normalize.css"; import * as React from 'react'; import { SketchPicker } from 'react-color'; import Measure from 'react-measure'; -import * as request from 'request'; import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; import { InkTool } from '../../new_fields/InkField'; diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index bd5a307b3..c50e02f0d 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -76,6 +76,7 @@ export class MetadataEntryMenu extends React.Component{ onValueKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { + e.stopPropagation(); const script = KeyValueBox.CompileKVPScript(this._currentValue); if (!script) return; let doc = this.props.docs; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 8ce3b40e5..0f67c47aa 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -11,7 +11,7 @@ import { Doc, DocListCast, DocListCastAsync, Field } from "../../../new_fields/D import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { Docs } from "../../documents/Documents"; import { Gateway } from "../../northstar/manager/Gateway"; import { SetupDrag, DragManager } from "../../util/DragManager"; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 3da13bff5..d5a7b90da 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -53,7 +53,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { let xhgt = height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap); return xhgt; }, this.yMargin); - this.layoutDoc.height = hgt * (this.props as any).ContentScaling(); + (this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc) + .height = hgt * (this.props as any).ContentScaling(); } }, { fireImmediately: true }); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index b546d1b78..6af87b138 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -21,10 +21,10 @@ export class CollectionFreeFormLinkView extends React.Component { // let width = l[WidthSym](); // l.x = (x1 + x2) / 2 - width / 2; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f83d02271..eaad43c10 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -471,7 +471,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) { - let minim = BoolCast(doc.isMinimized, false); + let minim = BoolCast(doc.isMinimized); if (minim === undefined || !minim) { const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : {}; state = pos.state === undefined ? state : pos.state; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3152d6a2a..bc2af2ae8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -275,7 +275,7 @@ export class DocumentView extends DocComponent(Docu let iconAnimating = Cast(maximizedDoc.isIconAnimating, List); if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) { if (isMinimized === undefined) { - isMinimized = BoolCast(maximizedDoc.isMinimized, false); + isMinimized = BoolCast(maximizedDoc.isMinimized); } maximizedDoc.willMaximize = isMinimized; maximizedDoc.isMinimized = false; @@ -308,7 +308,7 @@ export class DocumentView extends DocComponent(Docu Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { SelectionManager.SelectDoc(this, e.ctrlKey); let isExpander = (e.target as any).id === "isExpander"; - if (BoolCast(this.props.Document.isButton, false) || isExpander) { + if (BoolCast(this.props.Document.isButton) || isExpander) { SelectionManager.DeselectAll(); let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs); let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs); @@ -326,7 +326,7 @@ export class DocumentView extends DocComponent(Docu maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace")); if (!maxLocation || maxLocation === "inPlace") { let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); - let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false); + let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized), false); expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false); let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView); if (!hasView) { @@ -409,7 +409,7 @@ export class DocumentView extends DocComponent(Docu @undoBatch makeBtnClicked = (): void => { let doc = Doc.GetProto(this.props.Document); - doc.isButton = !BoolCast(doc.isButton, false); + doc.isButton = !BoolCast(doc.isButton); if (doc.isButton) { if (!doc.nativeWidth) { doc.nativeWidth = this.props.Document[WidthSym](); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0a79677e2..bd0fd8301 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -459,8 +459,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe specificContextMenu = (e: React.MouseEvent): void => { let subitems: ContextMenuProps[] = []; subitems.push({ - description: BoolCast(this.props.Document.autoHeight, false) ? "Manual Height" : "Auto Height", - event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight, false)), icon: "expand-arrows-alt" + description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height", + event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt" }); ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems }); } diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index d6ab2a34a..6f50033a4 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -64,7 +64,7 @@ export class IconBox extends React.Component { let hideLabel = BoolCast(this.props.Document.hideLabel); let maxDocs = DocListCast(this.props.Document.maximizedDocs); let firstDoc = maxDocs.length ? maxDocs[0] : undefined; - let label = hideLabel ? "" : (firstDoc && labelField && !BoolCast(this.props.Document.useOwnTitle, false) ? firstDoc[labelField] : this.props.Document.title); + let label = hideLabel ? "" : (firstDoc && labelField && !BoolCast(this.props.Document.useOwnTitle) ? firstDoc[labelField] : this.props.Document.title); return (
    {this.minimizedIcon} diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 9fc0f2080..77824b4ff 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -46,6 +46,7 @@ export class KeyValueBox extends React.Component { @action onEnterKey = (e: React.KeyboardEvent): void => { if (e.key === 'Enter') { + e.stopPropagation(); if (this._keyInput && this._valueInput && this.fieldDocToLayout) { if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput, this._valueInput)) { this._keyInput = ""; @@ -153,7 +154,7 @@ export class KeyValueBox extends React.Component { - + ) diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx index a0c37a719..d4c92c9f2 100644 --- a/src/client/views/nodes/LinkMenuItem.tsx +++ b/src/client/views/nodes/LinkMenuItem.tsx @@ -7,7 +7,7 @@ import { undoBatch } from "../../util/UndoManager"; import './LinkMenu.scss'; import React = require("react"); import { Doc } from '../../../new_fields/Doc'; -import { StrCast, Cast, BoolCast, FieldValue, NumCast } from '../../../new_fields/Types'; +import { StrCast, Cast, FieldValue, NumCast } from '../../../new_fields/Types'; import { observable, action } from 'mobx'; import { LinkManager } from '../../util/LinkManager'; import { DragLinkAsDocument } from '../../util/DragManager'; diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index c9d442fe5..a6864e0f3 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -1,22 +1,18 @@ +import { action, IReactionDisposer, observable } from "mobx"; import { observer } from "mobx-react"; -import React = require("react"); -import { observable, action, runInAction, IReactionDisposer, reaction } from "mobx"; import * as Pdfjs from "pdfjs-dist"; -import { Opt, Doc, FieldResult, Field, DocListCast, WidthSym, HeightSym, DocListCastAsync } from "../../../new_fields/Doc"; -import "./PDFViewer.scss"; import "pdfjs-dist/web/pdf_viewer.css"; -import { PDFBox } from "../nodes/PDFBox"; -import { DragManager } from "../../util/DragManager"; -import { Docs, DocUtils } from "../../documents/Documents"; +import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; -import { emptyFunction } from "../../../Utils"; -import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { menuBar } from "prosemirror-menu"; -import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Docs, DocUtils } from "../../documents/Documents"; +import { DragManager } from "../../util/DragManager"; +import { PDFBox } from "../nodes/PDFBox"; import PDFMenu from "./PDFMenu"; -import { UndoManager } from "../../util/UndoManager"; -import { copy } from "typescript-collections/dist/lib/arrays"; +import { scale } from "./PDFViewer"; +import "./PDFViewer.scss"; +import React = require("react"); interface IPageProps { diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 329630875..36f1178f1 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -1,21 +1,19 @@ -import { observer } from "mobx-react"; -import React = require("react"); -import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { NumCast, BoolCast, StrCast, Cast } from "../../../new_fields/Types"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { observable, action, computed, runInAction } from "mobx"; -import "./PresentationView.scss"; -import { Utils } from "../../../Utils"; import { library } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch } from '@fortawesome/free-solid-svg-icons'; 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 { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed, observable, runInAction } from "mobx"; +import { observer } from "mobx-react"; +import { Doc } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Utils } from "../../../Utils"; +import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; -import { indexOf } from "typescript-collections/dist/lib/arrays"; -import { map } from "bluebird"; +import "./PresentationView.scss"; +import React = require("react"); library.add(faArrowUp); library.add(fileSolid); diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index f2fef7f16..e25725275 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -171,7 +171,7 @@ export class PresentationView extends React.Component { //storing the presentation status,ie. whether it was stopped or playing - let presStatusBackUp = BoolCast(this.curPresentation.presStatus, null); + let presStatusBackUp = BoolCast(this.curPresentation.presStatus); runInAction(() => this.presStatus = presStatusBackUp); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index dbb0dc505..b5708e97b 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -455,7 +455,7 @@ export namespace Doc { return otherdoc; } - export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) { + export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) { // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??) let backgroundLayout = StrCast(fieldTemplate.backgroundLayout); let fieldLayoutDoc = fieldTemplate; @@ -466,21 +466,24 @@ export namespace Doc { if (backgroundLayout) { backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`); } - let nw = Cast(fieldTemplate.nativeWidth, "number"); - let nh = Cast(fieldTemplate.nativeHeight, "number"); let layoutDelegate = fieldTemplate.layout instanceof Doc ? fieldLayoutDoc : fieldTemplate; layoutDelegate.layout = layout; - fieldTemplate.title = metaKey; fieldTemplate.templateField = metaKey; + fieldTemplate.title = metaKey; + fieldTemplate.isTemplate = true; fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout; fieldTemplate.backgroundLayout = backgroundLayout; - fieldTemplate.nativeWidth = nw; - fieldTemplate.nativeHeight = nh; - fieldTemplate.isTemplate = true; + /* move certain layout properties from the original data doc to the template layout to avoid + inheriting them from the template's data doc which may also define these fields for its own use. + */ + fieldTemplate.ignoreAspect = BoolCast(fieldTemplate.ignoreAspect); + fieldTemplate.singleColumn = BoolCast(fieldTemplate.singleColumn); + fieldTemplate.nativeWidth = Cast(fieldTemplate.nativeWidth, "number"); + fieldTemplate.nativeHeight = Cast(fieldTemplate.nativeHeight, "number"); fieldTemplate.showTitle = "title"; - setTimeout(() => fieldTemplate.proto = proto); + setTimeout(() => fieldTemplate.proto = templateDataDoc); } export async function ToggleDetailLayout(d: Doc) { diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index f8a4a30b4..565ae2ee3 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -78,7 +78,7 @@ export function StrCast(field: FieldResult, defaultVal: string | null = "") { return Cast(field, "string", defaultVal); } -export function BoolCast(field: FieldResult, defaultVal: boolean | null = null) { +export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) { return Cast(field, "boolean", defaultVal); } export function DateCast(field: FieldResult) { -- cgit v1.2.3-70-g09d2 From 215b73fbcfe0d6f205668e1bb7c755228e858ac9 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Mon, 29 Jul 2019 19:19:49 -0400 Subject: PresMode, CLoseable Pres, and some bug fixes --- src/client/views/MainView.tsx | 2 +- .../views/presentationview/PresentationElement.tsx | 24 ++++- .../views/presentationview/PresentationList.tsx | 2 +- .../presentationview/PresentationModeMenu.scss | 30 ++++++ .../presentationview/PresentationModeMenu.tsx | 92 ++++++++++++++++ .../views/presentationview/PresentationView.scss | 2 +- .../views/presentationview/PresentationView.tsx | 116 +++++++++++++++++---- 7 files changed, 238 insertions(+), 30 deletions(-) create mode 100644 src/client/views/presentationview/PresentationModeMenu.scss create mode 100644 src/client/views/presentationview/PresentationModeMenu.tsx (limited to 'src/client/views/presentationview') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 53be0278e..0dbb241e4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -267,7 +267,7 @@ export class MainView extends React.Component { zoomToScale={emptyFunction} getScale={returnOne} />} - {castRes ? : null} + {castRes ? : null}
    } ; diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index fdddf0e41..05a70f79a 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -8,7 +8,7 @@ import "./PresentationView.scss"; import { Utils, emptyFunction, returnFalse, returnOne } from "../../../Utils"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch } from '@fortawesome/free-solid-svg-icons'; +import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch, faArrowRight } from '@fortawesome/free-solid-svg-icons'; import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons'; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; @@ -28,6 +28,7 @@ library.add(fileSolid); library.add(faLocationArrow); library.add(fileRegular as any); library.add(faSearch); +library.add(faArrowRight); interface PresentationElementProps { mainDocument: Doc; @@ -54,6 +55,7 @@ export enum buttonIndex { FadeAfter = 3, HideAfter = 4, Group = 5, + OpenRight = 6 } @@ -76,7 +78,7 @@ export default class PresentationElement extends React.Component { + 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. */ @@ -637,7 +651,7 @@ export default class PresentationElement extends React.Component { 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!) { @@ -887,6 +901,8 @@ export default class PresentationElement extends React.Component + +
    {this.renderEmbeddedInline()}
    diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx index 2d63d41b5..2a31137af 100644 --- a/src/client/views/presentationview/PresentationList.tsx +++ b/src/client/views/presentationview/PresentationList.tsx @@ -95,7 +95,7 @@ export default class PresentationViewList extends React.Component this.props.PresElementsMappings.set(doc, e); } }} - key={doc[Id]} + key={doc[Id] + index} mainDocument={this.props.mainDocument} document={doc} index={index} 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..b3edeb1e2 --- /dev/null +++ b/src/client/views/presentationview/PresentationModeMenu.tsx @@ -0,0 +1,92 @@ +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; +} + +@observer +export default class PresModeMenu extends React.Component { + + @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 = ""; + //@observable private Pinned: boolean = false; + + + private _mainCont: React.RefObject = React.createRef(); + + @action + pointerEntered = (e: React.PointerEvent) => { + this._transition = "opacity 0.1s"; + this._transitionDelay = ""; + this._opacity = 1; + } + + @action + dragging = (e: PointerEvent) => { + this._right -= e.movementX; + this._top += e.movementY; + + e.stopPropagation(); + e.preventDefault(); + } + + dragEnd = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + e.stopPropagation(); + e.preventDefault(); + } + + dragStart = (e: React.PointerEvent) => { + document.removeEventListener("pointermove", this.dragging); + document.addEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + document.addEventListener("pointerup", this.dragEnd); + let clientRect = this._mainCont.current!.getBoundingClientRect(); + + // runInAction(() => this._left = (clientRect.width - e.nativeEvent.offsetX) + clientRect.left); + // runInAction(() => this._top = e.nativeEvent.offsetY); + + e.stopPropagation(); + e.preventDefault(); + } + + renderPlayPauseButton = () => { + if (this.props.presStatus) { + return ; + } else { + return ; + } + } + + render() { + return ( +
    + + {this.renderPlayPauseButton()} + + +
    +
    + ); + } + + + + +} \ No newline at end of file diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index ee413f379..97cbd4a24 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -66,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 de6c8ff82..70d86624c 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,11 +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 { ContextMenu } from "../ContextMenu"; +import PresModeMenu from "./PresentationModeMenu"; library.add(faArrowLeft); library.add(faArrowRight); @@ -26,10 +27,12 @@ library.add(faPlus); library.add(faTimes); library.add(faMinus); library.add(faEdit); +library.add(faEye); export interface PresViewProps { Documents: List; + addDocTab: (doc: Doc) => void; } const expandedWidth = 400; @@ -63,7 +66,8 @@ export class PresentationView extends React.Component { //Variable that holds reference to title input, so that new presentations get titles assigned. @observable titleInputElement: HTMLInputElement | undefined; @observable PresTitleChangeOpen: boolean = false; - @observable PresViewWidth: number | undefined; + @observable presMode: boolean = false; + //initilize class variables constructor(props: PresViewProps) { @@ -360,11 +364,21 @@ export class PresentationView extends React.Component { //checking if curDoc has navigation open let curDocButtons = this.presElementsMappings.get(curDoc)!.selected; if (curDocButtons[buttonIndex.Navigate]) { - DocumentManager.Instance.jumpToDocument(curDoc, false); + // if (curDocButtons[buttonIndex.OpenRight]) { + // DocumentManager.Instance.jumpToDocument(curDoc, false); + // } else { + // DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); + // } + 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, this.props.addDocTab); + } + let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); curDoc.viewScale = newScale; @@ -377,9 +391,15 @@ export class PresentationView extends React.Component { 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, this.props.addDocTab); + } let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); curDoc.viewScale = newScale; //saving the scale that user was on @@ -389,6 +409,15 @@ export class PresentationView extends React.Component { } + jumpToTabOrRight = (curDocButtons: boolean[], curDoc: Doc) => { + if (curDocButtons[buttonIndex.OpenRight]) { + DocumentManager.Instance.jumpToDocument(curDoc, false); + } else { + console.log("Open in tab!!"); + DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); + } + } + /** * Async function that supposedly return the doc that is located at given index. */ @@ -578,18 +607,35 @@ export class PresentationView extends React.Component { //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; } + 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 @@ -808,9 +854,9 @@ export class PresentationView extends React.Component { this.presElementsMappings.set(keyDoc, elem); } - //_downsize = 0; + _downsize = 0; onPointerDown = (e: React.PointerEvent) => { - //this._downsize = e.clientX; + this._downsize = e.clientX; document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); @@ -821,15 +867,16 @@ export class PresentationView extends React.Component { @action onPointerMove = (e: PointerEvent) => { - this.curPresentation.width = Math.max(window.innerWidth - e.clientX, 255); + this.curPresentation.width = Math.max(window.innerWidth - e.clientX, 300); } @action onPointerUp = (e: PointerEvent) => { - //this.isPointerDown = false; - // if (Math.abs(e.clientX - this._downsize) < 4) { - // if (this.flyoutWidth < 5) this.flyoutWidth = 250; - // else this.flyoutWidth = 0; - // } + if (Math.abs(e.clientX - this._downsize) < 4) { + let presWidth = NumCast(this.curPresentation.width); + if (presWidth - 300 !== 0) { + this.curPresentation.width = 0; + } + } document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); } @@ -839,17 +886,38 @@ export class PresentationView extends React.Component { e.preventDefault(); let width = NumCast(this.curPresentation.width); if (width === 0) { - this.curPresentation.width = 255; - } else { + this.curPresentation.width = 300; + } + } + @action + openPresMode = () => { + if (!this.presMode) { this.curPresentation.width = 0; + this.presMode = true; + } + } + + @action + closePresMode = () => { + if (this.presMode) { + this.presMode = false; + this.curPresentation.width = 300; + } + + } + + renderPresMode = () => { + if (this.presMode) { + return ; + } else { + return (null); } + } render() { let width = NumCast(this.curPresentation.width); - this.PresViewWidth = width; - return (
    @@ -857,6 +925,7 @@ export class PresentationView extends React.Component {
    {this.renderSelectOrPresSelection()} +
    + {this.renderPresMode()}
    ); } -- cgit v1.2.3-70-g09d2 From 7b2bbf518779db3d5ef389f6a9f0d41aa2862999 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Mon, 29 Jul 2019 19:54:00 -0400 Subject: trying to get tab --- src/client/views/presentationview/PresentationView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index cd38fc2ec..c583ae4ce 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -18,6 +18,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager"; import PresentationViewList from "./PresentationList"; import { ContextMenu } from "../ContextMenu"; import PresModeMenu from "./PresentationModeMenu"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; library.add(faArrowLeft); library.add(faArrowRight); @@ -418,7 +419,8 @@ export class PresentationView extends React.Component { DocumentManager.Instance.jumpToDocument(curDoc, false); } else { console.log("Open in tab!!"); - DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); + // DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); + CollectionDockingView.Instance.AddTab(undefined, curDoc, undefined); } } -- cgit v1.2.3-70-g09d2 From 893e748f53e801dadfa31d7b1914c790742fbcde Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Mon, 29 Jul 2019 20:22:13 -0400 Subject: Important fix for backUp receive --- src/client/views/presentationview/PresentationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationList.tsx b/src/client/views/presentationview/PresentationList.tsx index 2a31137af..2d63d41b5 100644 --- a/src/client/views/presentationview/PresentationList.tsx +++ b/src/client/views/presentationview/PresentationList.tsx @@ -95,7 +95,7 @@ export default class PresentationViewList extends React.Component this.props.PresElementsMappings.set(doc, e); } }} - key={doc[Id] + index} + key={doc[Id]} mainDocument={this.props.mainDocument} document={doc} index={index} -- cgit v1.2.3-70-g09d2 From c4a8b656eff910fb6c2cd1693308f0b948547cb0 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Mon, 29 Jul 2019 20:43:18 -0400 Subject: Opening as a tab if not present as default instead of open right --- src/client/views/MainView.tsx | 2 +- src/client/views/presentationview/PresentationView.tsx | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0f9f2687b..91c8fe57c 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -277,7 +277,7 @@ export class MainView extends React.Component { zoomToScale={emptyFunction} getScale={returnOne} />} - {castRes ? : null} + {castRes ? : null}
    } ; diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index c583ae4ce..ea85a8c6a 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -33,7 +33,6 @@ library.add(faEye); export interface PresViewProps { Documents: List; - addDocTab: (doc: Doc) => void; } const expandedWidth = 400; @@ -369,11 +368,6 @@ export class PresentationView extends React.Component { //checking if curDoc has navigation open let curDocButtons = this.presElementsMappings.get(curDoc)!.selected; if (curDocButtons[buttonIndex.Navigate]) { - // if (curDocButtons[buttonIndex.OpenRight]) { - // DocumentManager.Instance.jumpToDocument(curDoc, false); - // } else { - // DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); - // } this.jumpToTabOrRight(curDocButtons, curDoc); } else if (curDocButtons[buttonIndex.Show]) { let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]); @@ -381,7 +375,7 @@ export class PresentationView extends React.Component { //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, this.props.addDocTab); + await DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined)); } let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); @@ -403,7 +397,7 @@ export class PresentationView extends React.Component { //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, this.props.addDocTab); + await DocumentManager.Instance.jumpToDocument(docToJump, willZoom, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined)); } let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); curDoc.viewScale = newScale; @@ -418,9 +412,7 @@ export class PresentationView extends React.Component { if (curDocButtons[buttonIndex.OpenRight]) { DocumentManager.Instance.jumpToDocument(curDoc, false); } else { - console.log("Open in tab!!"); - // DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, this.props.addDocTab); - CollectionDockingView.Instance.AddTab(undefined, curDoc, undefined); + DocumentManager.Instance.jumpToDocument(curDoc, false, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined)); } } -- cgit v1.2.3-70-g09d2 From 3468440a4297a105cf4138892c3d163ca9a0c83c Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Tue, 30 Jul 2019 11:30:48 -0400 Subject: CleanUp and Documentation --- .../views/presentationview/PresentationElement.tsx | 37 ++++++----- .../views/presentationview/PresentationList.tsx | 2 - .../presentationview/PresentationModeMenu.tsx | 34 ++++++---- .../views/presentationview/PresentationView.tsx | 76 ++++++++++++++-------- 4 files changed, 92 insertions(+), 57 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index ccc3a72a9..11f3eb846 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -12,12 +12,8 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Utils, returnFalse, emptyFunction, returnOne } from "../../../Utils"; import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; -import { indexOf } from "typescript-collections/dist/lib/arrays"; -import { map } from "bluebird"; import { ContextMenu } from "../ContextMenu"; -import { DocumentContentsView } from "../nodes/DocumentContentsView"; import { Transform } from "../../util/Transform"; -import { FieldView } from "../nodes/FieldView"; import { DocumentView } from "../nodes/DocumentView"; import { DocumentType } from "../../documents/Documents"; import React = require("react"); @@ -73,9 +69,6 @@ export default class PresentationElement extends React.Component { //get the list that stores docs that keep track of buttons @@ -404,6 +400,10 @@ export default class PresentationElement extends React.Component { e.stopPropagation(); @@ -671,7 +671,6 @@ export default class PresentationElement extends React.Component { - // this.props.document.libraryBrush = true; if (e.buttons === 1 && SelectionManager.GetIsDragging()) { let selected = NumCast(this.props.mainDocument.selectedDoc, 0); @@ -688,7 +687,6 @@ export default class PresentationElement extends React.Component { - // this.props.document.libraryBrush = false; //to get currently selected presentation doc let selected = NumCast(this.props.mainDocument.selectedDoc, 0); @@ -787,15 +785,23 @@ export default class PresentationElement extends React.Component) => { e.preventDefault(); e.stopPropagation(); @@ -803,20 +809,19 @@ export default class PresentationElement extends React.Component { if (!this.embedInline) { return (null); } - // return
      - // {TreeView.GetChildElements([this.props.document], "", new Doc(), undefined, "", (doc: Doc, relativeTo?: Doc, before?: boolean) => false, this.props.removeDocByRef, this.move, - // StrCast(this.props.document.dropAction) as dropActionType, (doc: Doc, dataDoc: Doc | undefined, where: string) => { }, Transform.Identity, () => ({ translateX: 0, translateY: 0 }), () => false, () => 400, 7)} - //
    ; 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); - console.log("New Scale: ", newScale); return newScale; }; return ( @@ -836,7 +841,7 @@ export default class PresentationElement extends React.Component 350} - PanelHeight={() => 100} + PanelHeight={() => 90} focus={emptyFunction} selectOnLoad={false} parentActive={returnFalse} 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.tsx b/src/client/views/presentationview/PresentationModeMenu.tsx index b3edeb1e2..4de8da587 100644 --- a/src/client/views/presentationview/PresentationModeMenu.tsx +++ b/src/client/views/presentationview/PresentationModeMenu.tsx @@ -13,6 +13,10 @@ export interface PresModeMenuProps { 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 { @@ -21,18 +25,14 @@ export default class PresModeMenu extends React.Component { @observable private _opacity: number = 1; @observable private _transition: string = "opacity 0.5s"; @observable private _transitionDelay: string = ""; - //@observable private Pinned: boolean = false; private _mainCont: React.RefObject = React.createRef(); - @action - pointerEntered = (e: React.PointerEvent) => { - this._transition = "opacity 0.1s"; - this._transitionDelay = ""; - this._opacity = 1; - } - + /** + * 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; @@ -42,6 +42,10 @@ export default class PresModeMenu extends React.Component { 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); @@ -49,20 +53,24 @@ export default class PresModeMenu extends React.Component { 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); - let clientRect = this._mainCont.current!.getBoundingClientRect(); - - // runInAction(() => this._left = (clientRect.width - e.nativeEvent.offsetX) + clientRect.left); - // runInAction(() => this._top = 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 ; @@ -73,7 +81,7 @@ export default class PresModeMenu extends React.Component { render() { return ( -
    {this.renderPlayPauseButton()} diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index ea85a8c6a..4fe9d3a1b 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -16,7 +16,6 @@ import { faArrowRight, faArrowLeft, faPlay, faStop, faPlus, faTimes, faMinus, fa import { Docs } from "../../documents/Documents"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import PresentationViewList from "./PresentationList"; -import { ContextMenu } from "../ContextMenu"; import PresModeMenu from "./PresentationModeMenu"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -36,6 +35,7 @@ export interface PresViewProps { } const expandedWidth = 400; +const presMinWidth = 300; @observer export class PresentationView extends React.Component { @@ -408,6 +408,10 @@ export class PresentationView extends React.Component { } + /** + * 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); @@ -460,22 +464,6 @@ export class PresentationView extends React.Component { } } - //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) { @@ -513,13 +501,16 @@ export class PresentationView extends React.Component { } } + /** + * 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; } @@ -618,6 +609,11 @@ export class PresentationView extends React.Component { 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) { @@ -848,10 +844,11 @@ export class PresentationView extends React.Component { 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; @@ -862,16 +859,26 @@ export class PresentationView extends React.Component { 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, 300); + 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 - 300 !== 0) { + if (presWidth - presMinWidth !== 0) { this.curPresentation.width = 0; } } @@ -879,14 +886,23 @@ export class PresentationView extends React.Component { 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 = 300; + 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) { @@ -895,15 +911,23 @@ export class PresentationView extends React.Component { } } + /** + * 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 = 300; + this.curPresentation.width = presMinWidth; } } + /** + * Function that is called to render the presentation mode, depending on its flag. + */ renderPresMode = () => { if (this.presMode) { return ; -- cgit v1.2.3-70-g09d2 From b0167303f067be219e015f06ca493a6fdf79e6a3 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Tue, 30 Jul 2019 17:17:53 -0400 Subject: Toggle Fix and styling --- src/client/views/presentationview/PresentationView.scss | 11 +++++++---- src/client/views/presentationview/PresentationView.tsx | 5 ++++- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss index 97cbd4a24..65b09c833 100644 --- a/src/client/views/presentationview/PresentationView.scss +++ b/src/client/views/presentationview/PresentationView.scss @@ -6,6 +6,8 @@ right: 0; top: 0; bottom: 0; + letter-spacing: 2px; + } .presentationView-item { @@ -19,13 +21,11 @@ -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; } @@ -52,10 +52,11 @@ .presentationView-selected { background: gray; + color: black; } .presentationView-heading { - background: lightseagreen; + background: gray; padding: 10px; display: inline-block; width: 100%; @@ -67,6 +68,8 @@ font-size: 25px; display: inline-block; width: calc(100% - 200px); + letter-spacing: 2px; + } .presentation-icon { diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 4fe9d3a1b..9742a2473 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -881,6 +881,9 @@ export class PresentationView extends React.Component { if (presWidth - presMinWidth !== 0) { this.curPresentation.width = 0; } + if (presWidth === 0) { + this.curPresentation.width = presMinWidth; + } } document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -992,7 +995,7 @@ export class PresentationView extends React.Component {
    + onPointerDown={this.onPointerDown}>
    {this.renderPresMode()} -- cgit v1.2.3-70-g09d2 From 8db8c9313ae6ff517568444a4ecb0f708b0d07e2 Mon Sep 17 00:00:00 2001 From: Mohammad Amoush Date: Tue, 30 Jul 2019 17:54:44 -0400 Subject: cleanup --- src/client/views/presentationview/PresentationView.tsx | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 9742a2473..c0251f20b 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -889,18 +889,6 @@ export class PresentationView extends React.Component { 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 -- cgit v1.2.3-70-g09d2 From 0fd8973433b0fc7f0cdb6604ed3b3486288a31f3 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 30 Jul 2019 19:27:19 -0400 Subject: changed willZoom to true so presentation zooms --- src/client/views/presentationview/PresentationView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/presentationview') diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx index 4fe9d3a1b..e74a169a9 100644 --- a/src/client/views/presentationview/PresentationView.tsx +++ b/src/client/views/presentationview/PresentationView.tsx @@ -375,7 +375,7 @@ export class PresentationView extends React.Component { //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)); + await DocumentManager.Instance.jumpToDocument(curDoc, true, undefined, doc => CollectionDockingView.Instance.AddTab(undefined, doc, undefined)); } let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc); -- cgit v1.2.3-70-g09d2 From 753615c80d4cf08605ebaaeeaf0a44a0fd88d898 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 3 Aug 2019 15:21:10 -0400 Subject: working version of clustering --- src/Utils.ts | 2 + src/client/documents/Documents.ts | 3 +- src/client/util/DragManager.ts | 8 +- src/client/views/MainView.tsx | 4 +- src/client/views/TemplateMenu.tsx | 5 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 142 +++++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 +- src/client/views/nodes/DocumentView.tsx | 17 +-- .../views/presentationview/PresentationElement.tsx | 3 +- src/client/views/search/SearchItem.tsx | 3 +- 13 files changed, 125 insertions(+), 81 deletions(-) (limited to 'src/client/views/presentationview') diff --git a/src/Utils.ts b/src/Utils.ts index 8df67df5d..502540eb0 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -140,6 +140,8 @@ export function returnOne() { return 1; } export function returnZero() { return 0; } +export function returnEmptyString() { return ""; } + export function emptyFunction() { } export type Without = Pick>; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 09bafcf43..07e38a4c0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -84,6 +84,7 @@ export interface DocumentOptions { templates?: List; viewType?: number; backgroundColor?: string; + defaultBackgroundColor?: string; dropAction?: dropActionType; backgroundLayout?: string; chromeStatus?: string; @@ -124,7 +125,7 @@ export namespace Docs { const TemplateMap: TemplateMap = new Map([ [DocumentType.TEXT, { layout: { view: FormattedTextBox }, - options: { height: 150, backgroundColor: "#f1efeb" } + options: { height: 150, backgroundColor: "#f1efeb", defaultBackgroundColor: "#f1efeb" } }], [DocumentType.HIST, { layout: { view: HistogramBox, collectionView: [CollectionView, data] as CollectionViewType }, diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 0b5c785a4..a7aaaed7c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -404,7 +404,8 @@ export namespace DragManager { hideSource = options.hideSource(); } } - eles.map(ele => (ele.hidden = hideSource)); + eles.map(ele => (ele.hidden = hideSource) && + (ele.parentElement && ele.parentElement.className.indexOf("collectionFreeFormDocumentView") !== -1 && (ele.parentElement.hidden = hideSource))); let lastX = downX; let lastY = downY; @@ -434,7 +435,10 @@ export namespace DragManager { let hideDragElements = () => { dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); - eles.map(ele => (ele.hidden = false)); + eles.map(ele => { + ele.hidden = false; + (ele.parentElement && ele.parentElement.className.indexOf("collectionFreeFormDocumentView") !== -1 && (ele.parentElement.hidden = false)); + }); }; let endDrag = () => { document.removeEventListener("pointermove", moveHandler, true); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2ecf5fd85..53f589684 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -15,7 +15,7 @@ import { listSpec } from '../../new_fields/Schema'; import { Cast, FieldValue, NumCast, BoolCast, StrCast } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; -import { emptyFunction, returnOne, returnTrue, Utils } from '../../Utils'; +import { emptyFunction, returnOne, returnTrue, Utils, returnEmptyString } from '../../Utils'; import { DocServer } from '../DocServer'; import { Docs } from '../documents/Documents'; import { SetupDrag } from '../util/DragManager'; @@ -270,6 +270,7 @@ export class MainView extends React.Component { PanelWidth={this.getPWidth} PanelHeight={this.getPHeight} renderDepth={0} + backgroundColor={returnEmptyString} selectOnLoad={false} focus={emptyFunction} parentActive={returnTrue} @@ -334,6 +335,7 @@ export class MainView extends React.Component { renderDepth={0} selectOnLoad={false} focus={emptyFunction} + backgroundColor={returnEmptyString} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index e654a0644..6dd908445 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -60,12 +60,9 @@ export class TemplateMenu extends React.Component { let de = new DragManager.DocumentDragData([topDoc], [undefined]); de.moveDocument = topDocView.props.moveDocument; let xf = newDocView.ContentDiv!.getBoundingClientRect(); - console.log("ex = " + ex + " " + xf.left + " " + (ex - xf.left)); DragManager.StartDocumentDrag([newDocView.ContentDiv!], de, ex, ey, { offsetX: (ex - xf.left), offsetY: (ey - xf.top), - handlers: { - dragComplete: () => { }, - }, + handlers: { dragComplete: () => { }, }, hideSource: false }); } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 588102f01..f559480ed 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -10,7 +10,7 @@ import { Id } from '../../../new_fields/FieldSymbols'; import { FieldId } from "../../../new_fields/RefField"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; -import { emptyFunction, returnTrue, Utils, returnOne } from "../../../Utils"; +import { emptyFunction, returnTrue, Utils, returnOne, returnEmptyString } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { DocumentManager } from '../../util/DocumentManager'; import { DragLinksAsDocuments, DragManager } from "../../util/DragManager"; @@ -607,6 +607,7 @@ export class DockedFrameRenderer extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} + backgroundColor={returnEmptyString} addDocTab={this.addDocTab} ContainingCollectionView={undefined} zoomToScale={emptyFunction} diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9efd0d3ec..8218877ba 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -6,7 +6,7 @@ import { action, computed, observable, trace, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, Column, RowInfo, ResizedChangeFunction, Resize } from "react-table"; import "react-table/react-table.css"; -import { emptyFunction, returnOne } from "../../../Utils"; +import { emptyFunction, returnOne, returnEmptyString } from "../../../Utils"; import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; @@ -999,6 +999,7 @@ export class CollectionSchemaPreview extends React.Component r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top); } - _groupingBorder = 100; + _clusterDistance = 75; bounsdSelect(doc: Doc, doc2: Doc) { - var x2 = NumCast(doc2.x) - this._groupingBorder; - var y2 = NumCast(doc2.y) - this._groupingBorder; - var w2 = NumCast(doc2.width) + this._groupingBorder; - var h2 = NumCast(doc2.height) + this._groupingBorder; - var x = NumCast(doc.x) - this._groupingBorder; - var y = NumCast(doc.y) - this._groupingBorder; - var w = NumCast(doc.width) + this._groupingBorder; - var h = NumCast(doc.height) + this._groupingBorder; - if (this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { + var x2 = NumCast(doc2.x) - this._clusterDistance; + var y2 = NumCast(doc2.y) - this._clusterDistance; + var w2 = NumCast(doc2.width) + this._clusterDistance; + var h2 = NumCast(doc2.height) + this._clusterDistance; + var x = NumCast(doc.x) - this._clusterDistance; + var y = NumCast(doc.y) - this._clusterDistance; + var w = NumCast(doc.width) + this._clusterDistance; + var h = NumCast(doc.height) + this._clusterDistance; + if (doc.z === doc2.z && this.intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 })) { return true; } return false; @@ -197,36 +199,83 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return false; } + tryDragCluster(e: PointerEvent) { + let probe = this.getTransform().transformPoint(e.clientX, e.clientY); + let cluster = this.childDocs.reduce((cluster, cd) => { + let cx = NumCast(cd.x) - this._clusterDistance; + let cy = NumCast(cd.y) - this._clusterDistance; + let cw = NumCast(cd.width) + 2 * this._clusterDistance; + let ch = NumCast(cd.height) + 2 * this._clusterDistance; + if (!cd.z && this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) + return NumCast(cd.cluster); + return cluster; + }, -1); + if (cluster !== -1) { + let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); + this.selectDocuments(eles); + let clusterDocs = SelectionManager.SelectedDocuments(); + SelectionManager.DeselectAll(); + let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); + de.moveDocument = this.props.moveDocument; + const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); + const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); + de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; + de.xOffset = xoff; + de.yOffset = yoff; + DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, { + handlers: { dragComplete: action(emptyFunction) }, + hideSource: !de.dropAction + }); + return true; + } + + return false; + } + @observable sets: (Doc[])[] = []; @action updateClusters() { - let sets: (Doc[])[] = [] + this.sets.length = 0; this.childDocs.map(c => { let included = [] - for (let i = 0; i < sets.length; i++) { - for (let j = 0; j < sets[i].length; j++) { - if (this.bounsdSelect(c, sets[i][j])) { + for (let i = 0; i < this.sets.length; i++) { + for (let j = 0; j < this.sets[i].length; j++) { + if (this.bounsdSelect(c, this.sets[i][j])) { included.push(i); break; } } } if (included.length === 0) - sets.push([c]); + this.sets.push([c]); else if (included.length === 1) - sets[included[0]].push(c); + this.sets[included[0]].push(c); else { - sets[included[0]].push(c); + this.sets[included[0]].push(c); for (let s = 1; s < included.length; s++) { - sets[included[0]].push(...sets[included[s]]); - sets[included[s]].length = 0; + this.sets[included[0]].push(...this.sets[included[s]]); + this.sets[included[s]].length = 0; } } }); - for (let s = 0; s < sets.length; s++) { - for (let i = 0; i < sets[s].length; i++) { - Doc.GetProto(sets[s][i]).cluster = s; + for (let s = 0; s < this.sets.length; s++) { + for (let i = 0; i < this.sets[s].length; i++) { + this.sets[s][i].cluster = s; + } + } + } + + getClusterColor = (doc: Doc) => { + if (this.props.Document.useClusters) { + let cluster = NumCast(doc.cluster); + let set = this.sets.length > cluster ? this.sets[NumCast(doc.cluster)] : undefined; + let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"]; + let clusterColor = colors[cluster % colors.length]; + for (let i = 0; set && i < set.length; i++) { + if (set[i].backgroundColor && set[i].backgroundColor !== set[i].defaultBackgroundColor) clusterColor = StrCast(set[i].backgroundColor); } + return clusterColor; } + return ""; } @action @@ -249,34 +298,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { - let probe = this.getTransform().transformPoint(e.clientX, e.clientY); - let cluster = this.childDocs.reduce((cluster, cd) => { - let cx = NumCast(cd.x) - this._groupingBorder; - let cy = NumCast(cd.y) - this._groupingBorder; - let cw = NumCast(cd.width) + 2 * this._groupingBorder; - let ch = NumCast(cd.height) + 2 * this._groupingBorder; - if (this.intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 })) - return NumCast(cd.cluster); - return cluster; - }, -1); - if (cluster !== -1) { - let eles = this.childDocs.filter(cd => NumCast(cd.cluster) === cluster); - this.selectDocuments(eles); - let clusterDocs = SelectionManager.SelectedDocuments(); - SelectionManager.DeselectAll(); - let de = new DragManager.DocumentDragData(eles, eles.map(d => undefined)); - de.moveDocument = this.props.moveDocument; - const [left, top] = clusterDocs[0].props.ScreenToLocalTransform().scale(clusterDocs[0].props.ContentScaling()).inverse().transformPoint(0, 0); - const [xoff, yoff] = this.getTransform().transformDirection(e.x - left, e.y - top); - de.dropAction = e.ctrlKey || e.altKey ? "alias" : undefined; - de.xOffset = xoff; - de.yOffset = yoff; - DragManager.StartDocumentDrag(clusterDocs.map(v => v.ContentDiv!), de, e.clientX, e.clientY, { - handlers: { - dragComplete: action(emptyFunction) - }, - hideSource: !de.dropAction - }); + if (this.props.Document.useClusters && this.tryDragCluster(e)) { e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); @@ -493,6 +515,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, + backgroundColor: this.getClusterColor, parentActive: this.props.active, whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, @@ -516,6 +539,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ContentScaling: returnOne, ContainingCollectionView: this.props.CollectionView, focus: this.focusDocument, + backgroundColor: returnEmptyString, parentActive: this.props.active, whenActiveChanged: this.props.whenActiveChanged, bringToFront: this.bringToFront, @@ -625,6 +649,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { event: async () => this.props.Document.fitToBox = !this.fitToBox, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" }); + layoutItems.push({ + description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`, + event: async () => { + Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; + Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white"; + this.props.Document.useClusters = !this.props.Document.useClusters; + }, + icon: !this.props.Document.useClusters ? "expand-arrows-alt" : "compress-arrows-alt" + }); layoutItems.push({ description: "Arrange contents in grid", icon: "table", @@ -700,10 +733,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { ...this.views ] private overlayChildViews = () => { - console.log(this.overlayViews.length); - return [ - ...this.overlayViews - ]; + return [...this.overlayViews]; } public static AddCustomLayout(doc: Doc, dataKey: string): () => void { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b9ee588dd..ff96bd993 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -278,6 +278,7 @@ export class MarqueeView extends React.Component panX: 0, panY: 0, backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", + defaultBackgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white", width: bounds.width, height: bounds.height, title: e.key === "s" || e.key === "S" ? "-summary-" : "a nested collection", diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 3b6c443c2..ee596c841 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -8,6 +8,7 @@ import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView" import "./DocumentView.scss"; import React = require("react"); import { Doc } from "../../../new_fields/Doc"; +import { returnEmptyString } from "../../../Utils"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { x?: number; @@ -69,6 +70,11 @@ export class CollectionFreeFormDocumentView extends DocComponent this.clusterColor; + render() { const hasPosition = this.props.x !== undefined || this.props.y !== undefined; return ( @@ -77,7 +83,10 @@ export class CollectionFreeFormDocumentView extends DocComponent void; collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void; zoomToScale: (scale: number) => void; + backgroundColor: (doc: Doc) => string; getScale: () => number; animateBetweenIcon?: (iconPos: number[], startTime: number, maximizing: boolean) => void; ChromeHeight?: () => number; @@ -675,12 +676,9 @@ export class DocumentView extends DocComponent(Docu // to determine the render JSX string, otherwise the layout field should directly contain a JSX layout string. return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document; } + render() { - if (this.Document.hidden) { - return null; - } - let self = this; - let backgroundColor = StrCast(this.layoutDoc.backgroundColor); + let backgroundColor = this.props.backgroundColor(this.props.Document) || StrCast(this.layoutDoc.backgroundColor); let foregroundColor = StrCast(this.layoutDoc.color); var nativeWidth = this.nativeWidth > 0 && !BoolCast(this.props.Document.ignoreAspect) ? `${this.nativeWidth}px` : "100%"; var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%"; @@ -695,8 +693,6 @@ export class DocumentView extends DocComponent(Docu }); } let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("(Docu color: foregroundColor, outlineColor: "maroon", outlineStyle: "dashed", - boxShadow: this.layoutDoc.isBackground ? - `0px 0px 50px 50px ${groupCol}` : - `${groupCol} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`, outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `${this.props.ScreenToLocalTransform().Scale}px` : "0px", marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? @@ -717,7 +710,7 @@ export class DocumentView extends DocComponent(Docu border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ? `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined, borderRadius: "inherit", - background: this.layoutDoc.isBackground ? groupCol : backgroundColor, + background: backgroundColor, width: nativeWidth, height: nativeHeight, transform: `scale(${this.props.ContentScaling()})`, diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 11f3eb846..e2d8daea9 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -9,7 +9,7 @@ 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, returnFalse, emptyFunction, returnOne } from "../../../Utils"; +import { Utils, returnFalse, emptyFunction, returnOne, returnEmptyString } from "../../../Utils"; import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager"; import { SelectionManager } from "../../util/SelectionManager"; import { ContextMenu } from "../ContextMenu"; @@ -843,6 +843,7 @@ export default class PresentationElement extends React.Component 350} PanelHeight={() => 90} focus={emptyFunction} + backgroundColor={returnEmptyString} selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 0390359b3..1b9bba5c6 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -7,7 +7,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { emptyFunction, returnFalse, returnOne, Utils } from "../../../Utils"; +import { emptyFunction, returnFalse, returnOne, Utils, returnEmptyString } from "../../../Utils"; import { DocumentType } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { SetupDrag, DragManager } from "../../util/DragManager"; @@ -223,6 +223,7 @@ export class SearchItem extends React.Component { PanelWidth={returnXDimension} PanelHeight={returnYDimension} focus={emptyFunction} + backgroundColor={returnEmptyString} selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} -- cgit v1.2.3-70-g09d2