aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts5
-rw-r--r--src/client/util/DocumentManager.ts6
-rw-r--r--src/client/views/.DS_Storebin6148 -> 6148 bytes
-rw-r--r--src/client/views/MainView.tsx3
-rw-r--r--src/client/views/collections/CollectionDockingView.scss62
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx24
-rw-r--r--src/client/views/collections/CollectionMenu.scss16
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss139
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx81
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx132
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/PresBox.scss672
-rw-r--r--src/client/views/nodes/PresBox.tsx1555
-rw-r--r--src/client/views/pdf/PDFViewer.tsx9
-rw-r--r--src/client/views/presentationview/PresElementBox.scss173
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx101
-rw-r--r--src/fields/Doc.ts4
-rw-r--r--src/typings/index.d.ts7
19 files changed, 2720 insertions, 272 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7e094089f..98d80e3b0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -135,6 +135,11 @@ export interface DocumentOptions {
currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
activeFrame?: number; // the active frame of a document in a frame base collection
+ appearFrame?: number; // the frame in which the document appears
+ presTransition?: number; //the time taken for the transition TO a document
+ presDuration?: number; //the duration of the slide in presentation view
+ // xArray?: number[];
+ // yArray?: number[];
borderRounding?: string;
boxShadow?: string;
dontRegisterChildViews?: boolean;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 523dbfca0..d18eac374 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -127,6 +127,10 @@ export class DocumentManager {
CollectionDockingView.AddRightSplit(doc);
finished?.();
}
+ // static openInPlace = (doc: Doc, finished?: () => void) => {
+ // CollectionDockingView.AddTab(doc);
+ // finished?.();
+ // }
public jumpToDocument = async (
targetDoc: Doc, // document to display
willZoom: boolean, // whether to zoom doc to take up most of screen
@@ -176,7 +180,7 @@ export class DocumentManager {
const targetDocContextView = getFirstDocView(targetDocContext);
targetDocContext._scrollY = 0; // this will force PDFs to activate and load their annotations / allow scrolling
if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first..
- targetDocContext._viewTransition = "transform 500ms";
+ targetDocContext._viewTransition = "transform 10000ms";
targetDocContextView.props.focus(targetDocContextView.props.Document, willZoom);
// now find the target document within the context
diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store
index 3717a2923..3ce88292c 100644
--- a/src/client/views/.DS_Store
+++ b/src/client/views/.DS_Store
Binary files differ
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 37d99fb16..14d46c5e9 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -148,7 +148,8 @@ export class MainView extends React.Component {
fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper,
- fa.faBezierCurve, fa.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight);
+ fa.faBezierCurve, fa.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
+ fa.faRocket, fa.faExchangeAlt);
this.initEventListeners();
this.initAuthenticationRouters();
}
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 1895c06a1..9b14df760 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -18,6 +18,68 @@
}
}
}
+
+.miniPres:hover {
+ opacity: 1;
+}
+
+.miniPres {
+ position: absolute;
+ overflow: hidden;
+ right: 10;
+ top: 10;
+ opacity: 0.1;
+ transition: all 0.4s;
+ /* border: solid 1px; */
+ color: white;
+ /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+
+ .miniPresOverlay {
+ display: grid;
+ grid-template-columns: auto auto auto auto auto auto auto auto;
+ grid-template-rows: 100%;
+ height: 100%;
+ justify-items: center;
+ align-items: center;
+
+ .miniPres-button-text {
+ display: flex;
+ height: 30;
+ font-weight: 400;
+ min-width: 100%;
+ border-radius: 5px;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-divider {
+ width: 1px;
+ height: 80%;
+ border-right: solid 2px #5a5a5a;
+ }
+
+ .miniPres-button {
+ display: flex;
+ height: 30;
+ min-width: 30;
+ border-radius: 100%;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-button:hover {
+ background-color: #5a5a5a;
+ }
+
+ .miniPres-button-text:hover {
+ background-color: #5a5a5a;
+ }
+ }
+}
+
+
.lm_title {
margin-top: 3px;
border-radius: 5px;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 53b2d5254..b82a33bd8 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -31,6 +31,8 @@ import { SnappingManager } from '../../util/SnappingManager';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import { listSpec } from '../../../fields/Schema';
import { clamp } from 'lodash';
+import { PresBox } from '../nodes/PresBox';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -838,6 +840,27 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
return false;
}), emptyFunction, emptyFunction);
}
+ getCurrentFrame = (): number => {
+ const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null);
+ const currentFrame = Cast(presTargetDoc.currentFrame, "number", null);
+ return currentFrame;
+ }
+ renderMiniPres() {
+ return <div className="miniPres" style={{
+ width: 400, height: 50, background: '#323232'
+ }}>
+ <div className="miniPresOverlay" >
+ <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+ <div className="miniPres-button" onClick={() => PresBox.Instance.startOrResetPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
+ <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text">Slide {PresBox.Instance.itemIndex + 1} / {PresBox.Instance.childDocs.length}</div>
+ {/* <div className="miniPres-button-text">{this.getCurrentFrame}</div> */}
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text" onClick={PresBox.Instance.updateMinimize}>EXIT</div>
+ </div>
+ </div>;
+ }
renderMiniMap() {
return <div className="miniMap" style={{
width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
@@ -920,6 +943,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
{document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
+ {document._viewType === CollectionViewType.Freeform && this._document?.miniPres ? this.renderMiniPres() : (null)}
</>;
}
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 9da204787..7201afcc0 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -2,8 +2,8 @@
.collectionMenu-cont {
- position:relative;
- display:inline-flex;
+ position: relative;
+ display: inline-flex;
width: 100%;
opacity: 0.9;
z-index: 9001;
@@ -12,14 +12,15 @@
color: white;
transform-origin: top left;
top: 0;
- width:100%;
+ width: 100%;
.antimodeMenu-button {
padding: 0;
width: 30px;
display: flex;
+
svg {
- margin:auto;
+ margin: auto;
}
}
@@ -108,6 +109,7 @@
margin-top: auto;
margin-bottom: auto;
}
+
.collectionViewBaseChrome-viewSpecs {
margin-left: 5px;
display: grid;
@@ -318,12 +320,14 @@
text-align: center;
display: block;
}
+
.color-previewI {
width: 80%;
height: 20%;
bottom: 0;
position: absolute;
}
+
.color-previewII {
width: 80%;
height: 80%;
@@ -336,7 +340,7 @@
margin: auto;
/* Make the buttons appear below each other */
}
-
+
.btn-draw {
display: inline-flex;
margin: auto;
@@ -364,6 +368,7 @@
}
}
+
.numKeyframe {
flex-direction: column;
padding-top: 5px;
@@ -374,6 +379,7 @@
display: block;
margin: auto;
}
+
border-right: solid gray 1px;
}
}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 0332b4bf2..c56ac9f77 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -184,7 +184,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
if (found) {
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
- smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ smoothScroll(doc.presTransition ? Number(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
}
afterFocus && setTimeout(() => {
if (afterFocus?.()) { }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 92aee3776..2b07c4efb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -13,16 +13,153 @@
}
.collectionfreeformview-viewdef {
- > .collectionFreeFormDocumentView-container {
+ >.collectionFreeFormDocumentView-container {
pointer-events: none;
+
.contentFittingDocumentDocumentView-previewDoc {
pointer-events: all;
}
}
+
+ svg.presPaths {
+ position: absolute;
+ z-index: 100000;
+ overflow: visible;
+ }
+
+ svg.presPaths-hidden {
+ display: none;
+ }
}
.collectionfreeformview-none {
touch-action: none;
+
+ svg.presPaths {
+ position: absolute;
+ z-index: 100000;
+ overflow: visible;
+ }
+
+ svg.presPaths-hidden {
+ display: none;
+ }
+}
+
+.pathOrder {
+ position: absolute;
+ z-index: 200000;
+
+ .pathOrder-frame {
+ position: absolute;
+ width: 40;
+ text-align: center;
+ font-size: 30;
+ background-color: #69a6db;
+ font-family: Roboto;
+ font-weight: 300;
+ }
+}
+
+.progressivizeButton {
+ position: absolute;
+ display: grid;
+ grid-template-columns: auto 20px auto;
+ transform: translate(-105%, 0);
+ align-items: center;
+ border: black solid 1px;
+ border-radius: 3px;
+ justify-content: center;
+ width: 40;
+ z-index: 30000;
+ height: 20;
+ overflow: hidden;
+ background-color: #d5dce2;
+ transition: all 1s;
+
+ .progressivizeButton-prev:hover {
+ color: #5a9edd;
+ }
+
+ .progressivizeButton-frame {
+ justify-self: center;
+ text-align: center;
+ width: 15px;
+ }
+
+ .progressivizeButton-next:hover {
+ color: #5a9edd;
+ }
+}
+
+.resizable {
+ background: rgba(0, 0, 0, 0.2);
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+
+ .resizers {
+ width: 100%;
+ height: 100%;
+ border: 3px solid #69a6db;
+ box-sizing: border-box;
+
+ .resizer {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ /*magic to turn square into circle*/
+ background: white;
+ border: 3px solid #69a6db;
+ }
+
+ .resizer.top-left {
+ left: -3px;
+ top: -3px;
+ cursor: nwse-resize;
+ /*resizer cursor*/
+ }
+
+ .resizer.top-right {
+ right: -3px;
+ top: -3px;
+ cursor: nesw-resize;
+ }
+
+ .resizer.bottom-left {
+ left: -3px;
+ bottom: -3px;
+ cursor: nesw-resize;
+ }
+
+ .resizer.bottom-right {
+ right: -3px;
+ bottom: -3px;
+ cursor: nwse-resize;
+ }
+ }
+}
+
+.progressivizeMove-frame {
+ width: 20px;
+ border-radius: 2px;
+ z-index: 100000;
+ color: white;
+ text-align: center;
+ background-color: #5a9edd;
+ transform: translate(-110%, 110%);
+}
+
+.progressivizeButton:hover {
+ box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
+
+ .progressivizeButton-frame {
+ background-color: #5a9edd;
+ color: white;
+ }
}
.collectionFreeform-customText {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 57336131a..151acb64d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faEye } from "@fortawesome/free-regular-svg-icons";
import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc";
@@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { PresBox } from "../../nodes/PresBox";
import { SearchUtil } from "../../../util/SearchUtil";
import { LinkManager } from "../../../util/LinkManager";
@@ -76,8 +77,7 @@ export type collectionFreeformViewProps = {
forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
viewDefDivClick?: ScriptField;
childPointerEvents?: boolean;
- scaleField?: string; // used by formattedTextBox when displaying a sidebar freeform view which needs its own scale field
- noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
+ scaleField?: string;
};
@observer
@@ -213,7 +213,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const layoutDoc = Doc.Layout(d);
if (this.Document.currentFrame !== undefined) {
const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.opacity);
+ CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.opacity);
} else {
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
@@ -911,7 +911,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
// !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1);
// } else {
if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
- if (!doc.z) this.setPan(newPanX, newPanY, "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ // glr: freeform transform speed can be set through user by adjusting for presentation transform
+ if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
}
Doc.BrushDoc(this.props.Document);
this.props.focus(this.props.Document);
@@ -954,8 +955,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
DataDoc: childData,
Document: childLayout,
LibraryPath: this.libraryPath,
- LayoutTemplate: childLayout.z ? undefined : this.props.ChildLayoutTemplate,
- LayoutTemplateString: childLayout.z ? undefined : this.props.ChildLayoutString,
+ LayoutTemplate: this.props.ChildLayoutTemplate,
+ LayoutTemplateString: this.props.ChildLayoutString,
FreezeDimensions: this.props.freezeChildDimensions,
layoutKey: undefined,
setupDragLines: this.setupDragLines,
@@ -1397,6 +1398,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
<CollectionFreeFormViewPannableContents
centeringShiftX={this.centeringShiftX}
centeringShiftY={this.centeringShiftY}
+ presPaths={BoolCast(this.Document.presPathView)}
+ progressivize={BoolCast(this.Document.editProgressivize)}
+ zoomProgressivize={BoolCast(this.Document.editZoomProgressivize)}
transition={Cast(this.layoutDoc._viewTransition, "string", null)}
viewDefDivClick={this.props.viewDefDivClick}
zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
@@ -1437,7 +1441,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}}>
{this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ?
this.placeholder : this.marqueeView}
- {!this.props.noOverlay ? <CollectionFreeFormOverlayView elements={this.elementFunc} /> : (null)}
+ <CollectionFreeFormOverlayView elements={this.elementFunc} />
<div className={"pullpane-indicator"}
style={{
@@ -1480,11 +1484,69 @@ interface CollectionFreeFormViewPannableContentsProps {
viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
transition?: string;
+ presPaths?: boolean;
+ progressivize?: boolean;
+ zoomProgressivize?: boolean;
}
@observer
class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+ @computed get zoomProgressivize() {
+ if (this.props.zoomProgressivize) {
+ console.log("should render");
+ return (
+ <>
+ {PresBox.Instance.zoomProgressivizeContainer}
+ </>
+ );
+ }
+ }
+
+ @computed get progressivize() {
+ if (this.props.progressivize) {
+ console.log("should render");
+ return (
+ <>
+ {PresBox.Instance.progressivizeChildDocs}
+ </>
+ );
+ }
+ }
+
+ @computed get presPaths() {
+ const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden");
+ if (this.props.presPaths) {
+ return (
+ <>
+ <div>{PresBox.Instance.order}</div>
+ <svg className={presPaths}>
+ <defs>
+ <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
+ </marker>
+ <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
+ refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
+ </marker>
+ <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
+ orient="auto" overflow="visible">
+ <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
+ </marker>
+
+ <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
+ orient="auto" overflow="visible">
+ <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
+ </marker>
+ </defs>;
+ {PresBox.Instance.paths}
+ </svg>
+ </>
+ );
+ }
+ }
+
render() {
+ // trace();
const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none");
const cenx = this.props.centeringShiftX();
const ceny = this.props.centeringShiftY();
@@ -1497,6 +1559,9 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
transition: this.props.transition
}}>
{this.props.children()}
+ {this.presPaths}
+ {this.progressivize}
+ {this.zoomProgressivize}
</div>;
}
}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ce39c3735..c29547eac 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -11,11 +11,15 @@ import { Document } from "../../../fields/documentSchemas";
import { TraceMobx } from "../../../fields/util";
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import { List } from "../../../fields/List";
-import { numberRange } from "../../../Utils";
+import { numberRange, smoothScroll } from "../../../Utils";
import { ComputedField } from "../../../fields/ScriptField";
import { listSpec } from "../../../fields/Schema";
import { DocumentType } from "../../documents/DocumentTypes";
+import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal';
+import { PresBox } from "./PresBox";
import { InkingStroke } from "../InkingStroke";
+import { PDFViewer } from "../pdf/PDFViewer";
+import { PDFBox } from "./PDFBox";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -74,30 +78,64 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static getValues(doc: Doc, time: number) {
const timecode = Math.round(time);
return ({
+ h: Cast(doc["h-indexed"], listSpec("number"), [NumCast(doc._height)]).reduce((p, h, i) => (i <= timecode && h !== undefined) || p === undefined ? h : p, undefined as any as number),
+ w: Cast(doc["w-indexed"], listSpec("number"), [NumCast(doc._width)]).reduce((p, w, i) => (i <= timecode && w !== undefined) || p === undefined ? w : p, undefined as any as number),
x: Cast(doc["x-indexed"], listSpec("number"), [NumCast(doc.x)]).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number),
y: Cast(doc["y-indexed"], listSpec("number"), [NumCast(doc.y)]).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number),
+ scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollTop, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number),
opacity: Cast(doc["opacity-indexed"], listSpec("number"), [NumCast(doc.opacity, 1)]).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number),
});
}
- public static setValues(time: number, d: Doc, x?: number, y?: number, opacity?: number) {
+ public static setValues(time: number, d: Doc, x?: number, y?: number, h?: number, w?: number, scroll?: number, opacity?: number) {
const timecode = Math.round(time);
+ const hindexed = Cast(d["h-indexed"], listSpec("number"), []).slice();
+ const windexed = Cast(d["w-indexed"], listSpec("number"), []).slice();
const xindexed = Cast(d["x-indexed"], listSpec("number"), []).slice();
const yindexed = Cast(d["y-indexed"], listSpec("number"), []).slice();
const oindexed = Cast(d["opacity-indexed"], listSpec("number"), []).slice();
+ const scrollIndexed = Cast(d["scroll-indexed"], listSpec("number"), []).slice();
xindexed[timecode] = x as any as number;
yindexed[timecode] = y as any as number;
+ hindexed[timecode] = h as any as number;
+ windexed[timecode] = w as any as number;
oindexed[timecode] = opacity as any as number;
+ scrollIndexed[timecode] = scroll as any as number;
d["x-indexed"] = new List<number>(xindexed);
d["y-indexed"] = new List<number>(yindexed);
+ d["h-indexed"] = new List<number>(hindexed);
+ d["w-indexed"] = new List<number>(windexed);
d["opacity-indexed"] = new List<number>(oindexed);
+ d["scroll-indexed"] = new List<number>(scrollIndexed);
}
+
+ public static updateScrollframe(doc: Doc, time: number) {
+ let _pdfViewer: PDFViewer | undefined;
+ const timecode = Math.round(time);
+ const scrollIndexed = Cast(doc['scroll-indexed'], listSpec("number"), null);
+ scrollIndexed?.length <= timecode + 1 && scrollIndexed.push(undefined as any as number);
+ setTimeout(() => doc.dataTransition = "inherit", 1010);
+ }
+
+ public static setupScroll(doc: Doc, timecode: number, scrollProgressivize: boolean = false) {
+ const scrollList = new List<number>();
+ scrollList[timecode] = NumCast(doc._scrollTop);
+ doc["scroll-indexed"] = scrollList;
+ doc.activeFrame = ComputedField.MakeFunction("self.currentFrame");
+ doc._scrollTop = ComputedField.MakeInterpolated("scroll", "activeFrame");
+ }
+
+
public static updateKeyframe(docs: Doc[], time: number) {
const timecode = Math.round(time);
docs.forEach(doc => {
const xindexed = Cast(doc['x-indexed'], listSpec("number"), null);
const yindexed = Cast(doc['y-indexed'], listSpec("number"), null);
+ const hindexed = Cast(doc['h-indexed'], listSpec("number"), null);
+ const windexed = Cast(doc['w-indexed'], listSpec("number"), null);
const opacityindexed = Cast(doc['opacity-indexed'], listSpec("number"), null);
+ hindexed?.length <= timecode + 1 && hindexed.push(undefined as any as number);
+ windexed?.length <= timecode + 1 && windexed.push(undefined as any as number);
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);
@@ -111,18 +149,53 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
}
+ public static setupZoom(doc: Doc, zoomProgressivize: boolean = false) {
+ const width = new List<number>();
+ const height = new List<number>();
+ const top = new List<number>();
+ const left = new List<number>();
+ width.push(NumCast(doc.width));
+ height.push(NumCast(doc.height));
+ top.push(NumCast(doc.height) / -2);
+ left.push(NumCast(doc.width) / -2);
+ doc["viewfinder-width-indexed"] = width;
+ doc["viewfinder-height-indexed"] = height;
+ doc["viewfinder-top-indexed"] = top;
+ doc["viewfinder-left-indexed"] = left;
+ }
+
public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) {
docs.forEach((doc, i) => {
+ if (!doc.appearFrame) doc.appearFrame = i;
const curTimecode = progressivize ? i : timecode;
const xlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
const ylist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
- const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < i ? 0 : 1));
+ const wlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
+ const hlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
+ const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
+ let oarray: List<number>;
+ console.log(doc.title + "AF: " + doc.appearFrame);
+ console.log("timecode: " + timecode);
+ oarray = olist;
+ oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
+ oarray.fill(1, NumCast(doc.appearFrame), timecode);
+ // oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
+ // oarray.fill(1, NumCast(doc.appearFrame), timecode);
+ // console.log(oarray);
+ wlist[curTimecode] = NumCast(doc._width);
+ hlist[curTimecode] = NumCast(doc._height);
xlist[curTimecode] = NumCast(doc.x);
ylist[curTimecode] = NumCast(doc.y);
+ doc.xArray = xlist;
+ doc.yArray = ylist;
doc["x-indexed"] = xlist;
doc["y-indexed"] = ylist;
- doc["opacity-indexed"] = olist;
+ doc["w-indexed"] = wlist;
+ doc["h-indexed"] = hlist;
+ doc["opacity-indexed"] = oarray;
doc.activeFrame = ComputedField.MakeFunction("self.context?.currentFrame||0");
+ doc._height = ComputedField.MakeInterpolated("h", "activeFrame");
+ doc._width = ComputedField.MakeInterpolated("w", "activeFrame");
doc.x = ComputedField.MakeInterpolated("x", "activeFrame");
doc.y = ComputedField.MakeInterpolated("y", "activeFrame");
doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame");
@@ -135,6 +208,44 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
this.props.Document.y = NumCast(this.props.Document.y) + y;
}
+ @computed get freeformNodeDiv() {
+ const node = <DocumentView {...this.props}
+ nudge={this.nudge}
+ dragDivName={"collectionFreeFormDocumentView-container"}
+ ContentScaling={this.contentScaling}
+ ScreenToLocalTransform={this.getTransform}
+ backgroundColor={this.props.backgroundColor}
+ opacity={this.opacity}
+ NativeHeight={this.NativeHeight}
+ NativeWidth={this.NativeWidth}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight} />;
+ if (PresBox.Instance && this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc) {
+ const effectProps = {
+ left: this.layoutDoc.presEffectDirection === 'left',
+ right: this.layoutDoc.presEffectDirection === 'right',
+ top: this.layoutDoc.presEffectDirection === 'top',
+ bottom: this.layoutDoc.presEffectDirection === 'bottom',
+ opposite: true,
+ delay: this.layoutDoc.presTransition,
+ // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
+ };
+ switch (this.layoutDoc.presEffect) {
+ case "Zoom": return (<Zoom {...effectProps}>{node}</Zoom>); break;
+ case "Fade": return (<Fade {...effectProps}>{node}</Fade>); break;
+ case "Flip": return (<Flip {...effectProps}>{node}</Flip>); break;
+ case "Rotate": return (<Rotate {...effectProps}>{node}</Rotate>); break;
+ case "Bounce": return (<Bounce {...effectProps}>{node}</Bounce>); break;
+ case "Roll": return (<Roll {...effectProps}>{node}</Roll>); break;
+ case "LightSpeed": return (<LightSpeed {...effectProps}>{node}</LightSpeed>); break;
+ case "None": return node; break;
+ default: return node; break;
+ }
+ } else {
+ return node;
+ }
+ }
+
contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.());
panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.());
@@ -165,6 +276,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
display: this.ZInd === -99 ? "none" : undefined,
pointerEvents: this.props.Document.isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents ? "all" : undefined
}} >
+
{Doc.UserDoc().renderStyle !== "comic" ? (null) :
<div style={{ width: "100%", height: "100%", position: "absolute" }}>
<svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14">
@@ -174,17 +286,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
</div>}
{!this.props.fitToBox ?
- <DocumentView {...this.props}
- nudge={this.nudge}
- dragDivName={"collectionFreeFormDocumentView-container"}
- ContentScaling={this.contentScaling}
- ScreenToLocalTransform={this.getTransform}
- backgroundColor={this.props.backgroundColor}
- opacity={this.opacity}
- NativeHeight={this.NativeHeight}
- NativeWidth={this.NativeWidth}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight} />
+ <>{this.freeformNodeDiv}</>
: <ContentFittingDocumentView {...this.props}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
DataDoc={this.props.DataDoc}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 48e1f6ce3..5d5bc1d73 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -45,6 +45,7 @@ export interface FieldViewProps {
whenActiveChanged: (isActive: boolean) => void;
dontRegisterView?: boolean;
focus: (doc: Doc) => void;
+ presMultiSelect?: (doc: Doc) => void; //added for selecting multiple documents in a presentation
ignoreAutoHeight?: boolean;
PanelWidth: () => number;
PanelHeight: () => number;
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 9f6af1bde..b06503472 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -1,7 +1,9 @@
.presBox-cont {
position: absolute;
+ display: block;
pointer-events: inherit;
z-index: 2;
+ font-family: Roboto;
box-shadow: #AAAAAA .2vw .2vw .4vw;
width: 100%;
min-width: 20px;
@@ -12,73 +14,667 @@
transition: 0.7s opacity ease;
.presBox-listCont {
- position: absolute;
+ position: relative;
height: calc(100% - 25px);
width: 100%;
+ margin-top: 3px;
+ }
+
+ .presBox-toolbar {
+ display: none;
+ }
+
+ .presBox-toolbar.active {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ height: 30px;
+ width: 100%;
+ color: white;
+ background-color: #323232;
+
+ .toolbar-button {
+ margin-left: 10px;
+ margin-right: 10px;
+ letter-spacing: 0;
+ display: flex;
+ align-items: center;
+ transition: 0.5s;
+ }
+
+ .toolbar-button.active {
+ color: #AEDDF8;
+ }
+
+ .toolbar-transitionButtons {
+ display: block;
+
+ .toolbar-transition {
+ display: flex;
+ font-size: 10;
+ width: 100;
+ background-color: rgba(0, 0, 0, 0);
+ min-width: max-content;
+
+ .toolbar-icon {
+ margin-right: 5px;
+ }
+ }
+ }
+ }
+
+ .toolbar-moreInfo {
+ position: absolute;
+ right: 5px;
+ display: flex;
+ width: max-content;
+ height: 25px;
+ /* background-color: pink; */
+ justify-content: center;
+ transform: rotate(90deg);
+ align-items: center;
+ transition: 0.7s ease;
+
+ .toolbar-moreInfoBall {
+ width: 4px;
+ height: 4px;
+ border-radius: 100%;
+ background-color: white;
+ margin: 1px;
+ position: relative;
+ }
+ }
+
+ .toolbar-moreInfo.active {
+ transform: rotate(0deg);
}
- .presBox-buttons {
+ .toolbar-divider {
+ border-left: solid #ffffff70 0.5px;
+ height: 20px;
+ }
+}
+
+.dropdown {
+ font-size: 10;
+ margin-left: 5px;
+ color: darkgrey;
+ transition: 0.5s ease;
+}
+
+.dropdown.active {
+ transform: rotate(180deg);
+ color: #AEDDF8;
+ opacity: 0.8;
+}
+
+.presBox-ribbon {
+ position: relative;
+ display: none;
+ font-family: Roboto;
+ background-color: white;
+ color: black;
+ width: 100%;
+ height: 0;
+ z-index: 100;
+ transition: 0.7s;
+
+ .ribbon-doubleButton {
+ display: inline-flex;
+ }
+
+ .toolbar-slider {
+ position: relative;
+ align-self: center;
+ justify-self: left;
+ -webkit-appearance: none;
+ transform: rotateY(180deg);
+ background-color: #40B3D8;
+ margin-top: 5px;
width: 100%;
- background: gray;
- padding-top: 5px;
- padding-bottom: 5px;
+ max-width: 120px;
+ height: 2.5px;
+ left: 0px;
+ }
+
+ .toolbar-slider:focus {
+ outline: none;
+ }
+
+ .effectDirection {
+ justify-self: center;
+ align-self: center;
+ align-items: center;
+ justify-content: center;
+ grid-template-columns: 13px 13px 13px;
display: grid;
- grid-column-end: 4;
- grid-column-start: 1;
+ }
- .presBox-viewPicker {
- height: 25;
+ .toolbar-slider::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ background-color: #40B3D8;
+ border: 1px white solid;
+ border-radius: 100%;
+ width: 9px;
+ height: 9px;
+ }
+
+ .slider-headers {
+ position: relative;
+ display: grid;
+ justify-content: space-between;
+ width: 100%;
+ height: max-content;
+ max-width: 120px;
+ grid-template-columns: auto auto auto;
+ grid-template-rows: max-content;
+ font-weight: 100;
+ /* margin-top: 5px; */
+ font-size: 8px;
+ }
+
+ .slider-value {
+ top: -20;
+ color: #2f86a2;
+ position: absolute;
+ }
+
+ .slider-value.none,
+ .slider-headers.none,
+ .toolbar-slider.none {
+ display: none;
+ }
+
+ .dropdown-header {
+ padding-bottom: 10px;
+ font-weight: 800;
+ text-align: center;
+ font-size: 16;
+ width: 90%;
+ color: black;
+ transform: translate(5%, 0px);
+ border-bottom: solid 2px darkgrey;
+ }
+
+
+ .ribbon-textInput {
+ border-radius: 2px;
+ height: 20px;
+ font-size: 10;
+ font-weight: 100;
+ align-self: center;
+ justify-self: center;
+ padding-left: 10px;
+ border: solid 1px black;
+ min-width: 80px;
+ width: 100%;
+ }
+
+ .ribbon-frameSelector {
+ border: black solid 1px;
+ width: 60px;
+ height: 20px;
+ display: grid;
+ grid-template-columns: auto 27px auto;
+ position: relative;
+ border-radius: 5px;
+ overflow: hidden;
+ align-items: center;
+ justify-self: left;
+
+ .fwdKeyframe,
+ .backKeyframe {
+ cursor: pointer;
position: relative;
- display: inline-block;
- grid-column: 1/2;
- min-width: 15px;
+ height: 100%;
+ background: #d5dce2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ color: black;
}
- select {
- background: #323232;
- color: white;
+ .numKeyframe {
+ font-size: 10;
+ font-weight: 600;
+ position: relative;
+ color: black;
+ display: flex;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ align-items: center;
+ justify-content: center;
}
+ }
- .presBox-button {
- margin-right: 2.5%;
- margin-left: 2.5%;
- height: 25px;
- border-radius: 5px;
+ .ribbon-final-box {
+ align-self: flex-start;
+ justify-self: center;
+ display: grid;
+ grid-template-rows: auto auto;
+ padding-left: 10px;
+ padding-right: 10px;
+ letter-spacing: normal;
+ min-width: max-content;
+ width: 100%;
+ font-size: 13;
+ font-weight: 600;
+ position: relative;
+
+
+ .ribbon-final-button {
+ position: relative;
+ font-size: 10;
+ font-weight: normal;
+ letter-spacing: normal;
display: flex;
+ justify-content: center;
align-items: center;
- background: #323232;
+ margin-bottom: 5px;
+ height: 25px;
color: white;
-
- svg {
- margin: auto;
- }
+ width: 100%;
+ max-width: 120;
+ padding-left: 10;
+ padding-right: 10;
+ border-radius: 10px;
+ background-color: #979797;
}
- .collectionViewBaseChrome-viewPicker {
- min-width: 50;
- width: 5%;
- height: 25;
+ .ribbon-final-button-hidden {
position: relative;
- display: inline-block;
+ font-size: 10;
+ font-weight: normal;
+ letter-spacing: normal;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-bottom: 5px;
+ height: 25px;
+ color: lightgrey;
+ width: 100%;
+ max-width: 120;
+ padding-left: 10;
+ padding-right: 10;
+ border-radius: 10px;
+ background-color: black;
+ }
+ }
+
+ .selectedList {
+ display: block;
+ min-width: 50;
+ max-width: 120;
+ height: 70;
+ overflow-y: scroll;
+
+ .selectedList-items {
+ font-size: 7;
+ font-weight: normal;
}
}
- .presBox-backward,
- .presBox-forward {
- width: 25px;
+ .ribbon-button {
+ font-size: 10;
+ font-weight: 200;
+ height: 20;
+ border: solid 1px black;
+ display: flex;
+ margin-top: 5px;
+ margin-bottom: 5px;
border-radius: 5px;
- top: 50%;
+ margin-right: 5px;
+ width: max-content;
+ justify-content: center;
+ align-items: center;
+ padding-right: 10px;
+ padding-left: 10px;
+ }
+
+ .ribbon-button.active {
+ background-color: #5B9FDD;
+ }
+
+ .ribbon-button:hover {
+ background-color: lightgrey;
+ }
+
+ svg.svg-inline--fa.fa-thumbtack.fa-w-12.toolbar-thumbtack {
+ right: 40;
position: absolute;
+ transform: rotate(45deg);
+ }
+
+ .ribbon-box {
+ display: grid;
+ grid-template-rows: max-content auto;
+ justify-self: center;
+ padding-left: 10px;
+ padding-right: 10px;
+ letter-spacing: normal;
+ width: 100%;
+ font-weight: 600;
+ position: relative;
+ font-size: 13;
+ border-right: solid 2px darkgrey;
+
+ .presBox-dropdown:hover {
+ border: solid 1px #378AD8;
+
+ .presBox-dropdownOption {
+ font-size: 10;
+ display: block;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 3;
+ padding-bottom: 3;
+ }
+
+ .presBox-dropdownOption:hover {
+ position: relative;
+ background-color: lightgrey;
+ }
+
+ .presBox-dropdownOption.active {
+ position: relative;
+ background-color: #aedef8;
+ }
+
+ .presBox-dropdownOptions {
+ position: absolute;
+ top: 19px;
+ left: -1px;
+ z-index: 200;
+ width: 85%;
+ min-width: max-content;
+ display: block;
+ background: #FFFFFF;
+ border: 0.5px solid #979797;
+ box-sizing: border-box;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ }
+
+ .presBox-dropdownIcon {
+ color: #378AD8;
+ }
+ }
+
+ .presBox-dropdown {
+ display: grid;
+ grid-template-columns: auto 20%;
+ position: relative;
+ border: solid 1px black;
+ font-size: 10;
+ height: 20;
+ padding-left: 5px;
+ align-items: center;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-weight: 200;
+ width: 100%;
+ min-width: max-content;
+ max-width: 120;
+ overflow: visible;
+
+ .presBox-dropdownOptions {
+ display: none;
+ }
+
+ .presBox-dropdownIcon {
+ position: relative;
+ color: black;
+ align-self: center;
+ justify-self: center;
+ margin-right: 2px;
+ }
+ }
+ }
+}
+
+.presBox-ribbon.active {
+ display: grid;
+ grid-template-columns: auto auto auto auto auto;
+ grid-template-rows: 100%;
+ height: 100px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ border: solid 1px black;
+ // overflow: auto;
+
+ ::-webkit-scrollbar {
+ -webkit-appearance: none;
+ height: 3px;
+ width: 8px;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ border-radius: 2px;
+ }
+}
+
+.dropdown-play-button {
+ font-size: 12;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ text-align: left;
+ justify-content: left;
+}
+
+.dropdown-play-button:hover {
+ background-color: lightgrey;
+}
+
+.presBox-button-left {
+ position: relative;
+ align-self: flex-start;
+ justify-self: flex-start;
+ width: 80%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.presBox-button-right {
+ position: relative;
+ text-align: center;
+ border-left: solid 1px darkgrey;
+ width: 20%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.presBox-button-right.active {
+ background-color: #223063;
+ border: #aedcf6 solid 1px;
+ box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
+}
+
+.dropdown-play {
+ right: 0px;
+ top: calc(100% + 2px);
+ display: none;
+ border-radius: 5px;
+ width: max-content;
+ min-height: 20px;
+ height: max-content;
+ box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.8);
+ z-index: 200;
+ background-color: white;
+ color: black;
+ position: absolute;
+ overflow: hidden;
+}
+
+.dropdown-play.active {
+ display: block;
+}
+
+.layout-container {
+ overflow-x: scroll;
+ display: flex;
+ width: 100%;
+ /* max-width: 200px; */
+ min-width: 100px;
+ height: 100%;
+ // border: solid 1px;
+ /* display: block; */
+ align-self: center;
+
+ .layout:hover {
+ border: solid 2px #5c9edd;
+ }
+
+ .layout {
+ position: relative;
+ top: 10%;
+ height: 80%;
+ margin-right: 10;
+ min-width: 90px;
+ width: 90px;
+ border: solid black 1px;
+ display: grid;
+ grid-template-rows: 20px 30px;
+ align-items: center;
+ text-align: center;
+
+ .header {
+ font-size: 10;
+ font-weight: 600;
+ width: 70%;
+ height: max-content;
+ align-self: center;
+ justify-self: center;
+ border: solid 0.8px black;
+ }
+
+ .subheader {
+ font-size: 8;
+ font-weight: 400;
+ width: 70%;
+ height: 90%;
+ align-self: center;
+ justify-self: center;
+ border: solid 0.4px black;
+ }
+ }
+}
+
+.presBox-buttons {
+ position: relative;
+ width: 100%;
+ background: gray;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ display: grid;
+ grid-template-columns: auto auto;
+
+ .presBox-viewPicker {
+ height: 25;
+ position: relative;
display: inline-block;
+ grid-column: 1;
+ border-radius: 5px;
+ min-width: 15px;
+ max-width: 100px;
+ left: 8px;
+ }
+
+ .presBox-presentPanel {
+ display: flex;
+ justify-self: end;
+ width: 100%;
+ max-width: 300px;
+ min-width: 150px;
+ }
+
+
+
+ select {
+ background: #323232;
+ color: white;
}
- .presBox-backward {
- left: 5;
+ .presBox-button {
+ margin-right: 2.5px;
+ margin-left: 2.5px;
+ height: 25px;
+ border-radius: 5px;
+ display: none;
+ justify-content: center;
+ align-content: center;
+ align-items: center;
+ text-align: center;
+ letter-spacing: normal;
+ width: inherit;
+ background: #323232;
+ color: white;
}
- .presBox-forward {
- right: 5;
+ .presBox-button.active {
+ display: flex;
+ }
+
+ .presBox-button.active:hover {
+ background-color: #233163;
+ }
+
+ .presBox-button.edit {
+ display: flex;
+ max-width: 25px;
+ }
+
+ .presBox-button.present {
+ display: flex;
+ min-width: 100px;
+ width: 100px;
+ position: absolute;
+ right: 8px;
+
+ .present-icon {
+ margin-right: 7px;
+ }
}
+
+
+
+ .collectionViewBaseChrome-viewPicker {
+ min-width: 50;
+ width: 5%;
+ height: 25;
+ position: relative;
+ display: inline-block;
+ left: 8px;
+ }
+}
+
+.presBox-backward,
+.presBox-forward {
+ width: 25px;
+ border-radius: 5px;
+ top: 50%;
+ position: absolute;
+ display: inline-block;
+}
+
+.presBox-backward {
+ left: 5;
+}
+
+.presBox-forward {
+ right: 5;
}
// CSS adjusted for mobile devices
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index a304ced18..95054205b 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -2,24 +2,33 @@ import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, DocCastAsync } from "../../../fields/Doc";
+import { Doc, DocListCast, DocCastAsync, WidthSym } from "../../../fields/Doc";
import { InkTool } from "../../../fields/InkField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { returnFalse, returnOne } from "../../../Utils";
+import { returnFalse, returnOne, numberRange } from "../../../Utils";
import { documentSchema } from "../../../fields/documentSchemas";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionDockingView, DockedFrameRenderer } from "../collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../collections/CollectionView";
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
import { ViewBoxBaseComponent } from "../DocComponent";
-import { makeInterface } from "../../../fields/Schema";
+import { makeInterface, listSpec } from "../../../fields/Schema";
import { Docs } from "../../documents/Documents";
import { PrefetchProxy } from "../../../fields/Proxy";
import { ScriptField } from "../../../fields/ScriptField";
import { Scripting } from "../../util/Scripting";
import { InkingStroke } from "../InkingStroke";
+import { HighlightSpanKind } from "typescript";
+import { SearchUtil } from "../../util/SearchUtil";
+import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
+import { child } from "serializr";
+import { List } from "../../../fields/List";
+import { Tooltip } from "@material-ui/core";
+import { CollectionFreeFormViewChrome } from "../collections/CollectionMenu";
+import { conformsTo } from "lodash";
+import { translate } from "googleapis/build/src/apis/translate";
type PresBoxSchema = makeInterface<[typeof documentSchema]>;
const PresBoxDocument = makeInterface(documentSchema);
@@ -27,20 +36,22 @@ const PresBoxDocument = makeInterface(documentSchema);
@observer
export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
+ static Instance: PresBox;
@observable _isChildActive = false;
@computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
@computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); }
@computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); }
constructor(props: any) {
super(props);
+ 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: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data"
+ title: "pres element template", backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
}));
// this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement
// this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent
// the preselement docs from being part of multiple presentations since they would all have the same field, or we'd have to keep per-presentation data
- // stored on each pres element.
+ // stored on each pres element.
(this.presElement as Doc).lookupField = ScriptField.MakeFunction("lookupPresBoxField(container, field, data)",
{ field: "string", data: Doc.name, container: Doc.name });
}
@@ -51,8 +62,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.rootDoc.presBox = this.rootDoc;
this.rootDoc._forceRenderEngine = "timeline";
this.rootDoc._replacedChrome = "replaced";
+ this.layoutDoc.presStatus = "edit";
+ // document.addEventListener("keydown", this.keyEvents, false);
+ }
+
+ // componentWillUnmount() {
+ // document.removeEventListener("keydown", this.keyEvents, false);
+ // }
+
+ onPointerOver = () => {
+ document.addEventListener("keydown", this.keyEvents, true);
+ }
+
+ onPointerLeave = () => {
+ document.removeEventListener("keydown", this.keyEvents, true);
+ }
+
+ updateCurrentPresentation = () => {
+ Doc.UserDoc().activePresentation = this.rootDoc;
+ if (this.itemIndex >= 0) {
+ const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
+ const srcContext = Cast(presTargetDoc.context, Doc, null);
+ if (srcContext) this.rootDoc.presCollection = srcContext;
+ else this.rootDoc.presCollection = presTargetDoc;
+ }
}
- updateCurrentPresentation = () => Doc.UserDoc().activePresentation = this.rootDoc;
@undoBatch
@action
@@ -61,12 +95,45 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
const lastFrame = Cast(presTargetDoc.lastFrame, "number", null);
const curFrame = NumCast(presTargetDoc.currentFrame);
+ // Case 1: There are still other frames and should go through all frames before going to next slide
if (lastFrame !== undefined && curFrame < lastFrame) {
presTargetDoc._viewTransition = "all 1s";
setTimeout(() => presTargetDoc._viewTransition = undefined, 1010);
presTargetDoc.currentFrame = curFrame + 1;
- }
- else if (this.childDocs[this.itemIndex + 1] !== undefined) {
+ if (presTargetDoc.zoomProgressivize) {
+ const srcContext = Cast(presTargetDoc.context, Doc, null);
+ const srcDocView = DocumentManager.Instance.getDocumentView(srcContext);
+ if (srcContext && srcDocView) {
+ const layoutdoc = Doc.Layout(presTargetDoc);
+ const panelWidth: number = srcDocView.props.PanelWidth();
+ const panelHeight: number = srcDocView.props.PanelHeight();
+ console.log("srcDocView: " + srcDocView.props.PanelWidth());
+ // console.log("layoutdoc._width: " + layoutdoc._width);
+ // console.log("srcContext._width: " + srcContext._width);
+ const newPanX = NumCast(presTargetDoc.x) + NumCast(layoutdoc._width) / 2;
+ const newPanY = NumCast(presTargetDoc.y) + NumCast(layoutdoc._height) / 2;
+ // const newPanX = NumCast(presTargetDoc.x) + panelWidth / 2;
+ // const newPanY = NumCast(presTargetDoc.y) + panelHeight / 2;
+ let newScale = 0.9 * Math.min(Number(panelWidth) / this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]), Number(panelHeight) / this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]));
+ // srcContext._panX = newPanX + (NumCast(presTargetDoc._viewScale) * this.checkList(presTargetDoc, presTargetDoc["viewfinder-left-indexed"]) + NumCast(presTargetDoc._panX) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]) / 2));
+ // srcContext._panY = newPanY + (NumCast(presTargetDoc._viewScale) * this.checkList(presTargetDoc, presTargetDoc["viewfinder-top-indexed"]) + NumCast(presTargetDoc._panY) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]) / 2));
+ srcContext._panX = newPanX + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-left-indexed"]) + NumCast(presTargetDoc._panX) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]) / 2));
+ srcContext._panY = newPanY + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-top-indexed"]) + NumCast(presTargetDoc._panY) + (this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]) / 2));
+ // srcContext._panX = newPanX
+ // srcContext._panY = newPanY
+ srcContext._viewScale = newScale;
+ console.log("X: " + srcContext._panX + ", Y: " + srcContext._panY + ", Scale: " + srcContext._viewScale);
+ const resize = document.getElementById('resizable');
+ if (resize) {
+ resize.style.width = this.checkList(presTargetDoc, presTargetDoc["viewfinder-width-indexed"]) + 'px';
+ resize.style.height = this.checkList(presTargetDoc, presTargetDoc["viewfinder-height-indexed"]) + 'px';
+ resize.style.top = this.checkList(presTargetDoc, presTargetDoc["viewfinder-top-indexed"]) + 'px';
+ resize.style.left = this.checkList(presTargetDoc, presTargetDoc["viewfinder-left-indexed"]) + 'px';
+ }
+ }
+ }
+ // Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
+ } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
let nextSelected = this.itemIndex + 1;
this.gotoDocument(nextSelected, this.itemIndex);
@@ -90,89 +157,143 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
//If so making sure to zoom out, which goes back to state before zooming action
let prevSelected = this.itemIndex;
let didZoom = docAtCurrent.zoomButton;
- for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
- didZoom = this.childDocs[prevSelected].zoomButton;
- }
+ // for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
+ // didZoom = this.childDocs[prevSelected].zoomButton;
+ // }
prevSelected = Math.max(0, prevSelected - 1);
this.gotoDocument(prevSelected, this.itemIndex);
}
}
+
+ @action
+ onHideDocumentUntilPressClick = () => {
+ this.childDocs.forEach((doc, index) => {
+ const curDoc = Cast(doc, Doc, null);
+ const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+ if (tagDoc.presEffect === 'None' || !tagDoc.presEffect) {
+ tagDoc.opacity = 1;
+ } else {
+ if (index <= this.itemIndex) {
+ tagDoc.opacity = 1;
+ } else {
+ tagDoc.opacity = 0;
+ }
+ }
+ });
+ }
+
/**
* This is the method that checks for the actions that need to be performed
- * after the document has been presented, which involves 3 button options:
+ * before the document has been presented, which involves 3 button options:
* Hide Until Presented, Hide After Presented, Fade After Presented
*/
- showAfterPresented = (index: number) => {
+ @action
+ hideDocumentInPres = () => {
this.updateCurrentPresentation();
- this.childDocs.forEach((doc, ind) => {
- const presTargetDoc = doc.presentationTargetDoc as Doc;
- //the order of cases is aligned based on priority
- if (doc.presHideTillShownButton && ind <= index) {
- presTargetDoc.opacity = 1;
- }
- if (doc.presHideAfterButton && ind < index) {
- presTargetDoc.opacity = 0;
+ this.childDocs.forEach((doc, i) => {
+ const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+ console.log("HB: " + doc.presHideTillShownButton);
+ console.log("HA: " + doc.presHideAfterButton);
+ if (doc.presHideTillShownButton) {
+ if (i < this.itemIndex) {
+ console.log(i + 1 + "hide before");
+ tagDoc.opacity = 0;
+ console.log(tagDoc.opacity);
+ } else {
+ tagDoc.opacity = 1;
+ }
}
- if (doc.presFadeButton && ind < index) {
- presTargetDoc.opacity = 0.5;
+ if (doc.presHideAfterButton) {
+ if (i > this.itemIndex) {
+ console.log(i + 1 + "hide after");
+ tagDoc.opacity = 0;
+ console.log(tagDoc.opacity);
+ } else {
+ tagDoc.opacity = 1;
+ }
}
});
}
/**
* This is the method that checks for the actions that need to be performed
- * before the document has been presented, which involves 3 button options:
+ * after the document has been presented, which involves 3 button options:
* Hide Until Presented, Hide After Presented, Fade After Presented
*/
- hideIfNotPresented = (index: number) => {
+ showAfterPresented = (index: number) => {
this.updateCurrentPresentation();
- this.childDocs.forEach((key, ind) => {
+ this.childDocs.forEach((doc, ind) => {
+ const presTargetDoc = doc.presentationTargetDoc as Doc;
//the order of cases is aligned based on priority
- const presTargetDoc = key.presentationTargetDoc as Doc;
- if (key.hideAfterButton && ind >= index) {
- presTargetDoc.opacity = 1;
- }
- if (key.fadeButton && ind >= index) {
+ if (doc.presHideTillShownButton && ind <= index) {
presTargetDoc.opacity = 1;
}
- if (key.hideTillShownButton && ind > index) {
+ if (doc.presHideAfterButton && ind < index) {
presTargetDoc.opacity = 0;
}
});
}
+ checkCollection = async (curTarget: Doc, nextTarget: Doc) => {
+ const aliasOf = await DocCastAsync(curTarget.aliasOf);
+ const curContext = aliasOf && await DocCastAsync(aliasOf.context);
+ const aliasOfNext = await DocCastAsync(nextTarget.aliasOf);
+ const nextContext = aliasOfNext && await DocCastAsync(aliasOfNext.context);
+ if (curContext && nextContext) {
+ const collectionDocView = DocumentManager.Instance.getDocumentView(Cast(this.rootDoc.presCollection, Doc, null));
+ // Case: Documents are not in the same collection
+ if (curContext !== nextContext) {
+ // Current document is contained in the next collection (zoom out)
+ if (curContext.context === nextContext) {
+ if (collectionDocView) collectionDocView.props.addDocTab(curContext, "replace"); console.log("hiii");
+ console.log("current in next");
+ // Next document is contained in the current collection (zoom in)
+ } else if (nextContext.context === curContext) {
+ if (collectionDocView) collectionDocView.props.addDocTab(nextContext, "replace"); console.log("hiii2");
+ console.log("next in current");
+ }
+ // No change in parent collection
+ } else {
+ console.log("same collection");
+ }
+
+ }
+ }
/**
* This method makes sure that cursor navigates to the element that
* has the option open and last in the group. If not in the group, and it has
- * te option open, navigates to that element.
+ * the option open, navigates to that element.
*/
navigateToElement = async (curDoc: Doc, fromDocIndex: number) => {
this.updateCurrentPresentation();
- let docToJump = curDoc;
- let willZoom = false;
-
- const presDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
- let nextSelected = presDocs.indexOf(curDoc);
- const currentDocGroups: Doc[] = [];
- for (; nextSelected < presDocs.length - 1; nextSelected++) {
- if (!presDocs[nextSelected + 1].groupButton) {
- break;
- }
- currentDocGroups.push(presDocs[nextSelected]);
- }
+ const docToJump = curDoc;
+ const willZoom = false;
- currentDocGroups.forEach((doc: Doc, index: number) => {
- if (doc.presNavButton) {
- docToJump = doc;
- willZoom = false;
- }
- if (doc.presZoomButton) {
- docToJump = doc;
- willZoom = true;
- }
- });
+ const nextTarget = curDoc;
+ const curTarget = this.childDocs[fromDocIndex];
+ this.checkCollection(curTarget, nextTarget);
+ // const presDocs = DocListCast(this.dataDoc[this.props.fieldKey]);
+ // let nextSelected = presDocs.indexOf(curDoc);
+ // const currentDocGroups: Doc[] = [];
+ // for (; nextSelected < presDocs.length - 1; nextSelected++) {
+ // if (!presDocs[nextSelected + 1].groupButton) {
+ // break;
+ // }
+ // currentDocGroups.push(presDocs[nextSelected]);
+ // }
+
+ // currentDocGroups.forEach((doc: Doc, index: number) => {
+ // if (doc.presNavButton) {
+ // docToJump = doc;
+ // willZoom = false;
+ // }
+ // if (doc.presZoomButton) {
+ // docToJump = doc;
+ // willZoom = true;
+ // }
+ // });
//docToJump stayed same meaning, it was not in the group or was the last element in the group
const aliasOf = await DocCastAsync(docToJump.aliasOf);
@@ -201,31 +322,61 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
- if (presTargetDoc.lastFrame !== undefined) {
+ if (presTargetDoc?.lastFrame !== undefined) {
presTargetDoc.currentFrame = 0;
}
-
- if (!this.layoutDoc.presStatus) {
- this.layoutDoc.presStatus = true;
- this.startPresentation(index);
- }
-
+ // if (this.layoutDoc.presStatus === "edit") {
+ // this.layoutDoc.presStatus = true;
+ // this.startPresentation(index);
+ // }
this.navigateToElement(this.childDocs[index], fromDoc);
- this.hideIfNotPresented(index);
- this.showAfterPresented(index);
+ this._selectedArray = [this.childDocs[index]];
+ // this.hideIfNotPresented(index);
+ // this.showAfterPresented(index);
+ // this.hideDocumentInPres();
+ this.onHideDocumentUntilPressClick();
}
});
+
+ @observable _presTimer!: NodeJS.Timeout;
+
//The function that starts or resets presentaton functionally, depending on status flag.
- startOrResetPres = () => {
+ @action
+ startOrResetPres = (startSlide: number) => {
this.updateCurrentPresentation();
- if (this.layoutDoc.presStatus) {
- this.resetPresentation();
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ if (this.layoutDoc.presStatus === "auto") {
+ if (this._presTimer) clearInterval(this._presTimer);
+ this.layoutDoc.presStatus = "manual";
} else {
- this.layoutDoc.presStatus = true;
- this.startPresentation(0);
- this.gotoDocument(0, this.itemIndex);
+ 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);
+ // for (let i = this.itemIndex + 1; i <= this.childDocs.length; i++) {
+ // if (this.itemIndex + 1 === this.childDocs.length) {
+ // clearTimeout(this._presTimer);
+ // this.layoutDoc.presStatus = "manual";
+ // } else timer = setTimeout(() => { console.log(i); this.next(); }, i * 2000);
+ // }
+
}
+
+ // if (this.layoutDoc.presStatus) {
+ // this.resetPresentation();
+ // } else {
+ // this.layoutDoc.presStatus = true;
+ // this.startPresentation(0);
+ // this.gotoDocument(0, this.itemIndex);
+ // }
}
//The function that resets the presentation by removing every action done by it. It also
@@ -234,7 +385,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.updateCurrentPresentation();
this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1);
this.rootDoc._itemIndex = 0;
- this.layoutDoc.presStatus = false;
+ // this.layoutDoc.presStatus = false;
}
//The function that starts the presentation, also checking if actions should be applied
@@ -255,28 +406,73 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
});
}
- updateMinimize = action((e: React.ChangeEvent, mode: CollectionViewType) => {
- if (BoolCast(this.layoutDoc.inOverlay) !== (mode === CollectionViewType.Invalid)) {
- if (this.layoutDoc.inOverlay) {
+ updateMinimize = () => {
+ const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
+ if (srcContext) {
+ if (srcContext.miniPres) {
+ document.removeEventListener("keydown", this.keyEvents, true);
+ srcContext.miniPres = false;
Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
CollectionDockingView.AddRightSplit(this.rootDoc);
this.layoutDoc.inOverlay = false;
} else {
- const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- this.rootDoc.x = pt[0];// 500;//e.clientX + 25;
- this.rootDoc.y = pt[1];////e.clientY - 25;
+ document.addEventListener("keydown", this.keyEvents, true);
+ srcContext.miniPres = true;
this.props.addDocTab?.(this.rootDoc, "close");
Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
}
+
+
}
- });
+ // if (srcContext) {
+ // Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
+ // CollectionDockingView.AddRightSplit(this.rootDoc);
+ // this.layoutDoc.inOverlay = false;
+ // }
+ // else {
+ // const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ // this.rootDoc.x = pt[0];// 500;//e.clientX + 25;
+ // this.rootDoc.y = pt[1];////e.clientY - 25;
+ // this.props.addDocTab?.(this.rootDoc, "close");
+ // Doc.AddDocToList((Doc.UserDoc().myOverlayDocuments as Doc), undefined, this.rootDoc);
+ // }
+ // }
+ };
@undoBatch
viewChanged = action((e: React.ChangeEvent) => {
//@ts-ignore
const viewType = e.target.selectedOptions[0].value as CollectionViewType;
viewType === CollectionViewType.Stacking && (this.rootDoc._pivotField = undefined); // pivot field may be set by the user in timeline view (or some other way) -- need to reset it here
- this.updateMinimize(e, this.rootDoc._viewType = viewType);
+ // this.updateMinimize(this.rootDoc._viewType = viewType);
+ if (viewType === CollectionViewType.Stacking) this.rootDoc._gridGap = 5;
+ });
+
+ @undoBatch
+ movementChanged = action((movement: string) => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ if (movement === 'zoom') {
+ activeItem.presZoomButton = !activeItem.presZoomButton;
+ if (activeItem.presZoomButton) activeItem.presMovement = 'Zoom';
+ else activeItem.presMovement = 'None';
+ activeItem.presNavButton = false;
+ } else if (movement === 'nav') {
+ activeItem.presZoomButton = false;
+ activeItem.presNavButton = !activeItem.presNavButton;
+ if (activeItem.presNavButton) activeItem.presMovement = 'Pan';
+ else activeItem.presMovement = 'None';
+ } else if (movement === 'switch') {
+ targetDoc.presTransition = 0;
+ activeItem.presSwitchButton = !activeItem.presSwitchButton;
+ if (activeItem.presSwitchButton) activeItem.presMovement = 'Switch';
+ else activeItem.presMovement = 'None';
+ } else {
+ activeItem.presMovement = 'None';
+ activeItem.presZoomButton = false;
+ activeItem.presNavButton = false;
+ activeItem.presSwitchButton = false;
+ }
});
whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
@@ -290,40 +486,1190 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement;
removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc);
- selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
- panelHeight = () => this.props.PanelHeight() - 20;
+ panelHeight = () => this.props.PanelHeight() - 40;
active = (outsideReaction?: boolean) => ((Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground) &&
(this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
- render() {
- // const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs);
- // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) {
- // this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice());
+ // render() {
+ // const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs);
+ // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) {
+ // this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice());
+
+ // KEYS
+ @observable _selectedArray: Doc[] = [];
+
+ @computed get listOfSelected() {
+ const list = this._selectedArray.map((doc: Doc, index: any) => {
+ const activeItem = Cast(doc, Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ return (
+ <div className="selectedList-items">{index + 1}. {targetDoc.title}</div>
+ );
+ });
+ return list;
+ }
+
+ //Regular click
+ @action
+ selectElement = (doc: Doc) => {
+ // this._selectedArray = [];
+ this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
+ // this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
+ console.log(this._selectedArray);
+ }
+
+ //Command click
+ @action
+ multiSelect = (doc: Doc) => {
+ this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]);
+ console.log(this._selectedArray);
+ }
+
+ //Shift click
+ @action
+ shiftSelect = (doc: Doc) => {
+ this._selectedArray = [];
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ if (activeItem) {
+ for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) {
+ this._selectedArray.push(this.childDocs[i]);
+ }
+ }
+ console.log(this._selectedArray);
+ }
+
+
+
+ //Esc click
+ @action
+ keyEvents = (e: KeyboardEvent) => {
+ e.stopPropagation();
+ e.preventDefault();
+ // switch(e.keyCode) {
+ // case 27: console.log("escape");
+ // case 65 && (e.metaKey || e.altKey):
// }
- this.childDocs.slice(); // needed to insure that the childDocs are loaded for looking up fields
+ // Escape key
+ if (e.keyCode === 27) {
+ if (this.layoutDoc.presStatus === "edit") this._selectedArray = [];
+ else this.layoutDoc.presStatus = "edit";
+ // Ctrl-A to select all
+ } if ((e.metaKey || e.altKey) && e.keyCode === 65) {
+ if (this.layoutDoc.presStatus === "edit") this._selectedArray = this.childDocs;
+ // left(37) / a(65) / up(38) to go back
+ } if (e.keyCode === 37) {
+ if (this.layoutDoc.presStatus !== "edit") this.back();
+ // right (39) / d(68) / down(40) to go to next
+ } if (e.keyCode === 39) {
+ if (this.layoutDoc.presStatus !== "edit") this.next();
+ // spacebar to 'present' or go to next slide
+ } if (e.keyCode === 32) {
+ if (this.layoutDoc.presStatus !== "edit") this.next();
+ else this.layoutDoc.presStatus = "manual";
+ }
+ }
+
+ @observable private transitionTools: boolean = false;
+ @observable private newDocumentTools: boolean = false;
+ @observable private progressivizeTools: boolean = false;
+ @observable private moreInfoTools: boolean = false;
+ @observable private playTools: boolean = false;
+ @observable private presentTools: boolean = false;
+ @observable private pathBoolean: boolean = false;
+ @observable private expandBoolean: boolean = false;
+
+ // For toggling transition toolbar
+ @action toggleTransitionTools = () => {
+ this.transitionTools = !this.transitionTools;
+ this.newDocumentTools = false;
+ this.progressivizeTools = false;
+ this.moreInfoTools = false;
+ this.playTools = false;
+ }
+ // For toggling the add new document dropdown
+ @action toggleNewDocument = () => {
+ this.newDocumentTools = !this.newDocumentTools;
+ this.transitionTools = false;
+ this.progressivizeTools = false;
+ this.moreInfoTools = false;
+ this.playTools = false;
+ }
+ // For toggling the tools for progressivize
+ @action toggleProgressivize = () => {
+ this.progressivizeTools = !this.progressivizeTools;
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ targetDoc.editZoomProgressivize = false;
+ targetDoc.editProgressivize = false;
+ this.transitionTools = false;
+ this.newDocumentTools = false;
+ this.moreInfoTools = false;
+ this.playTools = false;
+ }
+ // For toggling the tools for more info
+ @action toggleMoreInfo = () => {
+ this.moreInfoTools = !this.moreInfoTools;
+ this.transitionTools = false;
+ this.newDocumentTools = false;
+ this.progressivizeTools = false;
+ this.playTools = false;
+ }
+ // For toggling the options when the user wants to select play
+ @action togglePlay = () => {
+ this.playTools = !this.playTools;
+ this.transitionTools = false;
+ this.newDocumentTools = false;
+ this.progressivizeTools = false;
+ this.moreInfoTools = false;
+ }
+
+ // For toggling the options when the user wants to select play
+ @action togglePresent = () => {
+ this.presentTools = !this.presentTools;
+ this.playTools = false;
+ this.transitionTools = false;
+ this.newDocumentTools = false;
+ this.progressivizeTools = false;
+ this.moreInfoTools = false;
+ }
+
+ @action toggleAllDropdowns() {
+ this.transitionTools = false;
+ this.newDocumentTools = false;
+ this.progressivizeTools = false;
+ this.moreInfoTools = false;
+ this.playTools = false;
+ }
+
+ @undoBatch
+ @action
+ viewPaths = async () => {
+ const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
+ // const docToJump = this.childDocs[0];
+ // const aliasOf = await DocCastAsync(docToJump.aliasOf);
+ // const srcContext = aliasOf && await DocCastAsync(aliasOf.context);
+ if (this.pathBoolean) {
+ console.log("true");
+ if (srcContext) {
+ this.togglePath();
+ srcContext._fitToBox = false;
+ srcContext._viewType = "freeform";
+ srcContext.presPathView = false;
+ }
+ } else {
+ console.log("false");
+ if (srcContext) {
+ this.togglePath();
+ srcContext._fitToBox = true;
+ srcContext._viewType = "freeform";
+ srcContext.presPathView = true;
+ }
+ }
+ console.log("view paths");
+ const viewType = srcContext?._viewType;
+ const fit = srcContext?._fitToBox;
+
+ // if (!DocumentManager.Instance.getDocumentView(curPres)) {
+ // CollectionDockingView.AddRightSplit(curPres);
+ // }
+ }
+
+ @computed get order() {
+ const order: JSX.Element[] = [];
+ this.childDocs.forEach((doc, index) => {
+ const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
+ const srcContext = Cast(targetDoc.context, Doc, null);
+ if (this.rootDoc.presCollection === srcContext) {
+ order.push(
+ <div className="pathOrder" style={{ top: NumCast(targetDoc.y), left: NumCast(targetDoc.x) }}>
+ <div className="pathOrder-frame">{index + 1}</div>
+ </div>);
+ } else {
+ order.push(
+ <div className="pathOrder" style={{ top: 0, left: 0 }}>
+ <div className="pathOrder-frame">{index + 1}</div>
+ </div>);
+ }
+ });
+ return order;
+ }
+
+ @computed get paths() {
+ // const paths = []; //List of all of the paths that need to be added
+ let pathPoints = "";
+ console.log(this.childDocs.length - 1);
+ this.childDocs.forEach((doc, index) => {
+ const targetDoc = Cast(doc.presentationTargetDoc, 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);
+ if (index = 0) pathPoints = n1x + "," + n1y;
+ else pathPoints = pathPoints + " " + n1x + "," + n1y;
+ } else {
+ if (index = 0) pathPoints = 0 + "," + 0;
+ else pathPoints = pathPoints + " " + 0 + "," + 0;
+ }
+ });
+ console.log(pathPoints);
+ // return paths;
+ return (<polyline
+ points={pathPoints}
+ style={{
+ opacity: 1,
+ stroke: "#69a6db",
+ strokeWidth: 5,
+ strokeDasharray: '10 5',
+ }}
+ fill="none"
+ markerStart="url(#markerSquare)"
+ markerMid="url(#markerSquare)"
+ markerEnd="url(#markerArrow)"
+ />);
+ }
+
+ @action togglePath = () => this.pathBoolean = !this.pathBoolean;
+ @action toggleExpand = () => this.expandBoolean = !this.expandBoolean;
+
+ /**
+ * 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();
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ activeItem.presFadeButton = !activeItem.presFadeButton;
+ if (!activeItem.presFadeButton) {
+ if (targetDoc) {
+ targetDoc.opacity = 1;
+ }
+ } else {
+ activeItem.presHideAfterButton = false;
+ if (this.rootDoc.presStatus !== "edit" && targetDoc) {
+ targetDoc.opacity = 0.5;
+ }
+ }
+ }
+
+ @action
+ dropdownToggle = (menu: string) => {
+ console.log('presBox' + menu + 'Dropdown');
+ const dropMenu = document.getElementById('presBox' + menu + 'Dropdown');
+ console.log(dropMenu);
+ console.log(dropMenu?.style.display);
+ if (dropMenu) dropMenu.style.display === 'none' ? dropMenu.style.display = 'block' : dropMenu.style.display = 'none';
+ }
+
+ setTransitionTime = (number: String) => {
+ const timeInMS = Number(number) * 1000;
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ if (targetDoc) targetDoc.presTransition = timeInMS;
+ }
+
+ setDurationTime = (number: String) => {
+ const timeInMS = Number(number) * 1000;
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ if (targetDoc) targetDoc.presDuration = timeInMS;
+ }
+
+ @computed get transitionDropdown() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ if (activeItem && targetDoc) {
+ const transitionSpeed = targetDoc.presTransition ? String(Number(targetDoc.presTransition) / 1000) : 0.5;
+ const duration = targetDoc.presDuration ? String(Number(targetDoc.presDuration) / 1000) : 2;
+ const transitionThumbLocation = String(-9.48 * Number(transitionSpeed) + 93);
+ const durationThumbLocation = String(9.48 * Number(duration));
+ const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
+ activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
+ return (
+ <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="ribbon-box">
+ Movement
+ <div className="presBox-dropdown"
+ onPointerDown={e => e.stopPropagation()}
+ // onClick={() => this.dropdownToggle('Movement')}
+ >
+ {activeItem.presMovement}
+ <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={e => e.stopPropagation()}>
+ <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>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Pan' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('nav')}>Pan</div>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === 'Switch' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('switch')}>Switch</div>
+ </div>
+ </div>
+ <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed} className={`toolbar-slider ${activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "" : "none"}`} id="toolbar-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setTransitionTime(e.target.value); }} />
+ <div className={`slider-headers ${activeItem.presMovement === 'Pan' || activeItem.presMovement === 'Zoom' ? "" : "none"}`}>
+ <div className={`slider-value ${activeItem.presZoomButton || activeItem.presNavButton ? "" : "none"}`} style={{ left: transitionThumbLocation + '%' }}>{transitionSpeed}s</div>
+ <div className="slider-text">Slow</div>
+ <div className="slider-text"></div>
+ <div className="slider-text">Fast</div>
+ </div>
+ </div>
+ <div className="ribbon-box">
+ Visibility
+ <div className="ribbon-doubleButton">
+ <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-button ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton}>HB</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-button ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => activeItem.presHideAfterButton = !activeItem.presHideAfterButton}>HA</div></Tooltip>
+ </div>
+ <input type="range" step="0.1" min="0.1" max="10" value={duration} style={{ transform: 'rotate(0deg)' }} className={"toolbar-slider"} id="duration-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} />
+ <div className={"slider-headers"}>
+ <div className={"slider-value"} style={{ left: durationThumbLocation + '%' }}>{duration}s</div>
+ <div className="slider-text">Short</div>
+ <div className="slider-text"></div>
+ <div className="slider-text">Long</div>
+ </div>
+ {/* <div title="Fade After" className={`ribbon-button ${activeItem.presFadeButton ? "active" : ""}`} onClick={this.onFadeDocumentAfterPresentedClick}>Fade After</div> */}
+ {/* <div title="Hide After" className={`ribbon-button ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => console.log("hide before")}>Hide Before</div> */}
+ {/* <div title="Hide Before" className={`ribbon-button ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => console.log("hide after")}>Hide After</div> */}
+ </div>
+ <div className="ribbon-box">
+ Effects
+ <div className="presBox-dropdown"
+ onPointerDown={e => e.stopPropagation()}
+ // onClick={() => this.dropdownToggle('Movement')}
+ >
+ {effect}
+ <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={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>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Flip'}>Flip</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Rotate'}>Rotate</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Bounce'}>Bounce</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Roll'}>Roll</div>
+ </div>
+ </div>
+ <div className="effectDirection" style={{ display: effect === 'None' ? "none" : "grid" }}>
+ <Tooltip title={<><div className="dash-tooltip">{"Enter from left"}</div></>}><div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "left" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'left'}><FontAwesomeIcon icon={"angle-right"} /></div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Enter from right"}</div></>}><div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "right" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'right'}><FontAwesomeIcon icon={"angle-left"} /></div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Enter from top"}</div></>}><div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === "top" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'top'}><FontAwesomeIcon icon={"angle-down"} /></div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Enter from bottom"}</div></>}><div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === "bottom" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'bottom'}><FontAwesomeIcon icon={"angle-up"} /></div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Enter from center"}</div></>}><div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection ? "solid 2px black" : "solid 2px #5a9edd", borderRadius: "100%" }} onClick={() => targetDoc.presEffectDirection = false}></div></Tooltip>
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ {this._selectedArray.length} selected
+ <div className="selectedList">
+ {this.listOfSelected}
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div className={this._selectedArray.length === 0 ? "ribbon-final-button" : "ribbon-final-button-hidden"} onClick={() => this.applyTo(this._selectedArray)}>
+ Apply to selected
+ </div>
+ <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
+ Apply to all
+ </div>
+ </div>
+ </div>
+ );
+ }
+ }
+
+ applyTo = (array: Doc[]) => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ array.forEach((doc, index) => {
+ const curDoc = Cast(doc, Doc, null);
+ const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+ if (tagDoc && targetDoc) {
+ tagDoc.presTransition = targetDoc.presTransition;
+ tagDoc.presDuration = targetDoc.presDuration;
+ tagDoc.presEffect = targetDoc.presEffect;
+ }
+ });
+ }
+
+ public inputRef = React.createRef<HTMLInputElement>();
+
+
+ createNewSlide = (title: string, type: string) => {
+ let doc = null;
+ if (type === "text") {
+ doc = Docs.Create.TextDocument("", { _nativeWidth: 400, _width: 400, title: title });
+ const data = Cast(this.rootDoc.data, listSpec(Doc));
+ if (data) data.push(doc);
+ } else {
+ doc = Docs.Create.FreeformDocument([], { _nativeWidth: 400, _width: 400, title: title });
+ const data = Cast(this.rootDoc.data, listSpec(Doc));
+ if (data) data.push(doc);
+ }
+ }
+
+ @computed get newDocumentDropdown() {
+ let type = "";
+ let title = "";
+ return (
+ <div>
+ <div className={`presBox-ribbon ${this.newDocumentTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="ribbon-box">
+ Slide Title: <br></br>
+ {/* <div className="dropdown-textInput"> */}
+ <input className="ribbon-textInput" placeholder="..." type="text" name="fname" ref={this.inputRef} onChange={(e) => {
+ e.stopPropagation();
+ title = e.target.value;
+ }}></input>
+ {/* </div> */}
+ </div>
+ <div className="ribbon-box">
+ Choose type:
+ <div style={{ display: 'block', alignSelf: 'center' }}>
+ <div title="Text" className={'ribbon-button'} style={{ background: type === 'text' ? "#000000" : "#f6f6f6" }} onClick={action(() => { type = "text"; })}>Text</div>
+ <div title="Freeform" className={'ribbon-button'} style={{ background: type === 'freeform' ? "#000000" : "#f6f6f6" }} onClick={action(() => { type = "freeform"; })}>Freeform</div>
+ </div>
+ </div>
+ <div className="ribbon-box">
+ Preset layouts:
+ <div className="layout-container">
+ <div className="layout">
+ <div className="header">HEADER</div>
+ <div className="subheader">Content goes here</div>
+ </div>
+ <div className="layout">
+ <div className="header" style={{ gridColumn: 1 / 2, gridRow: 1 }}>HEADER</div>
+ <div className="subheader" style={{ gridColumn: 1, gridRow: 2 }}>Some content</div>
+ <div className="subheader" style={{ gridColumn: 2, gridRow: 2 }}>Some more content</div>
+ </div>
+ <div className="layout">
+ <div className="header">HEADER</div>
+ <div className="subheader">Content goes here</div>
+ </div>
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div className="ribbon-final-button" onClick={() => this.createNewSlide(title, type)}>
+ Create New Slide
+ </div>
+ </div>
+ </div>
+ </div >
+ );
+ }
+
+ @computed get playDropdown() {
+ return (
+ <div className={`dropdown-play ${this.playTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="dropdown-play-button" onClick={() => this.startOrResetPres(this.itemIndex)}>
+ Present from current slide
+ </div>
+ <div className="dropdown-play-button" onClick={() => this.startOrResetPres(0)}>
+ Present from first slide
+ </div>
+ </div>
+ );
+ }
+
+ @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}>
+ Minimize
+ </div>
+ <div className="dropdown-play-button" onClick={() => this.startOrResetPres(0)}>
+ Sidebar view
+ </div>
+ </div>
+ );
+ }
+
+ // progressivizeOptions = (viewType: string) => {
+ // const buttons = [];
+ // buttons.push(<div className="ribbon-button" onClick={this.progressivize}>Child documents</div>);
+ // buttons.push(<div className="ribbon-button" onClick={() => console.log("hide after")}>Internal zoom</div>);
+ // buttons.push(<div className="ribbon-button" onClick={() => console.log("hide after")}>Bullet points</div>);
+ // if (viewType === "rtf") {
+ // buttons.push(<div className="ribbon-button" title="Progressivize bullet points" onClick={() => console.log("hide after")}>Bullet points</div>);
+ // }
+ // return buttons;
+ // }
+
+ @undoBatch
+ @action
+ nextKeyframe = (tagDoc: Doc): void => {
+ const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
+ const currentFrame = Cast(tagDoc.currentFrame, "number", null);
+ if (currentFrame === undefined) {
+ tagDoc.currentFrame = 0;
+ CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
+ CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
+ }
+ let lastFrame: number = 0;
+ childDocs.forEach((doc) => {
+ if (NumCast(doc.appearFrame) > lastFrame) lastFrame = NumCast(doc.appearFrame);
+ });
+ CollectionFreeFormDocumentView.updateScrollframe(tagDoc, currentFrame);
+ CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
+ tagDoc.currentFrame = Math.max(0, (currentFrame || 0) + 1);
+ tagDoc.lastFrame = Math.max(NumCast(tagDoc.currentFrame), lastFrame);
+ if (tagDoc.zoomProgressivize) {
+ const resize = document.getElementById('resizable');
+ if (resize) {
+ resize.style.width = this.checkList(tagDoc, tagDoc["viewfinder-width-indexed"]) + 'px';
+ resize.style.height = this.checkList(tagDoc, tagDoc["viewfinder-height-indexed"]) + 'px';
+ resize.style.top = this.checkList(tagDoc, tagDoc["viewfinder-top-indexed"]) + 'px';
+ resize.style.left = this.checkList(tagDoc, tagDoc["viewfinder-left-indexed"]) + 'px';
+ }
+ }
+ }
+
+ @undoBatch
+ @action
+ prevKeyframe = (tagDoc: Doc): void => {
+ const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
+ const currentFrame = Cast(tagDoc.currentFrame, "number", null);
+ if (currentFrame === undefined) {
+ tagDoc.currentFrame = 0;
+ CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
+ }
+ CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
+ tagDoc.currentFrame = Math.max(0, (currentFrame || 0) - 1);
+ if (tagDoc.zoomProgressivize) {
+ const resize = document.getElementById('resizable');
+ if (resize) {
+ resize.style.width = this.checkList(tagDoc, tagDoc["viewfinder-width-indexed"]) + 'px';
+ resize.style.height = this.checkList(tagDoc, tagDoc["viewfinder-height-indexed"]) + 'px';
+ resize.style.top = this.checkList(tagDoc, tagDoc["viewfinder-top-indexed"]) + 'px';
+ resize.style.left = this.checkList(tagDoc, tagDoc["viewfinder-left-indexed"]) + 'px';
+ }
+ }
+ }
+
+ @computed get progressivizeDropdown() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+
+ 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">
+ {targetDoc.type} selected
+ <div className="selectedList" style={{ height: 'max-content' }}>
+ <div className="selectedList-items">{targetDoc.title}</div>
+ </div>
+ <div className="ribbon-doubleButton">
+ <div className="ribbon-frameSelector">
+ <div key="back" title="back frame" className="backKeyframe" onClick={e => { e.stopPropagation(); this.prevKeyframe(targetDoc); }}>
+ <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
+ </div>
+ <div key="num" title="toggle view all" className="numKeyframe" style={{ backgroundColor: targetDoc.editing ? "#5a9edd" : "#5a9edd" }}
+ onClick={action(() => targetDoc.editing = !targetDoc.editing)} >
+ {NumCast(targetDoc.currentFrame)}
+ </div>
+ <div key="fwd" title="forward frame" className="fwdKeyframe" onClick={e => { e.stopPropagation(); this.nextKeyframe(targetDoc); }}>
+ <FontAwesomeIcon icon={"caret-right"} size={"lg"} />
+ </div>
+ </div>
+ <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div style={{ fontWeight: 600, marginTop: 0, marginLeft: 3 }} className="ribbon-button">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div className="ribbon-doubleButton" style={{ display: targetDoc.type === "collection" ? "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>
+ <div className="ribbon-doubleButton" style={{ display: targetDoc.type === "collection" || targetDoc.type === "image" ? "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: targetDoc.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>
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: targetDoc.type === "rtf" ? "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>
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: targetDoc.type === "pdf" ? "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>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ }
+
+ //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) {
+ targetDoc.editZoomProgressivize = true;
+ } else {
+ targetDoc.editZoomProgressivize = false;
+ }
+ }
+
+ //Toggle whether the user edits or not
+ @action
+ editScrollProgressivize = (e: React.MouseEvent) => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ if (!targetDoc.editScrollProgressivize) {
+ targetDoc.editScrollProgressivize = true;
+ } else {
+ targetDoc.editScrollProgressivize = false;
+ }
+ }
+
+ //Progressivize Zoom
+ @action
+ progressivizeScroll = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ targetDoc.scrollProgressivize = !targetDoc.zoomProgressivize;
+ CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc.currentFrame), true);
+ if (targetDoc.editScrollProgressivize) {
+ targetDoc.editScrollProgressivize = false;
+ targetDoc.currentFrame = 0;
+ targetDoc.lastFrame = 0;
+ }
+ }
+
+ //Progressivize Zoom
+ @action
+ progressivizeZoom = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ activeItem.zoomProgressivize = !activeItem.zoomProgressivize;
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ targetDoc.zoomProgressivize = !targetDoc.zoomProgressivize;
+ CollectionFreeFormDocumentView.setupZoom(targetDoc, true);
+ if (targetDoc.editZoomProgressivize) {
+ targetDoc.editZoomProgressivize = false;
+ targetDoc.currentFrame = 0;
+ targetDoc.lastFrame = 0;
+ }
+ }
+
+ //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;
+ console.log(targetDoc.presProgressivize);
+ if (activeItem.presProgressivize) {
+ console.log("progressivize");
+ 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 {
+ targetDoc.editProgressivize = true;
+ }
+ }
+
+ @action
+ progressivizeChild = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
+ const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+ if (!activeItem.presProgressivize) {
+ activeItem.presProgressivize = true;
+ targetDoc.presProgressivize = true;
+ targetDoc.currentFrame = 0;
+ CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true);
+ targetDoc.lastFrame = docs.length - 1;
+ } else {
+ targetDoc.editProgressivize = false;
+ activeItem.presProgressivize = false;
+ targetDoc.presProgressivize = false;
+ // docs.forEach((doc, index) => {
+ // doc.appearFrame = 0;
+ // });
+ targetDoc.currentFrame = 0;
+ targetDoc.lastFrame = 0;
+ }
+ }
+
+ @action
+ checkMovementLists = (doc: Doc, xlist: any, ylist: any) => {
+ const x: List<number> = xlist;
+ const y: List<number> = ylist;
+ const tags: JSX.Element[] = [];
+ let pathPoints = ""; //List of all of the paths that need to be added
+ // console.log(x);
+ // console.log(x.length);
+ // console.log(x[0]);
+ for (let i = 0; i < x.length - 1; i++) {
+ if (y[i] || x[i]) {
+ if (i === 0) pathPoints = (x[i] - 11) + "," + (y[i] + 33);
+ else pathPoints = pathPoints + " " + (x[i] - 11) + "," + (y[i] + 33);
+ tags.push(<div className="progressivizeMove-frame" style={{ position: 'absolute', top: y[i], left: x[i] }}>{i}</div>);
+ }
+ }
+ tags.push(<svg style={{ overflow: 'visible', position: 'absolute' }}><polyline
+ points={pathPoints}
+ style={{
+ position: 'absolute',
+ opacity: 1,
+ stroke: "#000000",
+ strokeWidth: 2,
+ strokeDasharray: '10 5',
+ }}
+ fill="none"
+ /></svg>);
+ return tags;
+ }
+
+ @observable
+ toggleDisplayMovement = (doc: Doc) => {
+ if (doc.displayMovement) doc.displayMovement = false;
+ else doc.displayMovement = true;
+ }
+
+ 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;
+ 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
+ onPointerBR = (e: React.PointerEvent): void => {
+ e.stopPropagation();
+ e.preventDefault();
+ this._isDraggingBR = 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
+ 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();
+ e.preventDefault();
+ this._isDraggingTL = false;
+ this._isDraggingTR = false;
+ this._isDraggingBL = false;
+ this._isDraggingBR = false;
+ this._isDragging = false;
+ document.removeEventListener("pointermove", this.onPointerMove);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ }
+
+ //Adjusts the value in NodeStore
+ onPointerMove = (e: PointerEvent): void => {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const tagDocView = DocumentManager.Instance.getDocumentView(targetDoc);
+ e.stopPropagation();
+ e.preventDefault();
+ const doc = document.getElementById('resizable');
+ if (doc && tagDocView) {
+ console.log(tagDocView.props.ContentScaling());
+ const transform = (tagDocView.props.ScreenToLocalTransform().scale(tagDocView.props.ContentScaling())).inverse();
+ console.log(transform);
+ const scale = tagDocView.childScaling();
+ console.log(scale);
+ let height = doc.offsetHeight;
+ let width = doc.offsetWidth;
+ let top = doc.offsetTop;
+ let left = doc.offsetLeft;
+ // const newHeightB = height += (e.movementY * NumCast(targetDoc._viewScale));
+ // const newHeightT = height -= (e.movementY * NumCast(targetDoc._viewScale));
+ // const newWidthR = width += (e.movementX * NumCast(targetDoc._viewScale));
+ // const newWidthL = width -= (e.movementX * NumCast(targetDoc._viewScale));
+ // const newLeft = left += (e.movementX * NumCast(targetDoc._viewScale));
+ // const newTop = top += (e.movementY * NumCast(targetDoc._viewScale));
+ // 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';
+ // }
+ //Bottom right
+ if (this._isDraggingBR) {
+ const newHeight = height += (e.movementY * tagDocView.props.ContentScaling());
+ doc.style.height = newHeight + 'px';
+ const newWidth = width += (e.movementX * tagDocView.props.ContentScaling());
+ doc.style.width = newWidth + 'px';
+ // Bottom left
+ } else if (this._isDraggingBL) {
+ const newHeight = height += (e.movementY * scale);
+ doc.style.height = newHeight + 'px';
+ const newWidth = width -= (e.movementX * scale);
+ doc.style.width = newWidth + 'px';
+ const newLeft = left += (e.movementX * scale);
+ doc.style.left = newLeft + 'px';
+ // Top right
+ } else if (this._isDraggingTR) {
+ const newWidth = width += (e.movementX * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.width = newWidth + 'px';
+ const newHeight = height -= (e.movementY * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.height = newHeight + 'px';
+ const newTop = top += (e.movementY * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.top = newTop + 'px';
+ // Top left
+ } else if (this._isDraggingTL) {
+ const newWidth = width -= (e.movementX * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.width = newWidth + 'px';
+ const newHeight = height -= (e.movementY * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.height = newHeight + 'px';
+ const newTop = top += (e.movementY * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.top = newTop + 'px';
+ const newLeft = left += (e.movementX * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.left = newLeft + 'px';
+ } else if (this._isDragging) {
+ const newTop = top += (e.movementY * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.top = newTop + 'px';
+ const newLeft = left += (e.movementX * tagDocView.props.ScreenToLocalTransform().Scale);
+ doc.style.left = newLeft + 'px';
+ }
+ this.updateList(targetDoc, targetDoc["viewfinder-width-indexed"], width);
+ this.updateList(targetDoc, targetDoc["viewfinder-height-indexed"], height);
+ this.updateList(targetDoc, targetDoc["viewfinder-top-indexed"], top);
+ this.updateList(targetDoc, targetDoc["viewfinder-left-indexed"], left);
+ }
+ }
+
+ @action
+ checkList = (doc: Doc, list: any): number => {
+ const x: List<number> = list;
+ if (x && x.length >= NumCast(doc.currentFrame) + 1) {
+ return x[NumCast(doc.currentFrame)];
+ } else {
+ x.length = NumCast(doc.currentFrame) + 1;
+ x[NumCast(doc.currentFrame)] = x[NumCast(doc.currentFrame) - 1];
+ return x[NumCast(doc.currentFrame)];
+ }
+
+ }
+
+ @action
+ updateList = (doc: Doc, list: any, val: number) => {
+ const x: List<number> = list;
+ if (x && x.length >= NumCast(doc.currentFrame) + 1) {
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ } else {
+ x.length = NumCast(doc.currentFrame) + 1;
+ x[NumCast(doc.currentFrame)] = val;
+ list = x;
+ }
+ }
+
+ // scale: NumCast(targetDoc._viewScale),
+ @computed get zoomProgressivizeContainer() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ if (targetDoc.editZoomProgressivize) {
+ return (
+ <>
+ <div id="resizable" className="resizable" onPointerDown={this.onPointerMid} style={{ width: this.checkList(targetDoc, targetDoc["viewfinder-width-indexed"]), height: this.checkList(targetDoc, targetDoc["viewfinder-height-indexed"]), top: this.checkList(targetDoc, targetDoc["viewfinder-top-indexed"]), left: this.checkList(targetDoc, targetDoc["viewfinder-left-indexed"]), position: 'absolute' }}>
+ <div className='resizers'>
+ <div id="resizer-tl" className='resizer top-left' onPointerDown={this.onPointerTL}></div>
+ <div id="resizer-tr" className='resizer top-right' onPointerDown={this.onPointerTR}></div>
+ <div id="resizer-bl" className='resizer bottom-left' onPointerDown={this.onPointerBL}></div>
+ <div id="resizer-br" className='resizer bottom-right' onPointerDown={this.onPointerBR}></div>
+ </div>
+ </div>
+ </>
+ );
+ } else return null;
+ }
+
+ @computed get progressivizeChildDocs() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+ const tags: JSX.Element[] = [];
+ docs.forEach((doc, index) => {
+ if (doc["x-indexed"] && doc["y-indexed"]) {
+ tags.push(<div style={{ position: 'absolute', display: doc.displayMovement ? "block" : "none" }}>{this.checkMovementLists(doc, doc["x-indexed"], doc["y-indexed"])}</div>);
+ }
+ tags.push(
+ <div className="progressivizeButton" onPointerLeave={() => { if (NumCast(targetDoc.currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0; }} onPointerOver={() => { if (NumCast(targetDoc.currentFrame) < NumCast(doc.appearFrame)) doc.opacity = 0.5; }} onClick={e => { this.toggleDisplayMovement(doc); e.stopPropagation(); }} style={{ backgroundColor: doc.displayMovement ? "#aedff8" : "#c8c8c8", top: NumCast(doc.y), left: NumCast(doc.x) }}>
+ <div className="progressivizeButton-prev"><FontAwesomeIcon icon={"caret-left"} size={"lg"} onClick={e => { e.stopPropagation(); this.prevAppearFrame(doc, index); }} /></div>
+ <div className="progressivizeButton-frame">{doc.appearFrame}</div>
+ <div className="progressivizeButton-next"><FontAwesomeIcon icon={"caret-right"} size={"lg"} onClick={e => { e.stopPropagation(); this.nextAppearFrame(doc, index); }} /></div>
+ </div>);
+ });
+ return tags;
+ }
+
+ @undoBatch
+ @action
+ nextAppearFrame = (doc: Doc, i: number): void => {
+ console.log("next");
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const appearFrame = Cast(doc.appearFrame, "number", null);
+ if (appearFrame === undefined) {
+ doc.appearFrame = 0;
+ }
+ doc.appearFrame = appearFrame + 1;
+ const olist = new List<number>(numberRange(NumCast(targetDoc.lastFrame)).map(t => targetDoc.presProgressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
+ doc["opacity-indexed"] = olist;
+ console.log(doc.appearFrame);
+ }
+
+ @undoBatch
+ @action
+ prevAppearFrame = (doc: Doc, i: number): void => {
+ console.log("prev");
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
+ const appearFrame = Cast(doc.appearFrame, "number", null);
+ if (appearFrame === undefined) {
+ doc.appearFrame = 0;
+ }
+ doc.appearFrame = Math.max(0, appearFrame - 1);
+ const olist = new List<number>(numberRange(NumCast(targetDoc.lastFrame)).map(t => targetDoc.presProgressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
+ doc["opacity-indexed"] = olist;
+ console.log(doc.appearFrame);
+ }
+
+ @computed get moreInfoDropdown() {
+ return (<div></div>);
+ }
+
+ @computed
+ get toolbarWidth(): number {
+ const width = this.props.PanelWidth();
+ return width;
+ }
+
+
+ @computed get toolbar() {
+ const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
+ if (activeItem) {
+ return (
+ <>
+ <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={this.toggleNewDocument}><FontAwesomeIcon icon={"plus"} />
+ <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
+ </div></Tooltip>
+ <div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}><div className={`toolbar-button ${this.pathBoolean ? "active" : ""}`}>
+ <FontAwesomeIcon icon={"exchange-alt"} onClick={this.viewPaths} />
+ </div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{this.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
+ <div className={`toolbar-button ${this.expandBoolean ? "active" : ""}`} onClick={() => { this.toggleExpand(); this.childDocs.forEach((doc, ind) => { if (this.expandBoolean) doc.presExpandInlineButton = true; else doc.presExpandInlineButton = false; }); }}>
+ <FontAwesomeIcon icon={"eye"} />
+ </div>
+ </Tooltip>
+ {/* <div className="toolbar-button"><FontAwesomeIcon title={"Portal"} icon={"eye"} onClick={this.toolbarTest} /></div> */}
+ <div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{"Transitions"}</div></>}><div className={`toolbar-button ${this.transitionTools ? "active" : ""}`} onClick={this.toggleTransitionTools}>
+ <FontAwesomeIcon icon={"rocket"} />
+ <div style={{ display: this.props.PanelWidth() > 430 ? "block" : "none" }} className="toolbar-buttonText">&nbsp; Transitions</div>
+ <FontAwesomeIcon className={`dropdown ${this.transitionTools ? "active" : ""}`} icon={"angle-down"} />
+ </div></Tooltip>
+ <div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{"Progressivize"}</div></>}><div className={`toolbar-button ${this.progressivizeTools ? "active" : ""}`} onClick={this.toggleProgressivize}>
+ <FontAwesomeIcon icon={"tasks"} />
+ <div style={{ display: this.props.PanelWidth() > 430 ? "block" : "none" }} className="toolbar-buttonText">&nbsp; Progressivize</div>
+ <FontAwesomeIcon className={`dropdown ${this.progressivizeTools ? "active" : ""}`} icon={"angle-down"} />
+ </div></Tooltip>
+ <div className="toolbar-divider" />
+ <div className="toolbar-button" style={{ position: 'absolute', right: 23, transform: 'rotate(45deg)', fontSize: 16 }}>
+ <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"thumbtack"} />
+ </div>
+ <div className={`toolbar-button ${this.moreInfoTools ? "active" : ""}`} onClick={this.toggleMoreInfo}>
+ <div className={`toolbar-moreInfo ${this.moreInfoTools ? "active" : ""}`}>
+ <div className="toolbar-moreInfoBall" />
+ <div className="toolbar-moreInfoBall" />
+ <div className="toolbar-moreInfoBall" />
+ </div>
+ </div>
+ </>
+ );
+ } else {
+ return (
+ <>
+ <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={this.toggleNewDocument}><FontAwesomeIcon icon={"plus"} />
+ <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
+ </div></Tooltip>
+ <div className="toolbar-button" style={{ position: 'absolute', right: 23, transform: 'rotate(45deg)', fontSize: 16 }}>
+ <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"thumbtack"} />
+ </div>
+ <div className={`toolbar-button ${this.moreInfoTools ? "active" : ""}`} onClick={this.toggleMoreInfo}>
+ <div className={`toolbar-moreInfo ${this.moreInfoTools ? "active" : ""}`}>
+ <div className="toolbar-moreInfoBall" />
+ <div className="toolbar-moreInfoBall" />
+ <div className="toolbar-moreInfoBall" />
+ </div>
+ </div>
+ </>
+ );
+ }
+ }
+
+ render() {
+ this.childDocs.slice(); // needed to insure that the childDocs are loaded for looking up fields
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
- return <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
+ return <div onPointerOver={this.onPointerOver} onPointerLeave={this.onPointerLeave} className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
<div className="presBox-buttons" style={{ display: this.rootDoc._chromeStatus === "disabled" ? "none" : undefined }}>
<select className="presBox-viewPicker"
onPointerDown={e => e.stopPropagation()}
onChange={this.viewChanged}
value={mode}>
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Invalid}>Min</option>
+ {/* <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Invalid}>Min</option> */}
<option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Time}>Time</option>
+ {/* <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Time}>Time</option> */}
<option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel}>Slides</option>
</select>
- <div className="presBox-button" title="Back" style={{ gridColumn: 2 }} onClick={this.back}>
- <FontAwesomeIcon icon={"arrow-left"} />
- </div>
- <div className="presBox-button" title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} style={{ gridColumn: 3 }} onClick={this.startOrResetPres}>
- <FontAwesomeIcon icon={this.layoutDoc.presStatus ? "stop" : "play"} />
- </div>
- <div className="presBox-button" title="Next" style={{ gridColumn: 4 }} onClick={this.next}>
- <FontAwesomeIcon icon={"arrow-right"} />
+ <div className="presBox-presentPanel">
+ <span className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} style={{ minWidth: 60, gridColumn: 2 }}>
+ <div className="presBox-button-left" onClick={() => this.startOrResetPres(0)}>
+ <FontAwesomeIcon icon={"clock"} /> &nbsp;
+ <FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} />
+ </div>
+ <div className={`presBox-button-right ${this.playTools ? "active" : ""}`} onClick={e => { e.stopPropagation; this.togglePlay(); }}>
+ <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.playTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
+ {this.playDropdown}
+ </div>
+ </span>
+ <span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`} title="Present">
+ <div className="presBox-button-left" onClick={() => this.layoutDoc.presStatus = "manual"}><FontAwesomeIcon icon={"play-circle"} /> &nbsp; Present </div>
+ <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`} onClick={e => { e.stopPropagation; this.togglePresent(); }}>
+ <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={"angle-down"} />
+ {this.presentDropdown}
+ </div>
+ </span>
+ <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Back" onClick={this.back}>
+ <FontAwesomeIcon icon={"arrow-left"} />
+ </div>
+ <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Next" onClick={this.next}>
+ <FontAwesomeIcon icon={"arrow-right"} />
+ </div>
+ <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "edit" : ""}`} title="Next" onClick={() => this.layoutDoc.presStatus = "edit"}>
+ <FontAwesomeIcon icon={"times"} />
+ </div>
</div>
</div>
+ <div id="toolbarContainer" className={`presBox-toolbar ${this.layoutDoc.presStatus === "edit" ? "active" : ""}`}> {this.toolbar} </div>
+ {this.newDocumentDropdown}
+ {this.moreInfoDropdown}
+ {this.transitionDropdown}
+ {this.progressivizeDropdown}
<div className="presBox-listCont" >
{mode !== CollectionViewType.Invalid ?
<CollectionView {...this.props}
@@ -333,10 +1679,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
moveDocument={returnFalse}
childOpacity={returnOne}
childLayoutTemplate={this.childLayoutTemplate}
- filterAddDocument={this.addDocumentFilter}
+ filterAddDocument={returnFalse}
removeDocument={returnFalse}
dontRegisterView={true}
focus={this.selectElement}
+ presMultiSelect={this.multiSelect}
ScreenToLocalTransform={this.getTransform} />
: (null)
}
@@ -346,9 +1693,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, data: Doc) {
if (field === 'indexInPres') return DocListCast(container[StrCast(container.presentationFieldKey)]).indexOf(data);
- if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 50 : 46;
+ if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 30 : 26;
if (field === 'presStatus') return container.presStatus;
if (field === '_itemIndex') return container._itemIndex;
if (field === 'presBox') return container;
return undefined;
});
+
+
+
+ // console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus);
+ // const presOrderedDocs = DocListCast(activeItem.presOrderedDocs);
+ // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) {
+ // this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice());
+ // }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index c792df882..d1010de48 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -9,8 +9,8 @@ import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { InkTool } from "../../../fields/InkField";
import { List } from "../../../fields/List";
-import { createSchema, makeInterface } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
+import { createSchema, makeInterface, listSpec } from "../../../fields/Schema";
+import { ScriptField, ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast } from "../../../fields/Types";
import { PdfField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
@@ -344,6 +344,11 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
@action
+ scrollToFrame = (duration: number, top: number) => {
+ this._mainCont.current && smoothScroll(duration, this._mainCont.current, top);
+ }
+
+ @action
scrollToAnnotation = (scrollToAnnotation: Doc) => {
if (scrollToAnnotation) {
const offset = this.visibleHeight() / 2;
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index dbe6b0d4f..c87a1583a 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -1,11 +1,13 @@
.presElementBox-item {
- display: inline-block;
- background-color: #eeeeee;
+ display: grid;
+ grid-template-columns: max-content max-content max-content;
+ background-color: #d5dce2;
+ box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.25);
+ position: relative;
pointer-events: all;
width: 100%;
height: 100%;
- outline-color: maroon;
- outline-style: dashed;
+ font-weight: 400;
border-radius: 6px;
-webkit-touch-callout: none;
-webkit-user-select: none;
@@ -13,10 +15,19 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
- transition: all .1s;
+ transition: all .3s;
padding: 0px;
padding-bottom: 3px;
+ .presElementBox-highlight {
+ position: absolute;
+ transform: translate(-100px, -6px);
+ z-index: -1;
+ width: calc(100% + 200px);
+ height: calc(100% + 12px);
+ background-color: #AEDDF8;
+ }
+
.documentView-node {
position: absolute;
z-index: 1;
@@ -38,57 +49,74 @@
}
.presElementBox-active {
- background: gray;
color: black;
border-radius: 6px;
- box-shadow: black 2px 2px 5px;
+ border: solid 2px #5B9FDD;
}
-.presElementBox-closeIcon {
- border-radius: 20px;
- transform: scale(0.7);
- position: absolute;
- right: 0;
- top: 0;
- padding: 8px;
-}
-
-
.presElementBox-buttons {
- display: flow-root;
- position: relative;
+ display: grid;
+ grid-template-rows: 15px;
+ top: 15px;
+ left: -20;
+ position: absolute;
width: 100%;
height: auto;
.presElementBox-interaction {
- color: gray;
- float: left;
- padding: 0px;
- width: 20px;
- height: 20px;
+ display: none;
}
.presElementBox-interaction-selected {
- color: white;
+ color: grey;
+ background-color: rgba(0, 0, 0, 0);
float: left;
padding: 0px;
width: 20px;
height: 20px;
- border: solid 1px darkgray;
}
}
-.presElementBox-name {
+.presElementBox-number {
font-size: 12px;
+ font-weight: 700;
+ left: -15;
position: absolute;
display: inline-block;
- width: calc(100% - 45px);
+ overflow: hidden;
+}
+
+.presElementBox-name {
+ align-self: center;
+ font-size: 13px;
+ font-family: Roboto;
+ font-weight: 500;
+ position: relative;
+ top: 1px;
+ padding-left: 10px;
+ padding-right: 10px;
+ letter-spacing: normal;
+ max-width: max-content;
text-overflow: ellipsis;
overflow: hidden;
white-space: pre;
}
+.presElementBox-time {
+ align-self: center;
+ position: relative;
+ top: 2px;
+ padding-right: 10px;
+ font-size: 10;
+ font-weight: 300;
+ font-family: Roboto;
+ /* font-style: italic; */
+ letter-spacing: normal;
+ /* left: 10px; */
+}
+
.presElementBox-embedded {
+ grid-column: 1/8;
position: relative;
display: flex;
width: auto;
@@ -100,51 +128,56 @@
width: 100%;
height: 100%;
position: absolute;
- left: 0;
+ border-radius: 3px;
top: 0;
- background: transparent;
- z-index: 2;
+ left: 0;
+ z-index: 1;
+ overflow: hidden;
}
-@media only screen and (max-device-width: 480px) {
- .presElementBox-buttons {
- display: inline-flex;
- position: absolute;
- top: 0;
- right: 0;
- z-index: 3;
- width: 50%;
-
- .presElementBox-interaction {
- width: 50;
- height: 50;
- }
-
- .presElementBox-interaction-selected {
- width: 50;
- height: 50;
- }
- }
-
- .presElementBox-item {
- display: inline-flex;
- overflow: hidden;
- }
-
- .presElementBox-closeIcon {
- transform: scale(1.5);
- right: 10;
- top: 10;
- }
+.presElementBox-closeIcon {
+ position: absolute;
+ border-radius: 100%;
+ z-index: 300;
+ right: 3px;
+ top: 3px;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ font-size: 75%;
+ background-color: black;
+ color: white;
+ justify-content: center;
+ align-items: center;
+}
- .presElementBox-name {
- font-size: 30px;
- top: 10px;
- z-index: 3;
- width: 50%;
- }
+.presElementBox-expand {
+ position: absolute;
+ border-radius: 100%;
+ z-index: 300;
+ right: 26px;
+ top: 3px;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ font-size: 75%;
+ background-color: black;
+ color: white;
+ justify-content: center;
+ align-items: center;
+}
- .presElementBox-embedded {
- transform: translate(0, 90px) scale(1.5);
- }
+.presElementBox-expand-selected {
+ position: absolute;
+ border-radius: 100%;
+ right: 3px;
+ bottom: 3px;
+ width: 20px;
+ height: 20px;
+ z-index: 200;
+ display: flex;
+ background-color: black;
+ color: white;
+ justify-content: center;
+ align-items: center;
} \ No newline at end of file
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 4c0972736..4d1195808 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -5,7 +5,7 @@ import { Doc, DataSym, DocListCast } from "../../../fields/Doc";
import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from "../../../fields/FieldSymbols";
import { createSchema, makeInterface, listSpec } from '../../../fields/Schema';
-import { Cast, NumCast, BoolCast, ScriptCast } from "../../../fields/Types";
+import { Cast, NumCast, BoolCast, ScriptCast, StrCast } from "../../../fields/Types";
import { emptyFunction, emptyPath, returnFalse, returnTrue, returnOne, returnZero, numberRange } from "../../../Utils";
import { Transform } from "../../util/Transform";
import { CollectionViewType } from '../collections/CollectionView';
@@ -15,7 +15,9 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView';
import "./PresElementBox.scss";
import React = require("react");
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
+import { PresBox } from "../nodes/PresBox";
import { DocumentType } from "../../documents/DocumentTypes";
+import { Tooltip } from "@material-ui/core";
export const presSchema = createSchema({
presentationTargetDoc: Doc,
@@ -38,19 +40,18 @@ const PresDocument = makeInterface(presSchema, documentSchema);
@observer
export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDocument>(PresDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresElementBox, fieldKey); }
-
_heightDisposer: IReactionDisposer | undefined;
// these fields are conditionally computed fields on the layout document that take this document as a parameter
@computed get indexInPres() { return Number(this.lookupField("indexInPres")); } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
- @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation elemnt template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
- @computed get presStatus() { return BoolCast(this.lookupField("presStatus")); }
+ @computed get collapsedHeight() { return Number(this.lookupField("presCollapsedHeight")); } // the collapsed height changes depending on the state of the presBox. We could store this on the presentation element template if it's used by only one presentation - but if it's shared by multiple, then this value must be looked up
+ @computed get presStatus() { return StrCast(this.lookupField("presStatus")); }
@computed get itemIndex() { return NumCast(this.lookupField("_itemIndex")); }
@computed get presBox() { return Cast(this.lookupField("presBox"), Doc, null); }
@computed get targetDoc() { return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc; }
componentDidMount() {
this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
- params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 200 : 0), { fireImmediately: true });
+ params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
}
componentWillUnmount() {
this._heightDisposer?.();
@@ -69,7 +70,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
this.targetDoc.opacity = 1;
}
} else {
- if (this.presStatus && this.indexInPres > this.itemIndex && this.targetDoc) {
+ if (this.presStatus !== "edit" && this.indexInPres > this.itemIndex && this.targetDoc) {
this.targetDoc.opacity = 0;
}
}
@@ -90,7 +91,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
}
} else {
if (this.rootDoc.presFadeButton) this.rootDoc.presFadeButton = false;
- if (this.presStatus && this.indexInPres < this.itemIndex && this.targetDoc) {
+ if (this.presStatus !== "edit" && this.indexInPres < this.itemIndex && this.targetDoc) {
this.targetDoc.opacity = 0;
}
}
@@ -125,7 +126,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
}
} else {
this.rootDoc.presHideAfterButton = false;
- if (this.presStatus && (this.indexInPres < this.itemIndex) && this.targetDoc) {
+ if (this.presStatus !== "edit" && (this.indexInPres < this.itemIndex) && this.targetDoc) {
this.targetDoc.opacity = 0.5;
}
}
@@ -166,10 +167,17 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
*/
ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
- embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
+ @action
+ presExpandDocumentClick = () => {
+ this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
+ }
+
+ embedHeight = () => 100;
embedWidth = () => this.props.PanelWidth() - 20;
+ // embedHeight = () => Math.min(this.props.PanelWidth() - 20, this.props.PanelHeight() - this.collapsedHeight);
+ // embedWidth = () => this.props.PanelWidth() - 20;
/**
- * The function that is responsible for rendering the a preview or not for this
+ * The function that is responsible for rendering a preview or not for this
* presentation element.
*/
@computed get renderEmbeddedInline() {
@@ -178,6 +186,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
<ContentFittingDocumentView
Document={this.targetDoc}
DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
+ dragDivName={"collectionFreeFormDocumentView-container"}
LibraryPath={emptyPath}
fitToBox={true}
backgroundColor={this.props.backgroundColor}
@@ -207,6 +216,20 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
</div>;
}
+ @computed get duration() {
+ let durationInS: number;
+ if (this.targetDoc.presDuration) durationInS = NumCast(this.targetDoc.presDuration) / 1000;
+ else durationInS = 2;
+ return "V: " + durationInS + "s";
+ }
+
+ @computed get transition() {
+ let transitionInS: number;
+ if (this.targetDoc.presTransition) transitionInS = NumCast(this.targetDoc.presTransition) / 1000;
+ else transitionInS = 0.5;
+ return "M: " + transitionInS + "s";
+ }
+
render() {
const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
const className = "presElementBox-item" + (this.itemIndex === this.indexInPres ? " presElementBox-active" : "");
@@ -214,29 +237,55 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : (
<div className={className} key={this.props.Document[Id] + this.indexInPres}
style={{ outlineWidth: Doc.IsBrushed(this.targetDoc) ? `1px` : "0px", }}
- onClick={e => { this.props.focus(this.rootDoc); e.stopPropagation(); }}>
+ onClick={e => {
+ if (e.ctrlKey || e.metaKey) {
+ PresBox.Instance.multiSelect(this.rootDoc);
+ console.log("cmmd click");
+ } else if (e.shiftKey) {
+ PresBox.Instance.shiftSelect(this.rootDoc);
+ } else {
+ this.props.focus(this.rootDoc); e.stopPropagation();
+ console.log("normal click");
+ }
+ }}
+ onPointerDown={e => {
+ this.props.dropAction;
+ e.stopPropagation();
+ }}
+ >
{treecontainer ? (null) : <>
- <strong className="presElementBox-name">
- {`${this.indexInPres + 1}. ${this.targetDoc?.title}`}
- </strong>
- <button className="presElementBox-closeIcon" onPointerDown={e => e.stopPropagation()} onClick={e => {
- this.props.removeDocument?.(this.rootDoc);
- e.stopPropagation();
- }}>X</button>
- <br />
+ <div className="presElementBox-number">
+ {`${this.indexInPres + 1}.`}
+ </div>
+ <div className="presElementBox-name">
+ {`${this.targetDoc?.title}`}
+ </div>
+ <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.transition}</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Duration of visibility"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.duration}</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Remove from presentation"}</div></>}><div
+ className="presElementBox-closeIcon"
+ // onPointerDown={e => e.stopPropagation()}
+ onClick={e => {
+ this.props.removeDocument?.(this.rootDoc);
+ e.stopPropagation();
+ }}>
+ <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
+ </div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"presElementBox-expand" + (this.rootDoc.presExpandInlineButton ? "-selected" : "")} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
+ <FontAwesomeIcon icon={(this.rootDoc.presExpandInlineButton ? "angle-up" : "angle-down")} onPointerDown={e => e.stopPropagation()} />
+ </div></Tooltip>
</>}
- <div className="presElementBox-buttons">
- <button title="Zoom" className={pbi + (this.rootDoc.presZoomButton ? "-selected" : "")} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} onPointerDown={e => e.stopPropagation()} /></button>
+ <div className="presElementBox-highlight" style={{ display: PresBox.Instance._selectedArray.includes(this.rootDoc) ? "block" : "none" }} />
+ <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-plus"} 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="Fade After" className={pbi + (this.rootDoc.presFadeButton ? "-selected" : "")} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={"file-download"} 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="Group With Up" className={pbi + (this.rootDoc.presGroupButton ? "-selected" : "")} onClick={e => { e.stopPropagation(); this.rootDoc.presGroupButton = !this.rootDoc.presGroupButton; }}><FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Progressivize" className={pbi + (this.rootDoc.pres ? "-selected" : "")} onClick={this.progressivize}><FontAwesomeIcon icon={"tasks"} onPointerDown={e => e.stopPropagation()} /></button>
- <button title="Expand Inline" className={pbi + (this.rootDoc.presExpandInlineButton ? "-selected" : "")} onClick={e => { e.stopPropagation(); this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton; }}><FontAwesomeIcon icon={"arrow-down"} 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>
);
}
-} \ No newline at end of file
+}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 267defa4b..d2237380e 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -623,7 +623,7 @@ export namespace Doc {
var zip = new JSZip();
- zip.file("doc.json", docString);
+ zip.file(doc.title + ".json", docString);
// // Generate a directory within the Zip file structure
// var img = zip.folder("images");
@@ -635,7 +635,7 @@ export namespace Doc {
zip.generateAsync({ type: "blob" })
.then((content: any) => {
// Force down of the Zip file
- saveAs(content, "download.zip");
+ saveAs(content, doc.title + ".zip"); // glr: Possibly change the name of the document to match the title?
});
}
//
diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts
index 452882e09..24b70057a 100644
--- a/src/typings/index.d.ts
+++ b/src/typings/index.d.ts
@@ -6,8 +6,11 @@ declare module 'cors';
declare module 'webrtc-adapter';
declare module 'bezier-curve';
-declare module 'fit-curve'
-
+declare module 'fit-curve';
+declare module 'reveal';
+declare module 'react-reveal';
+declare module 'react-reveal/makeCarousel';
+declare module 'react-resizable-rotatable-draggable';
declare module '@react-pdf/renderer' {
import * as React from 'react';