diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 11 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 142 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionMenu.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 188 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/PropertiesView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.scss | 32 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.tsx | 369 | ||||
-rw-r--r-- | src/client/views/presentationview/PresElementBox.scss | 4 | ||||
-rw-r--r-- | src/client/views/presentationview/PresElementBox.tsx | 135 | ||||
-rw-r--r-- | src/server/ApiManagers/UploadManager.ts | 2 |
13 files changed, 416 insertions, 491 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6681b4260..c4702cafa 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -457,6 +457,8 @@ export class CurrentUserUtils { } + + // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools static async setupCreatorButtons(doc: Doc) { let alreadyCreatedButtons: string[] = []; @@ -847,8 +849,13 @@ export class CurrentUserUtils { // Import sidebar is where shared documents are contained static setupImportSidebar(doc: Doc) { + if (doc["sidebar-import-documents"] === undefined) { + doc["sidebar-import-documents"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Imported Documents", _showTitle: "title", _height: 300, _yMargin: 30, childDropAction: "alias" })); + } if (doc["sidebar-import"] === undefined) { - doc["sidebar-import"] = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Imported Documents", childDropAction: "alias" })); + const uploads = Cast(doc["sidebar-import-documents"], Doc, null) as Doc; + const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import external document", _backgroundColor: "black", title: "Import", icon: "upload", system: true }); + doc["sidebar-import"] = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "Imported Documents", _yMargin: 30, childDropAction: "alias" })); } } @@ -975,4 +982,4 @@ Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.cre Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Instance.getAllRelatedLinks(doc)); }, "returns all the links to the document or its annotations", "(doc: any)"); Scripting.addGlobal(function directLinks(doc: any) { return new List(LinkManager.Instance.getAllDirectLinks(doc)); }, - "returns all the links directly to the document", "(doc: any)");
\ No newline at end of file + "returns all the links directly to the document", "(doc: any)"); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f13acd9a7..43afb17bf 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -66,6 +66,7 @@ import { SearchBox } from './search/SearchBox'; import { SearchUtil } from '../util/SearchUtil'; import { Networking } from '../Network'; import * as rp from 'request-promise'; +import { LinkManager } from '../util/LinkManager'; @observer export class MainView extends React.Component { @@ -548,7 +549,7 @@ export class MainView extends React.Component { case "Catalog": panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break; case "Archive": panelDoc = Doc.UserDoc()["sidebar-recentlyClosed"] as Doc ?? undefined; break; case "Settings": SettingsManager.Instance.open(); break; - case "Import": panelDoc = Doc.UserDoc()["sidebar-import"] as Doc ?? undefined; this.importDocument(); break; + case "Import": panelDoc = Doc.UserDoc()["sidebar-import"] as Doc ?? undefined; break; case "Sharing": panelDoc = Doc.UserDoc()["sidebar-sharing"] as Doc ?? undefined; break; case "UserDoc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break; } @@ -563,66 +564,6 @@ export class MainView extends React.Component { return true; } - - importDocument = async () => { - const inputRef = React.createRef<HTMLInputElement>(); - const sidebar = Cast(Doc.UserDoc()["sidebar-import"], Doc) as Doc; - let process = ''; - let error = ''; - try { - const col = sidebar; - await Docs.Prototypes.initialize(); - const imgPrev = document.getElementById("img_preview"); - if (imgPrev) { - const files: FileList | null = inputRef.current!.files; - if (files && files.length !== 0) { - for (let index = 0; index < files.length; ++index) { - const file = files[index]; - const res = await Networking.UploadFilesToServer(file); - // For each item that the user has selected - res.map(async ({ result }) => { - const name = file.name; - if (result instanceof Error) { - return; - } - const path = Utils.prepend(result.accessPaths.agnostic.client); - let doc = null; - // Case 1: File is a video - if (file.type === "video/mp4") { - doc = Docs.Create.VideoDocument(path, { _nativeWidth: 400, _width: 400, title: name }); - // Case 2: File is a PDF document - } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _nativeWidth: 400, _width: 400, _fitWidth: true, title: name }); - // Case 3: File is another document type (most likely Image) - } else { - doc = Docs.Create.ImageDocument(path, { _nativeWidth: 400, _width: 400, title: name }); - } - const res = await rp.get(Utils.prepend("/getUserDocumentId")); - if (!res) { - throw new Error("No user id returned"); - } - const field = await DocServer.GetRefField(res); - let pending: Opt<Doc>; - if (field instanceof Doc) { - pending = col; - } - if (pending) { - const data = await Cast(pending.data, listSpec(Doc)); - if (data) data.push(doc); - else pending.data = new List([doc]); - } - }); - } - // Case in which the user pressed upload and no files were selected - } else { - process = "No file selected"; - } - } - } catch (error) { - error = JSON.stringify(error); - } - } - @action closeProperties = () => { CurrentUserUtils.propertiesWidth = 0; @@ -959,6 +900,81 @@ export class MainView extends React.Component { document.addEventListener("editSuccess", onSuccess); }); } + + importDocument = () => { + const sidebar = Cast(Doc.UserDoc()["sidebar-import-documents"], Doc, null) as Doc; + const sidebarDocView = DocumentManager.Instance.getDocumentView(sidebar); + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".zip, application/pdf, video/*, image/*, audio/*"; + input.onchange = async _e => { + const upload = Utils.prepend("/uploadDoc"); + const formData = new FormData(); + const file = input.files && input.files[0]; + if (file && file.type === 'application/zip') { + formData.append('file', file); + formData.append('remap', "true"); + const response = await fetch(upload, { method: "POST", body: formData }); + const json = await response.json(); + if (json !== "error") { + const doc = await DocServer.GetRefField(json); + if (doc instanceof Doc && sidebarDocView) { + sidebarDocView.props.addDocument?.(doc); + setTimeout(() => { + SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => { + docs.docs.forEach(d => LinkManager.Instance.addLink(d)); + }); + }, 2000); // need to give solr some time to update so that this query will find any link docs we've added. + + } + } + } else if (input.files && input.files.length !== 0) { + const files: FileList | null = input.files; + for (let i = 0; i < files.length; i++) { + const file = files[i]; + const res = await Networking.UploadFilesToServer(file); + res.map(async ({ result }) => { + const name = file.name; + if (result instanceof Error) { + return; + } + const path = Utils.prepend(result.accessPaths.agnostic.client); + let doc: Doc; + // Case 1: File is a video + if (file.type.includes("video")) { + doc = Docs.Create.VideoDocument(path, { _height: 100, title: name }); + // Case 2: File is a PDF document + } else if (file.type === "application/pdf") { + doc = Docs.Create.PdfDocument(path, { _height: 100, _fitWidth: true, title: name }); + // Case 3: File is an image + } else if (file.type.includes("image")) { + doc = Docs.Create.ImageDocument(path, { _height: 100, title: name }); + // Case 4: File is an audio document + } else { + doc = Docs.Create.AudioDocument(path, { title: name }); + } + const res = await rp.get(Utils.prepend("/getUserDocumentId")); + if (!res) { + throw new Error("No user id returned"); + } + const field = await DocServer.GetRefField(res); + let pending: Opt<Doc>; + if (field instanceof Doc) { + pending = sidebar; + } + if (pending) { + const data = await Cast(pending.data, listSpec(Doc)); + if (data) data.push(doc); + else pending.data = new List([doc]); + } + }); + } + } else { + console.log("No file selected"); + } + }; + input.click(); + } } Scripting.addGlobal(function freezeSidebar() { MainView.expandFlyout(); }); Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }); @@ -968,4 +984,6 @@ Scripting.addGlobal(function copyWorkspace() { Doc.AddDocToList(workspaces, "data", copiedWorkspace); // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => MainView.Instance.openWorkspace(copiedWorkspace), 0); -});
\ No newline at end of file +}); +Scripting.addGlobal(function importDocument() { return MainView.Instance.importDocument(); }, + "imports files from device directly into the import sidebar"); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 754d9257a..998e41bd2 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -731,6 +731,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> { if (!DocumentManager.Instance.getDocumentView(curPres)) { CollectionDockingView.AddRightSplit(curPres); } + DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null)); } } } diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 0377944b7..33617c7ba 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -622,7 +622,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu </div> </Tooltip> : null} {!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom"> - <div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }} + <div className="numKeyframe" style={{ color: this.document.editing ? "white" : "black", backgroundColor: this.document.editing ? "#5B9FDD" : "#AEDDF8" }} onClick={action(() => this.document.editing = !this.document.editing)} > {NumCast(this.document.currentFrame)} </div> @@ -735,8 +735,10 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu @action resetValue = () => { this._currentKey = this.pivotField; }; render() { + const doctype = this.props.docView.Document.type; + const isPres: boolean = (doctype === DocumentType.PRES); return ( - <div className="collectionStackingViewChrome-cont"> + isPres ? (null) : <div className="collectionStackingViewChrome-cont"> <div className="collectionStackingViewChrome-pivotField-cont"> <div className="collectionStackingViewChrome-pivotField-label"> GROUP BY: diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 162713c3b..b15bda87d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1496,82 +1496,22 @@ interface CollectionFreeFormViewPannableContentsProps { @observer class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{ - private _isDraggingTL = false; - private _isDraggingTR = false; - private _isDraggingBR = false; - private _isDraggingBL = false; - private _isDragging = false; - // private _drag = ""; - - // onPointerDown = (e: React.PointerEvent): void => { - // e.stopPropagation(); - // e.preventDefault(); - // if (e.button === 0) { - // this._drag = e.currentTarget.id; - // console.log(this._drag); - // } - // document.removeEventListener("pointermove", this.onPointerMove); - // document.addEventListener("pointermove", this.onPointerMove); - // document.removeEventListener("pointerup", this.onPointerUp); - // document.addEventListener("pointerup", this.onPointerUp); - // } - - - // //Adds event listener so knows pointer is down and moving - // onPointerMid = (e: React.PointerEvent): void => { - // e.stopPropagation(); - // e.preventDefault(); - // this._isDragging = true; - // const dragData = new DragManager.DocumentDragData([]); - // console.log(DragManager.StartDocumentDrag([], dragData, e.clientX, e.clientY)); - // } + @observable private _drag: string = ''; //Adds event listener so knows pointer is down and moving onPointerDown = (e: React.PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - const corner = document.elementFromPoint(e.clientX, e.clientY)?.id; - if (corner) this._drag = corner; - const rect = document.getElementById('resizable'); + const corner = e.target as any; + console.log(corner.id); + if (corner) this._drag = corner.id; + const rect = document.getElementById(this._drag); if (rect) { console.log(this._drag); setupMoveUpEvents(e.target, e, this.onPointerMove, (e) => { }, (e) => { }); } } - // //Adds event listener so knows pointer is down and moving - // onPointerBL = (e: React.PointerEvent): void => { - // e.stopPropagation(); - // e.preventDefault(); - // this._isDraggingBL = true; - // document.removeEventListener("pointermove", this.onPointerMove); - // document.addEventListener("pointermove", this.onPointerMove); - // document.removeEventListener("pointerup", this.onPointerUp); - // document.addEventListener("pointerup", this.onPointerUp); - // } - - // //Adds event listener so knows pointer is down and moving - // onPointerTR = (e: React.PointerEvent): void => { - // e.stopPropagation(); - // e.preventDefault(); - // this._isDraggingTR = true; - // document.removeEventListener("pointermove", this.onPointerMove); - // document.addEventListener("pointermove", this.onPointerMove); - // document.removeEventListener("pointerup", this.onPointerUp); - // document.addEventListener("pointerup", this.onPointerUp); - // } - - // //Adds event listener so knows pointer is down and moving - // onPointerTL = (e: React.PointerEvent): void => { - // e.stopPropagation(); - // e.preventDefault(); - // this._isDraggingTL = true; - // document.removeEventListener("pointermove", this.onPointerMove); - // document.addEventListener("pointermove", this.onPointerMove); - // document.removeEventListener("pointerup", this.onPointerUp); - // document.addEventListener("pointerup", this.onPointerUp); - // } - //Removes all event listeners onPointerUp = (e: PointerEvent): void => { e.stopPropagation(); @@ -1581,26 +1521,13 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF document.removeEventListener("pointerup", this.onPointerUp); } - // @action - // pan = (e: PointerEvent | React.Touch | { moveX: number, moveY: number }): void => { - // const scale = this.props.getLocalTransform().inverse().Scale; - // const newPanX = Math.min((1 - 1 / scale) * this.props.nativeWidth, Math.max(0, moveX)); - // const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight), Math.max(0, panY)); - // } - - @observable private _drag: string = ''; - //Adjusts the value in NodeStore @action onPointerMove = (e: PointerEvent) => { - const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null); - const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); const doc = document.getElementById('resizable'); - const rect = (e.target as any).getBoundingClientRect(); - const toNumber = (screen_delta: number, wh: number): number => { - // console.log(screen_delta); - // console.log(wh); - return screen_delta + wh; + const rect = doc!.getBoundingClientRect(); + const toNumber = (original: number, delta: number): number => { + return original + (delta * this.props.zoomScaling()); }; if (doc) { let height = doc.offsetHeight; @@ -1610,84 +1537,41 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF switch (this._drag) { case "": break; case "resizer-br": - doc.style.width = toNumber(e.clientX - rect.x, width) + 'px'; - doc.style.height = toNumber(e.clientY - rect.y, height) + 'px'; + doc.style.width = toNumber(width, e.movementX) + 'px'; + doc.style.height = toNumber(height, e.movementY) + 'px'; break; case "resizer-bl": - doc.style.width = toNumber(e.clientX - rect.x, width) + 'px'; - doc.style.height = toNumber(e.clientY - rect.y, height) + 'px'; - doc.style.left = toNumber(e.clientY - rect.y, height) + 'px'; + doc.style.width = toNumber(width, -e.movementX) + 'px'; + doc.style.height = toNumber(height, e.movementY) + 'px'; + doc.style.left = toNumber(left, e.movementX) + 'px'; break; case "resizer-tr": - doc.style.width = toNumber(e.clientX - rect.x, width) + 'px'; - doc.style.height = toNumber(e.clientY - rect.y, height) + 'px'; - doc.style.top = toNumber(e.clientY - rect.y, top) + 'px'; + doc.style.width = toNumber(width, -e.movementX) + 'px'; + doc.style.height = toNumber(height, -e.movementY) + 'px'; + doc.style.top = toNumber(top, e.movementY) + 'px'; case "resizer-tl": - doc.style.width = toNumber(e.clientX - rect.x, width) + 'px'; - doc.style.height = toNumber(e.clientY - rect.y, height) + 'px'; - doc.style.top = toNumber(e.clientY - rect.x, top) + 'px'; - doc.style.left = toNumber(e.clientX - rect.y, left) + 'px'; + doc.style.width = toNumber(width, -e.movementX) + 'px'; + doc.style.height = toNumber(height, -e.movementY) + 'px'; + doc.style.top = toNumber(top, e.movementY) + 'px'; + doc.style.left = toNumber(left, e.movementX) + 'px'; case "resizable": - doc.style.top = toNumber(e.clientY - rect.x, top) + 'px'; - doc.style.left = toNumber(e.clientX - rect.y, left) + 'px'; + doc.style.top = toNumber(top, e.movementY) + 'px'; + doc.style.left = toNumber(left, e.movementX) + 'px'; } - this.updateList(targetDoc, activeItem["viewfinder-width-indexed"], width); - this.updateList(targetDoc, activeItem["viewfinder-height-indexed"], height); - this.updateList(targetDoc, activeItem["viewfinder-top-indexed"], top); - this.updateList(targetDoc, activeItem["viewfinder-left-indexed"], left); + this.updateAll(height, width, top, left); return false; } return true; + } - - // const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null); - // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - // const tagDocView = DocumentManager.Instance.getDocumentView(targetDoc); - // e.stopPropagation(); - // e.preventDefault(); - // if (doc && tagDocView) { - - // const scale = this.props.zoomScaling(); - // const scale2 = tagDocView.childScaling(); - // const scale3 = tagDocView.props.ScreenToLocalTransform().Scale; - // const scale1 = NumCast(targetDoc._viewScale); - // // const scale = this.props.zoomScaling(); - // console.log("_viewScale: " + scale1); - // console.log("_StLT: " + scale3); - // console.log("zoomScaling: " + scale); - // console.log("movementX: " + e.movementX); - // console.log("movementX * scale: " + e.movementX * scale); - // let height = doc.offsetHeight; - // let width = doc.offsetWidth; - // let top = doc.offsetTop; - // let left = doc.offsetLeft; - // switch (this._drag) { - // case "": break; - // case "resizer-br": - // doc.style.height = newHeightB + 'px'; - // doc.style.width = newWidthR + 'px'; - // break; - // case "resizer-bl": - // doc.style.height = newHeightB + 'px'; - // doc.style.width = newWidthL + 'px'; - // doc.style.left = newLeft + 'px'; - // break; - // case "resizer-tr": - // doc.style.width = newWidthR + 'px'; - // doc.style.height = newHeightT + 'px'; - // doc.style.top = newTop + 'px'; - // case "resizer-tl": - // doc.style.width = newWidthL + 'px'; - // doc.style.height = newHeightT + 'px'; - // doc.style.top = newTop + 'px'; - // doc.style.left = newLeft + 'px'; - // case "resizable": - // doc.style.top = newTop + 'px'; - // doc.style.left = newLeft + 'px'; - // } - - - // } + @action + updateAll = (width: number, height: number, top: number, left: number) => { + const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + this.updateList(targetDoc, activeItem["viewfinder-width-indexed"], width); + this.updateList(targetDoc, activeItem["viewfinder-height-indexed"], height); + this.updateList(targetDoc, activeItem["viewfinder-top-indexed"], top); + this.updateList(targetDoc, activeItem["viewfinder-left-indexed"], left); } @action @@ -1708,10 +1592,10 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF const activeItem = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex], Doc, null); const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); if (activeItem && activeItem.zoomProgressivize) { - const vfLeft: number = !activeItem ? 0 : PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-left-indexed"]); - const vfWidth: number = !activeItem ? 0 : PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-width-indexed"]); - const vfTop: number = !activeItem ? 0 : PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-top-indexed"]); - const vfHeight: number = !activeItem ? 0 : PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-height-indexed"]); + const vfLeft: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-left-indexed"]); + const vfWidth: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-width-indexed"]); + const vfTop: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-top-indexed"]); + const vfHeight: number = PresBox.Instance.checkList(targetDoc, activeItem["viewfinder-height-indexed"]); return ( <> {!activeItem.editZoomProgressivize ? (null) : <div id="resizable" className="resizable" onPointerDown={this.onPointerDown} style={{ width: vfWidth, height: vfHeight, top: vfTop, left: vfLeft, position: 'absolute' }}> diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx index c7edd67b3..a945ae2ba 100644 --- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx +++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx @@ -963,8 +963,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { } if (this.isPres) { const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0; - return <div className="propertiesView"> - <div className="propertiesView-title"> + return <div className="propertiesView" style={{ width: this.props.width }}> + <div className="propertiesView-title" style={{ width: this.props.width }}> Presentation </div> <div className="propertiesView-name"> @@ -1028,7 +1028,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { {PresBox.Instance.newDocumentDropdown} </div> : null} </div> - <div className="propertiesView-sharing"> + {/* <div className="propertiesView-sharing"> <div className="propertiesView-sharing-title" onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })} style={{ backgroundColor: this.openSharing ? "black" : "" }}> @@ -1040,7 +1040,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> { {this.openSharing ? <div className="propertiesView-sharing-content"> {this.sharingTable} </div> : null} - </div> + </div> */} </div>; } } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 900963eb0..011b6ff87 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -510,6 +510,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD labelScript = () => AudioBox.LabelScript; render() { + AudioBox.Instance = this; const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; this._first = true; // for indicating the first marker that is rendered this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d11a10df8..52f6a66c8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -132,7 +132,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF } - public static updateKeyframe(docs: Doc[], time: number) { + public static updateKeyframe(docs: Doc[], time: number, targetDoc?: Doc) { const timecode = Math.round(time); docs.forEach(doc => { const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); @@ -145,11 +145,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number); yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number); opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number); - if (doc.appearFrame) { + if (doc.appearFrame && targetDoc) { if (doc.appearFrame === timecode + 1) { - doc["text-color"] = "red"; + doc["text-color"] = StrCast(targetDoc["pres-text-color"]); } else if (doc.appearFrame < timecode + 1) { - doc["text-color"] = "grey"; + doc["text-color"] = StrCast(targetDoc["pres-text-viewed-color"]); } else { doc["text-color"] = "black"; } } else if (doc.appearFrame === 0) { doc["text-color"] = "black"; diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 951044c71..54accb012 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -3,6 +3,7 @@ $dark-blue: #5B9FDD; $light-background: #ececec; .presBox-cont { + cursor: auto; position: absolute; display: block; pointer-events: inherit; @@ -50,6 +51,7 @@ $light-background: #ececec; background-color: #323232; .toolbar-button { + cursor: pointer; margin-left: 10px; margin-right: 10px; letter-spacing: 0; @@ -168,6 +170,7 @@ $light-background: #ececec; grid-template-rows: 10px 10px; .ribbon-propertyUpDownItem { + cursor: pointer; color: white; display: flex; justify-content: center; @@ -315,6 +318,7 @@ $light-background: #ececec; } .numKeyframe { + cursor: pointer; font-size: 10; font-weight: 600; position: relative; @@ -345,6 +349,7 @@ $light-background: #ececec; .ribbon-final-button { + cursor: pointer; position: relative; font-size: 11; font-weight: normal; @@ -363,7 +368,13 @@ $light-background: #ececec; background-color: #979797; } + .ribbon-final-button:hover { + transform: scale(1.05); + transition: all 0.4s; + } + .ribbon-final-button-hidden { + cursor: pointer; position: relative; font-size: 11; font-weight: normal; @@ -381,6 +392,11 @@ $light-background: #ececec; border-radius: 10px; background-color: black; } + + .ribbon-final-button-hidden:hover { + transform: scale(1.05); + transition: all 0.4s; + } } .selectedList { @@ -397,6 +413,7 @@ $light-background: #ececec; } .ribbon-button { + cursor: pointer; font-size: 10.5; font-weight: 200; height: 20; @@ -452,6 +469,7 @@ $light-background: #ececec; } .presBox-dropdown { + cursor: pointer; display: grid; grid-template-columns: auto 20%; position: relative; @@ -472,6 +490,7 @@ $light-background: #ececec; .presBox-dropdownOption { + cursor: pointer; font-size: 11; display: block; padding-left: 10px; @@ -492,8 +511,8 @@ $light-background: #ececec; .presBox-dropdownOptions { position: absolute; - top: 24px; - left: -1px; + top: 23px; + left: -2px; z-index: 200; width: 85%; min-width: max-content; @@ -537,6 +556,7 @@ $light-background: #ececec; } .dropdown-play-button { + cursor: pointer; font-size: 12; padding-left: 5px; padding-right: 5px; @@ -551,6 +571,7 @@ $light-background: #ececec; } .presBox-button-left { + cursor: pointer; position: relative; align-self: flex-start; justify-self: flex-start; @@ -567,6 +588,7 @@ $light-background: #ececec; } .presBox-button-right { + cursor: pointer; position: relative; text-align: center; border-left: solid 1px darkgrey; @@ -589,6 +611,7 @@ $light-background: #ececec; } .dropdown-play { + cursor: pointer; right: 0px; top: calc(100% + 2px); display: none; @@ -609,6 +632,7 @@ $light-background: #ececec; } .open-layout { + cursor: pointer; position: relative; display: flex; align-items: center; @@ -640,6 +664,7 @@ $light-background: #ececec; } .layout { + cursor: pointer; align-self: center; justify-self: center; margin-top: 5; @@ -710,6 +735,7 @@ $light-background: #ececec; grid-template-columns: auto auto; .presBox-viewPicker { + cursor: pointer; height: 25; position: relative; display: inline-block; @@ -736,6 +762,7 @@ $light-background: #ececec; } .presBox-button { + cursor: pointer; height: 25px; border-radius: 5px; display: none; @@ -828,6 +855,7 @@ $light-background: #ececec; } .miniPres-button { + cursor: pointer; display: flex; height: 20; min-width: 20; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index eb657ab02..f6f6a2333 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -23,11 +23,12 @@ import { Scripting } from "../../util/Scripting"; import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; import { List } from "../../../fields/List"; import { Tooltip } from "@material-ui/core"; -import { CollectionFreeFormViewChrome } from "../collections/CollectionMenu"; import { actionAsync } from "mobx-utils"; import { SelectionManager } from "../../util/SelectionManager"; import { AudioBox } from "./AudioBox"; import { DocumentView } from "./DocumentView"; +import { SketchPicker, ColorState } from "react-color"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -63,7 +64,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); - PresBox.Instance = this; + if (Doc.UserDoc().activePresentation = this.rootDoc) PresBox.Instance = this; if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ title: "pres element template", backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" @@ -95,8 +96,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } } @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; } + componentWillUnmount() { document.removeEventListener("keydown", this.keyEvents, true); + this.turnOffEdit(); } componentDidMount() { @@ -107,13 +110,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this.layoutDoc._gridGap = 5; } - onComponentUnmount() { - document.removeEventListener("keydown", this.keyEvents, true); - console.log("when does this happen?"); - } - updateCurrentPresentation = () => { Doc.UserDoc().activePresentation = this.rootDoc; + PresBox.Instance = this; } /** @@ -138,7 +137,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> setTimeout(() => presTargetDoc._viewTransition = undefined, 1010); presTargetDoc.currentFrame = curFrame + 1; if (presTargetDoc.scrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(presTargetDoc, currentFrame); - if (presTargetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0); + if (presTargetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, presTargetDoc); + else presTargetDoc.editing = true; if (activeItem.zoomProgressivize) this.zoomProgressivizeNext(presTargetDoc); // Case 2: Audio or video therefore wait to play the audio or video before moving on } else if ((presTargetDoc.type === DocumentType.AUDIO) && !this._moveOnFromAudio && this.layoutDoc.presStatus !== 'auto') { @@ -164,10 +164,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> back = () => { this.updateCurrentPresentation(); const docAtCurrent = this.childDocs[this.itemIndex]; - if (docAtCurrent) { + const targetDoc = Cast(docAtCurrent.presentationTargetDoc, Doc, null); + const prevItem = Cast(this.childDocs[Math.max(0, this.itemIndex - 1)], Doc, null); + const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null); + const lastFrame = Cast(targetDoc.lastFrame, "number", null); + const curFrame = NumCast(targetDoc.currentFrame); + if (lastFrame !== undefined && curFrame >= 1) { + this.prevKeyframe(targetDoc, docAtCurrent); + } else if (docAtCurrent) { let prevSelected = this.itemIndex; prevSelected = Math.max(0, prevSelected - 1); this.gotoDocument(prevSelected, this.itemIndex); + if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc.currentFrame = NumCast(prevTargetDoc.lastFrame) } } @@ -261,12 +269,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> */ zoomProgressivizeNext = (activeItem: Doc) => { const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); - const srcContext = Cast(targetDoc.context, Doc, null); + const srcContext = Cast(targetDoc?.context, Doc, null); const docView = DocumentManager.Instance.getDocumentView(targetDoc); - const vfLeft: number = !activeItem ? 0 : this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]); - const vfWidth: number = !activeItem ? 0 : this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]); - const vfTop: number = !activeItem ? 0 : this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]); - const vfHeight: number = !activeItem ? 0 : this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]); + const vfLeft = this.checkList(targetDoc, activeItem["viewfinder-left-indexed"]); + const vfWidth = this.checkList(targetDoc, activeItem["viewfinder-width-indexed"]); + const vfTop = this.checkList(targetDoc, activeItem["viewfinder-top-indexed"]); + const vfHeight = this.checkList(targetDoc, activeItem["viewfinder-height-indexed"]); // Case 1: document that is not a Golden Layout tab if (srcContext) { const srcDocView = DocumentManager.Instance.getDocumentView(srcContext); @@ -309,7 +317,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> onHideDocument = () => { this.childDocs.forEach((doc, index) => { const curDoc = Cast(doc, Doc, null); - const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + const tagDoc = Cast(curDoc.presentationTargetDoc!, Doc, null); if (tagDoc) tagDoc.opacity = 1; if (curDoc.presHideTillShownButton) { if (index > this.itemIndex) { @@ -329,33 +337,48 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } + //The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc @undoBatch @action startAutoPres = (startSlide: number) => { this.updateCurrentPresentation(); - const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + let activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + let targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + let duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition); + const timer = (ms: number) => { + return new Promise(res => this._presTimer = setTimeout(res, ms)); + } + const load = async () => { // Wrap the loop into an async function for this to work + for (var i = startSlide; i < this.childDocs.length; i++) { + activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (targetDoc.presDuration && targetDoc.presTransition) { + duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition); + } else duration = 2500; + if (NumCast(targetDoc.lastFrame) > 0) { + for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) { + await timer(duration / NumCast(targetDoc.lastFrame)); + this.next(); + } + } + await timer(duration); this.next(); // then the created Promise can be awaited + if (i === this.childDocs.length - 1) setTimeout(() => { clearTimeout(this._presTimer); if (this.layoutDoc.presStatus === 'auto') this.layoutDoc.presStatus = "manual"; }, duration); + } + } if (this.layoutDoc.presStatus === "auto") { - if (this._presTimer) clearInterval(this._presTimer); + if (this._presTimer) clearTimeout(this._presTimer); this.layoutDoc.presStatus = "manual"; } else { this.layoutDoc.presStatus = "auto"; this.startPresentation(startSlide); this.gotoDocument(startSlide, this.itemIndex); - this._presTimer = setInterval(() => { - if (this.itemIndex + 1 < this.childDocs.length) this.next(); - else { - clearInterval(this._presTimer); - this.layoutDoc.presStatus = "manual"; - } - }, targetDoc.presDuration ? NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition) : 2000); + load(); } } //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. - // TODO: Ensure resetPresentation is called when the presentation is closed resetPresentation = () => { this.updateCurrentPresentation(); this.rootDoc._itemIndex = 0; @@ -505,20 +528,28 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> return list; } + @action + selectPres = () => { + const presDocView = DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc)!; + SelectionManager.SelectDoc(presDocView, false); + } + //Regular click @action selectElement = (doc: Doc) => { this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex)); + this.selectPres(); } //Command click @action multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => { if (!this._selectedArray.includes(doc)) { - this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]); + this._selectedArray.push(doc); this._eleArray.push(ref); this._dragArray.push(drag); } + this.selectPres(); } //Shift click @@ -533,17 +564,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this._dragArray.push(drag); } } + this.selectPres(); } - // Key for when the presentaiton is active (according to Selection Manager) + // Key for when the presentaiton is active @action keyEvents = (e: KeyboardEvent) => { let handled = false; const anchorNode = document.activeElement as HTMLDivElement; if (anchorNode && anchorNode.className?.includes("lm_title")) return; if (e.keyCode === 27) { // Escape key - if (this.layoutDoc.presStatus === "edit") this._selectedArray = []; - else this.layoutDoc.presStatus = "edit"; + if (this.layoutDoc.presStatus === "edit") { this._selectedArray = []; this._eleArray = []; this._dragArray = []; } + else this.layoutDoc.presStatus = "edit"; if (this._presTimer) clearTimeout(this._presTimer); handled = true; } if ((e.metaKey || e.altKey) && e.keyCode === 65) { // Ctrl-A to select all if (this.layoutDoc.presStatus === "edit") { @@ -551,14 +583,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> handled = true; } } if (e.keyCode === 37 || e.keyCode === 38) { // left(37) / a(65) / up(38) to go back - this.back(); + this.back(); if (this._presTimer) clearTimeout(this._presTimer); handled = true; } if (e.keyCode === 39 || e.keyCode === 40) { // right (39) / d(68) / down(40) to go to next - this.next(); + this.next(); if (this._presTimer) clearTimeout(this._presTimer); handled = true; } if (e.keyCode === 32) { // spacebar to 'present' or autoplay if (this.layoutDoc.presStatus !== "edit") this.startAutoPres(0); - else this.layoutDoc.presStatus = "manual"; + else this.layoutDoc.presStatus = "manual"; if (this._presTimer) clearTimeout(this._presTimer); handled = true; } if (e.keyCode === 8) { // delete selected items @@ -582,23 +614,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> @action viewPaths = async () => { const srcContext = Cast(this.rootDoc.presCollection, Doc, null); - if (this.pathBoolean) { - if (srcContext) { - this.togglePath(); - srcContext._fitToBox = false; - srcContext._viewType = "freeform"; - srcContext.presPathView = false; - } - } else { - if (srcContext) { - this.togglePath(); - srcContext._fitToBox = true; - srcContext._viewType = "freeform"; - srcContext.presPathView = true; - } + if (this.pathBoolean && srcContext) { + this.togglePath(); + srcContext.presPathView = false; + } else if (srcContext) { + this.togglePath(); + srcContext.presPathView = true; } - const viewType = srcContext?._viewType; - const fit = srcContext?._fitToBox; } // Adds the index in the pres path graphically @@ -606,7 +628,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const order: JSX.Element[] = []; this.childDocs.forEach((doc, index) => { const targetDoc = Cast(doc.presentationTargetDoc, Doc, null); - const srcContext = Cast(targetDoc.context, Doc, null); + const srcContext = Cast(targetDoc?.context, Doc, null); // Case A: Document is contained within the colleciton if (this.rootDoc.presCollection === srcContext) { order.push( @@ -636,7 +658,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> let pathPoints = ""; this.childDocs.forEach((doc, index) => { const targetDoc = Cast(doc.presentationTargetDoc, Doc, null); - const srcContext = Cast(targetDoc.context, Doc, null); + const srcContext = Cast(targetDoc?.context, Doc, null); if (targetDoc && this.rootDoc.presCollection === srcContext) { const n1x = NumCast(targetDoc.x) + (NumCast(targetDoc._width) / 2); const n1y = NumCast(targetDoc.y) + (NumCast(targetDoc._height) / 2); @@ -689,7 +711,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> setTransitionTime = (number: String, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; - if (timeInMS < 0) timeInMS = 100; + if (timeInMS < 100) timeInMS = 100; if (timeInMS > 10000) timeInMS = 10000; const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); @@ -700,7 +722,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> setDurationTime = (number: String, change?: number) => { let timeInMS = Number(number) * 1000; if (change) timeInMS += change; - if (timeInMS < 0) timeInMS = 100; + if (timeInMS < 100) timeInMS = 100; if (timeInMS > 20000) timeInMS = 20000; const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); @@ -712,8 +734,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); if (activeItem && targetDoc) { - let transitionSpeed = targetDoc.presTransition ? String(Number(targetDoc.presTransition) / 1000) : 0.5; - let duration = targetDoc.presDuration ? String(Number(targetDoc.presDuration) / 1000) : 2; + let transitionSpeed = targetDoc.presTransition ? NumCast(targetDoc.presTransition) / 1000 : 0.5; + let duration = targetDoc.presDuration ? NumCast(targetDoc.presDuration) / 1000 : 2; if (targetDoc.type === DocumentType.AUDIO) duration = NumCast(targetDoc.duration); const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None'; activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom'; @@ -721,9 +743,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}> <div className="ribbon-box"> Movement - <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5 }}> + <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? 'solid 2px #5B9FDD' : 'solid 1px black' }}> {activeItem.presMovement} - <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} /> + <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} /> <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}> <div className={`presBox-dropdownOption ${activeItem.presMovement === 'None' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('none')}>None</div> <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Zoom' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('zoom')}>Pan and Zoom</div> @@ -735,15 +757,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className="presBox-subheading">Transition Speed</div> <div className="ribbon-property"> <input className="presBox-input" - type="text" value={transitionSpeed} + type="number" value={transitionSpeed} onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }} - onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { if (Number(e.target.value) >= 0 && Number(e.target.value) <= 10 && !isNaN(Number(e.target.value)) || e.target.value === '') this.setTransitionTime(e.target.value) })} /> s + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { this.setTransitionTime(e.target.value) })} /> s </div> <div className="ribbon-propertyUpDown"> - <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(duration), 1000)}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), 1000)}> <FontAwesomeIcon icon={"caret-up"} /> </div> - <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(duration), -1000)}> + <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), -1000)}> <FontAwesomeIcon icon={"caret-down"} /> </div> </div> @@ -765,9 +787,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className="presBox-subheading">Slide Duration</div> <div className="ribbon-property"> <input className="presBox-input" - type="text" value={duration} + type="number" value={duration} onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }} - onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { if (Number(e.target.value) >= 0 && Number(e.target.value) <= 20 && !isNaN(Number(e.target.value)) || e.target.value === '') this.setDurationTime(e.target.value) })} /> s + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { this.setDurationTime(e.target.value) })} /> s </div> <div className="ribbon-propertyUpDown"> <div className="ribbon-propertyUpDownItem" onClick={() => this.setDurationTime(String(duration), 1000)}> @@ -787,9 +809,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> <div className="ribbon-box"> Effects - <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5 }}> + <div className="presBox-dropdown" onClick={action(e => { e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? 'solid 2px #5B9FDD' : 'solid 1px black' }}> {effect} - <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} /> + <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} /> <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}> <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'None'}>None</div> <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Fade'}>Fade In</div> @@ -850,6 +872,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> tagDoc.presTransition = targetDoc.presTransition; tagDoc.presDuration = targetDoc.presDuration; tagDoc.presEffect = targetDoc.presEffect; + tagDoc.presEffectDirection = targetDoc.presEffectDirection; + curDoc.presMovement = activeItem.presMovement; + curDoc.presHideTillShownButton = activeItem.presHideTillShownButton; + curDoc.presHideAfterButton = activeItem.presHideAfterButton; } }); } @@ -882,9 +908,41 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } }}>Presentation pin view</div> </div> - <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}> - <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div> + <div style={{ display: activeItem.presPinView ? "block" : "none" }}> + <div className="ribbon-doubleButton" style={{ marginRight: 10 }}> + <div className="presBox-subheading">Pan X</div> + <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}> + <input className="presBox-input" + style={{ textAlign: 'left', width: 50 }} + type="number" value={NumCast(activeItem.presPinViewX)} + onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }} + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { let val = e.target.value; activeItem.presPinViewX = Number(val); })} /> + </div> + </div> + <div className="ribbon-doubleButton" style={{ marginRight: 10 }}> + <div className="presBox-subheading">Pan Y</div> + <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}> + <input className="presBox-input" + style={{ textAlign: 'left', width: 50 }} + type="number" value={NumCast(activeItem.presPinViewY)} + onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }} + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { let val = e.target.value; activeItem.presPinViewY = Number(val) })} /> + </div> + </div> + <div className="ribbon-doubleButton" style={{ marginRight: 10 }}> + <div className="presBox-subheading">Scale</div> + <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}> + <input className="presBox-input" + style={{ textAlign: 'left', width: 50 }} + type="number" value={NumCast(activeItem.presPinViewScale)} + onFocus={() => { document.removeEventListener("keydown", this.keyEvents, true); }} + onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { let val = e.target.value; activeItem.presPinViewScale = Number(val) })} /> + </div> + </div> </div> + {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}> + <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div> + </div> */} </div> </div> </div > @@ -909,11 +967,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div className="title" style={{ alignSelf: 'center' }}>Title</div> <div className="content">Text goes here</div> </div> - {/* <div className="layout" style={{ border: this.layout === 'twoColumns' ? 'solid 2px #5b9ddd' : '' }} onClick={() => runInAction(() => { this.layout = 'twoColumns'; this.createNewSlide(this.layout); })}> - <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>Title</div> - <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>Column one text</div> - <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>Column two text</div> - </div> */} </div> </div> </div > @@ -1043,7 +1096,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> @computed get presentDropdown() { return ( <div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> - <div className="dropdown-play-button" onClick={this.updateMinimize}> + <div className="dropdown-play-button" onClick={() => this.updateMinimize()}> Minimize </div> <div className="dropdown-play-button" onClick={(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(); }))}> @@ -1065,7 +1118,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0); } CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame); - CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0); + CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc); tagDoc.currentFrame = Math.max(0, (currentFrame || 0) + 1); tagDoc.lastFrame = Math.max(NumCast(tagDoc.currentFrame), NumCast(tagDoc.lastFrame)); if (activeItem.zoomProgressivize) { @@ -1116,38 +1169,52 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> case DocumentType.AUDIO: type = "Audio"; break; case DocumentType.VID: type = "Video"; break; case DocumentType.IMG: type = "Image"; break; + case DocumentType.WEB: type = "Web page"; break; default: type = "Other node"; break; } } return type; } + @observable private openActiveColorPicker: boolean = false; + @observable private openViewedColorPicker: boolean = false; + + + @computed get progressivizeDropdown() { const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); - + const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black"; + const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black"; if (activeItem && targetDoc) { return ( <div> <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> <div className="ribbon-box"> {this.stringType} selected - <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}> - <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Child documents</div> - <div className="ribbon-button" style={{ display: activeItem.presProgressivize ? "flex" : "none", backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div> + <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}> + <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div> + <div className="ribbon-button" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div> + </div> + <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}> + <div className="presBox-subheading">Active text color</div> + <div className="ribbon-property" style={{ backgroundColor: activeFontColor }} onClick={action(() => { console.log("hi"); this.openActiveColorPicker = !this.openActiveColorPicker })}> + </div> </div> - <div className="ribbon-doubleButton" style={{ display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}> - <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Internal zoom</div> - <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Viewfinder</div> - {/* <div className="ribbon-button" style={{ display: activeItem.zoomProgressivize ? "flex" : "none", backgroundColor: targetDoc.editSnapZoomProgressivize ? "#aedef8" : "" }} onClick={this.editSnapZoomProgressivize}>Snapshot</div> */} + {this.activeColorPicker} + <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}> + <div className="presBox-subheading">Viewed font color</div> + <div className="ribbon-property" style={{ backgroundColor: viewedFontColor }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}> + </div> </div> - {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}> - <div className="ribbon-button" onClick={this.progressivizeText}>Text progressivize</div> - <div className="ribbon-button" style={{ display: activeItem.textProgressivize ? "flex" : "none", backgroundColor: targetDoc.editTextProgressivize ? "#aedef8" : "" }} onClick={this.editTextProgressivize}>Edit</div> + {this.viewedColorPicker} + {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}> + <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Zoom</div> + <div className="ribbon-button" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Edit</div> </div> */} - <div className="ribbon-doubleButton" style={{ display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}> - <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll progressivize</div> - <div className="ribbon-button" style={{ display: activeItem.scrollProgressivize ? "flex" : "none", backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div> + <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}> + <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll</div> + <div className="ribbon-button" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div> </div> </div> <div className="ribbon-final-box" style={{ display: activeItem.zoomProgressivize || activeItem.scrollProgressivize || activeItem.presProgressivize || activeItem.textProgressivize ? "grid" : "none" }}> @@ -1157,7 +1224,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc, activeItem); }}> <FontAwesomeIcon icon={"caret-left"} size={"lg"} /> </div> - <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: targetDoc.editing ? "#5a9edd" : "#5a9edd" }} + <div key="num" title="toggle view all" className="numKeyframe" style={{ color: targetDoc.editing ? "white" : "black", backgroundColor: targetDoc.editing ? "#5B9FDD" : "#AEDDF8" }} onClick={action(() => targetDoc.editing = !targetDoc.editing)} > {NumCast(targetDoc.currentFrame)} </div> @@ -1167,7 +1234,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip> </div> - <div className="ribbon-button" style={{ height: 20, backgroundColor: "#5a9edd" }} onClick={() => console.log(" TODO: play frames")}>Play</div> + <div className="ribbon-button" style={{ height: 20, backgroundColor: "#AEDDF8" }} onClick={() => console.log(" TODO: play frames")}>Play</div> </div> </div> </div> @@ -1175,6 +1242,45 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } } + @undoBatch + @action + switchActive = (color: ColorState) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + const val = String(color.hex); + targetDoc["pres-text-color"] = val; + return true; + } + @undoBatch + @action + switchPresented = (color: ColorState) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + const val = String(color.hex); + targetDoc["pres-text-viewed-color"] = val; + return true; + } + + @computed get activeColorPicker() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + if (this.openActiveColorPicker) return <SketchPicker onChange={this.switchActive} + presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', + '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', + '#FFFFFF', '#f1efeb', 'transparent']} + color={StrCast(targetDoc["pres-text-color"])} />; + } + + @computed get viewedColorPicker() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + if (this.openViewedColorPicker) return <SketchPicker onChange={this.switchPresented} + presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', + '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', + '#FFFFFF', '#f1efeb', 'transparent']} + color={StrCast(targetDoc["pres-text-viewed-color"])} />; + } + turnOffEdit = () => { this.childDocs.forEach((doc) => { doc.editSnapZoomProgressivize = false; @@ -1184,31 +1290,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> targetDoc.editSnapZoomProgressivize = false; targetDoc.editZoomProgressivize = false; targetDoc.editScrollProgressivize = false; - if (doc.type === DocumentType.WEB) { - doc.presWebsite = doc.data; - } }); } //Toggle whether the user edits or not @action - editSnapZoomProgressivize = (e: React.MouseEvent) => { - const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); - if (!targetDoc.editSnapZoomProgressivize) { - targetDoc.editSnapZoomProgressivize = true; - } else { - targetDoc.editSnapZoomProgressivize = false; - } - - } - - //Toggle whether the user edits or not - @action editZoomProgressivize = (e: React.MouseEvent) => { const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); if (!targetDoc.editZoomProgressivize) { + if (!activeItem.zoomProgressivize) activeItem.zoomProgressivize = true; targetDoc.zoomProgressivize = true; targetDoc.editZoomProgressivize = true; activeItem.editZoomProgressivize = true; } else { @@ -1223,6 +1314,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); if (!targetDoc.editScrollProgressivize) { + if (!targetDoc.scrollProgressivize) { targetDoc.scrollProgressivize = true; activeItem.scrollProgressivize = true; } targetDoc.editScrollProgressivize = true; } else { targetDoc.editScrollProgressivize = false; @@ -1261,44 +1353,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } } - //Progressivize Text nodes - @action - editTextProgressivize = (e: React.MouseEvent) => { - const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); - targetDoc.currentFrame = targetDoc.lastFrame; - if (targetDoc?.editTextProgressivize) { - targetDoc.editTextProgressivize = false; - } else { - targetDoc.editTextProgressivize = true; - } - } - - @action - progressivizeText = (e: React.MouseEvent) => { - e.stopPropagation(); - const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); - activeItem.presProgressivize = !activeItem.presProgressivize; - const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); - const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); - targetDoc.presProgressivize = !targetDoc.presProgressivize; - if (activeItem.presProgressivize) { - targetDoc.currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true); - targetDoc.lastFrame = docs.length - 1; - } - } - //Progressivize Child Docs @action editProgressivize = (e: React.MouseEvent) => { const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); targetDoc.currentFrame = targetDoc.lastFrame; - if (targetDoc?.editProgressivize) { - targetDoc.editProgressivize = false; - } else { + if (!targetDoc.editProgressivize) { + if (!activeItem.presProgressivize) { activeItem.presProgressivize = true; targetDoc.presProgressivize = true; } targetDoc.editProgressivize = true; + } else { + targetDoc.editProgressivize = false; } } @@ -1309,6 +1374,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); if (!activeItem.presProgressivize) { + targetDoc.editing = false; activeItem.presProgressivize = true; targetDoc.presProgressivize = true; targetDoc.currentFrame = 0; @@ -1318,11 +1384,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> targetDoc.editProgressivize = false; activeItem.presProgressivize = false; targetDoc.presProgressivize = false; - // docs.forEach((doc, index) => { - // doc.appearFrame = 0; - // }); targetDoc.currentFrame = 0; targetDoc.lastFrame = 0; + targetDoc.editing = true; } } @@ -1360,15 +1424,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } @action - checkList = (doc: Doc, list: any) => { + checkList = (doc: Doc, list: any): number => { const x: List<number> = list; - if (x && x.length >= NumCast(doc.currentFrame) + 1) { + if (x && x.length >= NumCast(doc!.currentFrame) + 1) { return x[NumCast(doc.currentFrame)]; - } else if (doc && x) { + } else if (x) { x.length = NumCast(doc.currentFrame) + 1; x[NumCast(doc.currentFrame)] = x[NumCast(doc.currentFrame) - 1]; return x[NumCast(doc.currentFrame)]; - } + } else return 100; } @computed get progressivizeChildDocs() { @@ -1451,8 +1515,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> return width; } + @action + toggleProperties = () => { + if (CurrentUserUtils.propertiesWidth > 0) { + CurrentUserUtils.propertiesWidth = 0; + } else { + CurrentUserUtils.propertiesWidth = 250; + } + } + @computed get toolbar() { - const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left"; + const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel"; return ( <div id="toolbarContainer" className={'presBox-toolbar'} style={{ display: this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }}> <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}> @@ -1471,6 +1545,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> </div> </Tooltip> <div className="toolbar-divider" /> + <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}> + <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}> + <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? '#AEDDF8' : 'white' }} /> + </div> + </Tooltip> </div> ); } diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index 1e776384a..6ee190b82 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -3,6 +3,7 @@ $dark-blue: #5B9FDD; $light-background: #ececec; .presElementBox-item { + cursor: grab; display: grid; grid-template-columns: max-content max-content max-content max-content; background-color: #d5dce2; @@ -161,6 +162,7 @@ $light-background: #ececec; } .presElementBox-closeIcon { + cursor: pointer; position: absolute; border-radius: 100%; z-index: 300; @@ -177,6 +179,7 @@ $light-background: #ececec; } .presElementBox-expand { + cursor: pointer; position: absolute; border-radius: 100%; z-index: 300; @@ -193,6 +196,7 @@ $light-background: #ececec; } .presElementBox-expand-selected { + cursor: pointer; position: absolute; border-radius: 100%; right: 3px; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 42b43b402..a25a8ee33 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -19,6 +19,7 @@ import { PresBox } from "../nodes/PresBox"; import { DocumentType } from "../../documents/DocumentTypes"; import { Tooltip } from "@material-ui/core"; import { DragManager } from "../../util/DragManager"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; export const presSchema = createSchema({ presentationTargetDoc: Doc, @@ -59,111 +60,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc } /** - * The function that is called on click to turn Hiding document till press option on/off. - * It also sets the beginning and end opacitys. - */ - @action - onHideDocumentUntilPressClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.rootDoc.presHideTillShownButton = !this.rootDoc.presHideTillShownButton; - if (!this.rootDoc.presHideTillShownButton) { - if (this.indexInPres >= this.itemIndex && this.targetDoc) { - this.targetDoc.opacity = 1; - } - } else { - if (this.presStatus !== "edit" && this.indexInPres > this.itemIndex && this.targetDoc) { - this.targetDoc.opacity = 0; - } - } - } - - /** - * The function that is called on click to turn Hiding document after presented option on/off. - * It also makes sure that the option swithches from fade-after to this one, since both - * can't coexist. - */ - @action - onHideDocumentAfterPresentedClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.rootDoc.presHideAfterButton = !this.rootDoc.presHideAfterButton; - if (!this.rootDoc.presHideAfterButton) { - if (this.indexInPres <= this.itemIndex && this.targetDoc) { - this.targetDoc.opacity = 1; - } - } else { - if (this.rootDoc.presFadeButton) this.rootDoc.presFadeButton = false; - if (this.presStatus !== "edit" && this.indexInPres < this.itemIndex && this.targetDoc) { - this.targetDoc.opacity = 0; - } - } - } - - @action - progressivize = (e: React.MouseEvent) => { - e.stopPropagation(); - this.rootDoc.presProgressivize = !this.rootDoc.presProgressivize; - const rootTarget = Cast(this.rootDoc.presentationTargetDoc, Doc, null); - const docs = rootTarget.type === DocumentType.COL ? DocListCast(rootTarget[Doc.LayoutFieldKey(rootTarget)]) : - DocListCast(rootTarget[Doc.LayoutFieldKey(rootTarget) + "-annotations"]); - if (this.rootDoc.presProgressivize) { - rootTarget.currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true); - rootTarget.lastFrame = docs.length - 1; - } - } - - /** - * The function that is called on click to turn fading document after presented option on/off. - * It also makes sure that the option swithches from hide-after to this one, since both - * can't coexist. - */ - @action - onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.rootDoc.presFadeButton = !this.rootDoc.presFadeButton; - if (!this.rootDoc.presFadeButton) { - if (this.indexInPres <= this.itemIndex && this.targetDoc) { - this.targetDoc.opacity = 1; - } - } else { - this.rootDoc.presHideAfterButton = false; - if (this.presStatus !== "edit" && (this.indexInPres < this.itemIndex) && this.targetDoc) { - this.targetDoc.opacity = 0.5; - } - } - } - - /** - * The function that is called on click to turn navigation option of docs on/off. - */ - @action - onNavigateDocumentClick = (e: React.MouseEvent) => { - e.stopPropagation(); - this.rootDoc.presNavButton = !this.rootDoc.presNavButton; - if (this.rootDoc.presNavButton) { - this.rootDoc.presZoomButton = false; - if (this.itemIndex === this.indexInPres) { - this.props.focus(this.rootDoc); - } - } - } - - /** - * The function that is called on click to turn zoom option of docs on/off. - */ - @action - onZoomDocumentClick = (e: React.MouseEvent) => { - e.stopPropagation(); - - this.rootDoc.presZoomButton = !this.rootDoc.presZoomButton; - if (this.rootDoc.presZoomButton) { - this.rootDoc.presNavButton = false; - if (this.itemIndex === this.indexInPres) { - this.props.focus(this.rootDoc); - } - } - } - /** * Returns a local transformed coordinate array for given coordinates. */ ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord]; @@ -235,12 +131,11 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc @action headerDown = (e: React.PointerEvent<HTMLDivElement>) => { - const element1 = document.elementFromPoint(e.clientX, e.clientY)?.parentElement; const element = e.target as any; e.stopPropagation(); e.preventDefault(); - if (element) { - if (PresBox.Instance._eleArray.includes(element)) { + if (element && !(e.ctrlKey || e.metaKey)) { + if (PresBox.Instance._eleArray.includes(this._itemRef.current!)) { setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction); } else { PresBox.Instance._selectedArray = []; @@ -303,8 +198,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc } } + @action + toggleProperties = () => { + if (CurrentUserUtils.propertiesWidth === 0) { + CurrentUserUtils.propertiesWidth = 250; + } + } + render() { - const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree; const className = "presElementBox-item" + (PresBox.Instance._selectedArray.includes(this.rootDoc) ? " presElementBox-active" : ""); const pbi = "presElementBox-interaction"; return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : ( @@ -329,6 +230,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc PresBox.Instance._dragArray.push(this._dragRef.current!); } }} + onDoubleClick={e => { + this.toggleProperties(); + this.props.focus(this.rootDoc); + PresBox.Instance._eleArray = []; + PresBox.Instance._eleArray.push(this._itemRef.current!); + PresBox.Instance._dragArray = []; + PresBox.Instance._dragArray.push(this._dragRef.current!); + }} onPointerDown={this.headerDown} onPointerUp={this.headerUp} > @@ -357,14 +266,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc <div ref={this._highlightTopRef} onPointerOver={this.onPointerTop} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightTop" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} /> <div ref={this._highlightBottomRef} onPointerOver={this.onPointerBottom} onPointerLeave={this.onPointerLeave} className="presElementBox-highlightBottom" style={{ zIndex: 299, backgroundColor: "rgba(0,0,0,0)" }} /> <div className="presElementBox-highlight" style={{ backgroundColor: PresBox.Instance._selectedArray.includes(this.rootDoc) ? "#AEDDF8" : "rgba(0,0,0,0)" }} /> - <div className="presElementBox-buttons" style={{ display: this.rootDoc.presExpandInlineButton ? "grid" : "none" }}> - <button title="Zoom" className={pbi + (this.rootDoc.presZoomButton ? "-selected" : "")} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} onPointerDown={e => e.stopPropagation()} /></button> - <button title="Navigate" className={pbi + (this.rootDoc.presNavButton ? "-selected" : "")} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} onPointerDown={e => e.stopPropagation()} /></button> - <button title="Hide Before" className={pbi + (this.rootDoc.presHideTillShownButton ? "-selected" : "")} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={"file"} onPointerDown={e => e.stopPropagation()} /></button> - <button title="Hide After" className={pbi + (this.rootDoc.presHideAfterButton ? "-selected" : "")} onClick={this.onHideDocumentAfterPresentedClick}><FontAwesomeIcon icon={"file-download"} onPointerDown={e => e.stopPropagation()} /></button> - <button title="Progressivize" className={pbi + (this.rootDoc.presProgressivize ? "-selected" : "")} onClick={this.progressivize}><FontAwesomeIcon icon={"tasks"} onPointerDown={e => e.stopPropagation()} /></button> - <button title="Effect" className={pbi + (this.rootDoc.presEffect ? "-selected" : "")}>E</button> - </div> {this.renderEmbeddedInline} </div> ); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index bd8fe97eb..e088cd2c4 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -279,7 +279,7 @@ function delay(ms: number) { * * On failure, returns undefined. */ -async function captureYoutubeScreenshot(targetUrl: string){ +async function captureYoutubeScreenshot(targetUrl: string) { // const browser = await launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); // const page = await browser.newPage(); // // await page.setViewport({ width: 1920, height: 1080 }); |