+
{this.editableTitle}
@@ -1029,7 +1029,7 @@ export class PropertiesView extends React.Component
{
{PresBox.Instance.progressivizeDropdown}
: null}
} */}
- {/* {!selectedItem || (!scrollable && !pannable) ? (null) :
+ {!selectedItem ? (null) :
{ this.openSlideOptions = !this.openSlideOptions; })}
style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
@@ -1041,7 +1041,7 @@ export class PropertiesView extends React.Component
{
{this.openSlideOptions ?
{PresBox.Instance.optionsDropdown}
: null}
- } */}
+
}
{/*
{ this.openAddSlide = !this.openAddSlide; })}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 7f8f57088..4c0073dcc 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -442,8 +442,8 @@ export class TabDocView extends React.Component {
let docColor = StrCast(doc?._backgroundColor, StrCast(doc?.backgroundColor));
if (!docColor) {
switch (doc?.type) {
- case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "dimgrey" : ""; break;
- case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "black"; break;
+ case DocumentType.PRESELEMENT: docColor = TabDocView.darkScheme ? "" : ""; break;
+ case DocumentType.PRES: docColor = TabDocView.darkScheme ? "#3e3e3e" : "white"; break;
case DocumentType.FONTICON: docColor = "black"; break;
case DocumentType.RTF: docColor = TabDocView.darkScheme ? "#2d2d2d" : "#f1efeb";
case DocumentType.LABEL:
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4f6c5cebe..1bdba7f9e 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -27,6 +27,8 @@ import Waveform from "react-audio-waveform";
import axios from "axios";
import { SnappingManager } from "../../util/SnappingManager";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { LinkDocPreview } from "./LinkDocPreview";
+import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
declare class MediaRecorder {
// whatever MediaRecorder has
@@ -49,6 +51,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.layoutDoc.scrollToLinkID,
+ this._disposers.linkPlay = reaction(() => this.layoutDoc.scrollToLinkID,
scrollLinkId => {
if (scrollLinkId) {
DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
@@ -130,7 +134,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent SelectionManager.SelectedDocuments(),
+ this._disposers.reaction = reaction(() => SelectionManager.SelectedDocuments(),
selected => {
const sel = selected.length ? selected[0].props.Document : undefined;
let link;
@@ -145,7 +149,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+ this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
+
+ this._disposers._audioStart = reaction(
+ () => this.Document._audioStart,
+ (audioStart) => {
+ if (audioStart !== undefined) {
+ if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+ const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play
+ const startTime: number = NumCast(this.Document._audioStart);
+ setTimeout(() => this._audioRef.current && this.playFrom(startTime), delay);
+ setTimeout(() => { this.Document._currentTimecode = startTime; this.Document._audioStart = undefined; }, 10 + delay);
+ }
+ }
+ },
+ { fireImmediately: true }
+ );
}
playLink = (doc: Doc) => {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index fa58a67b6..dd6e368e8 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -117,7 +117,7 @@ export class PresBox extends ViewBoxBaseComponent
if (Doc.UserDoc().activePresentation = this.rootDoc) runInAction(() => 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", type: DocumentType.PRESELEMENT, backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data"
+ title: "pres element template", type: DocumentType.PRESELEMENT, _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
@@ -191,7 +191,9 @@ export class PresBox extends ViewBoxBaseComponent
// 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
nextAudioVideo = (targetDoc: Doc, activeItem: Doc) => {
- if (targetDoc.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeItem.presStartTime));
+ if (targetDoc.type === DocumentType.AUDIO) {
+ targetDoc._audioStart = NumCast(activeItem.presStartTime);
+ }
// if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
activeItem.playNow = false;
}
@@ -201,13 +203,12 @@ export class PresBox extends ViewBoxBaseComponent
const nextSelected = this.itemIndex + 1;
this.gotoDocument(nextSelected);
- // const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
+ const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
// If next slide is audio / video 'Play automatically' then the next slide should be played
- // if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
- // console.log('play next automatically');
- // if (targetNext.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeNext.presStartTime));
- // // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
- // } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
+ if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
+ if (targetNext.type === DocumentType.AUDIO) targetNext._audioStart = NumCast(activeNext.presStartTime);
+ // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
+ } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
}
// Called when the user activates 'next' - to move to the next part of the pres. trail
@@ -229,11 +230,10 @@ export class PresBox extends ViewBoxBaseComponent
} else if (this.childDocs[this.itemIndex + 1] === undefined && this.layoutDoc.presLoop) {
// Case 4: Last slide and presLoop is toggled ON
this.gotoDocument(0);
+ } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
+ // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
+ this.nextAudioVideo(targetDoc, activeItem);
}
- // else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== PresStatus.Autoplay) {
- // // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
- // this.nextAudioVideo(targetDoc, activeItem);
- // }
}
// Called when the user activates 'back' - to move to the previous part of the pres. trail
@@ -1927,7 +1927,7 @@ export class PresBox extends ViewBoxBaseComponent
*/}
{"View paths"}
>}>
- 1 ? 1 : 0.3, color: this._pathBoolean ? PresColor.DarkBlue : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined}>
+
1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? PresColor.DarkBlue : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 && this.layoutDoc.presCollection ? this.viewPaths : undefined}>
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 8d4bd4b8b..49049b805 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -305,10 +305,12 @@ export class PresElementBox extends ViewBoxBaseComponent
{miniView ?
+ // when width is LESS than 110 px
{`${this.indexInPres + 1}.`}
:
+ // when width is MORE than 110 px
{`${this.indexInPres + 1}.`}
}
--
cgit v1.2.3-70-g09d2
From c4016e01b48367f45bed0ba2041e955c8c009464 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sat, 28 Nov 2020 06:05:44 +0800
Subject: pres trail colors + group with up
---
src/Utils.ts | 43 ++++++++++++++++++++++
src/client/views/collections/TabDocView.tsx | 1 +
.../collections/collectionFreeForm/MarqueeView.tsx | 1 +
src/client/views/nodes/PresBox.tsx | 2 +-
.../views/presentationview/PresElementBox.scss | 10 +++--
.../views/presentationview/PresElementBox.tsx | 29 ++++++++++-----
6 files changed, 73 insertions(+), 13 deletions(-)
diff --git a/src/Utils.ts b/src/Utils.ts
index daacca51d..1a00c0bfb 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -549,6 +549,49 @@ export function simulateMouseClick(element: Element | null | undefined, x: numbe
}));
}
+export function lightOrDark(color: any) {
+
+ // Variables for red, green, blue values
+ var r, g, b, hsp;
+
+ // Check the format of the color, HEX or RGB?
+ if (color.match(/^rgb/)) {
+
+ // If RGB --> store the red, green, blue values in separate variables
+ color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
+
+ r = color[1];
+ g = color[2];
+ b = color[3];
+ }
+ else {
+
+ // If hex --> Convert it to RGB: http://gist.github.com/983661
+ color = +("0x" + color.slice(1).replace(
+ color.length < 5 && /./g, '$&$&'));
+
+ r = color >> 16;
+ g = color >> 8 & 255;
+ b = color & 255;
+ }
+
+ // HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
+ hsp = Math.sqrt(
+ 0.299 * (r * r) +
+ 0.587 * (g * g) +
+ 0.114 * (b * b)
+ );
+
+ // Using the HSP value, determine whether the color is light or dark
+ if (hsp > 127.5) {
+ return 'light';
+ }
+ else {
+
+ return 'dark';
+ }
+}
+
export function setupMoveUpEvents(
target: object,
e: React.PointerEvent,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 4c0073dcc..45fab480c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -166,6 +166,7 @@ export class TabDocView extends React.Component {
pinDoc.presentationTargetDoc = doc;
pinDoc.title = doc.title + " - Slide";
pinDoc.presMovement = PresMovement.Zoom;
+ pinDoc.groupWithUp = false;
pinDoc.context = curPres;
const presArray: Doc[] = PresBox.Instance?.sortArray();
const size: number = PresBox.Instance?._selectedArray.size;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 0eb05500c..c4d51f986 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -404,6 +404,7 @@ export class MarqueeView extends React.Component= 300;
const miniView: boolean = this.toolbarWidth <= 110;
+ const presBox: Doc = this.presBox; //presBox
+ const presBoxColor: string = StrCast(presBox._backgroundColor);
+ const lightPresBoxColor: boolean = lightOrDark(presBoxColor) === 'light';
const targetDoc: Doc = this.targetDoc;
const activeItem: Doc = this.rootDoc;
return (
- {
e.stopPropagation();
e.preventDefault();
@@ -314,7 +321,11 @@ export class PresElementBox extends ViewBoxBaseComponent
{`${this.indexInPres + 1}.`}
}
- {miniView ? (null) :
+ {miniView ? (null) :
this.updateView(targetDoc, activeItem)}
style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V
- {/*
{"Group with up"}
>}>
+ {"Group with up"}
>}>
activeItem.groupWithUp = !activeItem.groupWithUp}
- style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>
- e.stopPropagation()} />
+ style={{ fontWeight: 700, backgroundColor: activeItem.groupWithUp ? PresColor.DarkBlue : "none" }}>
+ e.stopPropagation()} />
- */}
+
{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}
>}> { e.stopPropagation(); this.presExpandDocumentClick(); }}>
e.stopPropagation()} />
--
cgit v1.2.3-70-g09d2
From c15513601495e70c8e4161308814e72972d51367 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 29 Nov 2020 03:08:30 +0800
Subject: group with up functionality
---
src/client/views/nodes/PresBox.tsx | 16 ++++++++++++++--
src/client/views/presentationview/PresElementBox.scss | 2 +-
src/client/views/presentationview/PresElementBox.tsx | 19 +++++++++++++------
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 19c553189..1405016ae 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -200,9 +200,16 @@ export class PresBox extends ViewBoxBaseComponent
// No more frames in current doc and next slide is defined, therefore move to next slide
nextSlide = (targetDoc: Doc, activeNext: Doc) => {
- const nextSelected = this.itemIndex + 1;
+ let nextSelected = this.itemIndex + 1;
this.gotoDocument(nextSelected);
-
+ for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
+ if (!this.childDocs[nextSelected].groupWithUp) {
+ break;
+ } else {
+ console.log("Title: " + this.childDocs[nextSelected].title);
+ this.gotoDocument(nextSelected);
+ }
+ }
const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
// If next slide is audio / video 'Play automatically' then the next slide should be played
if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
@@ -246,6 +253,11 @@ export class PresBox extends ViewBoxBaseComponent
const lastFrame = Cast(targetDoc.lastFrame, "number", null);
const curFrame = NumCast(targetDoc._currentFrame);
let prevSelected = this.itemIndex;
+ // Functionality for group with up
+ let didZoom = activeItem.presMovement;
+ for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
+ didZoom = this.childDocs[prevSelected].presMovement;
+ }
if (lastFrame !== undefined && curFrame >= 1) {
// Case 1: There are still other frames and should go through all frames before going to previous slide
this.prevKeyframe(targetDoc, activeItem);
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 2c2c195d6..ed1aa9a1e 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -139,7 +139,7 @@ $slide-active: #5B9FDD;
.slideButton {
cursor: pointer;
position: relative;
- border-radius: 100%;
+ border-radius: 100px;
z-index: 300;
width: 18px;
height: 18px;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index c2d9faba9..463249ab8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -286,7 +286,7 @@ export class PresElementBox extends ViewBoxBaseComponent {
@@ -344,13 +344,20 @@ export class PresElementBox extends ViewBoxBaseComponent this.updateView(targetDoc, activeItem)}
style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V
-
{"Group with up"}
>}>
+ {this.indexInPres === 0 ? (null) : {"Group with up"}
>}>
activeItem.groupWithUp = !activeItem.groupWithUp}
- style={{ fontWeight: 700, backgroundColor: activeItem.groupWithUp ? PresColor.DarkBlue : "none" }}>
-
e.stopPropagation()} />
+ style={{
+ fontWeight: 700,
+ backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : PresColor.DarkBlue : undefined,
+ height: activeItem.groupWithUp ? 53 : 18,
+ transform: activeItem.groupWithUp ? "translate(0, -17px)" : undefined
+ }}>
+
+ e.stopPropagation()} />
+
-
+ }
{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}
>}> { e.stopPropagation(); this.presExpandDocumentClick(); }}>
e.stopPropagation()} />
--
cgit v1.2.3-70-g09d2
From 534a4e81e84adbd46b629731ac3ca7d3ea41a670 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 29 Nov 2020 11:15:30 +0800
Subject: temporal media updates for pres. trails
---
deploy/index.html | 4 +-
src/client/views/MainView.tsx | 8 +-
src/client/views/PropertiesView.tsx | 8 +-
src/client/views/nodes/AudioBox.tsx | 22 +-
src/client/views/nodes/PresBox.scss | 83 +++-
src/client/views/nodes/PresBox.tsx | 323 +++++++++-----
src/client/views/nodes/VideoBox.tsx | 51 ++-
.../views/presentationview/PresElementBox.scss | 41 +-
.../views/presentationview/PresElementBox.tsx | 3 +-
.../views/presentationview/PresProperties.tsx | 492 +++++++++++++++++++++
10 files changed, 901 insertions(+), 134 deletions(-)
create mode 100644 src/client/views/presentationview/PresProperties.tsx
diff --git a/deploy/index.html b/deploy/index.html
index af67ac301..beb7dd205 100644
--- a/deploy/index.html
+++ b/deploy/index.html
@@ -14,8 +14,8 @@
justify-content: center;
background-color: #AEDDF8;
z-index: 10;
- width: 100%;
- height: 100%;
+ width: 100vw;
+ height: 100vh;
}
.dash-loader-container {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 03d2e33df..b1e008dad 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -87,11 +87,11 @@ export class MainView extends React.Component {
componentDidMount() {
document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!));
const ele = document.getElementById("loader");
+
if (ele) {
- setTimeout(() => {
- // remove from DOM
- ele.outerHTML = '';
- }, 0);
+ // remove from DOM
+ setTimeout(() => { ele.style.opacity = "0"; }, 0);
+ setTimeout(() => ele.outerHTML = '', 10000);
}
new InkStrokeProperties();
this._sidebarContent.proto = undefined;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 97bca110b..c656a020e 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1007,7 +1007,7 @@ export class PropertiesView extends React.Component
{
{ this.openPresTransitions = !this.openPresTransitions; })}
style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
-
Transitions
+
Transitions
@@ -1029,17 +1029,17 @@ export class PropertiesView extends React.Component
{
{PresBox.Instance.progressivizeDropdown}
: null}
} */}
- {!selectedItem ? (null) :
+ {!selectedItem || (type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) :
{ this.openSlideOptions = !this.openSlideOptions; })}
style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
-
{scrollable ? "Scroll options" : "Pan options"}
+
{type === DocumentType.AUDIO ? "Audio Options" : "Video Options"}
{this.openSlideOptions ?
- {PresBox.Instance.optionsDropdown}
+ {PresBox.Instance.mediaOptionsDropdown}
: null}
}
{/*
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 1bdba7f9e..2527a2db1 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -48,9 +48,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent
AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime));
- this._disposers._audioStart = reaction(
+ this._disposers.audioStart = reaction(
() => this.Document._audioStart,
(audioStart) => {
if (audioStart !== undefined) {
@@ -165,6 +165,20 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.Document._audioStop,
+ (audioStop) => {
+ if (audioStop !== undefined) {
+ if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+ const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play
+ setTimeout(() => this._audioRef.current && this.pause(), delay);
+ setTimeout(() => { this.Document._audioStop = undefined; }, 10 + delay);
+ }
+ }
+ },
+ { fireImmediately: true }
+ );
}
playLink = (doc: Doc) => {
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 56b3b0593..6579dbf41 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -127,6 +127,17 @@ $light-background: #ececec;
opacity: 0.8;
}
+.presBox-radioButtons {
+ background-color: rgba(0, 0, 0, 0.1);
+
+ .checkbox-container {
+ margin-left: 10px;
+ display: inline-flex;
+ height: 20px;
+ align-items: center;
+ }
+}
+
.presBox-ribbon {
position: relative;
display: inline;
@@ -209,6 +220,42 @@ $light-background: #ececec;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
+
+ .multiThumb-slider {
+ display: grid;
+ background-color: $light-background;
+ height: 10px;
+ border-radius: 10px;
+ overflow: hidden;
+
+ .toolbar-slider {
+ margin-top: 0px;
+ background: none;
+ -webkit-appearance: none;
+ pointer-events: none;
+ }
+
+ .toolbar-slider.start::-webkit-slider-thumb {
+ width: 10px;
+ pointer-events: auto;
+ -webkit-appearance: none;
+ height: 10px;
+ cursor: ew-resize;
+ background: $dark-blue;
+ box-shadow: -100vw 0 0 100vw $light-background;
+ }
+
+ .toolbar-slider.end::-webkit-slider-thumb {
+ width: 10px;
+ pointer-events: auto;
+ -webkit-appearance: none;
+ height: 10px;
+ cursor: ew-resize;
+ background: $dark-blue;
+ box-shadow: -100vw 0 0 100vw $light-blue;
+ }
+ }
+
.toolbar-slider {
margin-top: 5px;
position: relative;
@@ -219,7 +266,7 @@ $light-background: #ececec;
height: 10px;
border-radius: 10px;
-webkit-appearance: none;
- background-color: #ececec;
+ background-color: $light-background;
}
.toolbar-slider:focus {
@@ -234,14 +281,44 @@ $light-background: #ececec;
.toolbar-slider::-webkit-slider-thumb {
width: 10px;
+ pointer-events: auto;
-webkit-appearance: none;
height: 10px;
cursor: ew-resize;
- background: #5b9ddd;
- box-shadow: -100vw 0 0 100vw #aedef8;
+ background: $dark-blue;
+ box-shadow: -100vw 0 0 100vw $light-blue;
+ }
+
+ .presBox-checkbox {
+ -webkit-appearance: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ margin: 0;
+ margin-right: 3px;
+ border-radius: 100%;
+ height: 15px;
+ width: 15px;
+ cursor: pointer;
+ background: $light-background;
+ }
+
+ .presBox-checkbox:focus {
+ outline: none;
+ }
+
+ .presBox-checkbox:hover {
+ background: #c0c0c0;
+ }
+
+ .presBox-checkbox:checked {
+ background: $light-blue;
}
}
+
+
.slider-headers {
position: relative;
display: grid;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 1405016ae..9fb07040d 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -24,7 +24,6 @@ import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../collections/CollectionView";
import { TabDocView } from "../collections/TabDocView";
import { ViewBoxBaseComponent } from "../DocComponent";
-import { AudioBox } from "./AudioBox";
import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
@@ -193,6 +192,10 @@ export class PresBox extends ViewBoxBaseComponent
nextAudioVideo = (targetDoc: Doc, activeItem: Doc) => {
if (targetDoc.type === DocumentType.AUDIO) {
targetDoc._audioStart = NumCast(activeItem.presStartTime);
+
+ } else if (targetDoc.type === DocumentType.VID) {
+ targetDoc._currentTimecode = NumCast(activeItem.presStartTime);
+ setTimeout(() => targetDoc._videoStart = true, 0);
}
// if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
activeItem.playNow = false;
@@ -214,7 +217,6 @@ export class PresBox extends ViewBoxBaseComponent
// If next slide is audio / video 'Play automatically' then the next slide should be played
if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
if (targetNext.type === DocumentType.AUDIO) targetNext._audioStart = NumCast(activeNext.presStartTime);
- // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
} else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
}
@@ -1071,6 +1073,7 @@ export class PresBox extends ViewBoxBaseComponent
@computed get transitionDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
+ const type: DocumentType = targetDoc.type;
const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection);
const isPinWithView: boolean = BoolCast(activeItem.presPinView);
if (activeItem && targetDoc) {
@@ -1137,7 +1140,7 @@ export class PresBox extends ViewBoxBaseComponent
{isPresCollection ? (null) : {"Hide after presented"}
>}> this.updateHideAfter(activeItem)}>Hide after
}
{"Open document in a new tab"}
>}> this.updateOpenDoc(activeItem)}>Open
-
+ {(type === DocumentType.AUDIO || type === DocumentType.VID) ? (null) :
-
+
}
}
});
}
- @computed get optionsDropdown() {
+
+ @computed get presPinViewOptionsDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
const presPinWithViewIcon = ;
+ return (
+ <>
+ {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
+
+
{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}
>}> {
+ activeItem.presPinView = !activeItem.presPinView;
+ targetDoc.presPinView = activeItem.presPinView;
+ if (activeItem.presPinView) {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinView = true;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinView = true;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const width = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = width;
+ activeItem.presPinView = true;
+ }
+ }
+ }}>{presPinWithViewIcon}
+ {activeItem.presPinView ?
{"Update the pinned view with the view of the selected document"}
>}> {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const clipWidth = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = clipWidth;
+ } else {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ }
+ }}>Update
: (null)}
+
+ >
+ );
+ }
+
+ @computed get panOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ return (
+ <>
+ {this.panable ?
+
+
Pan X
+
+ ) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+
+
+
+
Pan Y
+
+ ) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+
+
+
+
Scale
+
+ ) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+
+
+
: (null)}
+ >
+ );
+ }
+
+ @computed get scrollOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ return (
+ <>
+ {this.scrollable ?
+
+
Scroll
+
+ ) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
+
+
+
: (null)}
+ >
+ );
+ }
+
+ @computed get mediaOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
if (activeItem && targetDoc) {
return (
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-
+
+
Start playing:
+
+
+
activeItem.mediaPlay = "manual"}
+ checked={activeItem.mediaPlay === "manual"}
+ />
+
Start manually
+
+
+
activeItem.mediaPlay = "auto"}
+ checked={activeItem.mediaPlay === "auto"}
+ />
+
Play with slide
+
+
+
activeItem.mediaPlay = "onClick"}
+ checked={activeItem.mediaPlay === "onClick"}
+ />
+
Play on click
+
+
+
Stop playing:
+
+
+
activeItem.mediaStop = "manual"}
+ checked={activeItem.mediaStop === "manual"}
+ />
+
Stop manually
+
+
+
activeItem.mediaStop = "afterCurrent"}
+ checked={activeItem.mediaStop === "afterCurrent"}
+ />
+
After current slide
+
+
+
activeItem.mediaStop = "afterSlide"}
+ checked={activeItem.mediaStop === "afterSlide"}
+ />
+
After slide
+ {activeItem.mediaStop !== "afterSlide" ?
+ (null)
+ :
+
{ e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+ {this.setMovementName(activeItem.presMovement, activeItem)}
+
+
e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut
+
+
}
+
+
+
+
Range:
+
+ this._batch = UndoManager.StartBatch("presEndTime")}
+ onPointerUp={() => this._batch?.end()}
+ onChange={(e: React.ChangeEvent) => {
+ e.stopPropagation();
+ activeItem.presEndTime = Number(e.target.value);
+ }} />
+ this._batch = UndoManager.StartBatch("presEndTime")}
+ onPointerUp={() => this._batch?.end()}
+ onChange={(e: React.ChangeEvent) => {
+ e.stopPropagation();
+ activeItem.presStartTime = Number(e.target.value);
+ }} />
+
+
+
0 s
+
+
{Math.round(NumCast(activeItem.duration))} s
+
+
+ {/*
activeItem.playAuto = !activeItem.playAuto}>Play automatically
activeItem.playAuto = !activeItem.playAuto}>Play on next
- {/* {targetDoc.type === DocumentType.VID ?
activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen
: (null)} */}
{targetDoc.type === DocumentType.AUDIO ?
Start time
@@ -1267,98 +1483,7 @@ export class PresBox extends ViewBoxBaseComponent
onChange={action((e: React.ChangeEvent) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
: (null)}
- {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
-
-
{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}
>}> {
- activeItem.presPinView = !activeItem.presPinView;
- targetDoc.presPinView = activeItem.presPinView;
- if (activeItem.presPinView) {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinView = true;
- activeItem.presPinViewScroll = scroll;
- } else if (targetDoc.type === DocumentType.VID) {
- activeItem.presPinTimecode = targetDoc._currentTimecode;
- } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinView = true;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
- } else if (targetDoc.type === DocumentType.COMPARISON) {
- const width = targetDoc._clipWidth;
- activeItem.presPinClipWidth = width;
- activeItem.presPinView = true;
- }
- }
- }}>{presPinWithViewIcon}
- {activeItem.presPinView ?
{"Update the pinned view with the view of the selected document"}
>}> {
- if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
- const scroll = targetDoc._scrollTop;
- activeItem.presPinViewScroll = scroll;
- } else if (targetDoc.type === DocumentType.VID) {
- activeItem.presPinTimecode = targetDoc._currentTimecode;
- } else if (targetDoc.type === DocumentType.COMPARISON) {
- const clipWidth = targetDoc._clipWidth;
- activeItem.presPinClipWidth = clipWidth;
- } else {
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeItem.presPinViewX = x;
- activeItem.presPinViewY = y;
- activeItem.presPinViewScale = scale;
- }
- }}>Update
: (null)}
-
- {this.panable ?
-
-
Pan X
-
- ) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
-
-
-
-
Pan Y
-
- ) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
-
-
-
-
Scale
-
- ) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
-
-
-
: (null)}
- {this.scrollable ?
-
-
Scroll
-
- ) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
-
-
-
: (null)}
- {/*
-
Store original website
-
*/}
-
+
*/}
);
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 8ce76a347..998ca839d 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -21,6 +21,8 @@ import { documentSchema } from "../../../fields/documentSchemas";
import { Networking } from "../../Network";
import { SnappingManager } from "../../util/SnappingManager";
import { SelectionManager } from "../../util/SelectionManager";
+import { LinkDocPreview } from "./LinkDocPreview";
+import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
const path = require('path');
export const timeSchema = createSchema({
@@ -32,8 +34,9 @@ const VideoDocument = makeInterface(documentSchema, timeSchema);
@observer
export class VideoBox extends ViewBoxAnnotatableComponent(VideoDocument) {
static _youtubeIframeCounter: number = 0;
- private _reactionDisposer?: IReactionDisposer;
- private _youtubeReactionDisposer?: IReactionDisposer;
+ // private _reactionDisposer?: IReactionDisposer;
+ // private _youtubeReactionDisposer?: IReactionDisposer;
+ private _disposers: { [name: string]: IReactionDisposer } = {};
private _youtubePlayer: YT.Player | undefined = undefined;
private _videoRef: HTMLVideoElement | null = null;
private _youtubeIframeId: number = -1;
@@ -181,7 +184,32 @@ export class VideoBox extends ViewBoxAnnotatableComponent this.Document._videoStart,
+ (videoStart) => {
+ if (videoStart !== undefined) {
+ if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+ const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
+ setTimeout(() => this.player && this.Play(), delay);
+ setTimeout(() => { this.Document._videoStart = undefined; }, 10 + delay);
+ }
+ }
+ },
+ { fireImmediately: true }
+ );
+ this._disposers.videoStop = reaction(
+ () => this.Document._videoStop,
+ (videoStop) => {
+ if (videoStop !== undefined) {
+ if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+ const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
+ setTimeout(() => this.player && this.Pause(), delay);
+ setTimeout(() => { this.Document._videoStop = undefined; }, 10 + delay);
+ }
+ }
+ },
+ { fireImmediately: true }
+ );
if (this.youtubeVideoId) {
const youtubeaspect = 400 / 315;
const nativeWidth = Doc.NativeWidth(this.layoutDoc);
@@ -196,8 +224,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent this._fullScreen = vref.webkitDisplayingFullscreen);
- this._reactionDisposer?.();
- this._reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0),
+ this._disposers.reactionDisposer?.();
+ this._disposers.reactionDisposer = reaction(() => (this.layoutDoc._currentTimecode || 0),
time => !this._playing && (vref.currentTime = time), { fireImmediately: true });
}
}
@@ -293,10 +322,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent {
- this._reactionDisposer?.();
- this._youtubeReactionDisposer?.();
- this._reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
- this._youtubeReactionDisposer = reaction(
+ this._disposers.reactionDisposer?.();
+ this._disposers.youtubeReactionDisposer?.();
+ this._disposers.reactionDisposer = reaction(() => this.layoutDoc._currentTimecode, () => !this._playing && this.Seek((this.layoutDoc._currentTimecode || 0)));
+ this._disposers.youtubeReactionDisposer = reaction(
() => !this.props.Document.isAnnotating && Doc.GetSelectedTool() === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting,
(interactive) => iframe.style.pointerEvents = interactive ? "all" : "none", { fireImmediately: true });
};
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index ed1aa9a1e..e1eeefc30 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -122,12 +122,6 @@ $slide-active: #5B9FDD;
}
- .presItem-slideButtons {
- display: none;
- }
-}
-
-.presItem-slide:hover {
.presItem-slideButtons {
display: flex;
grid-column: 7;
@@ -162,6 +156,41 @@ $slide-active: #5B9FDD;
}
}
+// .presItem-slide:hover {
+ // .presItem-slideButtons {
+ // display: flex;
+ // grid-column: 7;
+ // grid-row: 1/3;
+ // width: max-content;
+ // justify-self: right;
+ // justify-content: flex-end;
+
+ // .slideButton {
+ // cursor: pointer;
+ // position: relative;
+ // border-radius: 100px;
+ // z-index: 300;
+ // width: 18px;
+ // height: 18px;
+ // display: flex;
+ // font-size: 12px;
+ // justify-self: center;
+ // align-self: center;
+ // background-color: rgba(0, 0, 0, 0.5);
+ // color: white;
+ // justify-content: center;
+ // align-items: center;
+ // transition: 0.2s;
+ // margin-right: 3px;
+ // }
+
+ // .slideButton:hover {
+ // background-color: rgba(0, 0, 0, 1);
+ // transform: scale(1.2);
+ // }
+ // }
+ // }
+
.presItem-slide.active {
box-shadow: 0 0 0px 1.5px $dark-blue;
}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 463249ab8..9ec39b792 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -348,6 +348,7 @@ export class PresElementBox extends ViewBoxBaseComponent activeItem.groupWithUp = !activeItem.groupWithUp}
style={{
+ zIndex: 1000 - this.indexInPres,
fontWeight: 700,
backgroundColor: activeItem.groupWithUp ? presColorBool ? presBoxColor : PresColor.DarkBlue : undefined,
height: activeItem.groupWithUp ? 53 : 18,
@@ -367,7 +368,7 @@ export class PresElementBox extends ViewBoxBaseComponent e.stopPropagation()} />
-
{activeItem.presPinView ? (<>View of {targetDoc.title}>) : targetDoc.title}
+
{activeItem.presPinView ? (<>View of {targetDoc.title}>) : targetDoc.title}
{this.renderEmbeddedInline}
}
);
diff --git a/src/client/views/presentationview/PresProperties.tsx b/src/client/views/presentationview/PresProperties.tsx
new file mode 100644
index 000000000..edad41861
--- /dev/null
+++ b/src/client/views/presentationview/PresProperties.tsx
@@ -0,0 +1,492 @@
+import React from "react";
+import { action, computed, observable, reaction } from "mobx";
+import { Doc } from "../../../fields/Doc";
+import { BoolCast, Cast, NumCast } from "../../../fields/Types";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
+import { PresBox, PresColor, PresEffect, PresMovement } from "../nodes/PresBox";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { CollectionViewType } from "../collections/CollectionView";
+import { Tooltip } from "@material-ui/core";
+
+
+export class PresProperties {
+
+ @observable public static Instance: PresProperties;
+
+ @computed get pres(): PresBox { return PresBox.Instance; }
+
+ @computed get activeItem() { return Cast(this.pres.childDocs[NumCast(PresBox.Instance.rootDoc._itemIndex)], Doc, null); }
+ @computed get targetDoc() { return Cast(this.pres.activeItem?.presentationTargetDoc, Doc, null); }
+
+ @computed get scrollable(): boolean {
+ if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
+ else return false;
+ }
+ @computed get panable(): boolean {
+ if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
+ else return false;
+ }
+
+
+ @observable private openMovementDropdown: boolean = false;
+ @observable private openEffectDropdown: boolean = false;
+
+ _batch: UndoManager.Batch | undefined = undefined;
+
+
+ @computed get effectDirection(): string {
+ let effect = '';
+ switch (this.targetDoc.presEffectDirection) {
+ case 'left': effect = "Enter from left"; break;
+ case 'right': effect = "Enter from right"; break;
+ case 'top': effect = "Enter from top"; break;
+ case 'bottom': effect = "Enter from bottom"; break;
+ default: effect = "Enter from center"; break;
+ }
+ return effect;
+ }
+
+ @undoBatch
+ @action
+ updateHideBefore = (activeItem: Doc) => {
+ activeItem.presHideBefore = !activeItem.presHideBefore;
+ Array.from(this.pres._selectedArray.keys()).forEach((doc) => doc.presHideBefore = activeItem.presHideBefore);
+ }
+
+ @undoBatch
+ @action
+ updateHideAfter = (activeItem: Doc) => {
+ activeItem.presHideAfter = !activeItem.presHideAfter;
+ Array.from(this.pres._selectedArray.keys()).forEach((doc) => doc.presHideAfter = activeItem.presHideAfter);
+ }
+
+ @undoBatch
+ @action
+ updateOpenDoc = (activeItem: Doc) => {
+ activeItem.openDocument = !activeItem.openDocument;
+ Array.from(this.pres._selectedArray.keys()).forEach((doc) => {
+ doc.openDocument = activeItem.openDocument;
+ });
+ }
+
+ /**
+ * When the movement dropdown is changes
+ */
+ @undoBatch
+ updateMovement = action((movement: any, all?: boolean) => {
+ const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+ array.forEach((doc) => {
+ switch (movement) {
+ case PresMovement.Zoom: //Pan and zoom
+ doc.presMovement = PresMovement.Zoom;
+ break;
+ case PresMovement.Pan: //Pan
+ doc.presMovement = PresMovement.Pan;
+ break;
+ case PresMovement.Jump: //Jump Cut
+ doc.presJump = true;
+ doc.presMovement = PresMovement.Jump;
+ break;
+ case PresMovement.None: default:
+ doc.presMovement = PresMovement.None;
+ break;
+ }
+ });
+ });
+
+ @undoBatch
+ @action
+ updateEffect = (effect: any, all?: boolean) => {
+ const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+ array.forEach((doc) => {
+ const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+ switch (effect) {
+ case PresEffect.Bounce:
+ tagDoc.presEffect = PresEffect.Bounce;
+ break;
+ case PresEffect.Fade:
+ tagDoc.presEffect = PresEffect.Fade;
+ break;
+ case PresEffect.Flip:
+ tagDoc.presEffect = PresEffect.Flip;
+ break;
+ case PresEffect.Roll:
+ tagDoc.presEffect = PresEffect.Roll;
+ break;
+ case PresEffect.Rotate:
+ tagDoc.presEffect = PresEffect.Rotate;
+ break;
+ case PresEffect.None: default:
+ tagDoc.presEffect = PresEffect.None;
+ break;
+ }
+ });
+ }
+
+ @undoBatch
+ @action
+ updateEffectDirection = (effect: any, all?: boolean) => {
+ const array: any[] = all ? this.pres.childDocs : Array.from(this.pres._selectedArray.keys());
+ array.forEach((doc) => {
+ const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
+ switch (effect) {
+ case PresEffect.Left:
+ tagDoc.presEffectDirection = PresEffect.Left;
+ break;
+ case PresEffect.Right:
+ tagDoc.presEffectDirection = PresEffect.Right;
+ break;
+ case PresEffect.Top:
+ tagDoc.presEffectDirection = PresEffect.Top;
+ break;
+ case PresEffect.Bottom:
+ tagDoc.presEffectDirection = PresEffect.Bottom;
+ break;
+ case PresEffect.Center: default:
+ tagDoc.presEffectDirection = PresEffect.Center;
+ break;
+ }
+ });
+ }
+
+ // Converts seconds to ms and updates presTransition
+ setTransitionTime = (number: String, change?: number) => {
+ let timeInMS = Number(number) * 1000;
+ if (change) timeInMS += change;
+ if (timeInMS < 100) timeInMS = 100;
+ if (timeInMS > 10000) timeInMS = 10000;
+ Array.from(PresBox.Instance._selectedArray.keys()).forEach((doc) => doc.presTransition = timeInMS);
+ }
+
+ // Converts seconds to ms and updates presDuration
+ setDurationTime = (number: String, change?: number) => {
+ let timeInMS = Number(number) * 1000;
+ if (change) timeInMS += change;
+ if (timeInMS < 100) timeInMS = 100;
+ if (timeInMS > 20000) timeInMS = 20000;
+ Array.from(PresBox.Instance._selectedArray.keys()).forEach((doc) => doc.presDuration = timeInMS);
+ }
+
+ setMovementName = action((movement: any, activeItem: Doc): string => {
+ let output: string = 'none';
+ switch (movement) {
+ case PresMovement.Zoom: output = 'Pan & Zoom'; break; //Pan and zoom
+ case PresMovement.Pan: output = 'Pan'; break; //Pan
+ case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut
+ case PresMovement.None: output = 'No Movement'; break; //None
+ default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom
+ }
+ return output;
+ });
+
+ @computed get transitionDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ const isPresCollection: boolean = (targetDoc === this.pres.layoutDoc.presCollection);
+ const isPinWithView: boolean = BoolCast(activeItem.presPinView);
+ if (activeItem && targetDoc) {
+ const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
+ let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
+ if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
+ const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
+ activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
+ return (
+
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this.openMovementDropdown = false; this.openEffectDropdown = false; })}>
+
+ Movement
+ {isPresCollection || (isPresCollection && isPinWithView) ?
+
+ {this.scrollable ? "Scroll to pinned view" : !isPinWithView ? "No movement" : "Pan & Zoom to pinned view"}
+
+ :
+
{ e.stopPropagation(); this.openMovementDropdown = !this.openMovementDropdown; })} style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+ {this.setMovementName(activeItem.presMovement, activeItem)}
+
+
e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan
+
e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut
+
+
+ }
+
+
Transition Speed
+
+ this.setTransitionTime(e.target.value))} /> s
+
+
+
this.setTransitionTime(String(transitionSpeed), 1000))}>
+
+
+
this.setTransitionTime(String(transitionSpeed), -1000))}>
+
+
+
+
+
this._batch = UndoManager.StartBatch("presTransition")}
+ onPointerUp={() => this._batch?.end()}
+ onChange={(e: React.ChangeEvent
) => {
+ e.stopPropagation();
+ this.setTransitionTime(e.target.value);
+ }} />
+
+
+
+ Visibility {"&"} Duration
+
+ {isPresCollection ? (null) :
{"Hide before presented"}
>}> this.updateHideBefore(activeItem)}>Hide before
}
+ {isPresCollection ? (null) :
{"Hide after presented"}
>}> this.updateHideAfter(activeItem)}>Hide after
}
+
{"Open document in a new tab"}
>}> this.updateOpenDoc(activeItem)}>Open
+
+
+
Slide Duration
+
+ this.setDurationTime(e.target.value))} /> s
+
+
+
this.setDurationTime(String(duration), 1000))}>
+
+
+
this.setDurationTime(String(duration), -1000))}>
+
+
+
+
+
{ this._batch = UndoManager.StartBatch("presDuration"); }}
+ onPointerUp={() => { if (this._batch) this._batch.end(); }}
+ onChange={(e: React.ChangeEvent
) => { e.stopPropagation(); this.setDurationTime(e.target.value); }}
+ />
+
+
Short
+
Medium
+
Long
+
+
+ {isPresCollection ? (null) :
+ Effects
+
{ e.stopPropagation(); this.openEffectDropdown = !this.openEffectDropdown; })} style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${PresColor.DarkBlue}` : 'solid 1px black' }}>
+ {effect}
+
+
e.stopPropagation()}>
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce
+
e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll
+
+
+
+
Effect direction
+
+ {this.effectDirection}
+
+
+
+
{"Enter from left"}
>}> this.updateEffectDirection(PresEffect.Left)}>
+
{"Enter from right"}
>}> this.updateEffectDirection(PresEffect.Right)}>
+
{"Enter from top"}
>}> this.updateEffectDirection(PresEffect.Top)}>
+
{"Enter from bottom"}
>}> this.updateEffectDirection(PresEffect.Bottom)}>
+
{"Enter from center"}
>}> this.updateEffectDirection(PresEffect.Center)}>
+
+
}
+
+
this.applyTo(this.pres.childDocs)}>
+ Apply to all
+
+
+
+ );
+ }
+ }
+
+ @undoBatch
+ @action
+ applyTo = (array: Doc[]) => {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ this.updateMovement(activeItem.presMovement, true);
+ this.updateEffect(targetDoc.presEffect, true);
+ this.updateEffectDirection(targetDoc.presEffectDirection, true);
+ array.forEach((doc) => {
+ const curDoc = Cast(doc, Doc, null);
+ const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
+ if (tagDoc && targetDoc) {
+ curDoc.presTransition = activeItem.presTransition;
+ curDoc.presDuration = activeItem.presDuration;
+ curDoc.presHideBefore = activeItem.presHideBefore;
+ curDoc.presHideAfter = activeItem.presHideAfter;
+ }
+ });
+ }
+
+ @computed get mediaOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ if (activeItem && targetDoc) {
+ return (
+
+
e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+
+
+
activeItem.playAuto = !activeItem.playAuto}>Play automatically
+
activeItem.playAuto = !activeItem.playAuto}>Play on next
+
+ {/* {targetDoc.type === DocumentType.VID ?
activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen
: (null)} */}
+ {targetDoc.type === DocumentType.AUDIO ?
+
Start time
+
+ ) => { activeItem.presStartTime = Number(e.target.value); })} />
+
+
: (null)}
+ {targetDoc.type === DocumentType.AUDIO ?
+
End time
+
+ ) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
+
+
: (null)}
+
+
+
+ );
+ }
+ }
+
+ @computed get presPinViewOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ const presPinWithViewIcon =
;
+ return (
+ <>
+ {this.panable || this.scrollable || this.targetDoc.type === DocumentType.COMPARISON ? 'Pinned view' : (null)}
+
+
{activeItem.presPinView ? "Turn off pin with view" : "Turn on pin with view"}
>}> {
+ activeItem.presPinView = !activeItem.presPinView;
+ targetDoc.presPinView = activeItem.presPinView;
+ if (activeItem.presPinView) {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinView = true;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG) {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinView = true;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const width = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = width;
+ activeItem.presPinView = true;
+ }
+ }
+ }}>{presPinWithViewIcon}
+ {activeItem.presPinView ?
{"Update the pinned view with the view of the selected document"}
>}> {
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF) {
+ const scroll = targetDoc._scrollTop;
+ activeItem.presPinViewScroll = scroll;
+ } else if (targetDoc.type === DocumentType.VID) {
+ activeItem.presPinTimecode = targetDoc._currentTimecode;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const clipWidth = targetDoc._clipWidth;
+ activeItem.presPinClipWidth = clipWidth;
+ } else {
+ const x = targetDoc._panX;
+ const y = targetDoc._panY;
+ const scale = targetDoc._viewScale;
+ activeItem.presPinViewX = x;
+ activeItem.presPinViewY = y;
+ activeItem.presPinViewScale = scale;
+ }
+ }}>Update
: (null)}
+
+ >
+ );
+ }
+
+ @computed get panOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ return (
+ <>
+ {this.panable ?
+
+
Pan X
+
+ ) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
+
+
+
+
Pan Y
+
+ ) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
+
+
+
+
Scale
+
+ ) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
+
+
+
: (null)}
+ >
+ );
+ }
+
+ @computed get scrollOptionsDropdown() {
+ const activeItem: Doc = this.activeItem;
+ const targetDoc: Doc = this.targetDoc;
+ return (
+ <>
+ {this.scrollable ?
+
+
Scroll
+
+ ) => { const val = e.target.value; activeItem.presPinViewScroll = Number(val); })} />
+
+
+
: (null)}
+ >
+ );
+ }
+}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From e72068df41088f2bd842733f0e45cdfb4d28e6de Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 29 Nov 2020 13:24:34 +0800
Subject: pres trails temporal media and fixing group with up
---
src/client/views/MainView.tsx | 2 +-
.../views/collections/CollectionStackingView.tsx | 2 +-
src/client/views/collections/TabDocView.tsx | 6 +-
src/client/views/nodes/PresBox.tsx | 116 ++++++++++++++-------
.../views/presentationview/PresElementBox.tsx | 2 +-
5 files changed, 83 insertions(+), 45 deletions(-)
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b1e008dad..3c46e0f89 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -148,7 +148,7 @@ export class MainView extends React.Component {
fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft,
fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faChevronLeft, fa.faChevronDown, fa.faChevronUp,
fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt,
- fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
+ fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer,
fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote,
fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes,
fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 35331cc15..4b3393e14 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -290,7 +290,7 @@ export class CollectionStackingView extends CollectionSubView
(pos[axis] + pos1[axis]) / 2 ? 1 : 0;
}
});
- // const oldDocs = this.childDocs.length;
+ const oldDocs = this.childDocs.length;
if (super.onInternalDrop(e, de)) {
const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= oldDocs); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note).
const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments; // if nothing was added to the end of the list, then presumably the dropped documents were already in the list, but possibly got reordered so we use them.
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 45fab480c..0f228bc06 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -172,9 +172,11 @@ export class TabDocView extends React.Component {
const size: number = PresBox.Instance?._selectedArray.size;
const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
- if (pinDoc.type === "audio" && !audioRange) {
+ if (pinDoc.type === DocumentType.AUDIO || pinDoc.type === DocumentType.VID && !audioRange) {
+ pinDoc.mediaStart = "manual";
+ pinDoc.mediaStop = "manual";
pinDoc.presStartTime = 0;
- pinDoc.presEndTime = doc.duration;
+ pinDoc.presEndTime = pinDoc.type === DocumentType.AUDIO ? doc.duration : NumCast(doc["data-duration"]);
}
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
const dview = CollectionDockingView.Instance.props.Document;
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 9fb07040d..ed2cb9fa1 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -210,7 +210,7 @@ export class PresBox extends ViewBoxBaseComponent
break;
} else {
console.log("Title: " + this.childDocs[nextSelected].title);
- this.gotoDocument(nextSelected);
+ this.gotoDocument(nextSelected, true);
}
}
const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
@@ -276,7 +276,7 @@ export class PresBox extends ViewBoxBaseComponent
//The function that is called when a document is clicked or reached through next or back.
//it'll also execute the necessary actions if presentation is playing.
- public gotoDocument = action((index: number) => {
+ public gotoDocument = action((index: number, group?: boolean) => {
Doc.UnBrushAllDocs();
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
@@ -292,9 +292,9 @@ export class PresBox extends ViewBoxBaseComponent
if (presTargetDoc?.lastFrame !== undefined) {
presTargetDoc._currentFrame = 0;
}
- this._selectedArray.clear();
+ if (!group) this._selectedArray.clear();
this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
- if (this.layoutDoc._viewType === "stacking") this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+ if (this.layoutDoc._viewType === "stacking" && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
this.onHideDocument(); //Handles hide after/before
}
});
@@ -1073,7 +1073,7 @@ export class PresBox extends ViewBoxBaseComponent
@computed get transitionDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
- const type: DocumentType = targetDoc.type;
+ const type = targetDoc.type;
const isPresCollection: boolean = (targetDoc === this.layoutDoc.presCollection);
const isPinWithView: boolean = BoolCast(activeItem.presPinView);
if (activeItem && targetDoc) {
@@ -1103,7 +1103,7 @@ export class PresBox extends ViewBoxBaseComponent
}