aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/CurrentUserUtils.ts1
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/views/DocumentButtonBar.tsx46
-rw-r--r--src/client/views/EditableView.tsx34
-rw-r--r--src/client/views/GestureOverlay.tsx15
-rw-r--r--src/client/views/OverlayView.tsx9
-rw-r--r--src/client/views/PropertiesView.tsx6
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx12
-rw-r--r--src/client/views/collections/CollectionMenu.tsx10
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx23
-rw-r--r--src/client/views/collections/CollectionSubView.tsx17
-rw-r--r--src/client/views/collections/TabDocView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
-rw-r--r--src/client/views/nodes/PresBox.scss1
-rw-r--r--src/client/views/nodes/PresBox.tsx507
-rw-r--r--src/client/views/nodes/VideoBox.scss3
-rw-r--r--src/client/views/nodes/VideoBox.tsx10
-rw-r--r--src/client/views/nodes/WebBox.tsx20
-rw-r--r--src/client/views/presentationview/PresElementBox.scss88
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx141
-rw-r--r--src/fields/documentSchemas.ts1
-rw-r--r--src/fields/util.ts16
-rw-r--r--src/server/SharedMediaTypes.ts2
-rw-r--r--src/server/websocket.ts73
28 files changed, 682 insertions, 391 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d7c9af1a3..d7af88b72 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1101,7 +1101,7 @@ export namespace DocUtils {
});
}
ctor = Docs.Create.WebDocument;
- options = { ...options, _fitWidth: true, _nativeWidth: 850, _width: 400, _height: 512, title: path, };
+ options = { ...options, _fitWidth: true, _width: 400, _height: 512, title: path, };
}
return ctor ? ctor(path, options) : undefined;
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index f43b6df44..38bfe3fb6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1190,6 +1190,7 @@ export class CurrentUserUtils {
public static get MyRecentlyClosed() { return Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc, null); }
public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); }
public static get EmptyPane() { return Cast(Doc.UserDoc().emptyPane, Doc, null); }
+ public static get OverlayDocs() { return DocListCast((Doc.UserDoc().myOverlayDocs as Doc)?.data); }
}
Scripting.addGlobal(function openDragFactory(dragFactory: Doc) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 2670de7a6..805e0e897 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -110,7 +110,7 @@ export class DocumentManager {
public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
const views = this.getDocumentViews(toFind).filter(view => view.props.Document !== originatingDoc);
- return views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined);
+ return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined);
}
public getDocumentViews(toFind: Doc): DocumentView[] {
const toReturn: DocumentView[] = [];
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 076502042..ed248c473 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -26,6 +26,7 @@ import { TemplateMenu } from "./TemplateMenu";
import React = require("react");
import { PresBox } from './nodes/PresBox';
import { undoBatch } from '../util/UndoManager';
+import { CollectionViewType } from './collections/CollectionView';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -186,7 +187,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
get pinButton() {
const targetDoc = this.view0?.props.Document;
const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
- return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation"}</div></>}>
+ return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{SelectionManager.SelectedDocuments().length > 1 ? "Pin multiple documents to presentation" : "Pin to presentation"}</div></>}>
<div className="documentButtonBar-linker"
style={{ color: "white" }}
onClick={undoBatch(e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, false)))}>
@@ -194,25 +195,40 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
</div></Tooltip>;
}
+ @undoBatch
+ @action
+ pinWithView = (targetDoc: Doc) => {
+ if (targetDoc) {
+ TabDocView.PinDoc(targetDoc, false);
+ const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+ if (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking) {
+ const scroll = targetDoc._scrollTop;
+ activeDoc.presPinView = true;
+ activeDoc.presPinViewScroll = scroll;
+ } 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;
+ activeDoc.presPinView = true;
+ activeDoc.presPinViewX = x;
+ activeDoc.presPinViewY = y;
+ activeDoc.presPinViewScale = scale;
+ } else if (targetDoc.type === DocumentType.COMPARISON) {
+ const width = targetDoc._clipWidth;
+ activeDoc.presPinClipWidth = width;
+ activeDoc.presPinView = true;
+ }
+ }
+ }
+
@computed
get pinWithViewButton() {
const presPinWithViewIcon = <img src="/assets/pinWithView.png" style={{ margin: "auto", width: 17, transform: 'translate(0, 1px)' }} />;
const targetDoc = this.view0?.props.Document;
return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin with current view"}</div></>}>
- <div className="documentButtonBar-linker"
- onClick={undoBatch(e => {
- if (targetDoc) {
- TabDocView.PinDoc(targetDoc, false);
- const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
- const x = targetDoc._panX;
- const y = targetDoc._panY;
- const scale = targetDoc._viewScale;
- activeDoc.presPinView = true;
- activeDoc.presPinViewX = x;
- activeDoc.presPinViewY = y;
- activeDoc.presPinViewScale = scale;
- }
- })}>
+ <div
+ className="documentButtonBar-linker"
+ onClick={() => this.pinWithView(targetDoc)}>
{presPinWithViewIcon}
</div>
</Tooltip>;
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 8b1b12365..9606b5a91 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -82,11 +82,24 @@ export class EditableView extends React.Component<EditableProps> {
// }
@action
+ componentDidUpdate() {
+ if (this._editing && this.props.editing === false) {
+ this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false);
+ } else if (this.props.editing !== undefined) {
+ this._editing = this.props.editing;
+ }
+ }
+
+ @action
componentDidMount() {
if (this._ref.current && this.props.onDrop) {
DragManager.MakeDropTarget(this._ref.current, this.props.onDrop.bind(this));
}
}
+ @action
+ componentWillUnmount() {
+ this._inputref.current?.value && this.finalizeEdit(this._inputref.current.value, false, true, false);
+ }
_didShow = false;
@@ -131,14 +144,16 @@ export class EditableView extends React.Component<EditableProps> {
@action
onClick = (e: React.MouseEvent) => {
- e.nativeEvent.stopPropagation();
- if (this._ref.current && this.props.showMenuOnLoad) {
- this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y);
- } else if (!this.props.onClick?.(e)) {
- this._editing = true;
- this.props.isEditingCallback?.(true);
+ if (this.props.editing !== false) {
+ e.nativeEvent.stopPropagation();
+ if (this._ref.current && this.props.showMenuOnLoad) {
+ this.props.menuCallback?.(this._ref.current.getBoundingClientRect().x, this._ref.current.getBoundingClientRect().y);
+ } else if (!this.props.onClick?.(e)) {
+ this._editing = true;
+ this.props.isEditingCallback?.(true);
+ }
+ e.stopPropagation();
}
- e.stopPropagation();
}
@action
@@ -168,6 +183,7 @@ export class EditableView extends React.Component<EditableProps> {
}
_ref = React.createRef<HTMLDivElement>();
+ _inputref = React.createRef<HTMLInputElement>();
renderEditor() {
return this.props.autosuggestProps
? <Autosuggest
@@ -185,7 +201,7 @@ export class EditableView extends React.Component<EditableProps> {
onChange: this.props.autosuggestProps.onChange
}}
/>
- : <input className="editableView-input"
+ : <input className="editableView-input" ref={this._inputref}
defaultValue={this.props.GetValue()}
onKeyDown={this.onKeyDown}
autoFocus={true}
@@ -213,7 +229,7 @@ export class EditableView extends React.Component<EditableProps> {
<div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`} ref={this._ref}
style={{ display: this.props.display, minHeight: "17px", whiteSpace: "nowrap", height: this.props.height || "auto", maxHeight: this.props.maxHeight }}
onClick={this.onClick} placeholder={this.props.placeholder}>
- <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{
+ <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }} >{
this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}
</span>
</div>;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 18743e850..ffa089af1 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -655,7 +655,7 @@ export class GestureOverlay extends Touchable {
this._points = [];
}
//get out of ink mode after each stroke=
- if (!CollectionFreeFormViewChrome.Instance._keepMode) {
+ if (CollectionFreeFormViewChrome.Instance && !CollectionFreeFormViewChrome.Instance?._keepMode) {
Doc.SetSelectedTool(InkTool.None);
CollectionFreeFormViewChrome.Instance._selected = CollectionFreeFormViewChrome.Instance._shapesNum;
SetActiveArrowStart("none");
@@ -839,14 +839,15 @@ export class GestureOverlay extends Touchable {
) || false;
}
- getBounds = (stroke: InkData) => {
- const xs = stroke.map(p => p.X);
- const ys = stroke.map(p => p.Y);
+ getBounds = (stroke: InkData, pad?: boolean) => {
+ const padding = pad ? [-20000, 20000] : [];
+ const xs = [...padding, ...stroke.map(p => p.X)];
+ const ys = [...padding, ...stroke.map(p => p.Y)];
const right = Math.max(...xs);
const left = Math.min(...xs);
const bottom = Math.max(...ys);
const top = Math.min(...ys);
- return { right: right, left: left, bottom: bottom, top: top, width: right - left, height: bottom - top };
+ return { right, left, bottom, top, width: right - left, height: bottom - top };
}
@computed get svgBounds() {
@@ -856,7 +857,7 @@ export class GestureOverlay extends Touchable {
@computed get elements() {
const width = Number(ActiveInkWidth());
const rect = this._overlayRef.current?.getBoundingClientRect();
- const B = this.svgBounds;
+ const B = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 }; //this.getBounds(this._points, true);
B.left = B.left - width / 2;
B.right = B.right + width / 2;
B.top = B.top - width / 2 - (rect?.y || 0);
@@ -867,7 +868,7 @@ export class GestureOverlay extends Touchable {
this.props.children,
this._palette,
[this._strokes.map((l, i) => {
- const b = this.getBounds(l);
+ const b = { left: -20000, right: 20000, top: -20000, bottom: 20000, width: 40000, height: 40000 };//this.getBounds(l, true);
return <svg key={i} width={b.width} height={b.height} style={{ transform: `translate(${b.left}px, ${b.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
{InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), width, width,
ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(),
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index b40c9edfb..7d47abdce 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -14,6 +14,7 @@ import { Scripting } from "../util/Scripting";
import { ScriptingRepl } from './ScriptingRepl';
import { DragManager } from "../util/DragManager";
import { List } from "../../fields/List";
+import { CurrentUserUtils } from "../util/CurrentUserUtils";
export type OverlayDisposer = () => void;
@@ -146,12 +147,7 @@ export class OverlayView extends React.Component {
@computed get overlayDocs() {
- const userDocOverlays = Doc.UserDoc().myOverlayDocs;
- if (!userDocOverlays) {
- return null;
- }
- return userDocOverlays instanceof Doc && DocListCast(userDocOverlays.data).map(d => {
- setTimeout(() => d.inOverlay = true, 0);
+ return CurrentUserUtils.OverlayDocs?.map(d => {
let offsetx = 0, offsety = 0;
const dref = React.createRef<HTMLDivElement>();
const onPointerMove = action((e: PointerEvent, down: number[]) => {
@@ -161,7 +157,6 @@ export class OverlayView extends React.Component {
}
if (e.metaKey) {
const dragData = new DragManager.DocumentDragData([d]);
- d.removeDropProperties = new List<string>(["inOverlay"]);
dragData.offset = [-offsetx, -offsety];
dragData.dropAction = "move";
dragData.removeDocument = (doc: Doc | Doc[]) => {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 39a4d293b..e93173c9e 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1010,7 +1010,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{PresBox.Instance.transitionDropdown}
</div> : null}
</div>}
- {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
+ {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1022,8 +1022,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
{PresBox.Instance.progressivizeDropdown}
</div> : null}
- </div>}
- {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
+ </div>} */}
+ {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2eaa284cc..39a52fb6d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -308,9 +308,15 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
@action
onPointerDown = (e: React.PointerEvent): void => {
- window.addEventListener("mouseup", this.onPointerUp);
- if (!(e.target as HTMLElement).closest("*.lm_content") && ((e.target as HTMLElement).closest("*.lm_tab") || (e.target as HTMLElement).closest("*.lm_stack"))) {
- this._flush = UndoManager.StartBatch("golden layout edit");
+ let hitFlyout = false;
+ for (let par = e.target as any; !hitFlyout && par; par = par.parentElement) {
+ hitFlyout = (par.className === "dockingViewButtonSelector");
+ }
+ if (!hitFlyout) {
+ window.addEventListener("mouseup", this.onPointerUp);
+ if (!(e.target as HTMLElement).closest("*.lm_content") && ((e.target as HTMLElement).closest("*.lm_tab") || (e.target as HTMLElement).closest("*.lm_stack"))) {
+ this._flush = UndoManager.StartBatch("golden layout edit");
+ }
}
if (!e.nativeEvent.cancelBubble && !InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) &&
Doc.GetSelectedTool() !== InkTool.Highlighter && Doc.GetSelectedTool() !== InkTool.Pen) {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a4f5118d6..34fb2bdee 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -344,7 +344,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get viewModes() {
const excludedViewTypes = Doc.UserDoc().noviceMode ? [CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Map, CollectionViewType.Linear, CollectionViewType.Time] :
[CollectionViewType.Invalid, CollectionViewType.Docking, CollectionViewType.Pile, CollectionViewType.Linear];
- return <div className="collectionViewBaseChrome-viewModes" >
+ const isPres: boolean = (this.document && this.document.type === DocumentType.PRES);
+ return isPres ? (null) : (<div className="collectionViewBaseChrome-viewModes" >
<Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
<div className="commandEntry-outerDiv" ref={this._viewRef} onPointerDown={this.dragViewDown}>
<button className={"antimodeMenu-button"}>
@@ -367,7 +368,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
</select>
</div>
</Tooltip>
- </div>;
+ </div>);
}
@computed get selectedDocumentView() {
@@ -425,7 +426,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
const presPinWithViewIcon = <img src={`/assets/pinWithView.png`} style={{ margin: "auto", width: 19 }} />;
const targetDoc = this.selectedDoc;
{/* return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top"> */ }
- return (targetDoc && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+ return (targetDoc && targetDoc.type !== DocumentType.PRES && (targetDoc._viewType === CollectionViewType.Freeform || targetDoc._viewType === CollectionViewType.Stacking || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.COMPARISON)) ? <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
<button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
onClick={() => this.pinWithView(targetDoc)}>
{presPinWithViewIcon}
@@ -472,7 +473,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed
get aliasButton() {
const targetDoc = this.selectedDoc;
- return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
+ return !targetDoc || targetDoc.type === DocumentType.PRES ? (null) : <Tooltip title={<div className="dash-tooltip">{"Tap or Drag to create an alias"}</div>} placement="top">
<button className="antimodeMenu-button" onPointerDown={this.onAliasButtonDown} onClick={this.onAlias} style={{ cursor: "drag" }}>
<FontAwesomeIcon className="documentdecorations-icon" icon="copy" size="lg" />
</button>
@@ -761,6 +762,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
} else {
history.push(this._url);
}
+ this.props.docView.props.Document._scrollTop = 0;
future && (future.length = 0);
}
this._url = url;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b62fde4c8..4880d342c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -277,30 +277,27 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@action
onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
const where = [de.x, de.y];
- let targInd = -1;
- let plusOne = 0;
+ let dropInd = -1;
+ let dropAfter = 0;
if (de.complete.docDragData) {
this._docXfs.map((cd, i) => {
const pos = cd.dxf().inverse().transformPoint(-2 * this.gridGap, -2 * this.gridGap);
const pos1 = cd.dxf().inverse().transformPoint(cd.width(), cd.height());
- if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
- targInd = i;
+ if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && (i === this._docXfs.length - 1 || where[1] < pos1[1])) {
+ dropInd = i;
const axis = this.Document._viewType === CollectionViewType.Masonry ? 0 : 1;
- plusOne = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0;
+ dropAfter = where[axis] > (pos[axis] + pos1[axis]) / 2 ? 1 : 0;
}
});
if (super.onInternalDrop(e, de)) {
const newDocs = de.complete.docDragData.droppedDocuments;
const docs = this.childDocList;
DragManager.docsBeingDragged = [];
- if (docs) {
- newDocs.map((doc, i) => {
- targInd = targInd === -1 ? docs.length : targInd;
- const srcInd = docs.indexOf(doc);
- if (targInd !== -1) targInd = i === 0 ? docs.indexOf(this.filteredChildren[targInd]) : docs.indexOf(newDocs[0]) + 1;
- docs.splice(srcInd, 1);
- docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
- });
+ if (docs && newDocs.length) {
+ const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
+ const offset = newDocs.reduce((off, ndoc) => this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off, 0);
+ newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1));
+ docs.splice(insertInd - offset, 0, ...newDocs);
}
}
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index f3e563422..5c3c70be2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -344,12 +344,16 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
this.props.addDocument(htmlDoc);
if (srcWeb) {
- const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0]?.contentDocument?.getSelection()?.focusNode as any);
+ const iframe = SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0];
+ const focusNode = (iframe?.contentDocument?.getSelection()?.focusNode as any);
if (focusNode) {
- const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
- const x = (rect?.x || 0);
- const y = NumCast(srcWeb._scrollTop) + (rect?.y || 0);
- const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: 75, _height: 40, x, y, annotationOn: srcWeb });
+ const rects = iframe?.contentWindow?.getSelection()?.getRangeAt(0).getClientRects();
+ "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
+ const x = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x < x ? r.x : x, undefined as any)) || 0;
+ const y = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y < y ? r.y : y, undefined as any)) || 0);
+ const r = (rects && Array.from(rects).reduce((x: any, r: DOMRect) => x === undefined || r.x + r.width > x ? r.x + r.width : x, undefined as any)) || 0;
+ const b = NumCast(srcWeb._scrollTop) + ((rects && Array.from(rects).reduce((y: any, r: DOMRect) => y === undefined || r.y + r.height > y ? r.y + r.height : y, undefined as any)) || 0);
+ const anchor = Docs.Create.FreeformDocument([], { _backgroundColor: "transparent", _width: r - x, _height: b - y, x, y, annotationOn: srcWeb });
anchor.context = srcWeb;
const key = Doc.LayoutFieldKey(srcWeb);
Doc.AddDocToList(srcWeb, key + "-annotations", anchor);
@@ -406,7 +410,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
this.addDocument(alias);
} else {
console.log("Adding ...");
- const newDoc = Docs.Create.WebDocument(uriList, {
+ const newDoc = Docs.Create.WebDocument(uriList.split("#annotations:")[0], {// clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
...options,
_fitWidth: true,
title: uriList.split("#annotations:")[0],
@@ -416,7 +420,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
useCors: true
});
console.log(" ... " + newDoc.title);
- newDoc.data = new WebField(uriList.split("#annotations:")[0]); // clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig)
console.log(" ... " + this.addDocument(newDoc) + " " + newDoc.title);
}
return;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index cd84d2d78..d816dea0d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -6,7 +6,7 @@ import { clamp } from 'lodash';
import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
-import { DataSym, Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { DataSym, Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc";
import { Id } from '../../../fields/FieldSymbols';
import { FieldId } from "../../../fields/RefField";
import { listSpec } from '../../../fields/Schema';
@@ -122,13 +122,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
/**
* Adds a document to the presentation view
**/
- @undoBatch
@action
- public static PinDoc(doc: Doc, unpin = false, audioRange?: boolean) {
+ public static async PinDoc(doc: Doc, unpin = false, audioRange?: boolean) {
if (unpin) console.log('TODO: Remove UNPIN from this location');
//add this new doc to props.Document
const curPres = CurrentUserUtils.ActivePresentation;
if (curPres) {
+ const batch = UndoManager.StartBatch("pinning doc");
const pinDoc = Doc.MakeAlias(doc);
pinDoc.presentationTargetDoc = doc;
pinDoc.title = doc.title;
@@ -140,11 +140,17 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.presEndTime = doc.duration;
}
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
- const curPresDocView = DocumentManager.Instance.getDocumentView(curPres);
- if (!curPresDocView) {
+ const dview = CollectionDockingView.Instance.props.Document;
+ const fieldKey = CollectionDockingView.Instance.props.fieldKey;
+ const sublists = DocListCast(dview[fieldKey]);
+ const tabs = Cast(sublists[0], Doc, null);
+ const tabdocs = await DocListCastAsync(tabs.data);
+ if (!tabdocs?.includes(curPres)) {
+ tabdocs?.push(curPres); // bcz: Argh! this is annoying. if multiple documents are pinned, this will get called multiple times before the presentation view is drawn. Thus it won't be in the tabdocs list and it will get created multple times. so need to explicilty add the presbox to the list of open tabs
CollectionDockingView.AddSplit(curPres, "right");
}
- DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
+ DocumentManager.Instance.jumpToDocument(doc, false, undefined);
+ batch.end();
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 56624f42d..fdcfb00d8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss";
import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
export const panZoomSchema = createSchema({
_panX: "number",
@@ -803,7 +804,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
@action
onPointerWheel = (e: React.WheelEvent): void => {
- if (this.layoutDoc._lockedTransform || this.props.Document.inOverlay || this.props.Document.treeViewOutlineMode) return;
+ if (this.layoutDoc._lockedTransform || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode) return;
if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
e.stopPropagation();
}
@@ -839,7 +840,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
else if (ranges.yrange.max <= (panY - panelDim[1] / 2)) panY = ranges.yrange.min - panelDim[1] / 2;
}
}
- if (!this.layoutDoc._lockedTransform || this.Document.inOverlay) {
+ if (!this.layoutDoc._lockedTransform || CurrentUserUtils.OverlayDocs.includes(this.Document)) {
this.Document._viewTransition = panType;
const scale = this.getLocalTransform().inverse().Scale;
const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index fd4fa0c7e..d8e44e781 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -54,7 +54,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
<FontAwesomeIcon icon="font" size="lg" />
</button>
</Tooltip>,
- <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected view</div></>} placement="bottom">
+ <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin the selected region to presentation</div></>} placement="bottom">
<button
className="antimodeMenu-button"
onPointerDown={this.pinWithView}>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 7c64fd429..42a601aa2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -397,6 +397,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
pinDoc.presentationTargetDoc = doc;
pinDoc.presMovement = PresMovement.Zoom;
pinDoc.context = curPres;
+ pinDoc.title = doc.title;
Doc.AddDocToList(curPres, "data", pinDoc);
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
if (!DocumentManager.Instance.getDocumentView(curPres)) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d227d3a8e..08a4a7e23 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -423,7 +423,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this._downX = touch.clientX;
this._downY = touch.clientY;
if (!e.nativeEvent.cancelBubble) {
- if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) e.stopPropagation();
+ if ((this.active || this.layoutDoc.onDragStart || this.onClickHandler) && !e.ctrlKey && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) e.stopPropagation();
this.removeMoveListeners();
this.addMoveListeners();
this.removeEndListeners();
@@ -438,7 +438,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (e.cancelBubble && this.active) {
this.removeMoveListeners();
}
- else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) {
+ else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart || this.onClickHandler) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
const touch = me.touchEvent.changedTouches.item(0);
if (touch && (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3)) {
@@ -554,7 +554,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if ((this.active || this.layoutDoc.onDragStart) &&
!e.ctrlKey &&
(e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
- !this.layoutDoc.inOverlay) {
+ !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
e.stopPropagation();
if (SelectionManager.IsSelected(this, true) && this.layoutDoc._viewType !== CollectionViewType.Docking) e.preventDefault(); // goldenlayout needs to be able to move its tabs, so can't preventDefault for it
}
@@ -573,7 +573,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (e.cancelBubble && this.active) {
document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
}
- else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart) && !this.layoutDoc.lockedPosition && !this.layoutDoc.inOverlay) {
+ else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.layoutDoc.onDragStart) && !this.layoutDoc.lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
document.removeEventListener("pointermove", this.onPointerMove);
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 9a8b861ba..961d1707b 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -56,6 +56,7 @@ $light-background: #ececec;
letter-spacing: 0;
display: flex;
align-items: center;
+ justify-content: center;
transition: 0.5s;
}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 01a7bed8c..180ebd6f1 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -28,7 +28,6 @@ import { AudioBox } from "./AudioBox";
import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
-import { VideoBox } from "./VideoBox";
export enum PresMovement {
Zoom = "zoom",
@@ -38,12 +37,12 @@ export enum PresMovement {
}
export enum PresEffect {
- Fade = "fade",
- Flip = "flip",
- Rotate = "rotate",
- Bounce = "bounce",
- Roll = "roll",
- None = "none",
+ Fade = "Fade",
+ Flip = "Flip",
+ Rotate = "Rotate",
+ Bounce = "Bounce",
+ Roll = "Roll",
+ None = "None",
}
enum PresStatus {
@@ -52,6 +51,11 @@ enum PresStatus {
Edit = "edit"
}
+enum PresColors {
+ Active = "#AEDDF8",
+
+}
+
type PresBoxSchema = makeInterface<[typeof documentSchema]>;
const PresBoxDocument = makeInterface(documentSchema);
@@ -64,19 +68,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@observable _isChildActive = false;
@observable _moveOnFromAudio: boolean = true;
@observable _presTimer!: NodeJS.Timeout;
+ @observable _presKeyEventsActive: boolean = false;
@observable _selectedArray: Doc[] = [];
@observable _sortedSelectedArray: Doc[] = [];
@observable _eleArray: HTMLElement[] = [];
@observable _dragArray: HTMLElement[] = [];
+ @observable _pathBoolean: boolean = false;
+ @observable _expandBoolean: boolean = false;
@observable private transitionTools: boolean = false;
@observable private newDocumentTools: boolean = false;
@observable private progressivizeTools: boolean = false;
- @observable private presentTools: boolean = false;
- @observable private pathBoolean: boolean = false;
@observable private openMovementDropdown: boolean = false;
@observable private openEffectDropdown: boolean = false;
+ @observable private presentTools: boolean = false;
@computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); }
@computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); }
@computed get activeItem() { return Cast(this.childDocs[this.itemIndex], Doc, null); }
@@ -121,19 +127,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
@computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
+ @action
componentWillUnmount() {
document.removeEventListener("keydown", this.keyEvents, true);
+ this._presKeyEventsActive = false;
// Turn of progressivize editors
this.turnOffEdit(true);
}
- componentDidMount = async () => {
+ @action
+ componentDidMount = () => {
this.rootDoc.presBox = this.rootDoc;
this.rootDoc._forceRenderEngine = "timeline";
this.rootDoc._replacedChrome = "replaced";
this.layoutDoc.presStatus = PresStatus.Edit;
this.layoutDoc._gridGap = 0;
this.layoutDoc._yMargin = 0;
+ document.addEventListener("keydown", this.keyEvents, true);
+ this._presKeyEventsActive = true;
this.turnOffEdit(true);
DocListCastAsync((Doc.UserDoc().myPresentations as Doc).data).then(pres =>
!pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc));
@@ -147,7 +158,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
/**
* Called when the user moves to the next slide in the presentation trail.
*/
- @undoBatch
@action
next = () => {
this.updateCurrentPresentation();
@@ -199,7 +209,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
* Design choice: If there are frames within the presentation, moving back will not
* got back through the frames but instead directly to the next point in the presentation.
*/
- @undoBatch
@action
back = () => {
this.updateCurrentPresentation();
@@ -291,7 +300,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
};
// If openDocument is selected then it should open the document for the user
if (activeItem.openDocument) {
+ const presStatus = this.rootDoc.presStatus;
openInTab();
+ // this still needs some fixing
+ setTimeout(() => {
+ const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc);
+ if (presDocView) SelectionManager.SelectDoc(presDocView, false);
+ this.rootDoc.presStatus = presStatus;
+ }, 2000);
} else
//docToJump stayed same meaning, it was not in the group or was the last element in the group
if (activeItem.zoomProgressivize && this.rootDoc.presStatus !== PresStatus.Edit) {
@@ -412,7 +428,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
//The function that starts or resets presentaton functionally, depending on presStatus of the layoutDoc
- @undoBatch
@action
startAutoPres = (startSlide: number) => {
this.updateCurrentPresentation();
@@ -466,20 +481,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@action togglePath = (srcContext: Doc, off?: boolean) => {
if (off) {
- this.pathBoolean = false;
+ this._pathBoolean = false;
srcContext.presPathView = false;
} else {
- this.pathBoolean = !this.pathBoolean;
- srcContext.presPathView = this.pathBoolean;
+ runInAction(() => this._pathBoolean = !this._pathBoolean);
+ srcContext.presPathView = this._pathBoolean;
}
}
- @undoBatch
@action toggleExpandMode = () => {
- this.rootDoc.expandBoolean = !this.rootDoc.expandBoolean;
+ runInAction(() => this._expandBoolean = !this._expandBoolean);
this.childDocs.forEach((doc) => {
- if (this.rootDoc.expandBoolean) doc.presExpandInlineButton = true;
- else if (!this.rootDoc.expandBoolean) doc.presExpandInlineButton = false;
+ doc.presExpandInlineButton = this._expandBoolean;
});
}
@@ -504,15 +517,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
/**
* The method called to open the presentation as a minimized view
*/
- @undoBatch
@action
updateMinimize = () => {
const docView = DocumentManager.Instance.getDocumentView(this.layoutDoc);
- if (this.layoutDoc.inOverlay) {
+ if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
this.layoutDoc.presStatus = PresStatus.Edit;
Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
CollectionDockingView.AddSplit(this.rootDoc, "right");
- this.layoutDoc.inOverlay = false;
} else if (this.layoutDoc.context && docView) {
this.layoutDoc.presStatus = PresStatus.Edit;
clearTimeout(this._presTimer);
@@ -540,7 +551,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
* Called when the user changes the view type
* Either 'List' (stacking) or 'Slides' (carousel)
*/
- @undoBatch
+ // @undoBatch
viewChanged = action((e: React.ChangeEvent) => {
//@ts-ignore
const viewType = e.target.selectedOptions[0].value as CollectionViewType;
@@ -550,32 +561,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
if (viewType === CollectionViewType.Stacking) this.layoutDoc._gridGap = 0;
});
- /**
- * When the movement dropdown is changes
- */
- @undoBatch
- updateMovement = action((movement: any, activeItem: Doc, targetDoc: Doc) => {
- switch (movement) {
- case PresMovement.Zoom: //Pan and zoom
- activeItem.presMovement = PresMovement.Zoom;
- break;
- case PresMovement.Pan: //Pan
- activeItem.presMovement = PresMovement.Pan;
- break;
- case PresMovement.Jump: //Jump Cut
- activeItem.presJump = true;
- activeItem.presMovement = PresMovement.Jump;
- break;
- case PresMovement.None: default:
- activeItem.presMovement = PresMovement.None;
- break;
- }
- });
setMovementName = action((movement: any, activeItem: Doc): string => {
let output: string = 'none';
switch (movement) {
- case PresMovement.Zoom: output = 'Zoom'; break; //Pan and zoom
+ 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 = 'None'; break; //None
@@ -589,9 +579,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
addDocumentFilter = (doc: Doc | Doc[]) => {
const docs = doc instanceof Doc ? [doc] : doc;
docs.forEach((doc, i) => {
- if (this.childDocs.includes(doc)) {
- if (docs.length === i + 1) return false;
- } else if (doc.type === DocumentType.LABEL) {
+ if (doc.type === DocumentType.LABEL) {
const audio = Cast(doc.annotationOn, Doc, null);
if (audio) {
audio.aliasOf instanceof Doc;
@@ -605,7 +593,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
} else {
doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
!this.childDocs.includes(doc) && (doc.presMovement = PresMovement.Zoom);
- if (this.rootDoc.expandBoolean) doc.presExpandInlineButton = true;
+ if (this._expandBoolean) doc.presExpandInlineButton = true;
}
});
return true;
@@ -678,72 +666,94 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.selectPres();
}
+ //regular click
+ @action
+ regularSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean) => {
+ this._selectedArray.splice(0, this._selectedArray.length, doc);
+ this._eleArray.splice(0, this._eleArray.length, ref);
+ this._dragArray.splice(0, this._dragArray.length, drag);
+ focus && this.selectElement(doc);
+ this.selectPres();
+ }
+
+ modifierSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement, focus: boolean, cmdClick: boolean, shiftClick: boolean) => {
+ if (cmdClick) this.multiSelect(doc, ref, drag);
+ else if (shiftClick) this.shiftSelect(doc, ref, drag);
+ else this.regularSelect(doc, ref, drag, focus);
+ }
+
// Key for when the presentaiton is active
- @undoBatch
- keyEvents = action(async (e: KeyboardEvent) => {
+ @action
+ keyEvents = (e: KeyboardEvent) => {
if (e.target instanceof HTMLInputElement) return;
let handled = false;
const anchorNode = document.activeElement as HTMLDivElement;
if (anchorNode && anchorNode.className?.includes("lm_title")) return;
- if (e.keyCode === 27) { // Escape key
- if (this.layoutDoc.inOverlay) { this.updateMinimize(); }
- else if (this.layoutDoc.presStatus === "edit") { this._selectedArray = []; this._eleArray = []; this._dragArray = []; }
- else this.layoutDoc.presStatus = "edit";
- if (this._presTimer) clearTimeout(this._presTimer);
- handled = true;
- } if ((e.metaKey || e.altKey) && e.keyCode === 65) { // Ctrl-A to select all
- if (this.layoutDoc.presStatus === "edit") {
- this._selectedArray = this.childDocs;
+ switch (e.key) {
+ case "Backspace":
+ if (this.layoutDoc.presStatus === "edit") {
+ runInAction(() => {
+ for (const doc of this._selectedArray) {
+ this.removeDocument(doc);
+ }
+ this._selectedArray = [];
+ this._eleArray = [];
+ this._dragArray = [];
+ });
+ handled = true;
+ }
+ break;
+ case "Escape":
+ if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) { this.updateMinimize(); }
+ else if (this.layoutDoc.presStatus === "edit") { this._selectedArray = []; this._eleArray = []; this._dragArray = []; }
+ else this.layoutDoc.presStatus = "edit";
+ if (this._presTimer) clearTimeout(this._presTimer);
handled = true;
- }
- } if (e.keyCode === 37 || e.keyCode === 38) { // left(37) / a(65) / up(38) to go back
- this.back();
- if (this._presTimer) clearTimeout(this._presTimer);
- handled = true;
- } if (e.keyCode === 39 || e.keyCode === 40) { // right (39) / d(68) / down(40) to go to next
- this.next();
- if (this._presTimer) clearTimeout(this._presTimer);
- handled = true;
- } if (e.keyCode === 32) { // spacebar to 'present' or autoplay
- if (this.layoutDoc.presStatus === "manual") this.startAutoPres(this.itemIndex);
- else if (this.layoutDoc.presStatus === "auto") if (this._presTimer) clearTimeout(this._presTimer);
- handled = true;
- } if (e.keyCode === 8) { // delete selected items
- if (this.layoutDoc.presStatus === "edit") {
- await Promise.all<boolean>(this._selectedArray.map((doc, i): boolean => {
- const removed: boolean = this.removeDocument(doc);
- console.log("Is removed? : " + i + " | " + removed);
- return removed;
- }));
- action(() => this._selectedArray = []);
- action(() => this._eleArray = []);
- action(() => this._dragArray = []);
+ break;
+ case "Down": case "ArrowDown":
+ case "Right": case "ArrowRight":
+ if (e.shiftKey) { // TODO: update to work properly
+ this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) + 1;
+ this._selectedArray.push(this.childDocs[this.rootDoc._itemIndex]);
+ } else {
+ this.next();
+ if (this._presTimer) clearTimeout(this._presTimer);
+ }
handled = true;
- }
- } if (handled) {
+ break;
+ case "Up": case "ArrowUp":
+ case "Left": case "ArrowLeft":
+ if (e.shiftKey) { // TODO: update to work properly
+ this.rootDoc._itemIndex = NumCast(this.rootDoc._itemIndex) - 1;
+ this._selectedArray.push(this.childDocs[this.rootDoc._itemIndex]);
+ } else {
+ this.back();
+ if (this._presTimer) clearTimeout(this._presTimer);
+ }
+ handled = true;
+ break;
+ case "Spacebar": case " ":
+ if (this.layoutDoc.presStatus === "manual") this.startAutoPres(this.itemIndex);
+ else if (this.layoutDoc.presStatus === "auto") if (this._presTimer) clearTimeout(this._presTimer);
+ handled = true;
+ break;
+ case "a":
+ if ((e.metaKey || e.altKey) && this.layoutDoc.presStatus === "edit") {
+ this._selectedArray = this.childDocs;
+ handled = true;
+ }
+ default:
+ break;
+ }
+ if (handled) {
e.stopPropagation();
e.preventDefault();
- } if ((e.keyCode === 37 || e.keyCode === 38) && e.shiftKey) { // left(37) / a(65) / up(38) to go back
- if (this.layoutDoc.presStatus === "edit" && this._selectedArray.length > 0) {
- const index = this.childDocs.indexOf(this._selectedArray[this._selectedArray.length]);
- if ((index - 1) > 0) this._selectedArray.push(this.childDocs[index - 1]);
- }
- handled = true;
- } if ((e.keyCode === 39 || e.keyCode === 40) && e.shiftKey) { // left(37) / a(65) / up(38) to go back
- if (this.layoutDoc.presStatus === "edit" && this._selectedArray.length > 0) {
- const index = this.childDocs.indexOf(this._selectedArray[this._selectedArray.length]);
- if ((index - 1) > 0) {
- this._selectedArray.push(this.childDocs[index - 1]);
- }
- }
- handled = true;
}
- });
+ }
/**
*
*/
- @undoBatch
@action
viewPaths = () => {
const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
@@ -755,9 +765,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
// Adds the index in the pres path graphically
@computed get order() {
const order: JSX.Element[] = [];
- this.childDocs.forEach((doc, index) => {
+ this.childDocs.filter(doc => Cast(doc.presentationTargetDoc, Doc, null)).forEach((doc, index) => {
const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
- const srcContext = Cast(tagDoc?.context, Doc, null);
+ const srcContext = Cast(tagDoc.context, Doc, null);
const width = NumCast(tagDoc._width) / 10;
const height = Math.max(NumCast(tagDoc._height) / 10, 15);
const edge = Math.max(width, height);
@@ -823,44 +833,162 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
* 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: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- 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
+ // onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => {
+ // e.stopPropagation();
+ // const activeItem: Doc = this.activeItem;
+ // const targetDoc: Doc = this.targetDoc;
+ // 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;
+ // }
+ // }
+ // }
// Converts seconds to ms and updates presTransition
- @undoBatch
setTransitionTime = (number: String, change?: number) => {
let timeInMS = Number(number) * 1000;
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 10000) timeInMS = 10000;
- if (this.activeItem) this.activeItem.presTransition = timeInMS;
+ this._selectedArray?.forEach((doc) => doc.presTransition = timeInMS);
}
// Converts seconds to ms and updates presDuration
- @undoBatch
setDurationTime = (number: String, change?: number) => {
let timeInMS = Number(number) * 1000;
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 20000) timeInMS = 20000;
- if (this.activeItem) this.activeItem.presDuration = timeInMS;
+ this._selectedArray?.forEach((doc) => doc.presDuration = timeInMS);
}
+ /**
+ * When the movement dropdown is changes
+ */
+ @undoBatch
+ updateMovement = action((movement: any, all?: boolean) => {
+ if (all) {
+ this.childDocs.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;
+ }
+ });
+ } else {
+ this._selectedArray?.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
+ updateHideBefore = (activeItem: Doc) => {
+ activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton;
+ this._selectedArray?.forEach((doc) => doc.presHideTillShownButton = activeItem.presHideTillShownButton);
+ }
+
+ @undoBatch
+ @action
+ updateHideAfter = (activeItem: Doc) => {
+ activeItem.presHideAfterButton = !activeItem.presHideAfterButton;
+ this._selectedArray?.forEach((doc) => doc.presHideAfterButton = activeItem.presHideAfterButton);
+ }
+
+ @undoBatch
+ @action
+ updateOpenDoc = (activeItem: Doc) => {
+ activeItem.openDocument = !activeItem.openDocument;
+ this._selectedArray.forEach((doc) => {
+ doc.openDocument = activeItem.openDocument;
+ });
+ }
+
+ @undoBatch
+ @action
+ updateEffect = (effect: any, all?: boolean) => {
+ if (all) {
+ this.childDocs.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;
+ }
+ });
+ } else {
+ this._selectedArray?.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;
+ }
+ });
+ }
+ }
@computed get transitionDropdown() {
const activeItem: Doc = this.activeItem;
@@ -879,24 +1007,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
{this.setMovementName(activeItem.presMovement, activeItem)}
<FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} />
<div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None, activeItem, targetDoc)}>None</div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom, activeItem, targetDoc)}>Pan and Zoom</div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan, activeItem, targetDoc)}>Pan</div>
- <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump, activeItem, targetDoc)}>Jump cut</div>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None)}>None</div>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom)}>Pan {"&"} Zoom</div>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan)}>Pan</div>
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump)}>Jump cut</div>
</div>
</div>
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "inline-flex" : "none" }}>
<div className="presBox-subheading">Transition Speed</div>
<div className="ribbon-property">
<input className="presBox-input"
+ onInput={() => console.log('onInput')}
+ onDrag={() => console.log('onDrag')}
+ onDragEnd={() => console.log('onDragEnd')}
+ onBlur={() => console.log('onBlur')}
+ onCompositionEnd={() => console.log('onCompEnd')}
type="number" value={transitionSpeed}
onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
</div>
<div className="ribbon-propertyUpDown">
- <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), 1000)}>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), 1000))}>
<FontAwesomeIcon icon={"caret-up"} />
</div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.setTransitionTime(String(transitionSpeed), -1000)}>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setTransitionTime(String(transitionSpeed), -1000))}>
<FontAwesomeIcon icon={"caret-down"} />
</div>
</div>
@@ -911,23 +1044,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<div className="ribbon-box">
Visibility {"&"} Duration
<div className="ribbon-doubleButton">
- <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={undoBatch(() => activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton)}>Hide before</div></Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={undoBatch(() => activeItem.presHideAfterButton = !activeItem.presHideAfterButton)}>Hide after</div></Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={undoBatch(() => activeItem.openDocument = !activeItem.openDocument)}>Open</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => this.updateHideBefore(activeItem)}>Hide before</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => this.updateHideAfter(activeItem)}>Hide after</div></Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => this.updateOpenDoc(activeItem)}>Open</div></Tooltip>
</div>
<div className="ribbon-doubleButton" >
<div className="presBox-subheading">Slide Duration</div>
<div className="ribbon-property">
<input className="presBox-input"
type="number" value={duration}
- // onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
onChange={action((e) => this.setDurationTime(e.target.value))} /> s
</div>
<div className="ribbon-propertyUpDown">
- <div className="ribbon-propertyUpDownItem" onClick={() => this.setDurationTime(String(duration), 1000)}>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), 1000))}>
<FontAwesomeIcon icon={"caret-up"} />
</div>
- <div className="ribbon-propertyUpDownItem" onClick={() => this.setDurationTime(String(duration), -1000)}>
+ <div className="ribbon-propertyUpDownItem" onClick={undoBatch(() => this.setDurationTime(String(duration), -1000))}>
<FontAwesomeIcon icon={"caret-down"} />
</div>
</div>
@@ -945,12 +1077,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
{effect}
<FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openEffectDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} />
<div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? "grid" : "none" }} onPointerDown={e => e.stopPropagation()}>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'None')}>None</div>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'Fade')}>Fade In</div>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'Flip')}>Flip</div>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'Rotate')}>Rotate</div>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'Bounce')}>Bounce</div>
- <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={undoBatch(() => targetDoc.presEffect = 'Roll')}>Roll</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.None)}>None</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>Fade In</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>Flip</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>Rotate</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>Bounce</div>
+ <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>Roll</div>
</div>
</div>
<div className="ribbon-doubleButton" style={{ display: effect === 'None' ? "none" : "inline-flex" }}>
@@ -968,9 +1100,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
</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)}>
+ {/* <div className={this._selectedArray.length === 0 ? "ribbon-final-button" : "ribbon-final-button-hidden"} onClick={() => this.applyTo(this._selectedArray)}>
Apply to selected
- </div>
+ </div> */}
<div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}>
Apply to all
</div>
@@ -997,17 +1129,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
applyTo = (array: Doc[]) => {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
+ this.updateMovement(activeItem.presMovement, true);
+ this.updateEffect(targetDoc.presEffect, 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;
- tagDoc.presEffect = targetDoc.presEffect;
tagDoc.presEffectDirection = targetDoc.presEffectDirection;
- tagDoc.presMovement = targetDoc.presMovement;
- curDoc.presMovement = activeItem.presMovement;
- this.updateMovement(activeItem.presMovement, curDoc, tagDoc);
curDoc.presHideTillShownButton = activeItem.presHideTillShownButton;
curDoc.presHideAfterButton = activeItem.presHideAfterButton;
}
@@ -1022,12 +1152,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<div>
<div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div className="ribbon-box">
- <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
+ <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
<div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? "#aedef8" : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
<div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : "#aedef8" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
</div>
- {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? "#aedef8" : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)}
- {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+ {/* {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? "#aedef8" : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)} */}
+ {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
<div className="presBox-subheading">Start time</div>
<div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
<input className="presBox-input"
@@ -1036,7 +1166,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })} />
</div>
</div> : (null)}
- {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+ {targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
<div className="presBox-subheading">End time</div>
<div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
<input className="presBox-input"
@@ -1255,10 +1385,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
@computed get presentDropdown() {
return (
<div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
- <div className="dropdown-play-button" onClick={(action(() => { this.updateMinimize(); this.turnOffEdit(true); }))}>
+ <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.updateMinimize(); this.turnOffEdit(true); }))}>
Minimize
</div>
- <div className="dropdown-play-button" onClick={(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); }))}>
+ <div className="dropdown-play-button" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); }))}>
Sidebar view
</div>
</div>
@@ -1266,7 +1396,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
}
// Case in which the document has keyframes to navigate to next key frame
- @undoBatch
@action
nextKeyframe = (tagDoc: Doc, curDoc: Doc): void => {
const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
@@ -1282,7 +1411,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
}
- @undoBatch
@action
prevKeyframe = (tagDoc: Doc, actItem: Doc): void => {
const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
@@ -1604,7 +1732,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
return tags;
}
- @undoBatch
@action
nextAppearFrame = (doc: Doc, i: number): void => {
// const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
@@ -1617,7 +1744,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
this.updateOpacityList(doc["opacity-indexed"], NumCast(doc.appearFrame));
}
- @undoBatch
@action
prevAppearFrame = (doc: Doc, i: number): void => {
// const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
@@ -1678,6 +1804,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Presentation Panel" : "Open Presentation Panel";
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
+ const isMini: boolean = this.toolbarWidth <= 100;
+ const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
return (mode === CollectionViewType.Carousel3D) ? (null) : (
<div id="toolbarContainer" className={'presBox-toolbar'} style={{ display: this.layoutDoc.presStatus === "edit" ? "inline-flex" : "none" }}>
{/* <Tooltip title={<><div className="dash-tooltip">{"Add new slide"}</div></>}><div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={action(() => this.newDocumentTools = !this.newDocumentTools)}>
@@ -1685,23 +1813,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
<FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
</div></Tooltip> */}
<Tooltip title={<><div className="dash-tooltip">{"View paths"}</div></>}>
- <div style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3 }} className={`toolbar-button ${this.pathBoolean ? "active" : ""}`} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined}>
+ <div style={{ opacity: this.childDocs.length > 1 ? 1 : 0.3, color: this._pathBoolean ? '#AEDDF8' : 'white', width: isMini ? "100%" : undefined }} className={"toolbar-button"} onClick={this.childDocs.length > 1 ? this.viewPaths : undefined}>
<FontAwesomeIcon icon={"exchange-alt"} />
</div>
</Tooltip>
- <div className="toolbar-divider" />
- <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
- <div className={`toolbar-button ${this.rootDoc.expandBoolean ? "active" : ""}`} onClick={this.toggleExpandMode}>
- {/* <FontAwesomeIcon icon={this.rootDoc.expandBoolean ? "eye-slash" : "eye"} /> */}
- <FontAwesomeIcon icon={"eye"} />
- </div>
- </Tooltip>
- <div className="toolbar-divider" />
- <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}>
- <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
- <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? '#AEDDF8' : 'white' }} />
- </div>
- </Tooltip>
+ {isMini ? (null) :
+ <>
+ <div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{this._expandBoolean ? "Minimize all" : "Expand all"}</div></>}>
+ <div className={"toolbar-button"}
+ style={{ color: this._expandBoolean ? '#AEDDF8' : 'white' }}
+ onClick={this.toggleExpandMode}>
+ {/* <FontAwesomeIcon icon={this.rootDoc.expandBoolean ? "eye-slash" : "eye"} /> */}
+ <FontAwesomeIcon icon={"eye"} />
+ </div>
+ </Tooltip>
+ <div className="toolbar-divider" />
+ <Tooltip title={<><div className="dash-tooltip">{presKeyEvents ? "Key events are active" : "Keys are not active - click anywhere on the presentation trail to activate keys"}</div></>}>
+ <div className="toolbar-button" style={{ cursor: 'default', position: 'absolute', right: 30, fontSize: 16 }}>
+ <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"keyboard"} style={{ color: presKeyEvents ? '#AEDDF8' : 'white' }} />
+ </div>
+ </Tooltip>
+ <Tooltip title={<><div className="dash-tooltip">{propTitle}</div></>}>
+ <div className="toolbar-button" style={{ position: 'absolute', right: 4, fontSize: 16 }} onClick={this.toggleProperties}>
+ <FontAwesomeIcon className={"toolbar-thumbtack"} icon={propIcon} style={{ color: CurrentUserUtils.propertiesWidth > 0 ? '#AEDDF8' : 'white' }} />
+ </div>
+ </Tooltip>
+ </>
+ }
</div>
);
}
@@ -1713,23 +1852,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
*/
@computed get topPanel() {
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
+ const isMini: boolean = this.toolbarWidth <= 100;
return (
<div className="presBox-buttons" style={{ display: this.rootDoc._chromeStatus === "disabled" ? "none" : undefined }}>
- <select className="presBox-viewPicker"
+ {isMini ? (null) : <select className="presBox-viewPicker"
style={{ display: this.layoutDoc.presStatus === "edit" ? "block" : "none" }}
onPointerDown={e => e.stopPropagation()}
onChange={this.viewChanged}
value={mode}>
<option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Stacking}>List</option>
<option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>3D Carousel</option>
- </select>
+ </select>}
<div className="presBox-presentPanel" style={{ opacity: this.childDocs.length > 0 ? 1 : 0.3 }}>
<span className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`}>
<div className="presBox-button-left" onClick={() => (this.childDocs.length > 0) && (this.layoutDoc.presStatus = "manual")}>
<FontAwesomeIcon icon={"play-circle"} />
<div style={{ display: this.props.PanelWidth() > 200 ? "inline-flex" : "none" }}>&nbsp; Present</div>
</div>
- {(mode === CollectionViewType.Carousel3D) ? (null) : <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`}
+ {(mode === CollectionViewType.Carousel3D || isMini) ? (null) : <div className={`presBox-button-right ${this.presentTools ? "active" : ""}`}
onClick={(action(() => {
if (this.childDocs.length > 0) this.presentTools = !this.presentTools;
}))}>
@@ -1836,8 +1976,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
{this.playButtonFrames}
</div>
<div className="presPanel-divider"></div>
- {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={() => { this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }}>EXIT</div>
- : <div className="presPanel-button" onClick={() => this.layoutDoc.presStatus = "edit"}>
+ {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }))}>EXIT</div>
+ : <div className="presPanel-button" onClick={undoBatch(action(() => this.layoutDoc.presStatus = "edit"))}>
<FontAwesomeIcon icon={"times"} />
</div>}
</div>);
@@ -1855,9 +1995,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
// needed to ensure that the childDocs are loaded for looking up fields
this.childDocs.slice();
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
- return this.layoutDoc.inOverlay ?
+ const presKeyEvents: boolean = (this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.UserDoc().activePresentation);
+ return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ?
<div className="miniPres">
- <div className="presPanelOverlay" style={{ display: "inline-flex", height: 35, background: '#323232', top: 0, zIndex: 3000000 }}>
+ <div className="presPanelOverlay" style={{ display: "inline-flex", height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px #AEDDF8' : undefined }}>
<Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? '#AEDDF8' : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
<div className="presPanel-divider"></div>
<div className="presPanel-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
@@ -1869,11 +2010,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
{this.playButtonFrames}
</div>
<div className="presPanel-divider"></div>
- <div className="presPanel-button-text" onClick={() => { this.updateMinimize(); this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }}>EXIT</div>
+ <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.updateMinimize(); this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }))}>EXIT</div>
</div>
</div>
:
- <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
+ <div className="presBox-cont" style={{ minWidth: CurrentUserUtils.OverlayDocs.includes(this.layoutDoc) ? 240 : undefined }} >
{this.topPanel}
{this.toolbar}
{this.newDocumentToolbarDropdown}
@@ -1900,7 +2041,7 @@ 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 ? 30 : 26;
+ if (field === 'presCollapsedHeight') return container._viewType === CollectionViewType.Stacking ? 35 : 31;
if (field === 'presStatus') return container.presStatus;
if (field === '_itemIndex') return container._itemIndex;
if (field === 'presBox') return container;
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 0c0854ac2..05714f665 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,5 +1,8 @@
.videoBox {
transform-origin: top left;
+ width: 100%;
+ height: 100%;
+ position: relative;
.videoBox-viewer {
opacity: 0.99; // hack! overcomes some kind of Chrome weirdness where buttons (e.g., snapshot) disappear at some point as the video is resized larger
}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 168c87764..30e8db645 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -358,12 +358,20 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
return this.addDocument(doc);
}
+ @computed get contentScaling() { return this.props.ContentScaling(); }
contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
render() {
return (<div className="videoBox" onContextMenu={this.specificContextMenu}
- style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
+ style={{
+ transform: this.props.PanelWidth() ? undefined : `scale(${this.contentScaling})`,
+ width: this.props.PanelWidth() ? undefined : `${100 / this.contentScaling}%`,
+ height: this.props.PanelWidth() ? undefined : `${100 / this.contentScaling}%`,
+ pointerEvents: this.layoutDoc._isBackground ? "none" : undefined,
+ borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.contentScaling}px`
+ }} >
<div className="videoBox-viewer" >
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ forceScaling={true}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
annotationsKey={this.annotationKey}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index eb9e08e20..de5546fa9 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -72,14 +72,23 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
constructor(props: any) {
super(props);
- Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || 850);
- Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
+ if (this.dataDoc[this.fieldKey] instanceof WebField) {
+ Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || 850);
+ Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
+ }
}
iframeLoaded = action((e: any) => {
const iframe = this._iframeRef.current;
if (iframe && iframe.contentDocument) {
iframe.setAttribute("enable-annotation", "true");
+ iframe.contentDocument.addEventListener("click", undoBatch(action(e => {
+ const href = e.target?.href;
+ if (href) {
+ this._url = href.replace(Utils.prepend(""), Cast(this.dataDoc[this.fieldKey], WebField, null)?.url.origin);
+ this.submitURL();
+ }
+ })));
iframe.contentDocument.addEventListener('pointerdown', this.iframedown, false);
iframe.contentDocument.addEventListener('scroll', this.iframeScrolled, false);
this.layoutDoc.scrollHeight = iframe.contentDocument.children?.[0].scrollHeight || 1000;
@@ -178,14 +187,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
this._iframeRef.current?.contentDocument?.removeEventListener('scroll', this.iframeScrolled);
}
- @action
- onURLChange = (e: React.ChangeEvent<HTMLInputElement>) => {
- this._url = e.target.value;
- }
-
onUrlDragover = (e: React.DragEvent) => {
e.preventDefault();
}
+
+ @undoBatch
@action
onUrlDrop = (e: React.DragEvent) => {
const { dataTransfer } = e;
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index f1bdb7737..00ba5f9bb 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -25,7 +25,7 @@ $slide-active: #5B9FDD;
align-items: center;
.presItem-number {
- margin-top: 7px;
+ margin-top: 3.5px;
font-size: 12px;
font-weight: 700;
text-align: center;
@@ -36,7 +36,6 @@ $slide-active: #5B9FDD;
overflow: hidden;
}
-
}
.presItem-slide {
@@ -46,17 +45,18 @@ $slide-active: #5B9FDD;
height: calc(100% - 7px);
width: calc(100% - 5px);
display: grid;
- grid-template-rows: 23px auto;
+ grid-template-rows: 16px 10px auto;
grid-template-columns: max-content max-content max-content max-content auto;
.presItem-name {
+ min-width: 20px;
z-index: 300;
+ top: 2px;
align-self: center;
- font-size: 13px;
+ font-size: 11px;
font-family: Roboto;
font-weight: 500;
position: relative;
- top: 1px;
padding-left: 10px;
padding-right: 10px;
letter-spacing: normal;
@@ -64,22 +64,44 @@ $slide-active: #5B9FDD;
text-overflow: ellipsis;
overflow: hidden;
white-space: pre;
+ transition: 500ms;
+ }
+
+ .presItem-docName {
+ min-width: 20px;
+ z-index: 300;
+ align-self: center;
+ font-size: 9px;
+ font-family: Roboto;
+ font-weight: 300;
+ position: relative;
+ padding-left: 10px;
+ padding-right: 10px;
+ letter-spacing: normal;
+ width: max-content;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: pre;
+ transition: 500ms;
+ grid-row: 2;
+ grid-column: 1/6;
}
.presItem-time {
align-self: center;
position: relative;
- top: 2px;
padding-right: 10px;
+ top: 1px;
font-size: 10;
font-weight: 300;
font-family: Roboto;
z-index: 300;
letter-spacing: normal;
}
-
+
.presItem-embedded {
overflow: hidden;
+ grid-row: 3;
grid-column: 1/8;
position: relative;
display: flex;
@@ -90,7 +112,7 @@ $slide-active: #5B9FDD;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
-
+
.presItem-embeddedMask {
width: 100%;
height: 100%;
@@ -106,6 +128,7 @@ $slide-active: #5B9FDD;
.presItem-slideButtons {
display: flex;
grid-column: 7;
+ grid-row: 1/3;
width: 60px;
justify-self: right;
justify-content: flex-end;
@@ -115,10 +138,10 @@ $slide-active: #5B9FDD;
position: relative;
border-radius: 100%;
z-index: 300;
- width: 15px;
- height: 15px;
+ width: 18px;
+ height: 18px;
display: flex;
- font-size: 10px;
+ font-size: 12px;
justify-self: center;
align-self: center;
background-color: rgba(0, 0, 0, 0.5);
@@ -131,17 +154,52 @@ $slide-active: #5B9FDD;
.slideButton:hover {
background-color: rgba(0, 0, 0, 1);
- transform: scale(1.15);
+ transform: scale(1.2);
}
}
}
+
+
.presItem-slide.active {
box-shadow: 0 0 0px 1.5px $dark-blue;
}
-// .presItem-slide:hover {
-// background: $slide-hover;
-// }
+.presItem-multiDrag {
+ font-family: Roboto;
+ font-weight: 600;
+ color: white;
+ text-align: center;
+ justify-content: center;
+ align-content: center;
+ width: 100px;
+ height: 30px;
+ position: absolute;
+ background-color: $dark-blue;
+ z-index: 4000;
+ border-radius: 10px;
+ box-shadow: black 0.4vw 0.4vw 0.8vw;
+ line-height: 30px;
+}
+
+.presItem-miniSlide {
+ font-weight: 700;
+ font-size: 12;
+ grid-column: 1/8;
+ align-self: center;
+ justify-self: center;
+ background-color: #d5dce2;
+ width: 26px;
+ text-align: center;
+ height: 26px;
+ line-height: 28px;
+ border-radius: 100%;
+}
+.presItem-miniSlide.active {
+ box-shadow: 0 0 0px 1.5px $dark-blue;
+}
+// .presItem-slide:hover {
+// background: $slide-hover;
+// } \ No newline at end of file
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index aea00f812..b260bc00d 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, reaction, runInAction, observable } from "mobx";
+import { action, computed, IReactionDisposer, reaction, runInAction, observable, trace } from "mobx";
import { observer } from "mobx-react";
import { Doc, DataSym, DocListCast } from "../../../fields/Doc";
import { documentSchema } from '../../../fields/documentSchemas';
@@ -20,8 +20,7 @@ import { DragManager } from "../../util/DragManager";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { undoBatch } from "../../util/UndoManager";
import { EditableView } from "../EditableView";
-import { DocUtils } from "../../documents/Documents";
-import { DateField } from "../../../fields/DateField";
+import { DocumentManager } from "../../util/DocumentManager";
export const presSchema = createSchema({
presentationTargetDoc: Doc,
@@ -142,16 +141,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
e.stopPropagation();
e.preventDefault();
if (element && !(e.ctrlKey || e.metaKey)) {
- if (PresBox.Instance._eleArray.includes(this._itemRef.current!)) {
+ if (PresBox.Instance._selectedArray.includes(this.rootDoc)) {
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
} else {
- PresBox.Instance._selectedArray = [];
- PresBox.Instance._selectedArray.push(this.rootDoc);
- PresBox.Instance._eleArray = [];
- PresBox.Instance._eleArray.push(this._itemRef.current!);
- PresBox.Instance._dragArray = [];
- PresBox.Instance._dragArray.push(this._dragRef.current!);
- setupMoveUpEvents(this, e, this.startDrag, emptyFunction, emptyFunction);
+ setupMoveUpEvents(this, e, ((e: PointerEvent) => {
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, false);
+ return this.startDrag(e);
+ }), emptyFunction, emptyFunction);
}
}
}
@@ -161,26 +158,30 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
e.preventDefault();
}
- @action
- stopDrag = (e: PointerEvent) => {
- this._dragging = false;
- e.stopPropagation();
- e.preventDefault();
- }
-
- startDrag = (e: PointerEvent, down: number[], delta: number[]) => {
+ startDrag = (e: PointerEvent) => {
+ const miniView: boolean = this.toolbarWidth <= 100;
const activeItem = this.rootDoc;
- const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray().map(doc => doc));
+ const dragArray = PresBox.Instance._dragArray;
+ const dragData = new DragManager.DocumentDragData(PresBox.Instance.sortArray());
const dragItem: HTMLElement[] = [];
- PresBox.Instance._dragArray.map(ele => {
- const doc = ele;
- doc.className = "presItem-slide";
+ if (dragArray.length === 1) {
+ const doc = dragArray[0];
+ doc.className = miniView ? "presItem-miniSlide" : "presItem-slide";
+ dragItem.push(doc);
+ } else if (dragArray.length >= 1) {
+ const doc = document.createElement('div');
+ doc.className = "presItem-multiDrag";
+ doc.innerText = "Move " + PresBox.Instance._selectedArray.length + " slides";
+ doc.style.position = 'absolute';
+ doc.style.top = (e.clientY) + 'px';
+ doc.style.left = (e.clientX - 50) + 'px';
dragItem.push(doc);
- });
- const dropEvent = () => runInAction(() => this._dragging = false);
+ }
+
+ // const dropEvent = () => runInAction(() => this._dragging = false);
if (activeItem) {
- DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined, dropEvent);
- runInAction(() => this._dragging = true);
+ DragManager.StartDocumentDrag(dragItem.map(ele => ele), dragData, e.clientX, e.clientY, undefined);
+ // runInAction(() => this._dragging = true);
return true;
}
return false;
@@ -231,20 +232,13 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
e.stopPropagation();
});
+ @undoBatch
@action
onSetValue = (value: string) => {
- this.rootDoc.title = value;
+ this.rootDoc.title = !value.trim().length ? "-untitled-" : value;
return true;
}
- @action
- clearArrays = () => {
- PresBox.Instance._eleArray = [];
- PresBox.Instance._eleArray.push(this._itemRef.current!);
- PresBox.Instance._dragArray = [];
- PresBox.Instance._dragArray.push(this._dragRef.current!);
- }
-
/**
* Method called for updating the view of the currently selected document
*
@@ -271,11 +265,20 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
}
}
+ @computed
+ get toolbarWidth(): number {
+ const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
+ let width: number = NumCast(this.presBox._width);
+ if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
+ return width;
+ }
+
@computed get mainItem() {
const isSelected: boolean = PresBox.Instance._selectedArray.includes(this.rootDoc);
- const toolbarWidth: number = PresBox.Instance.toolbarWidth;
- const showMore: boolean = PresBox.Instance.toolbarWidth >= 300;
- const targetDoc: Doc = Cast(this.rootDoc.presentationTargetDoc, Doc, null);
+ const toolbarWidth: number = this.toolbarWidth;
+ const showMore: boolean = this.toolbarWidth >= 300;
+ const miniView: boolean = this.toolbarWidth <= 100;
+ const targetDoc: Doc = this.targetDoc;
const activeItem: Doc = this.rootDoc;
return (
<div className={`presItem-container`} key={this.props.Document[Id] + this.indexInPres}
@@ -284,44 +287,34 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
onClick={e => {
e.stopPropagation();
e.preventDefault();
- // Command/ control click
- if (e.ctrlKey || e.metaKey) {
- PresBox.Instance.multiSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!);
- // Shift click
- } else if (e.shiftKey) {
- PresBox.Instance.shiftSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!);
- // Regular click
- } else {
- this.props.focus(this.rootDoc);
- this.clearArrays();
- }
+ PresBox.Instance.modifierSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, !e.shiftKey && !e.ctrlKey && !e.metaKey, e.ctrlKey || e.metaKey, e.shiftKey);
}}
- onDoubleClick={e => {
+ onDoubleClick={action(e => {
this.toggleProperties();
- this.props.focus(this.rootDoc);
- this.clearArrays();
- }}
+ PresBox.Instance.regularSelect(this.rootDoc, this._itemRef.current!, this._dragRef.current!, true);
+ })}
onPointerOver={this.onPointerOver}
onPointerLeave={this.onPointerLeave}
onPointerDown={this.headerDown}
onPointerUp={this.headerUp}
>
- <div className="presItem-number">
- {`${this.indexInPres + 1}.`}
- </div>
- <div ref={this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}>
- <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 175) : toolbarWidth - 85 }}>
- {isSelected ? <EditableView
+ {miniView ?
+ <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
+ {`${this.indexInPres + 1}.`}
+ </div>
+ :
+ <div className="presItem-number">
+ {`${this.indexInPres + 1}.`}
+ </div>}
+ {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}>
+ <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 175) : toolbarWidth - 85, cursor: isSelected ? 'text' : 'grab' }}>
+ <EditableView
ref={this._titleRef}
- contents={this.rootDoc.title}
- GetValue={() => StrCast(this.rootDoc.title)}
- SetValue={action((value: string) => {
- this.onSetValue(value);
- return true;
- })}
- /> :
- this.rootDoc.title
- }
+ editing={!isSelected ? false : undefined}
+ contents={activeItem.title}
+ GetValue={() => StrCast(activeItem.title)}
+ SetValue={this.onSetValue}
+ />
</div>
<Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
<Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
@@ -331,6 +324,13 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
onClick={() => this.updateView(targetDoc, activeItem)}
style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>V</div>
</Tooltip>
+ {/* <Tooltip title={<><div className="dash-tooltip">{"Group with up"}</div></>}>
+ <div className="slideButton"
+ onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
+ style={{ fontWeight: 700, display: activeItem.presPinView ? "flex" : "none" }}>
+ <FontAwesomeIcon icon={""} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip> */}
<Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
<FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
</div></Tooltip>
@@ -340,8 +340,9 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
<FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
</div></Tooltip>
</div>
+ <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 175) : toolbarWidth - 85 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
{this.renderEmbeddedInline}
- </div>
+ </div>}
</div >);
}
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index 71294c59c..311aaa769 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -19,7 +19,6 @@ export const documentSchema = createSchema({
activeFrame: "number", // the active frame of a frame based animated document
_currentTimecode: "number", // current play back time of a temporal document (video / audio)
displayTimecode: "number", // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
- inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently
isLabel: "boolean", // whether the document is a label or not (video / audio)
audioStart: "number", // the time frame where the audio should begin playing
audioEnd: "number", // the time frame where the audio should stop playing
diff --git a/src/fields/util.ts b/src/fields/util.ts
index a374c7f54..ecb3fb343 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -379,12 +379,12 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
diff?.op === "$addToSet" ?
{
redo: () => {
- receiver[prop].push(...diff.items.map((item: any) => item.value()));
+ receiver[prop].push(...diff.items.map((item: any) => item.value ? item.value() : item));
lastValue = ObjectField.MakeCopy(receiver[prop]);
},
undo: action(() => {
- diff.items.forEach((doc: any) => {
- const ind = receiver[prop].indexOf(doc.value());
+ diff.items.forEach((item: any) => {
+ const ind = receiver[prop].indexOf(item.value ? item.value() : item);
ind !== -1 && receiver[prop].splice(ind, 1);
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
@@ -393,16 +393,16 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
diff?.op === "$remFromSet" ?
{
redo: action(() => {
- diff.items.forEach((doc: any) => {
- const ind = receiver[prop].indexOf(doc.value());
+ diff.items.forEach((item: any) => {
+ const ind = receiver[prop].indexOf(item.value ? item.value() : item);
ind !== -1 && receiver[prop].splice(ind, 1);
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
}),
undo: () => {
- diff.items.map((item: any) => {
- const ind = (prevValue as List<any>).indexOf(diff.items[0].value());
- ind !== -1 && receiver[prop].indexOf(diff.items[0].value()) === -1 && receiver[prop].splice(ind, 0, item);
+ diff.items.forEach((item: any) => {
+ const ind = (prevValue as List<any>).indexOf(item.value ? item.value() : item);
+ ind !== -1 && receiver[prop].indexOf(item.value ? item.value() : item) === -1 && receiver[prop].splice(ind, 0, item);
});
lastValue = ObjectField.MakeCopy(receiver[prop]);
}
diff --git a/src/server/SharedMediaTypes.ts b/src/server/SharedMediaTypes.ts
index a341fd1c2..f1fe582e5 100644
--- a/src/server/SharedMediaTypes.ts
+++ b/src/server/SharedMediaTypes.ts
@@ -8,7 +8,7 @@ export namespace AcceptableMedia {
export const webps = [".webp"];
export const tiffs = [".tiff"];
export const imageFormats = [...pngs, ...jpgs, ...gifs, ...webps, ...tiffs];
- export const videoFormats = [".mov", ".mp4"];
+ export const videoFormats = [".mov", ".mp4", ".quicktime"];
export const applicationFormats = [".pdf"];
export const audioFormats = [".wav", ".mp3", ".mpeg", ".flac", ".au", ".aiff", ".m4a", ".webm"];
}
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 6ceb9e29f..7d111f359 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -285,11 +285,13 @@ export namespace WebSocket {
Database.Instance.update(diff.id, diff.diff,
() => {
if (sendBack) {
+ console.log("RET BACK");
const id = socket.id;
socket.id = "";
socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
socket.id = id;
} else socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ dispatchNextOp(diff.id);
}, false);
}
@@ -304,47 +306,74 @@ export namespace WebSocket {
Database.Instance.update(diff.id, diff.diff,
() => {
if (sendBack) {
+ console.log("SEND BACK");
const id = socket.id;
socket.id = "";
socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
socket.id = id;
} else socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ dispatchNextOp(diff.id);
}, false);
}
+ const pendingOps = new Map<string, { diff: Diff, socket: Socket }[]>();
+
+ function dispatchNextOp(id: string) {
+ const next = pendingOps.get(id)!.shift();
+ if (next) {
+ const { diff, socket } = next;
+ if (diff.diff.$addToSet) {
+ return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
+ }
+ if (diff.diff.$remFromSet) {
+ return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
+ }
+ return GetRefFieldLocal([diff.id, (result?: Transferable) => SetField(socket, diff, result)]);
+ }
+ if (!pendingOps.get(id)!.length) pendingOps.delete(id);
+ }
function UpdateField(socket: Socket, diff: Diff) {
- if (diff.diff.$addToSet) return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
- if (diff.diff.$remFromSet) return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
+ if (pendingOps.has(diff.id)) {
+ pendingOps.get(diff.id)!.push({ diff, socket });
+ return true;
+ }
+ pendingOps.set(diff.id, [{ diff, socket }]);
+ if (diff.diff.$addToSet) {
+ return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
+ }
+ if (diff.diff.$remFromSet) {
+ return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own
+ }
return GetRefFieldLocal([diff.id, (result?: Transferable) => SetField(socket, diff, result)]);
}
function SetField(socket: Socket, diff: Diff, curListItems?: Transferable) {
Database.Instance.update(diff.id, diff.diff,
() => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false);
const docfield = diff.diff.$set || diff.diff.$unset;
- if (!docfield) {
- return;
- }
- const update: any = { id: diff.id };
- let dynfield = false;
- for (let key in docfield) {
- if (!key.startsWith("fields.")) continue;
- dynfield = true;
- const val = docfield[key];
- key = key.substring(7);
- Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
- const term = ToSearchTerm(val);
- if (term !== undefined) {
- const { suffix, value } = term;
- update[key + suffix] = { set: value };
- if (key.endsWith('lastModified')) {
- update["lastModified" + suffix] = value;
+ if (docfield) {
+ const update: any = { id: diff.id };
+ let dynfield = false;
+ for (let key in docfield) {
+ if (!key.startsWith("fields.")) continue;
+ dynfield = true;
+ const val = docfield[key];
+ key = key.substring(7);
+ Object.values(suffixMap).forEach(suf => { update[key + getSuffix(suf)] = { set: null }; });
+ const term = ToSearchTerm(val);
+ if (term !== undefined) {
+ const { suffix, value } = term;
+ update[key + suffix] = { set: value };
+ if (key.endsWith('lastModified')) {
+ update["lastModified" + suffix] = value;
+ }
}
}
+ if (dynfield) {
+ Search.updateDocument(update);
+ }
}
- if (dynfield) {
- Search.updateDocument(update);
- }
+ dispatchNextOp(diff.id);
}
function DeleteField(socket: Socket, id: string) {