aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authormehekj <mehek.jethani@gmail.com>2022-10-12 13:21:07 -0400
committermehekj <mehek.jethani@gmail.com>2022-10-12 13:21:07 -0400
commit0b3a83acd4f75b7f6ff4b9bb7daf4377dede51a1 (patch)
tree438789f7e7f50e5eb9829e1f301b4d043d8d4906 /src/client/views/nodes
parent69ca9baca6ff1da272a5191187542351bd242ccc (diff)
parenteb5f75785fd28acb50f1b30434e89223fff00185 (diff)
Merge branch 'master' into schema-mehek
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/AudioBox.tsx4
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx46
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.scss4
-rw-r--r--src/client/views/nodes/DocumentView.tsx132
-rw-r--r--src/client/views/nodes/FilterBox.tsx10
-rw-r--r--src/client/views/nodes/ImageBox.tsx7
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx4
-rw-r--r--src/client/views/nodes/LoadingBox.scss35
-rw-r--r--src/client/views/nodes/LoadingBox.tsx68
-rw-r--r--src/client/views/nodes/PDFBox.tsx6
-rw-r--r--src/client/views/nodes/RecordingBox/RecordingView.scss18
-rw-r--r--src/client/views/nodes/ScriptingBox.tsx9
-rw-r--r--src/client/views/nodes/VideoBox.scss22
-rw-r--r--src/client/views/nodes/VideoBox.tsx326
-rw-r--r--src/client/views/nodes/WebBox.scss8
-rw-r--r--src/client/views/nodes/WebBox.tsx64
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx38
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx22
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts9
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx104
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts17
-rw-r--r--src/client/views/nodes/trails/PresBox.scss27
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx1445
-rw-r--r--src/client/views/nodes/trails/PresElementBox.scss337
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx167
-rw-r--r--src/client/views/nodes/trails/PresEnums.ts42
28 files changed, 1415 insertions, 1562 deletions
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 7bbd7c055..f96be9eef 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -349,8 +349,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
Doc.GetProto(newDoc).recordingStart = ComputedField.MakeFunction(`self.recordingSource["${this.fieldKey}-recordingStart"]`);
Doc.GetProto(newDoc).mediaState = ComputedField.MakeFunction('self.recordingSource.mediaState');
if (DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc)) {
- newDoc.x = this.rootDoc.x;
- newDoc.y = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
+ newDoc.overlayX = this.rootDoc.x;
+ newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
Doc.AddDocToList(Doc.MyOverlayDocs, undefined, newDoc);
} else {
this.props.addDocument?.(newDoc);
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 86566ac6a..a48906372 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,12 +1,14 @@
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, Opt } from '../../../fields/Doc';
+import { InkField } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { listSpec } from '../../../fields/Schema';
import { ComputedField } from '../../../fields/ScriptField';
import { Cast, NumCast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { numberRange } from '../../../Utils';
+import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
import { SelectionManager } from '../../util/SelectionManager';
import { Transform } from '../../util/Transform';
@@ -16,11 +18,6 @@ import { StyleProp } from '../StyleProvider';
import './CollectionFreeFormDocumentView.scss';
import { DocumentView, DocumentViewProps } from './DocumentView';
import React = require('react');
-import { InkField } from '../../../fields/InkField';
-import { DocumentType } from '../../documents/DocumentTypes';
-import { Field } from '../../util/ProsemirrorCopy/prompt';
-import { RefField } from '../../../fields/RefField';
-import { ObjectField } from '../../../fields/ObjectField';
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc, replica: string) => { x: number; y: number; zIndex?: number; color?: string; backgroundColor?: string; opacity?: number; highlight?: boolean; z: number; transition?: string } | undefined;
@@ -36,9 +33,20 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
@observer
export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps>() {
- public static animFields = ['_height', '_width', 'x', 'y', '_scrollTop', 'opacity']; // fields that are configured to be animatable using animation frames
+ public static animFields: { key: string; val?: number }[] = [
+ { key: '_height' },
+ { key: '_width' },
+ { key: 'x' },
+ { key: 'y' },
+ { key: '_jitterRotation', val: 0 },
+ { key: '_scrollTop' },
+ { key: 'opacity', val: 1 },
+ { key: 'viewScale', val: 1 },
+ { key: 'panX' },
+ { key: 'panY' },
+ ]; // fields that are configured to be animatable using animation frames
public static animStringFields = ['backgroundColor', 'color']; // fields that are configured to be animatable using animation frames
- public static animDataFields = ['data', 'text']; // fields that are configured to be animatable using animation frames
+ public static animDataFields = (doc: Doc) => (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames
@observable _animPos: number[] | undefined = undefined;
@observable _contentView: DocumentView | undefined | null;
get displayName() {
@@ -62,10 +70,10 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return this.dataProvider?.opacity;
}
get BackgroundColor() {
- return this.dataProvider?.backgroundColor;
+ return this.dataProvider?.backgroundColor ?? Cast(this.Document._backgroundColor, 'string', null);
}
get Color() {
- return this.dataProvider?.color;
+ return this.dataProvider?.color ?? Cast(this.Document._color, 'string', null);
}
get Highlight() {
return this.dataProvider?.highlight;
@@ -88,16 +96,16 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return this.props.styleProvider?.(doc, props, property);
};
- public static getValues(doc: Doc, time: number) {
+ public static getValues(doc: Doc, time: number, fillIn: boolean = true) {
return CollectionFreeFormDocumentView.animFields.reduce((p, val) => {
- p[val] = Cast(`${val}-indexed`, listSpec('number'), [NumCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number);
+ p[val.key] = Cast(doc[`${val.key}-indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number);
return p;
}, {} as { [val: string]: Opt<number> });
}
public static getStringValues(doc: Doc, time: number) {
return CollectionFreeFormDocumentView.animStringFields.reduce((p, val) => {
- p[val] = Cast(`${val}-indexed`, listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string);
+ p[val] = Cast(doc[`${val}-indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string);
return p;
}, {} as { [val: string]: Opt<string> });
}
@@ -117,14 +125,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
action(doc => {
doc._viewTransition = doc.dataTransition = 'all 1s';
CollectionFreeFormDocumentView.animFields.forEach(val => {
- const findexed = Cast(doc[`${val}-indexed`], listSpec('number'), null);
+ const findexed = Cast(doc[`${val.key}-indexed`], listSpec('number'), null);
findexed?.length <= timecode + 1 && findexed.push(undefined as any as number);
});
CollectionFreeFormDocumentView.animStringFields.forEach(val => {
const findexed = Cast(doc[`${val}-indexed`], listSpec('string'), null);
findexed?.length <= timecode + 1 && findexed.push(undefined as any as string);
});
- CollectionFreeFormDocumentView.animDataFields.forEach(val => {
+ CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => {
const findexed = Cast(doc[`${val}-indexed`], listSpec(InkField), null);
findexed?.length <= timecode + 1 && findexed.push(undefined as any);
});
@@ -140,8 +148,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
);
}
- public static gotoKeyframe(docs: Doc[]) {
- docs.forEach(doc => (doc._viewTransition = doc.dataTransition = 'all 1s'));
+ public static gotoKeyframe(docs: Doc[], duration = 1000) {
+ docs.forEach(doc => (doc._viewTransition = doc.dataTransition = `all ${duration}ms`));
setTimeout(
() =>
docs.forEach(doc => {
@@ -174,9 +182,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
// opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in
doc['opacity-indexed'] = new List<number>(numberRange(currTimecode + 1).map(t => (!doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1)));
}
- CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedNumber(val, 'activeFrame', doc, currTimecode)));
+ CollectionFreeFormDocumentView.animFields.forEach(val => (doc[val.key] = ComputedField.MakeInterpolatedNumber(val.key, 'activeFrame', doc, currTimecode, val.val)));
CollectionFreeFormDocumentView.animStringFields.forEach(val => (doc[val] = ComputedField.MakeInterpolatedString(val, 'activeFrame', doc, currTimecode)));
- CollectionFreeFormDocumentView.animDataFields.forEach(val => (Doc.GetProto(doc)[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', Doc.GetProto(doc), currTimecode)));
+ CollectionFreeFormDocumentView.animDataFields(doc).forEach(val => (Doc.GetProto(doc)[val] = ComputedField.MakeInterpolatedDataField(val, 'activeFrame', Doc.GetProto(doc), currTimecode)));
const targetDoc = doc.type === DocumentType.RTF ? Doc.GetProto(doc) : doc; // data fields, like rtf 'text' exist on the data doc, so
doc !== targetDoc && (targetDoc.context = doc.context); // the computed fields don't see the layout doc -- need to copy the context to the data doc (HACK!!!) and set the activeFrame on the data doc (HACK!!!)
targetDoc.activeFrame = ComputedField.MakeFunction('self.context?._currentFrame||0');
@@ -226,7 +234,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
PanelWidth: this.panelWidth,
PanelHeight: this.panelHeight,
};
- const mixBlendMode = undefined; // (StrCast(this.layoutDoc.mixBlendMode) as any) || (typeof background === 'string' && background && !background.startsWith('linear') && DashColor(background).alpha() !== 1 ? 'multiply' : undefined);
return (
<div
className={'collectionFreeFormDocumentView-container'}
@@ -238,7 +245,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
transformOrigin: '50% 50%',
transition: this.dataProvider?.transition ?? (this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition)),
zIndex: this.ZInd,
- mixBlendMode: mixBlendMode,
display: this.ZInd === -99 ? 'none' : undefined,
}}>
{this.props.renderCutoffProvider(this.props.Document) ? (
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index d065c62fb..6d6609317 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -43,6 +43,7 @@ import { VideoBox } from './VideoBox';
import { WebBox } from './WebBox';
import React = require('react');
import XRegExp = require('xregexp');
+import { LoadingBox } from './LoadingBox';
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -266,6 +267,7 @@ export class DocumentContentsView extends React.Component<
DataVizBox,
HTMLtag,
ComparisonBox,
+ LoadingBox,
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index a37de7f69..9ffbf8e37 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import { Doc, Opt } from '../../../fields/Doc';
import { StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { emptyFunction, returnFalse, setupMoveUpEvents, StopEvent } from '../../../Utils';
import { DocUtils } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { Hypothesis } from '../../util/HypothesisUtils';
@@ -287,7 +287,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
</div>
) : null}
{this.props.InMenu && this.props.StartLink ? ( //if link has been started from current node, then set behavior of link button to deactivate linking when clicked again
- <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} ref={this._linkButton} onPointerDown={isActive ? undefined : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
+ <div className={`documentLinksButton ${isActive ? `startLink` : ``}`} ref={this._linkButton} onPointerDown={isActive ? StopEvent : this.onLinkButtonDown} onClick={isActive ? this.clearLinks : this.onLinkClick}>
<FontAwesomeIcon className="documentdecorations-icon" icon="link" />
</div>
) : null}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 9aaaf1e68..6cadeec41 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -2,6 +2,7 @@
.documentView-effectsWrapper {
border-radius: inherit;
+ transition: inherit;
}
// documentViews have a docView-hack tag which is replaced by this tag when capturing bitmaps (when the dom is converted to an html string)
@@ -25,7 +26,6 @@
height: 100%;
border-radius: inherit;
transition: outline 0.3s linear;
- cursor: grab;
// background: $white; //overflow: hidden;
transform-origin: left top;
@@ -212,10 +212,12 @@
display: flex;
width: 100%;
height: 100%;
+ transition: inherit;
.contentFittingDocumentView-previewDoc {
position: relative;
display: inline;
+ transition: inherit;
}
.contentFittingDocumentView-input {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 74143a731..145d8bf3d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,8 +1,9 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
-import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, HeightSym, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
@@ -10,7 +11,7 @@ import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { listSpec } from '../../../fields/Schema';
import { ScriptField } from '../../../fields/ScriptField';
-import { BoolCast, Cast, DocCast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { AudioField } from '../../../fields/URLField';
import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
@@ -20,6 +21,7 @@ import { DocServer } from '../../DocServer';
import { Docs, DocUtils } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { Networking } from '../../Network';
+import { DictationManager } from '../../util/DictationManager';
import { DocumentManager } from '../../util/DocumentManager';
import { DragManager, dropActionType } from '../../util/DragManager';
import { InteractionUtils } from '../../util/InteractionUtils';
@@ -37,7 +39,6 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from '../DocComponent';
import { EditableView } from '../EditableView';
-import { InkingStroke } from '../InkingStroke';
import { LightboxView } from '../LightboxView';
import { StyleProp } from '../StyleProvider';
import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView';
@@ -52,8 +53,6 @@ import { RadialMenu } from './RadialMenu';
import { ScriptingBox } from './ScriptingBox';
import { PresBox } from './trails/PresBox';
import React = require('react');
-import { DictationManager } from '../../util/DictationManager';
-import { Tooltip } from '@material-ui/core';
const { Howl } = require('howler');
interface Window {
@@ -81,12 +80,13 @@ export interface DocFocusOptions {
instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom)
}
export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>;
-export type DocFocusFunc = (doc: Doc, options?: DocFocusOptions) => void;
+export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void;
export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
export interface DocComponentView {
updateIcon?: () => void; // updates the icon representation of the document
getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus
+ brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void;
setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling.
shrinkWrap?: () => void; // requests a document to display all of its contents with no white space. currently only implemented (needed?) for freeform views
@@ -498,8 +498,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
.ScreenToLocalTransform()
.scale(this.NativeDimScaling)
.transformDirection(x - left, y - top);
- dragData.offset[0] = Math.min(this.rootDoc[WidthSym](), dragData.offset[0]);
- dragData.offset[1] = Math.min(this.rootDoc[HeightSym](), dragData.offset[1]);
+ // dragData.offset[0] = Math.min(this.rootDoc[WidthSym](), dragData.offset[0]); // bcz: this was breaking dragging rotated objects since the offset may be out of bounds with regard to the unrotated document
+ // dragData.offset[1] = Math.min(this.rootDoc[HeightSym](), dragData.offset[1]);
dragData.dropAction = dropAction;
dragData.treeViewDoc = this.props.treeViewDoc;
dragData.removeDocument = this.props.removeDocument;
@@ -534,7 +534,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}
};
- focus = (anchor: Doc, options?: DocFocusOptions) => {
+ focus = (anchor: Doc, options: DocFocusOptions) => {
LightboxView.SetCookie(StrCast(anchor['cookies-set']));
// copying over VIEW fields immediately allows the view type to switch to create the right _componentView
Array.from(Object.keys(Doc.GetProto(anchor)))
@@ -582,7 +582,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
console.log
);
UndoManager.RunInBatch(() => (func().result?.select === true ? this.props.select(false) : ''), 'on double click');
- } else if (!Doc.IsSystem(this.rootDoc)) {
+ } else if (!Doc.IsSystem(this.rootDoc) && !this.rootDoc.isLinkButton) {
UndoManager.RunInBatch(() => LightboxView.AddDocTab(this.rootDoc, 'lightbox', this.props.LayoutTemplate?.(), this.props.addDocTab), 'double tap');
SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
@@ -881,9 +881,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
- const zorders = cm.findByDescription('ZOrder...');
- const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
if (this.props.bringToFront !== emptyFunction) {
+ const zorders = cm.findByDescription('ZOrder...');
+ const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : [];
zorderItems.push({ description: 'Bring to Front', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: 'expand-arrows-alt' });
zorderItems.push({ description: 'Send to Back', event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: 'expand-arrows-alt' });
zorderItems.push({
@@ -891,8 +891,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
event: undoBatch(action(() => (this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined))),
icon: 'expand-arrows-alt',
});
+ !zorders && cm.addItem({ description: 'ZOrder...', noexpand: true, subitems: zorderItems, icon: 'compass' });
}
- !zorders && cm.addItem({ description: 'ZOrder...', noexpand: true, subitems: zorderItems, icon: 'compass' });
!Doc.noviceMode && onClicks.push({ description: 'Enter Portal', event: this.makeIntoPortal, icon: 'window-restore' });
!Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' });
@@ -1001,7 +1001,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
LightboxView.LightboxDoc !== this.rootDoc &&
this.thumb &&
!Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
- !Doc.isBrushedHighlightedDegree(this.props.Document) &&
+ (!Doc.isBrushedHighlightedDegree(this.props.Document) || this.rootDoc._viewType === CollectionViewType.Docking) &&
!this._componentView?.isAnyChildContentActive?.()
? true
: false;
@@ -1259,46 +1259,47 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor,
Doc.UserDoc().showTitle && [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : 'rgba(0,0,0,0.4)'
);
- const titleView = !showTitle ? null : (
- <div
- className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
- key="title"
- style={{
- position: this.headerMargin ? 'relative' : 'absolute',
- height: this.titleHeight,
- width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
- color: lightOrDark(background),
- background,
- pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
- }}>
- <EditableView
- ref={this._titleRef}
- contents={showTitle
- .split(';')
- .map(field => field.trim())
- .map(field => targetDoc[field]?.toString())
- .join('\\')}
- display={'block'}
- fontSize={10}
- GetValue={() => (showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle)}
- SetValue={undoBatch((input: string) => {
- if (input?.startsWith('#')) {
- if (this.props.showTitle) {
- this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+ const titleView =
+ !showTitle || Doc.noviceMode ? null : (
+ <div
+ className={`documentView-titleWrapper${showTitleHover ? '-hover' : ''}`}
+ key="title"
+ style={{
+ position: this.headerMargin ? 'relative' : 'absolute',
+ height: this.titleHeight,
+ width: !this.headerMargin ? `calc(100% - 18px)` : '100%', // leave room for annotation button
+ color: lightOrDark(background),
+ background,
+ pointerEvents: this.onClickHandler || this.Document.ignoreClick ? 'none' : this.isContentActive() || this.props.isDocumentActive?.() ? 'all' : undefined,
+ }}>
+ <EditableView
+ ref={this._titleRef}
+ contents={showTitle
+ .split(';')
+ .map(field => field.trim())
+ .map(field => targetDoc[field]?.toString())
+ .join('\\')}
+ display={'block'}
+ fontSize={10}
+ GetValue={() => (showTitle.split(';').length === 1 ? showTitle + '=' + Field.toString(targetDoc[showTitle.split(';')[0]] as any as Field) : '#' + showTitle)}
+ SetValue={undoBatch((input: string) => {
+ if (input?.startsWith('#')) {
+ if (this.props.showTitle) {
+ this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined;
+ } else {
+ Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+ }
} else {
- Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : 'creationDate';
+ var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
+ if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
+ if (showTitle.includes('Date') || showTitle === 'author') return true;
+ Doc.SetInPlace(targetDoc, showTitle, value, true);
}
- } else {
- var value = input.replace(new RegExp(showTitle + '='), '') as string | number;
- if (showTitle !== 'title' && Number(value).toString() === value) value = Number(value);
- if (showTitle.includes('Date') || showTitle === 'author') return true;
- Doc.SetInPlace(targetDoc, showTitle, value, true);
- }
- return true;
- })}
- />
- </div>
- );
+ return true;
+ })}
+ />
+ </div>
+ );
return this.props.hideTitle || (!showTitle && !showCaption) ? (
this.contents
) : (
@@ -1322,7 +1323,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@observable _isHovering = false;
@observable _: string = '';
_hoverTimeout: any = undefined;
- @computed get renderDoc() {
+ renderDoc = (style: object) => {
TraceMobx();
const thumb = ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url?.href.replace('.png', '_m.png');
const isButton = this.props.Document.type === DocumentType.FONTICON;
@@ -1344,8 +1345,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
);
})}
style={{
+ ...style,
background: isButton || thumb ? undefined : this.backgroundColor,
opacity: this.opacity,
+ cursor: Doc.ActiveTool === InkTool.None ? 'grab' : 'crosshair',
color: StrCast(this.layoutDoc.color, 'inherit'),
fontFamily: StrCast(this.Document._fontFamily, 'inherit'),
fontSize: Cast(this.Document._fontSize, 'string', null),
@@ -1358,7 +1361,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
</div>
)
);
- }
+ };
render() {
TraceMobx();
const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : Doc.DocBrushStatus.unbrushed) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
@@ -1369,13 +1372,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== '[pres element template]'; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath) || { path: undefined };
- const internal = PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc;
const boxShadow = this.props.treeViewDoc
? null
: highlighting && this.borderRounding && highlightStyle !== 'dashed'
? `0 0 0 ${highlightIndex}px ${highlightColor}`
: this.boxShadow || (this.props.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined);
+ const renderDoc = this.renderDoc({
+ borderRadius: this.borderRounding,
+ outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px',
+ border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
+ boxShadow,
+ clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined,
+ });
+ const animRenderDoc = PresBox.Instance?.isActiveItemTarget(this.layoutDoc) ? PresBox.AnimationEffect(renderDoc, PresBox.Instance.activeItem) : renderDoc;
// Return surrounding highlight
return (
<div
@@ -1391,19 +1401,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
display: this.hidden ? 'inline' : undefined,
borderRadius: this.borderRounding,
pointerEvents: this.pointerEvents,
- outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px',
- border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
- boxShadow,
- clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined,
}}>
{!borderPath.path ? (
- internal
+ animRenderDoc
) : (
<>
{/* <div style={{ clipPath: `path('${borderPath.fill}')` }}>
- {internal}
+ {animRenderDoc}
</div> */}
- {internal}
+ {animRenderDoc}
<div key="border2" className="documentView-customBorder" style={{ pointerEvents: 'none' }}>
<svg style={{ overflow: 'visible' }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
<path d={borderPath.path} style={{ stroke: 'black', fill: 'transparent', strokeWidth: borderPath.width }} />
@@ -1552,7 +1558,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}
toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.NativeDimScaling, this.props.PanelWidth(), this.props.PanelHeight());
- focus = (doc: Doc, options?: DocFocusOptions) => this.docView?.focus(doc, options);
+ focus = (doc: Doc, options: DocFocusOptions) => this.docView?.focus(doc, options);
getBounds = () => {
if (!this.docView || !this.docView.ContentDiv || this.props.Document.presBox || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
return undefined;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index dc3fc0396..04d252abe 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -379,7 +379,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
* Changes the title of the filterDoc
*/
onTitleValueChange = (val: string) => {
- this.props.Document.title = val || `FilterDoc for ${FilterBox.targetDoc?.title}`;
+ Doc.GetProto(this.props.Document).title = val || `FilterDoc for ${FilterBox.targetDoc?.title}`;
return true;
};
@@ -389,11 +389,9 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get flyoutPanel() {
return DocListCast(Doc.UserDoc().savedFilters).map(doc => {
return (
- <>
- <div className="filterBox-tempFlyout" onWheel={e => e.stopPropagation()} style={{ height: 50, border: '2px' }} onPointerDown={() => this.props.updateFilterDoc?.(doc)}>
- {StrCast(doc.title)}
- </div>
- </>
+ <div className="filterBox-tempFlyout" onWheel={e => e.stopPropagation()} style={{ height: 20, border: '2px' }} onPointerDown={() => this.props.updateFilterDoc?.(doc)}>
+ {StrCast(doc.title)}
+ </div>
);
});
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9590bcb15..959c641a8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -74,7 +74,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
scrSize: this.props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth,
selected: this.props.isSelected(),
}),
- ({ forceFull, scrSize, selected }) => (this._curSuffix = this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 || !selected ? '_l' : '_o'),
+ ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'),
{ fireImmediately: true, delay: 1000 }
);
this._disposers.path = reaction(
@@ -136,6 +136,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
crop = (region: Doc | undefined, addCrop?: boolean) => {
if (!region) return;
const cropping = Doc.MakeCopy(region, true);
+ Doc.GetProto(region).backgroundColor = 'transparent';
Doc.GetProto(region).lockedPosition = true;
Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
Doc.GetProto(region).isPushpin = true;
@@ -230,7 +231,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const lower = url.href.toLowerCase();
if (url.protocol === 'data') return url.href;
if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
- if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return url.href; //Why is this here
+ if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return `/assets/unknown-file-icon-hi.png`;
const ext = extname(url.href);
return url.href.replace(ext, this._curSuffix + ext);
@@ -339,7 +340,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
</div>
)}
</div>
- {this.considerDownloadIcon}
+ {!Doc.noviceMode && this.considerDownloadIcon}
{this.considerGooglePhotosLink()}
<FaceRectangles document={this.dataDoc} color={'#0000FF'} backgroundColor={'#0000FF'} />
</div>
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 93ca22d5d..27e79a83b 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -228,7 +228,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
<DocumentView
ref={r => {
const targetanchor = this._linkDoc && this._linkSrc && LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
- targetanchor && this._targetDoc !== targetanchor && r?.focus(targetanchor);
+ targetanchor && this._targetDoc !== targetanchor && r?.focus(targetanchor, {});
}}
Document={this._targetDoc!}
moveDocument={returnFalse}
@@ -249,7 +249,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
searchFilterDocs={returnEmptyDoclist}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
- renderDepth={-1}
+ renderDepth={0}
suppressSetHeight={true}
PanelWidth={this.width}
PanelHeight={this.height}
diff --git a/src/client/views/nodes/LoadingBox.scss b/src/client/views/nodes/LoadingBox.scss
new file mode 100644
index 000000000..d63ed2575
--- /dev/null
+++ b/src/client/views/nodes/LoadingBox.scss
@@ -0,0 +1,35 @@
+.loadingBoxContainer {
+ display: flex;
+ flex-direction: column;
+ align-content: center;
+ justify-content: center;
+ background-color: #fdfdfd;
+ height: 100%;
+ align-items: center;
+}
+
+.textContainer {
+ margin: 5px;
+}
+
+.textContainer {
+ justify-content: center;
+ align-content: center;
+}
+
+.textContainer,
+.text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 80%;
+ text-align: center;
+}
+
+.headerText {
+ text-align: center;
+ font-weight: bold;
+}
+
+.spinner {
+ text-align: center;
+}
diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx
new file mode 100644
index 000000000..8c5255f80
--- /dev/null
+++ b/src/client/views/nodes/LoadingBox.tsx
@@ -0,0 +1,68 @@
+import { action, observable, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import ReactLoading from 'react-loading';
+import { Doc } from '../../../fields/Doc';
+import { StrCast } from '../../../fields/Types';
+import { Networking } from '../../Network';
+import { ViewBoxAnnotatableComponent } from '../DocComponent';
+import { FieldView, FieldViewProps } from './FieldView';
+import './LoadingBox.scss';
+
+/**
+ * LoadingBox Class represents a placeholder doc for documents that are currently
+ * being uploaded to the server and being fetched by the client. The LoadingBox doc is then used to
+ * generate the actual type of doc that is required once the document has been successfully uploaded.
+ *
+ * Design considerations:
+ * We are using the docToFiles map in Documents to keep track of all files being uploaded in one session of the client.
+ * If the file is not found we assume an error has occurred with the file upload, e.g. it has been interrupted by a client refresh
+ * or network issues. The docToFiles essentially gets reset everytime the page is refreshed.
+ *
+ * TODOs:
+ * 1) ability to query server to retrieve files that already exist if users upload duplicate files.
+ * 2) ability to restart upload if there is an error
+ * 3) detect network error and notify the user
+ * 4 )if file upload gets interrupted, it still gets uploaded to the server if there are no network interruptions which leads to unused space. this could be
+ * handled with (1)
+ * 5) Fixing the stacking view bug
+ * 6) Fixing the CSS
+ *
+ * @author naafiyan
+ */
+@observer
+export class LoadingBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(LoadingBox, fieldKey);
+ }
+
+ _timer: any;
+ @observable progress = '';
+ componentDidMount() {
+ if (!Doc.CurrentlyLoading?.includes(this.rootDoc)) {
+ this.rootDoc.loadingError = 'Upload interrupted, please try again';
+ } else {
+ const updateFunc = async () => {
+ const result = await Networking.QueryYoutubeProgress(StrCast(this.rootDoc.title));
+ runInAction(() => (this.progress = result.progress));
+ this._timer = setTimeout(updateFunc, 1000);
+ };
+ this._timer = setTimeout(updateFunc, 1000);
+ }
+ }
+ componentWillUnmount() {
+ clearTimeout(this._timer);
+ }
+
+ render() {
+ return (
+ <div className="loadingBoxContainer" style={{ background: !this.rootDoc.loadingError ? '' : 'red' }}>
+ <div className="textContainer">
+ <p className="headerText">{StrCast(this.rootDoc.loadingError, 'Loading ' + (this.progress.replace('[download]', '') || '(can take several minutes)'))}</p>
+ <span className="text">{StrCast(this.rootDoc.title)}</span>
+ {this.rootDoc.loadingError ? null : <ReactLoading type={'spinningBubbles'} color={'blue'} height={100} width={100} />}
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 345407c2f..c7001f846 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -18,6 +18,7 @@ import { ContextMenu } from '../ContextMenu';
import { ContextMenuProps } from '../ContextMenuItem';
import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent';
import { Colors } from '../global/globalEnums';
+import { LightboxView } from '../LightboxView';
import { CreateImage } from '../nodes/WebBoxRenderer';
import { PDFViewer } from '../pdf/PDFViewer';
import { SidebarAnnos } from '../SidebarAnnos';
@@ -195,6 +196,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
}
+ brushView = (view: { width: number; height: number; panX: number; panY: number }) => {
+ this._pdfViewer?.brushView(view);
+ };
scrollFocus = (doc: Doc, smooth: boolean) => {
let didToggle = false;
if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) {
@@ -438,7 +442,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
}
- isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected();
+ isPdfContentActive = () => this.isAnyChildContentActive() || this.props.isSelected() || (this.props.renderDepth === 0 && LightboxView.IsLightboxDocView(this.props.docViewPath()));
@computed get renderPdfView() {
TraceMobx();
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
diff --git a/src/client/views/nodes/RecordingBox/RecordingView.scss b/src/client/views/nodes/RecordingBox/RecordingView.scss
index 2e6f6bc26..287cccd8f 100644
--- a/src/client/views/nodes/RecordingBox/RecordingView.scss
+++ b/src/client/views/nodes/RecordingBox/RecordingView.scss
@@ -41,30 +41,22 @@ button {
.controls {
display: flex;
align-items: center;
- justify-content: space-evenly;
+ justify-content: center;
position: absolute;
- // padding: 14px;
- //width: 100%;
- max-width: 500px;
- // max-height: 20%;
+ width: 100%;
flex-wrap: wrap;
background: rgba(255, 255, 255, 0.25);
box-shadow: 0 8px 32px 0 rgba(255, 255, 255, 0.1);
- backdrop-filter: blur(4px);
+ // backdrop-filter: blur(4px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.18);
- // transform: translateY(150%);
transition: all 0.3s ease-in-out;
- // opacity: 0%;
bottom: 34.5px;
height: 60px;
- right: 2px;
- // bottom: -150px;
}
.controls:active {
bottom: 40px;
- // bottom: -150px;
}
.actions button {
@@ -134,8 +126,10 @@ button {
.controls-inner-container {
display: flex;
flex-direction: row;
- align-content: center;
position: relative;
+ width: 100%;
+ align-items: center;
+ justify-content: center;
}
.record-button-wrapper {
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 1c9b0bc0e..4883ad538 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -397,8 +397,8 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
onPointerDown={e => e.stopPropagation()}
onChange={e => this.viewChanged(e, parameter)}
value={typeof this.rootDoc[parameter] === 'string' ? 'S' + StrCast(this.rootDoc[parameter]) : typeof this.rootDoc[parameter] === 'number' ? 'N' + NumCast(this.rootDoc[parameter]) : 'B' + BoolCast(this.rootDoc[parameter])}>
- {types.map(type => (
- <option className="scriptingBox-viewOption" value={(typeof type === 'string' ? 'S' : typeof type === 'number' ? 'N' : 'B') + type}>
+ {types.map((type, i) => (
+ <option key={i} className="scriptingBox-viewOption" value={(typeof type === 'string' ? 'S' : typeof type === 'number' ? 'N' : 'B') + type}>
{' '}
{type.toString()}{' '}
</option>
@@ -666,7 +666,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
const definedParameters = !this.compileParams.length ? null : (
<div className="scriptingBox-plist" style={{ width: '30%' }}>
{this.compileParams.map((parameter, i) => (
- <div className="scriptingBox-pborder" onKeyPress={e => e.key === 'Enter' && this._overlayDisposer?.()}>
+ <div key={i} className="scriptingBox-pborder" onKeyPress={e => e.key === 'Enter' && this._overlayDisposer?.()}>
<EditableView
display={'block'}
maxHeight={72}
@@ -745,7 +745,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
{!this.compileParams.length || !this.paramsNames ? null : (
<div className="scriptingBox-plist">
{this.paramsNames.map((parameter: string, i: number) => (
- <div className="scriptingBox-pborder" onKeyPress={e => e.key === 'Enter' && this._overlayDisposer?.()}>
+ <div key={i} className="scriptingBox-pborder" onKeyPress={e => e.key === 'Enter' && this._overlayDisposer?.()}>
<div className="scriptingBox-wrapper" style={{ maxHeight: '40px' }}>
<div className="scriptingBox-paramNames"> {`${parameter}:${this.paramsTypes[i]} = `} </div>
{this.paramsTypes[i] === 'boolean' ? this.renderEnum(parameter, [true, false]) : null}
@@ -805,7 +805,6 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
// renders script UI if _applied = false and params UI if _applied = true
render() {
- console.log(ReactTextareaAutocomplete);
TraceMobx();
return (
<div className={`scriptingBox`} onContextMenu={this.specificContextMenu} onPointerUp={!this._function ? this.suggestionPos : undefined}>
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index aa51714da..5e1359441 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -1,4 +1,4 @@
-@import "../global/globalCssVariables.scss";
+@import '../global/globalCssVariables.scss';
.mini-viewer {
cursor: grab;
@@ -83,6 +83,8 @@
.videoBox-ui-wrapper {
width: 0;
height: 0;
+ position: relative;
+ z-index: 100001;
}
.videoBox-ui {
@@ -97,7 +99,7 @@
height: 40px;
padding: 0 10px 0 7px;
transition: opacity 0.3s;
- z-index: 100001;
+ z-index: 10001;
.timecode-controls {
display: flex;
@@ -114,7 +116,8 @@
}
}
- .toolbar-slider.volume, .toolbar-slider.zoom {
+ .toolbar-slider.volume,
+ .toolbar-slider.zoom {
width: 50px;
}
@@ -157,7 +160,8 @@
}
}
-.videoBox-content-fullScreen, .videoBox-content-fullScreen-interactive {
+.videoBox-content-fullScreen,
+.videoBox-content-fullScreen-interactive {
display: flex;
justify-content: center;
align-items: flex-end;
@@ -175,16 +179,16 @@ video::-webkit-media-controls {
display: none !important;
}
-input[type="range"] {
+input[type='range'] {
-webkit-appearance: none;
background: none;
}
-input[type="range"]:focus {
+input[type='range']:focus {
outline: none;
}
-input[type="range"]::-webkit-slider-runnable-track {
+input[type='range']::-webkit-slider-runnable-track {
width: 100%;
height: 10px;
cursor: pointer;
@@ -193,7 +197,7 @@ input[type="range"]::-webkit-slider-runnable-track {
border-radius: 10px;
}
-input[type="range"]::-webkit-slider-thumb {
+input[type='range']::-webkit-slider-thumb {
box-shadow: 0;
border: 0;
height: 12px;
@@ -203,4 +207,4 @@ input[type="range"]::-webkit-slider-thumb {
cursor: pointer;
-webkit-appearance: none;
margin-top: -1px;
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 0ff15f93b..f7f558bb4 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -30,6 +30,7 @@ import { StyleProp } from '../StyleProvider';
import { FieldView, FieldViewProps } from './FieldView';
import { RecordingBox } from './RecordingBox';
import './VideoBox.scss';
+import { ObjectField } from '../../../fields/ObjectField';
const path = require('path');
/**
@@ -396,12 +397,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// sets video info on load
videoLoad = action(() => {
- const aspect = this.player!.videoWidth / this.player!.videoHeight;
- Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
- Doc.SetNativeHeight(this.dataDoc, this.player!.videoHeight);
- this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
+ const aspect = this.player!.videoWidth / (this.player!.videoHeight || 1);
+ if (aspect && !this.isCropped) {
+ Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
+ Doc.SetNativeHeight(this.dataDoc, this.player!.videoHeight);
+ this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
+ }
if (Number.isFinite(this.player!.duration)) {
this.rawDuration = this.player!.duration;
+ this.dataDoc[this.fieldKey + '-duration'] = this.rawDuration;
} else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '-duration']);
});
@@ -549,7 +553,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
return !field ? (
<div key="loading">Loading</div>
) : (
- <div className="videoBox-contentContainer" key="container" style={{ mixBlendMode: 'multiply', cursor: this._fullScreen && !this._controlsVisible ? 'none' : 'pointer' }}>
+ <div className="videoBox-contentContainer" key="container" style={{ mixBlendMode: 'multiply', cursor: this._fullScreen && !this._controlsVisible ? 'none' : 'default' }}>
<div className={classname} ref={this.setContentRef} onPointerDown={e => this._fullScreen && e.stopPropagation()}>
{this._fullScreen && (
<div
@@ -568,7 +572,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
key="video"
autoPlay={this._screenCapture}
ref={this.setVideoRef}
- style={this._fullScreen ? this.fullScreenSize() : {}}
+ style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._viewScale)})`, transformOrigin: 'top left' } : {}}
onCanPlay={this.videoLoad}
controls={VideoBox._nativeControls}
onPlay={() => this.Play()}
@@ -853,7 +857,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// starts marquee selection
marqueeDown = (e: React.PointerEvent) => {
- if (!e.altKey && e.button === 0 && this.layoutDoc._viewScale === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._viewScale, 1) === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
setupMoveUpEvents(
this,
e,
@@ -912,132 +916,46 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// renders video controls
componentUI = (boundsLeft: number, boundsTop: number) => {
- const bounds = this.props.docViewPath().lastElement().getBounds();
- const left = bounds?.left || 0;
- const right = bounds?.right || 0;
- const top = bounds?.top || 0;
- const height = (bounds?.bottom || 0) - top;
- const width = Math.max(right - left, 100);
- const uiHeight = Math.max(25, Math.min(50, height / 10));
- const uiMargin = Math.min(10, height / 20);
- const vidHeight = (height * this.heightPercent) / 100;
- const yPos = top + vidHeight - uiHeight - uiMargin;
- const xPos = uiHeight / vidHeight > 0.4 ? right + 10 : left + 10;
+ const xf = this.props.ScreenToLocalTransform().inverse();
+ const height = this.props.PanelHeight();
+ const vidHeight = (height * this.heightPercent) / 100 / this.scaling();
+ const vidWidth = this.props.PanelWidth() / this.scaling();
+ const uiHeight = 25;
+ const uiMargin = 10;
+ const yBot = xf.transformPoint(0, vidHeight)[1];
+ // prettier-ignore
+ const yMid = (xf.transformPoint(0, 0)[1] +
+ xf.transformPoint(0, height / this.scaling())[1]) / 2;
+ const xPos = xf.transformPoint(vidWidth / 2, 0)[0];
+ const xRight = xf.transformPoint(vidWidth, 0)[0];
const opacity = this._scrubbing ? 0.3 : this._controlsVisible ? 1 : 0;
- return this._fullScreen || right - left < 50 ? null : (
+ return this._fullScreen || this.isCropped || (xRight - xPos) * 2 < 50 ? null : (
<div className="videoBox-ui-wrapper" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
- <div className="videoBox-ui" style={{ left: xPos, top: yPos, height: uiHeight, width: width - 20, transition: this._clicking ? 'top 0.5s' : '', opacity: opacity }}>
+ <div
+ className="videoBox-ui"
+ style={{
+ transformOrigin: 'top left',
+ transform: `rotate(${NumCast(this.rootDoc.jitterRotation)}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`,
+ left: xPos,
+ top: yMid,
+ height: uiHeight,
+ width: (xRight - xPos) * 2 - 20,
+ transition: this._clicking ? 'top 0.5s' : '',
+ opacity,
+ }}>
{this.UIButtons}
</div>
</div>
);
};
- @computed get UIButtons() {
- const bounds = this.props.docViewPath().lastElement().getBounds();
- const width = (bounds?.right || 0) - (bounds?.left || 0);
- const curTime = NumCast(this.layoutDoc._currentTimecode) - (this.timeline?.clipStart || 0);
- return (
- <>
- <div className="videobox-button" title={this._playing ? 'play' : 'pause'} onPointerDown={this.onPlayDown}>
- <FontAwesomeIcon icon={this._playing ? 'pause' : 'play'} />
- </div>
-
- {this.timeline && width > 150 && (
- <div className="timecode-controls">
- <div className="timecode-current">{formatTime(curTime)}</div>
-
- {this._fullScreen || (this.heightPercent === 100 && width > 200) ? (
- <div className="timeline-slider">
- <input
- type="range"
- step="0.1"
- min={this.timeline.clipStart}
- max={this.timeline.clipEnd}
- value={curTime}
- className="toolbar-slider time-progress"
- onPointerDown={action((e: React.PointerEvent) => {
- e.stopPropagation();
- this._scrubbing = true;
- })}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setPlayheadTime(Number(e.target.value))}
- onPointerUp={action((e: React.PointerEvent) => {
- e.stopPropagation();
- this._scrubbing = false;
- })}
- />
- </div>
- ) : (
- <div>/</div>
- )}
-
- <div className="timecode-end">{formatTime(this.timeline.clipDuration)}</div>
- </div>
- )}
-
- <div className="videobox-button" title={'full screen'} onPointerDown={this.onFullDown}>
- <FontAwesomeIcon icon="expand" />
- </div>
-
- {!this._fullScreen && width > 300 && (
- <div className="videobox-button" title={'show timeline'} onPointerDown={this.onTimelineHdlDown}>
- <FontAwesomeIcon icon="eye" />
- </div>
- )}
-
- {!this._fullScreen && width > 300 && (
- <div className="videobox-button" title={this.timeline?.IsTrimming !== TrimScope.None ? 'finish trimming' : 'start trim'} onPointerDown={this.onClipPointerDown}>
- <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? 'check' : 'cut'} />
- </div>
- )}
-
- <div
- className="videobox-button"
- title={this._muted ? 'unmute' : 'mute'}
- onPointerDown={e => {
- e.stopPropagation();
- this.toggleMute();
- }}>
- <FontAwesomeIcon icon={this._muted ? 'volume-mute' : 'volume-up'} />
- </div>
- {width > 300 && (
- <input
- type="range"
- style={{ width: `min(25%, 50px)` }}
- step="0.1"
- min="0"
- max="1"
- value={this._muted ? 0 : this._volume}
- className="toolbar-slider volume"
- onPointerDown={(e: React.PointerEvent) => e.stopPropagation()}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setVolume(Number(e.target.value))}
- />
- )}
-
- {!this._fullScreen && this.heightPercent !== 100 && width > 300 && (
- <>
- <div className="videobox-button" title="zoom">
- <FontAwesomeIcon icon="search-plus" />
- </div>
- <input
- type="range"
- step="0.1"
- min="1"
- max="5"
- value={this.timeline?._zoomFactor}
- className="toolbar-slider zoom"
- onPointerDown={(e: React.PointerEvent) => {
- e.stopPropagation();
- }}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- this.zoom(Number(e.target.value));
- }}
- />
- </>
- )}
- </>
- );
- }
+ scrollFocus = (doc: Doc, smooth: boolean) => {
+ if (doc !== this.rootDoc) {
+ const showTime = Cast(doc._timecodeToShow, 'number', null);
+ showTime !== undefined && setTimeout(() => this.Seek(showTime), 100);
+ return 0.1;
+ }
+ };
// renders CollectionStackedTimeline
@computed get renderTimeline() {
@@ -1072,12 +990,63 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
</div>
);
}
+ @computed get isCropped() {
+ return this.dataDoc.videoCrop; // bcz: hack to identify a cropped video
+ }
// renders annotation layer
@computed get annotationLayer() {
return <div className="videoBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />;
}
+ crop = (region: Doc | undefined, addCrop?: boolean) => {
+ if (!region) return;
+ const cropping = Doc.MakeCopy(region, true);
+ Doc.GetProto(region).backgroundColor = 'transparent';
+ Doc.GetProto(region).lockedPosition = true;
+ Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+ Doc.GetProto(region).isPushpin = true;
+ region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
+ this.addDocument(region);
+ const anchx = NumCast(cropping.x);
+ const anchy = NumCast(cropping.y);
+ const anchw = NumCast(cropping._width);
+ const anchh = NumCast(cropping._height);
+ const viewScale = NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']) / anchw;
+ cropping.title = 'crop: ' + this.rootDoc.title;
+ cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width);
+ cropping.y = NumCast(this.rootDoc.y);
+ cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
+ cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
+ cropping.timecodeToHide = undefined;
+ cropping.timecodeToShow = undefined;
+ cropping.isLinkButton = undefined;
+ const croppingProto = Doc.GetProto(cropping);
+ croppingProto.annotationOn = undefined;
+ croppingProto.isPrototype = true;
+ croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO
+ croppingProto.type = DocumentType.VID;
+ croppingProto.layout = VideoBox.LayoutString('data');
+ croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField);
+ croppingProto['data-nativeWidth'] = anchw;
+ croppingProto['data-nativeHeight'] = anchh;
+ croppingProto.videoCrop = true;
+ croppingProto.currentTimecode = this.layoutDoc._currentTimecode;
+ croppingProto.viewScale = viewScale;
+ croppingProto.viewScaleMin = viewScale;
+ croppingProto.panX = anchx / viewScale;
+ croppingProto.panY = anchy / viewScale;
+ croppingProto.panXMin = anchx / viewScale;
+ croppingProto.panXMax = anchw / viewScale;
+ croppingProto.panYMin = anchy / viewScale;
+ croppingProto.panYMax = anchh / viewScale;
+ if (addCrop) {
+ DocUtils.MakeLink({ doc: region }, { doc: cropping }, 'cropped image', '');
+ }
+ this.props.bringToFront(cropping);
+ return cropping;
+ };
+
savedAnnotations = () => this._savedAnnotations;
render() {
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
@@ -1140,6 +1109,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
savedAnnotations={this.savedAnnotations}
annotationLayer={this._annotationLayer.current}
mainCont={this._mainCont.current}
+ anchorMenuCrop={this.crop}
/>
)}
{this.renderTimeline}
@@ -1147,6 +1117,112 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
</div>
);
}
+
+ @computed get UIButtons() {
+ const bounds = this.props.docViewPath().lastElement().getBounds();
+ const width = (bounds?.right || 0) - (bounds?.left || 0);
+ const curTime = NumCast(this.layoutDoc._currentTimecode) - (this.timeline?.clipStart || 0);
+ return (
+ <>
+ <div className="videobox-button" title={this._playing ? 'play' : 'pause'} onPointerDown={this.onPlayDown}>
+ <FontAwesomeIcon icon={this._playing ? 'pause' : 'play'} />
+ </div>
+
+ {this.timeline && width > 150 && (
+ <div className="timecode-controls">
+ <div className="timecode-current">{formatTime(curTime)}</div>
+
+ {this._fullScreen || (this.heightPercent === 100 && width > 200) ? (
+ <div className="timeline-slider">
+ <input
+ type="range"
+ step="0.1"
+ min={this.timeline.clipStart}
+ max={this.timeline.clipEnd}
+ value={curTime}
+ className="toolbar-slider time-progress"
+ onPointerDown={action((e: React.PointerEvent) => {
+ e.stopPropagation();
+ this._scrubbing = true;
+ })}
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setPlayheadTime(Number(e.target.value))}
+ onPointerUp={action((e: React.PointerEvent) => {
+ e.stopPropagation();
+ this._scrubbing = false;
+ })}
+ />
+ </div>
+ ) : (
+ <div>/</div>
+ )}
+
+ <div className="timecode-end">{formatTime(this.timeline.clipDuration)}</div>
+ </div>
+ )}
+
+ <div className="videobox-button" title={'full screen'} onPointerDown={this.onFullDown}>
+ <FontAwesomeIcon icon="expand" />
+ </div>
+
+ {!this._fullScreen && width > 300 && (
+ <div className="videobox-button" title={'show timeline'} onPointerDown={this.onTimelineHdlDown}>
+ <FontAwesomeIcon icon="eye" />
+ </div>
+ )}
+
+ {!this._fullScreen && width > 300 && (
+ <div className="videobox-button" title={this.timeline?.IsTrimming !== TrimScope.None ? 'finish trimming' : 'start trim'} onPointerDown={this.onClipPointerDown}>
+ <FontAwesomeIcon icon={this.timeline?.IsTrimming !== TrimScope.None ? 'check' : 'cut'} />
+ </div>
+ )}
+
+ <div
+ className="videobox-button"
+ title={this._muted ? 'unmute' : 'mute'}
+ onPointerDown={e => {
+ e.stopPropagation();
+ this.toggleMute();
+ }}>
+ <FontAwesomeIcon icon={this._muted ? 'volume-mute' : 'volume-up'} />
+ </div>
+ {width > 300 && (
+ <input
+ type="range"
+ style={{ width: `min(25%, 50px)` }}
+ step="0.1"
+ min="0"
+ max="1"
+ value={this._muted ? 0 : this._volume}
+ className="toolbar-slider volume"
+ onPointerDown={(e: React.PointerEvent) => e.stopPropagation()}
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.setVolume(Number(e.target.value))}
+ />
+ )}
+
+ {!this._fullScreen && this.heightPercent !== 100 && width > 300 && (
+ <>
+ <div className="videobox-button" title="zoom">
+ <FontAwesomeIcon icon="search-plus" />
+ </div>
+ <input
+ type="range"
+ step="0.1"
+ min="1"
+ max="5"
+ value={this.timeline?._zoomFactor}
+ className="toolbar-slider zoom"
+ onPointerDown={(e: React.PointerEvent) => {
+ e.stopPropagation();
+ }}
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
+ this.zoom(Number(e.target.value));
+ }}
+ />
+ </>
+ )}
+ </>
+ );
+ }
}
VideoBox._nativeControls = false;
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 85986ff27..a41f66ef0 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -5,7 +5,7 @@
width: 100%;
top: 0;
left: 0;
- position: absolute;
+ position: relative;
display: flex;
.webBox-sideResizer {
@@ -182,6 +182,12 @@
height: 100%;
position: absolute;
top: 0;
+ body {
+ ::selection {
+ color: white;
+ background: orange;
+ }
+ }
}
}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 6c2e42f86..460edb7c2 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -47,6 +47,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
public static openSidebarWidth = 250;
public static sidebarResizerWidth = 5;
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean) => void);
+ private _setBrushViewer: undefined | ((view: { width: number; height: number; panX: number; panY: number }) => void);
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _outerRef: React.RefObject<HTMLDivElement> = React.createRef();
private _disposers: { [name: string]: IReactionDisposer } = {};
@@ -242,6 +243,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
);
}
@action componentWillUnmount() {
+ this._iframetimeout && clearTimeout(this._iframetimeout);
+ this._iframetimeout = undefined;
Object.values(this._disposers).forEach(disposer => disposer?.());
// this._iframe?.removeEventListener('wheel', this.iframeWheel, true);
// this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp);
@@ -275,6 +278,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
+ setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => (this._setBrushViewer = func);
+ brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view);
scrollFocus = (doc: Doc, smooth: boolean) => {
if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth);
if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) {
@@ -285,7 +290,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1);
const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(doc.y) + doc[HeightSym](), this.getScrollHeight()));
if (scrollTo !== undefined && this._initialScroll === undefined) {
- const focusSpeed = smooth ? 500 : 0;
+ const focusSpeed = smooth ? NumCast(doc.focusSpeed, 500) : 0;
this.goTo(scrollTo, focusSpeed);
return focusSpeed;
} else if (!this._webPageHasBeenRendered || !this.getScrollHeight() || this._initialScroll !== undefined) {
@@ -332,7 +337,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
this._setPreviewCursor?.(e.clientX, e.clientY, false, true);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
- this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale];
+ e.button !== 2 && (this._marqueeing = [e.clientX * scale + mainContBounds.translateX, e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale]);
if (word || ((e.target as any) || '').className.includes('rangeslider') || (e.target as any)?.onclick || (e.target as any)?.parentNode?.onclick) {
setTimeout(
action(() => (this._marqueeing = undefined)),
@@ -349,7 +354,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
// bcz: hack - iframe grabs all events which messes up how we handle contextMenus. So this super naively simulates the event stack to get the specific menu items and the doc view menu items.
if (e.button === 2 || (e.button === 0 && e.altKey)) {
e.preventDefault();
- e.stopPropagation();
+ //e.stopPropagation();
ContextMenu.Instance.closeMenu();
ContextMenu.Instance.setIgnoreEvents(true);
}
@@ -363,12 +368,32 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
iframeClick = () => this._iframeClick;
iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale;
+ addStyleSheet(document: any, styleType: string = 'text/css') {
+ const style = document.createElement('style');
+ style.type = styleType;
+ const sheets = document.head.appendChild(style);
+ return (sheets as any).sheet;
+ }
+ addStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
+ const propText =
+ typeof css === 'string'
+ ? css
+ : Object.keys(css)
+ .map(p => p + ':' + (p === 'content' ? "'" + css[p] + "'" : css[p]))
+ .join(';');
+ return sheet.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
+ }
+
+ _iframetimeout: any = undefined;
@action
iframeLoaded = (e: any) => {
const iframe = this._iframe;
if (this._initialScroll !== undefined) {
this.setScrollPos(this._initialScroll);
}
+
+ this.addStyleSheetRule(this.addStyleSheet(this._iframe?.contentDocument), '::selection', { color: 'white', background: 'orange' }, '');
+
let requrlraw = decodeURIComponent(iframe?.contentWindow?.location.href.replace(Utils.prepend('') + '/corsProxy/', '') ?? this._url.toString());
if (requrlraw !== this._url.toString()) {
if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
@@ -387,16 +412,25 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
}
this.submitURL(requrlraw, undefined, true);
}
- if (iframe?.contentDocument) {
- iframe.contentDocument.addEventListener('pointerup', this.iframeUp);
- iframe.contentDocument.addEventListener('pointerdown', this.iframeDown);
- this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument.body.scrollHeight);
- setTimeout(
- action(() => (this._scrollHeight = Math.max(this._scrollHeight, iframe?.contentDocument?.body.scrollHeight || 0))),
+ const iframeContent = iframe?.contentDocument;
+ if (iframeContent) {
+ iframeContent.addEventListener('pointerup', this.iframeUp);
+ iframeContent.addEventListener('pointerdown', this.iframeDown);
+ const initHeights = () => {
+ this._scrollHeight = Math.max(this._scrollHeight, (iframeContent.body.children[0] as any)?.scrollHeight || 0);
+ if (this._scrollHeight) {
+ this.rootDoc.nativeHeight = Math.min(NumCast(this.rootDoc.nativeHeight), this._scrollHeight);
+ this.layoutDoc.height = Math.min(this.layoutDoc[HeightSym](), (this.layoutDoc[WidthSym]() * NumCast(this.rootDoc.nativeHeight)) / NumCast(this.rootDoc.nativeWidth));
+ }
+ };
+ initHeights();
+ this._iframetimeout && clearTimeout(this._iframetimeout);
+ this._iframetimeout = setTimeout(
+ action(() => initHeights),
5000
);
iframe.setAttribute('enable-annotation', 'true');
- iframe.contentDocument.addEventListener(
+ iframeContent.addEventListener(
'click',
undoBatch(
action((e: MouseEvent) => {
@@ -831,6 +865,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
fieldKey={this.annotationKey}
CollectionView={undefined}
setPreviewCursor={this.setPreviewCursor}
+ setBrushViewer={this.setBrushViewer}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
ScreenToLocalTransform={this.scrollXf}
@@ -859,7 +894,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
onWheel={StopEvent} // block wheel events from propagating since they're handled by the iframe
onScroll={e => this.setDashScrollTop(this._outerRef.current?.scrollTop || 0)}
onPointerDown={this.onMarqueeDown}>
- <div className={'webBox-innerContent'} style={{ height: this._webPageHasBeenRendered ? NumCast(this.scrollHeight, 50) : '100%', pointerEvents }}>
+ <div className={'webBox-innerContent'} style={{ height: this._webPageHasBeenRendered && this._scrollHeight ? this.scrollHeight : '100%', pointerEvents }}>
{this.content}
{<div style={{ display: DragManager.docsBeingDragged.length ? 'none' : undefined, mixBlendMode: 'multiply' }}>{renderAnnotations(this.transparentFilter)}</div>}
{renderAnnotations(this.opaqueFilter)}
@@ -919,13 +954,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
return this.props.styleProvider?.(doc, props, property);
};
pointerEvents = () => (!this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
- annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() ? 'all' : 'none');
+ annotationPointerEvents = () => (this._isAnnotating || SnappingManager.GetIsDragging() || Doc.ActiveTool !== InkTool.None ? 'all' : 'none');
render() {
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this.props.pointerEvents?.() as any);
const scale = previewScale * (this.props.NativeDimScaling?.() || 1);
return (
- <div className="webBox" ref={this._mainCont} style={{ pointerEvents: this.pointerEvents(), display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined }}>
+ <div
+ className="webBox"
+ ref={this._mainCont}
+ style={{ pointerEvents: this.pointerEvents(), position: SnappingManager.GetIsDragging() ? 'absolute' : undefined, display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined }}>
<div className="webBox-background" style={{ backgroundColor: this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor) }} />
<div
className="webBox-container"
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index c72b5ca9b..6d1751b25 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -275,7 +275,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
icon = 'globe-asia';
text = 'User Default';
}
- noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking];
+ noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking, CollectionViewType.NoteTaking];
} else if (script?.script.originalScript.startsWith('setFont')) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
text = StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
@@ -576,27 +576,19 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
// toggle: Set overlay status of selected document
ScriptingGlobals.add(function setFont(font: string, checkResult?: boolean) {
- SelectionManager.Docs().map(doc => (doc._fontFamily = font));
- const editorView = RichTextMenu.Instance.TextView?.EditorView;
- if (checkResult) {
- return StrCast((editorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily);
- }
- if (editorView) RichTextMenu.Instance.setFontFamily(font);
- else Doc.UserDoc().fontFamily = font;
+ if (checkResult) return RichTextMenu.Instance?.fontFamily;
+ font && RichTextMenu.Instance.setFontFamily(font);
});
ScriptingGlobals.add(function getActiveTextInfo(info: 'family' | 'size' | 'color' | 'highlight') {
const editorView = RichTextMenu.Instance.TextView?.EditorView;
const style = editorView?.state && RichTextMenu.Instance.getActiveFontStylesOnSelection();
+ // prettier-ignore
switch (info) {
- case 'family':
- return style?.activeFamilies[0];
- case 'size':
- return style?.activeSizes[0];
- case 'color':
- return style?.activeColors[0];
- case 'highlight':
- return style?.activeHighlights[0];
+ case 'family': return style?.activeFamilies[0];
+ case 'size': return style?.activeSizes[0];
+ case 'color': return style?.activeColors[0];
+ case 'highlight': return style?.activeHighlights[0];
}
});
@@ -621,14 +613,8 @@ ScriptingGlobals.add(function setBulletList(mapStyle: 'bullet' | 'decimal', chec
// toggle: Set overlay status of selected document
ScriptingGlobals.add(function setFontColor(color?: string, checkResult?: boolean) {
- const editorView = RichTextMenu.Instance?.TextView?.EditorView;
-
- if (checkResult) {
- return editorView ? RichTextMenu.Instance.fontColor : Doc.UserDoc().fontColor;
- }
-
- if (editorView) color && RichTextMenu.Instance.setColor(color, editorView, editorView?.dispatch);
- else Doc.UserDoc().fontColor = color;
+ if (checkResult) return RichTextMenu.Instance.fontColor;
+ color && RichTextMenu.Instance.setColor(color);
});
// toggle: Set overlay status of selected document
@@ -650,14 +636,12 @@ ScriptingGlobals.add(function setFontHighlight(color?: string, checkResult?: boo
// toggle: Set overlay status of selected document
ScriptingGlobals.add(function setFontSize(size: string | number, checkResult?: boolean) {
- const editorView = RichTextMenu.Instance?.TextView?.EditorView;
if (checkResult) {
return RichTextMenu.Instance?.fontSize.replace('px', '');
}
if (typeof size === 'number') size = size.toString();
if (size && Number(size).toString() === size) size += 'px';
- if (editorView) RichTextMenu.Instance.setFontSize(size);
- else Doc.UserDoc()._fontSize = size;
+ RichTextMenu.Instance.setFontSize(size);
});
ScriptingGlobals.add(function toggleNoAutoLinkAnchor(checkResult?: boolean) {
const editorView = RichTextMenu.Instance?.TextView?.EditorView;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 81ac45521..6db199149 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -603,20 +603,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { background: 'moccasin' });
}
if (highlights.indexOf('Todo Items') !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-' + 'todo', { outline: 'black solid 1px' });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-todo', { outline: 'black solid 1px' });
}
if (highlights.indexOf('Important Items') !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-' + 'important', { 'font-size': 'larger' });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-important', { 'font-size': 'larger' });
}
if (highlights.indexOf('Bold Text') !== -1) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner-selected .ProseMirror strong > span', { 'font-size': 'large' }, '');
addStyleSheetRule(FormattedTextBox._userStyleSheet, '.formattedTextBox-inner-selected .ProseMirror :not(strong > span)', { 'font-size': '0px' }, '');
}
if (highlights.indexOf('Disagree Items') !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-' + 'disagree', { 'text-decoration': 'line-through' });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-disagree', { 'text-decoration': 'line-through' });
}
if (highlights.indexOf('Ignore Items') !== -1) {
- addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-' + 'ignore', { 'font-size': '1' });
+ addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UT-ignore', { 'font-size': '1' });
}
if (highlights.indexOf('By Recent Minute') !== -1) {
addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-' + Doc.CurrentUserEmail.replace('.', '').replace('@', ''), { opacity: '0.1' });
@@ -1006,7 +1006,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
() => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }),
({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => {
const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight));
- if (autoHeight && newHeight && newHeight !== this.rootDoc.height) {
+ if (autoHeight && newHeight && newHeight !== this.rootDoc.height && !this.props.dontRegisterView) {
this.props.setHeight?.(newHeight);
}
},
@@ -1387,10 +1387,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
selectOnLoad && this._editorView!.focus();
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
- if (this._editorView && !this._editorView.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark)) {
+ if (this._editorView) {
this._editorView.state.storedMarks = [
...(this._editorView.state.storedMarks ?? []),
- schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }),
+ ...(!this._editorView.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark) ? [schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })] : []),
...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []),
...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []),
...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []),
@@ -1697,9 +1697,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
if (children) {
- const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace('px', '')), margins);
+ const proseHeight = !this.ProseRef
+ ? 0
+ : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace('px', '')) + Number(getComputedStyle(child).marginTop.replace('px', '')) + Number(getComputedStyle(child).marginBottom.replace('px', '')), margins);
const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
- if (this.props.setHeight && scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) {
+ if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
// if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
const setScrollHeight = () => (this.rootDoc[this.fieldKey + '-scrollHeight'] = scrollHeight);
if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
@@ -1860,7 +1862,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
className={`formattedTextBox-cont`}
ref={this._ref}
style={{
- overflow: this.autoHeight ? 'hidden' : undefined,
+ overflow: this.autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an autoHeight doc in its own tab, or in the lightbox
height: this.props.height || (this.autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
pointerEvents: interactive ? undefined : 'none',
}}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 31552cf1b..be501329f 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -168,6 +168,15 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
bind('Alt-Enter', () => (props.onKey?.(event, props) ? true : true));
bind('Ctrl-Enter', () => (props.onKey?.(event, props) ? true : true));
+ bind('Cmd-a', (state: EditorState, dispatch: (tx: Transaction) => void) => {
+ dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(1), state.doc.resolve(state.doc.content.size - 1))));
+ return true;
+ });
+
+ bind('Ctrl-a', (state: EditorState, dispatch: (tx: Transaction) => void) => {
+ dispatch(state.tr.setSelection(new TextSelection(state.doc.resolve(1), state.doc.resolve(state.doc.content.size - 1))));
+ return true;
+ });
// backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward);
bind('Backspace', (state: EditorState, dispatch: (tx: Transaction) => void) => {
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 0cbe60c0c..6c6d26af5 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -64,6 +64,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
super(props);
runInAction(() => {
RichTextMenu.Instance = this;
+ this.updateMenu(undefined, undefined, props);
this._canFade = false;
this.Pinned = true;
});
@@ -103,13 +104,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return;
}
this.view = view;
- if (!view || !view.hasFocus()) {
- return;
- }
props && (this.editorProps = props);
// Don't do anything if the document/selection didn't change
- if (lastState?.doc.eq(view.state.doc) && lastState.selection.eq(view.state.selection)) return;
+ if (view && view.hasFocus()) {
+ if (lastState?.doc.eq(view.state.doc) && lastState.selection.eq(view.state.selection)) return;
+ }
// update active marks
const activeMarks = this.getActiveMarksOnSelection();
@@ -124,9 +124,9 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.activeListType = this.getActiveListStyle();
this._activeAlignment = this.getActiveAlignment();
- this._activeFontFamily = !activeFamilies.length ? 'Arial' : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various';
- this._activeFontSize = !activeSizes.length ? StrCast(this.TextView.Document.fontSize, StrCast(Doc.UserDoc().fontSize, '10px')) : activeSizes[0];
- this._activeFontColor = !activeColors.length ? 'black' : activeColors.length > 0 ? String(activeColors[0]) : '...';
+ this._activeFontFamily = !activeFamilies.length ? StrCast(this.TextView?.Document.fontFamily, StrCast(Doc.UserDoc().fontFamily, 'Arial')) : activeFamilies.length === 1 ? String(activeFamilies[0]) : 'various';
+ this._activeFontSize = !activeSizes.length ? StrCast(this.TextView?.Document.fontSize, StrCast(Doc.UserDoc().fontSize, '10px')) : activeSizes[0];
+ this._activeFontColor = !activeColors.length ? StrCast(this.TextView?.Document.fontColor, StrCast(Doc.UserDoc().fontColor, 'black')) : activeColors.length > 0 ? String(activeColors[0]) : '...';
this.activeHighlightColor = !activeHighlights.length ? '' : activeHighlights.length > 0 ? String(activeHighlights[0]) : '...';
// update link in current selection
@@ -144,13 +144,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const tr = updateBullets(state.tr.setNodeMarkup(state.selection.from, node.type, attrs), state.schema);
dispatch(tr.setSelection(new NodeSelection(tr.doc.resolve(state.selection.from))));
} else if (dontToggle) {
- toggleMark(mark.type, mark.attrs)(state, (tx: any) => {
- const { from, $from, to, empty } = tx.selection;
- if (!tx.doc.rangeHasMark(from, to, mark.type)) {
- // hack -- should have just set the mark in the first place
- toggleMark(mark.type, mark.attrs)({ tr: tx, doc: tx.doc, selection: tx.selection, storedMarks: tx.storedMarks }, dispatch);
- } else dispatch(tx);
- });
+ const tr = state.tr.addMark(state.selection.from, state.selection.to, mark);
+ dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(state.selection.from), tr.doc.resolve(state.selection.to)))); // bcz: need to redo the selection because ctrl-a selections disappear otherwise
} else {
toggleMark(mark.type, mark.attrs)(state, dispatch);
}
@@ -159,7 +154,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
// finds font sizes and families in selection
getActiveAlignment() {
- if (this.view && this.TextView.props.isSelected(true)) {
+ if (this.view && this.TextView?.props.isSelected(true)) {
const path = (this.view.state.selection.$from as any).path;
for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) {
if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) {
@@ -172,7 +167,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
// finds font sizes and families in selection
getActiveListStyle() {
- if (this.view && this.TextView.props.isSelected(true)) {
+ if (this.view && this.TextView?.props.isSelected(true)) {
const path = (this.view.state.selection.$from as any).path;
for (let i = 0; i < path.length; i += 3) {
if (path[i].type === this.view.state.schema.nodes.ordered_list) {
@@ -188,17 +183,16 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
// finds font sizes and families in selection
getActiveFontStylesOnSelection() {
- if (!this.view) return { activeFamilies: [], activeSizes: [], activeColors: [], activeHighlights: [] };
-
- const activeFamilies: string[] = [];
- const activeSizes: string[] = [];
- const activeColors: string[] = [];
- const activeHighlights: string[] = [];
- if (this.TextView.props.isSelected(true)) {
+ const activeFamilies = new Set<string>();
+ const activeSizes = new Set<string>();
+ const activeColors = new Set<string>();
+ const activeHighlights = new Set<string>();
+ if (this.view && this.TextView?.props.isSelected(true)) {
const state = this.view.state;
const pos = this.view.state.selection.$from;
const marks: Mark[] = [...(state.storedMarks ?? [])];
- if (state.selection.empty) {
+ if (state.storedMarks !== null) {
+ } else if (state.selection.empty) {
const ref_node = this.reference_node(pos);
marks.push(...(ref_node !== this.view.state.doc && ref_node?.isText ? Array.from(ref_node.marks) : []));
} else {
@@ -207,13 +201,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
});
}
marks.forEach(m => {
- m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family);
- m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color);
- m.type === state.schema.marks.pFontSize && activeSizes.push(m.attrs.fontSize);
- m.type === state.schema.marks.marker && activeHighlights.push(String(m.attrs.highlight));
+ m.type === state.schema.marks.pFontFamily && activeFamilies.add(m.attrs.family);
+ m.type === state.schema.marks.pFontColor && activeColors.add(m.attrs.color);
+ m.type === state.schema.marks.pFontSize && activeSizes.add(m.attrs.fontSize);
+ m.type === state.schema.marks.marker && activeHighlights.add(String(m.attrs.highlight));
});
}
- return { activeFamilies, activeSizes, activeColors, activeHighlights };
+ return { activeFamilies: Array.from(activeFamilies), activeSizes: Array.from(activeSizes), activeColors: Array.from(activeColors), activeHighlights: Array.from(activeHighlights) };
}
getMarksInSelection(state: EditorState) {
@@ -226,7 +220,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
//finds all active marks on selection in given group
getActiveMarksOnSelection() {
let activeMarks: MarkType[] = [];
- if (!this.view || !this.TextView.props.isSelected(true)) return activeMarks;
+ if (!this.view || !this.TextView?.props.isSelected(true)) return activeMarks;
const markGroup = [schema.marks.noAutoLinkAnchor, schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript];
if (this.view.state.storedMarks) return this.view.state.storedMarks.map(mark => mark.type);
@@ -279,28 +273,15 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this._superscriptActive = false;
activeMarks.forEach(mark => {
+ // prettier-ignore
switch (mark.name) {
- case 'noAutoLinkAnchor':
- this._noLinkActive = true;
- break;
- case 'strong':
- this._boldActive = true;
- break;
- case 'em':
- this._italicsActive = true;
- break;
- case 'underline':
- this._underlineActive = true;
- break;
- case 'strikethrough':
- this._strikethroughActive = true;
- break;
- case 'subscript':
- this._subscriptActive = true;
- break;
- case 'superscript':
- this._superscriptActive = true;
- break;
+ case 'noAutoLinkAnchor': this._noLinkActive = true; break;
+ case 'strong': this._boldActive = true; break;
+ case 'em': this._italicsActive = true; break;
+ case 'underline': this._underlineActive = true; break;
+ case 'strikethrough': this._strikethroughActive = true; break;
+ case 'subscript': this._subscriptActive = true; break;
+ case 'superscript': this._superscriptActive = true; break;
}
});
}
@@ -342,14 +323,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
if (this.view.state.selection.from === 1 && this.view.state.selection.empty && (!this.view.state.doc.nodeAt(1) || !this.view.state.doc.nodeAt(1)?.marks.some(m => m.type.name === fontSize))) {
this.TextView.dataDoc.fontSize = fontSize;
this.view.focus();
- this.updateMenu(this.view, undefined, this.props);
} else {
const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize });
this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
this.view.focus();
- this.updateMenu(this.view, undefined, this.props);
}
- }
+ } else Doc.UserDoc()._fontSize = fontSize;
+ this.updateMenu(this.view, undefined, this.props);
};
setFontFamily = (family: string) => {
@@ -357,8 +337,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const fmark = this.view.state.schema.marks.pFontFamily.create({ family: family });
this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
this.view.focus();
- this.updateMenu(this.view, undefined, this.props);
- }
+ } else Doc.UserDoc()._fontFamily = family;
+ this.updateMenu(this.view, undefined, this.props);
};
setHighlight(color: String, view: EditorView, dispatch: any) {
@@ -368,13 +348,13 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.setMark(highlightMark, view.state, dispatch, false);
}
- setColor(color: String, view: EditorView, dispatch: any) {
+ setColor(color: string) {
if (this.view) {
- const colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color });
+ const colorMark = this.view.state.schema.mark(this.view.state.schema.marks.pFontColor, { color });
this.setMark(colorMark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(colorMark)), true);
- view.focus();
- this.updateMenu(this.view, undefined, this.props);
- }
+ this.view.focus();
+ } else Doc.UserDoc().fontColor = color;
+ this.updateMenu(this.view, undefined, this.props);
}
// TODO: remove doesn't work
@@ -430,7 +410,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => {
- if (this.TextView.props.isSelected(true)) {
+ if (this.TextView?.props.isSelected(true)) {
var tr = view.state.tr;
view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos, parent, index) => {
if ([schema.nodes.paragraph, schema.nodes.heading].includes(node.type)) {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 2097b321f..e5ea7b3b0 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -276,7 +276,7 @@ export class RichTextRules {
this.Document[DataSym][fieldKey] = value === 'true' ? true : value === 'false' ? false : num ? Number(value) : value;
}
const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid });
- return state.tr.deleteRange(start, end).insert(start, fieldView);
+ return state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).replaceSelectionWith(fieldView, true);
}),
// create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
@@ -327,7 +327,10 @@ export class RichTextRules {
this.Document[DataSym].tags = `${tags + '#' + tag + ':'}`;
}
const fieldView = state.schema.nodes.dashField.create({ fieldKey: '#' + tag });
- return state.tr.deleteRange(start, end).insert(start, fieldView).insertText(' ');
+ return state.tr
+ .setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end)))
+ .replaceSelectionWith(fieldView, true)
+ .insertText(' ');
}),
// # heading
@@ -343,8 +346,14 @@ export class RichTextRules {
const node = (state.doc.resolve(start) as any).nodeAfter;
if (node?.marks.findIndex((m: any) => m.type === schema.marks.user_tag) !== -1) return state.tr.removeMark(start, end, schema.marks.user_tag);
-
- return node ? state.tr.addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: tag, modified: Math.round(Date.now() / 1000 / 60) })) : state.tr;
+ if (node?.marks.findIndex((m: any) => m.type === schema.marks.user_mark) !== -1) {
+ }
+ return node
+ ? state.tr
+ .removeMark(start, end, schema.marks.user_mark)
+ .addMark(start, end, schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }))
+ .addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: tag, modified: Math.round(Date.now() / 1000 / 60) }))
+ : state.tr;
}),
new InputRule(new RegExp(/%\(/), (state, match, start, end) => {
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index a0a2dd4f8..4d60a02f1 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -1,4 +1,4 @@
-@import "../../global/globalCssVariables";
+@import '../../global/globalCssVariables';
.presBox-cont {
cursor: auto;
@@ -231,8 +231,7 @@
margin-top: 10px;
}
- @media screen and (-webkit-min-device-pixel-ratio:0) {
-
+ @media screen and (-webkit-min-device-pixel-ratio: 0) {
.multiThumb-slider {
display: grid;
background-color: $white;
@@ -289,6 +288,7 @@
height: 10px;
-webkit-appearance: none;
margin-top: -1px;
+ background: transparent;
}
.toolbar-slider::-webkit-slider-thumb {
@@ -330,8 +330,6 @@
}
}
-
-
.slider-headers {
position: relative;
display: grid;
@@ -354,8 +352,8 @@
.slider-number {
border-radius: 3px;
- width: 30px;
margin: auto;
+ overflow: hidden;
}
}
@@ -382,7 +380,6 @@
border-bottom: solid 2px $medium-gray;
}
-
.ribbon-textInput {
border-radius: 2px;
height: 20px;
@@ -467,7 +464,6 @@
font-weight: 500;
position: relative;
-
.ribbon-final-button {
cursor: pointer;
position: relative;
@@ -687,7 +683,6 @@
max-width: 200px;
overflow: visible;
-
.presBox-dropdownOption {
cursor: pointer;
font-size: 11;
@@ -716,7 +711,7 @@
width: 85%;
min-width: max-content;
display: block;
- background: #FFFFFF;
+ background: #ffffff;
border: 0.5px solid #979797;
box-sizing: border-box;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
@@ -741,7 +736,7 @@
padding-top: 5px;
padding-bottom: 5px;
border: solid 1px $black;
- // overflow: auto;
+ // overflow: auto;
::-webkit-scrollbar {
-webkit-appearance: none;
@@ -953,8 +948,6 @@
min-width: 150px;
}
-
-
select {
background: $dark-gray;
color: $white;
@@ -999,8 +992,6 @@
}
}
-
-
.collectionViewBaseChrome-viewPicker {
min-width: 50;
width: 5%;
@@ -1080,7 +1071,7 @@
position: absolute;
top: 0;
left: 0;
- opacity: 0.1;
+ opacity: 0.5;
transition: all 0.4s;
color: $white;
width: 100%;
@@ -1165,8 +1156,6 @@
.presPanel-button-text:hover {
background-color: $medium-gray;
}
-
-
}
// .miniPres {
@@ -1241,4 +1230,4 @@
// background-color: #5a5a5a;
// }
// }
-// } \ No newline at end of file
+// }
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index eb40089ec..0c4d514cd 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -5,12 +5,14 @@ import { action, computed, IReactionDisposer, observable, ObservableSet, reactio
import { observer } from 'mobx-react';
import { ColorState, SketchPicker } from 'react-color';
import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
-import { Doc, DocListCast, DocListCastAsync, FieldResult } from '../../../../fields/Doc';
+import { Doc, DocListCast, DocListCastAsync, FieldResult, Opt } from '../../../../fields/Doc';
+import { Copy } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { List } from '../../../../fields/List';
+import { ObjectField } from '../../../../fields/ObjectField';
import { listSpec } from '../../../../fields/Schema';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents, StopEvent } from '../../../../Utils';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
import { DocumentManager } from '../../../util/DocumentManager';
@@ -19,8 +21,7 @@ import { SelectionManager } from '../../../util/SelectionManager';
import { SettingsManager } from '../../../util/SettingsManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
-import { MarqueeViewBounds } from '../../collections/collectionFreeForm';
-import { CollectionFreeFormViewChrome } from '../../collections/CollectionMenu';
+import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm';
import { CollectionView } from '../../collections/CollectionView';
import { TabDocView } from '../../collections/TabDocView';
import { ViewBoxBaseComponent } from '../../DocComponent';
@@ -43,7 +44,6 @@ export interface PinProps {
export interface PinViewProps {
bounds: MarqueeViewBounds;
- scale: number;
}
@observer
@@ -53,22 +53,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
/**
- * transitions & effects for documents
- * @param renderDoc
- * @param layoutDoc
+ * returns an entrance animation effect function to wrap a JSX element
+ * @param presEffectDoc presentation effects document that specifies the animation effect parameters
+ * @returns a function that will wrap a JSX animation element wrapping any JSX element
*/
- static renderEffectsDoc(renderDoc: any, layoutDoc: Doc, presDoc: Doc) {
+ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc) {
const effectProps = {
- left: presDoc.presEffectDirection === PresEffect.Left,
- right: presDoc.presEffectDirection === PresEffect.Right,
- top: presDoc.presEffectDirection === PresEffect.Top,
- bottom: presDoc.presEffectDirection === PresEffect.Bottom,
+ left: presEffectDoc.presEffectDirection === PresEffect.Left,
+ right: presEffectDoc.presEffectDirection === PresEffect.Right,
+ top: presEffectDoc.presEffectDirection === PresEffect.Top,
+ bottom: presEffectDoc.presEffectDirection === PresEffect.Bottom,
opposite: true,
- delay: presDoc.presTransition,
- // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
+ delay: NumCast(presEffectDoc.presTransition),
};
//prettier-ignore
- switch (presDoc.presEffect) {
+ switch (StrCast(presEffectDoc.presEffect)) {
default:
case PresEffect.None: return renderDoc;
case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
@@ -80,37 +79,30 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
case PresEffect.Lightspeed: return <LightSpeed {...effectProps}>{renderDoc}</LightSpeed>;
}
}
- public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
- return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ? PresBox.renderEffectsDoc(renderDoc, layoutDoc, PresBox.Instance.childDocs[PresBox.Instance.itemIndex]) : renderDoc;
- }
private _disposers: { [name: string]: IReactionDisposer } = {};
-
- constructor(props: any) {
- super(props);
- if ((Doc.ActivePresentation = this.rootDoc)) runInAction(() => (PresBox.Instance = this));
- this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
- }
+ public selectedArray = new ObservableSet<Doc>();
@observable public static Instance: PresBox;
+ @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView
@observable _isChildActive = false;
@observable _moveOnFromAudio: boolean = true;
@observable _presTimer!: NodeJS.Timeout;
- @observable _presKeyEventsActive: boolean = false;
@observable _eleArray: HTMLElement[] = [];
@observable _dragArray: HTMLElement[] = [];
@observable _pathBoolean: boolean = false;
@observable _expandBoolean: boolean = false;
-
- @observable static startMarquee: boolean = false; // onclick "+ new slide" in presentation mode, set as true, then when marquee selection finish, onPointerUp automatically triggers PinWithView
- @observable private transitionTools: boolean = false;
- @observable private newDocumentTools: boolean = false;
- @observable private progressivizeTools: boolean = false;
- @observable private openMovementDropdown: boolean = false;
- @observable private openEffectDropdown: boolean = false;
- @observable private presentTools: boolean = false;
+ @observable _transitionTools: boolean = false;
+ @observable _newDocumentTools: boolean = false;
+ @observable _progressivizeTools: boolean = false;
+ @observable _openMovementDropdown: boolean = false;
+ @observable _openEffectDropdown: boolean = false;
+ @observable _presentTools: boolean = false;
+ @observable _treeViewMap: Map<Doc, number> = new Map();
+ @observable _presKeyEvents: boolean = false;
+ @observable _forceKeyEvents: boolean = false;
@computed get isTreeOrStack() {
return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(StrCast(this.layoutDoc._viewType) as any);
}
@@ -123,15 +115,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get childDocs() {
return DocListCast(this.rootDoc[this.presFieldKey]);
}
- @observable _treeViewMap: Map<Doc, number> = new Map();
-
@computed get tagDocs() {
- const tagDocs: Doc[] = [];
- for (const doc of this.childDocs) {
- const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
- tagDocs.push(tagDoc);
- }
- return tagDocs;
+ return this.childDocs.map(doc => Cast(doc.presentationTargetDoc, Doc, null));
}
@computed get itemIndex() {
return NumCast(this.rootDoc._itemIndex);
@@ -142,41 +127,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get targetDoc() {
return Cast(this.activeItem?.presentationTargetDoc, Doc, null);
}
- @computed get scrollable(): boolean {
+ @computed get scrollable() {
if (this.targetDoc.type === DocumentType.PDF || this.targetDoc.type === DocumentType.WEB || this.targetDoc.type === DocumentType.RTF || this.targetDoc._viewType === CollectionViewType.Stacking) return true;
- else return false;
+ return false;
}
- @computed get panable(): boolean {
+ @computed get panable() {
if ((this.targetDoc.type === DocumentType.COL && this.targetDoc._viewType === CollectionViewType.Freeform) || this.targetDoc.type === DocumentType.IMG) return true;
- else return false;
+ return false;
}
@computed get selectedDocumentView() {
if (SelectionManager.Views().length) return SelectionManager.Views()[0];
- if (this._selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
+ if (this.selectedArray.size) return DocumentManager.Instance.getDocumentView(this.rootDoc);
}
- @computed get isPres(): boolean {
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- if (this.selectedDoc?.type === DocumentType.PRES) {
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
- return true;
- }
- return false;
+ @computed get isPres() {
+ return this.selectedDoc === this.rootDoc;
}
@computed get selectedDoc() {
return this.selectedDocumentView?.rootDoc;
}
- _selectedArray = new ObservableSet<Doc>();
- clearSelectedArray = () => this._selectedArray.clear();
- addToSelectedArray = (doc: Doc) => this._selectedArray.add(doc);
- removeFromSelectedArray = (doc: Doc) => this._selectedArray.delete(doc);
+ isActiveItemTarget = (layoutDoc: Doc) => this.activeItem?.presentationTargetDoc === layoutDoc;
+ clearSelectedArray = () => this.selectedArray.clear();
+ addToSelectedArray = (doc: Doc) => this.selectedArray.add(doc);
+ removeFromSelectedArray = (doc: Doc) => this.selectedArray.delete(doc);
_unmounting = false;
@action
componentWillUnmount() {
this._unmounting = true;
document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- this._presKeyEventsActive = false;
this.resetPresentation();
// Turn of progressivize editors
this.turnOffEdit(true);
@@ -185,6 +163,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
componentDidMount() {
+ this._disposers.keyboard = reaction(
+ () => this.selectedDoc,
+ selected => {
+ document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
+ (this._presKeyEvents = selected === this.rootDoc) && document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
+ },
+ { fireImmediately: true }
+ );
+ this._disposers.forcekeyboard = reaction(
+ () => this._forceKeyEvents,
+ force => {
+ if (force) {
+ document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
+ document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
+ this._presKeyEvents = true;
+ }
+ this._forceKeyEvents = false;
+ },
+ { fireImmediately: true }
+ );
this.props.setContentView?.(this);
this._unmounting = false;
this.rootDoc._forceRenderEngine = 'timeline';
@@ -192,7 +190,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc._gridGap = 0;
this.layoutDoc._yMargin = 0;
this.turnOffEdit(true);
- DocListCastAsync(Doc.MyTrails.data).then(pres => !pres?.includes(this.rootDoc) && Doc.AddDocToList(Doc.MyTrails, 'data', this.rootDoc));
this._disposers.selection = reaction(
() => SelectionManager.Views(),
views => views.some(view => view.props.Document === this.rootDoc) && this.updateCurrentPresentation()
@@ -201,11 +198,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
updateCurrentPresentation = (pres?: Doc) => {
- if (pres) Doc.ActivePresentation = pres;
- else Doc.ActivePresentation = this.rootDoc;
- document.removeEventListener('keydown', PresBox.keyEventsWrapper, true);
- document.addEventListener('keydown', PresBox.keyEventsWrapper, true);
- this._presKeyEventsActive = true;
+ Doc.ActivePresentation = pres ?? this.rootDoc;
PresBox.Instance = this;
};
@@ -241,17 +234,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//TODO: al: it seems currently that tempMedia doesn't stop onslidechange after clicking the button; the time the tempmedia stop depends on the start & end time
// TODO: to handle child slides (entering into subtrail and exiting), also the next() and back() functions
// No more frames in current doc and next slide is defined, therefore move to next slide
- nextSlide = (activeNext: Doc) => {
- const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
- console.info('nextSlide', activeNext.title, targetNext?.title);
- let nextSelected = this.itemIndex + 1;
+ nextSlide = (slideNum?: number) => {
+ let nextSelected = slideNum ?? this.itemIndex + 1;
this.gotoDocument(nextSelected, this.activeItem);
for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
- if (!this.childDocs[nextSelected].groupWithUp) {
- break;
- } else {
- console.log('Title: ' + this.childDocs[nextSelected].title);
+ if (this.childDocs[nextSelected].groupWithUp) {
this.gotoDocument(nextSelected, this.activeItem, true);
+ } else {
+ break;
}
}
};
@@ -271,10 +261,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.nextInternalFrame(targetDoc, activeItem);
} else if (this.childDocs[this.itemIndex + 1] !== undefined) {
// Case 2: No more frames in current doc and next slide is defined, therefore move to next slide
- this.nextSlide(activeNext);
+ const slides = DocListCast(this.rootDoc[StrCast(this.presFieldKey, 'data')]);
+ const curLast = this.selectedArray.size ? Math.max(...Array.from(this.selectedArray).map(d => slides.indexOf(DocCast(d)))) : this.itemIndex;
+ this.nextSlide(curLast + 1);
} else if (this.childDocs[this.itemIndex + 1] === undefined && (this.layoutDoc.presLoop || this.layoutDoc.presStatus === PresStatus.Edit)) {
// Case 3: Last slide and presLoop is toggled ON or it is in Edit mode
- this.gotoDocument(0, this.activeItem);
+ this.nextSlide(0);
}
};
@@ -290,8 +282,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
let prevSelected = this.itemIndex;
// Functionality for group with up
let didZoom = activeItem.presMovement;
- for (; !didZoom && prevSelected > 0 && this.childDocs[prevSelected].groupButton; prevSelected--) {
- didZoom = this.childDocs[prevSelected].presMovement;
+ for (; prevSelected > 0 && this.childDocs[Math.max(0, prevSelected - 1)].groupWithUp; prevSelected--) {
+ didZoom = didZoom === 'none' ? this.childDocs[prevSelected].presMovement : didZoom;
}
if (lastFrame !== undefined && curFrame >= 1) {
// Case 1: There are still other frames and should go through all frames before going to previous slide
@@ -299,7 +291,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
} else if (activeItem && this.childDocs[this.itemIndex - 1] !== undefined) {
// Case 2: There are no other frames so it should go to the previous slide
prevSelected = Math.max(0, prevSelected - 1);
- this.gotoDocument(prevSelected, activeItem);
+ this.nextSlide(prevSelected);
+ this.rootDoc._itemIndex = prevSelected;
if (NumCast(prevTargetDoc.lastFrame) > 0) prevTargetDoc._currentFrame = NumCast(prevTargetDoc.lastFrame);
} else if (this.childDocs[this.itemIndex - 1] === undefined && this.layoutDoc.presLoop) {
// Case 3: Pres loop is on so it should go to the last slide
@@ -309,6 +302,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//The function that is called when a document is clicked or reached through next or back.
//it'll also execute the necessary actions if presentation is playing.
+ @undoBatch
public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
Doc.UnBrushAllDocs();
@@ -317,8 +311,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
if (activeItem.presActiveFrame !== undefined) {
+ const transTime = NumCast(activeItem.presTransition, 500);
const context = DocCast(DocCast(activeItem.presentationTargetDoc).context);
- context && CollectionFreeFormViewChrome.gotoKeyFrame(context, NumCast(activeItem.presActiveFrame));
+ if (context) {
+ const contextView = DocumentManager.Instance.getFirstDocumentView(context);
+ if (contextView?.ComponentView) {
+ CollectionFreeFormDocumentView.gotoKeyframe((contextView.ComponentView as CollectionFreeFormView).childDocs.slice(), transTime);
+ context._currentFrame = NumCast(activeItem.presActiveFrame);
+ }
+ }
}
if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
@@ -332,95 +333,109 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (targetDoc) {
Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc);
- targetDoc &&
- runInAction(() => {
- if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
- else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
- });
- setTimeout(() => (targetDoc.focusSpeed = 500), this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+ targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500)));
+ setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10);
}
if (targetDoc?.lastFrame !== undefined) {
targetDoc._currentFrame = 0;
}
if (!group) this.clearSelectedArray();
this.childDocs[index] && this.addToSelectedArray(this.childDocs[index]); //Update selected array
- this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+ this.turnOffEdit();
+ this.navigateToActiveItem(); //Handles movement to element only when presTrail is list
this.onHideDocument(); //Handles hide after/before
}
});
-
- _navTimer!: NodeJS.Timeout;
- navigateToView = (targetDoc: Doc, activeItem: Doc) => {
- clearTimeout(this._navTimer);
- const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
- if (bestTarget) console.log(bestTarget.title, bestTarget.type);
- else console.log('no best target');
- if (bestTarget) this._navTimer = PresBox.navigateToDoc(bestTarget, activeItem, false);
- };
-
static pinDataTypes(target: Doc) {
const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(target.type as any) || target._viewType === CollectionViewType.Stacking;
const pannable = [DocumentType.IMG].includes(target.type as any) || (target.type === DocumentType.COL && target._viewType === CollectionViewType.Freeform);
const temporal = [DocumentType.AUDIO, DocumentType.VID].includes(target.type as any);
const clippable = [DocumentType.COMPARISON].includes(target.type as any);
- return { scrollable, pannable, temporal, clippable };
+ const dataview = [DocumentType.INK].includes(target.type as any) && target.activeFrame === undefined;
+ const textview = [DocumentType.RTF].includes(target.type as any) && target.activeFrame === undefined;
+ return { scrollable, pannable, temporal, clippable, dataview, textview };
}
- // navigates to the bestTarget document by making sure it is on screen,
- // then it applies the view specs stored in activeItem to
+
@action
- static navigateToDoc(bestTarget: Doc, activeItem: Doc, jumpToDoc: boolean) {
- bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
- const { scrollable, pannable, temporal, clippable } = this.pinDataTypes(bestTarget);
+ static restoreTargetDocView(bestTarget: Doc, activeItem: Doc) {
+ const transTime = NumCast(activeItem.presTransition, 500);
+ const presTransitionTime = `all ${transTime}ms`;
+ const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(bestTarget);
+ bestTarget._viewTransition = presTransitionTime;
if (clippable) bestTarget._clipWidth = activeItem.presPinClipWidth;
if (temporal) bestTarget._currentTimecode = activeItem.presStartTime;
- if (scrollable) bestTarget._scrollTop = activeItem.presPinViewScroll;
+ if (scrollable) {
+ bestTarget._scrollTop = activeItem.presPinViewScroll;
+ const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
+ if (contentBounds) {
+ const dv = DocumentManager.Instance.getDocumentView(bestTarget)?.ComponentView;
+ dv?.brushView?.({ panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] });
+ }
+ }
+ if (dataview) Doc.GetProto(bestTarget).data = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
+ if (textview) Doc.GetProto(bestTarget).text = activeItem.presData instanceof ObjectField ? activeItem.presData[Copy]() : activeItem.presData;
if (pannable) {
- const contentBounds = Cast(activeItem.contentBounds, listSpec('number'));
+ const contentBounds = Cast(activeItem.presPinViewBounds, listSpec('number'));
if (contentBounds) {
- bestTarget._panX = (contentBounds[0] + contentBounds[2]) / 2;
- bestTarget._panY = (contentBounds[1] + contentBounds[3]) / 2;
+ const viewport = { panX: (contentBounds[0] + contentBounds[2]) / 2, panY: (contentBounds[1] + contentBounds[3]) / 2, width: contentBounds[2] - contentBounds[0], height: contentBounds[3] - contentBounds[1] };
+ bestTarget._panX = viewport.panX;
+ bestTarget._panY = viewport.panY;
const dv = DocumentManager.Instance.getDocumentView(bestTarget);
if (dv) {
- bestTarget._viewScale = Math.min(dv.props.PanelHeight() / (contentBounds[3] - contentBounds[1]), dv.props.PanelWidth() / (contentBounds[2] - contentBounds[0]));
+ const computedScale = NumCast(activeItem.presZoom, 1) * Math.min(dv.props.PanelWidth() / viewport.width, dv.props.PanelHeight() / viewport.height);
+ activeItem.presMovement === 'zoom' && (bestTarget._viewScale = activeItem.presZoom !== undefined ? computedScale : Math.min(computedScale, NumCast(bestTarget._viewScale)));
+ dv.ComponentView?.brushView?.(viewport);
}
} else {
bestTarget._panX = activeItem.presPinViewX;
bestTarget._panY = activeItem.presPinViewY;
- bestTarget._viewScale = activeItem.presPinViewScale;
+ activeItem.presMovement === 'zoom' && (bestTarget._viewScale = activeItem.presPinViewScale);
}
}
- return setTimeout(() => (bestTarget._viewTransition = undefined), activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 510);
+ return setTimeout(() => (bestTarget._viewTransition = undefined), transTime + 10);
}
/// copies values from the targetDoc (which is the prototype of the pinDoc) to
/// reserved fields on the pinDoc so that those values can be restored to the
/// target doc when navigating to it.
@action
- static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined) {
+ static pinDocView(pinDoc: Doc, pinProps: PinProps | undefined, targetDoc: Doc) {
if (pinProps?.pinWithView) {
// If pinWithView option set then update scale and x / y props of slide
const bounds = pinProps.pinWithView.bounds;
pinDoc.presPinView = true;
pinDoc.presPinViewX = bounds.left + bounds.width / 2;
pinDoc.presPinViewY = bounds.top + bounds.height / 2;
- pinDoc.presPinViewScale = pinProps.pinWithView.scale;
- pinDoc.contentBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
+ pinDoc.presPinViewBounds = new List<number>([bounds.left, bounds.top, bounds.left + bounds.width, bounds.top + bounds.height]);
}
if (pinProps?.pinDocView) {
- const { scrollable, pannable, temporal, clippable } = this.pinDataTypes(pinDoc);
- pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable;
-
- if (scrollable) pinDoc.presPinViewScroll = pinDoc._scrollTop;
- else if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth;
- else if (temporal) pinDoc.presEndTime = NumCast((pinDoc.presStartTime = pinDoc._currentTimecode)) + 0.1;
- else if (pannable) {
+ const { scrollable, pannable, temporal, clippable, dataview, textview } = this.pinDataTypes(pinDoc);
+ pinDoc.presPinView = (pinProps?.pinWithView ? true : false) || scrollable || temporal || pannable || clippable || dataview || textview || pinProps.activeFrame !== undefined;
+ pinDoc.presX = NumCast(targetDoc.x);
+ pinDoc.presY = NumCast(targetDoc.y);
+ pinDoc.presRot = NumCast(targetDoc.jitterRotation);
+ pinDoc.presWidth = NumCast(targetDoc.width);
+ pinDoc.presHeight = NumCast(targetDoc.height);
+
+ if (scrollable) {
+ pinDoc.presPinViewScroll = pinDoc._scrollTop;
+ }
+ if (clippable) pinDoc.presPinClipWidth = pinDoc._clipWidth;
+ if (temporal) {
+ pinDoc.presStartTime = pinDoc._currentTimecode;
+ const duration = NumCast(pinDoc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], NumCast(pinDoc.presStartTime) + 0.1);
+ pinDoc.presEndTime = NumCast(pinDoc.clipEnd, duration);
+ }
+ if (textview) pinDoc.presData = targetDoc.text instanceof ObjectField ? targetDoc.text[Copy]() : targetDoc.text;
+ if (dataview) pinDoc.presData = targetDoc.data instanceof ObjectField ? targetDoc.data[Copy]() : targetDoc.data;
+ if (pannable || scrollable) {
const panX = NumCast(pinDoc._panX);
const panY = NumCast(pinDoc._panY);
const pw = NumCast(pinProps.panelWidth);
const ph = NumCast(pinProps.panelHeight);
- const ps = NumCast(pinDoc._viewScale);
+ const ps = NumCast(pinDoc._viewScale, 1);
if (pw && ph && ps) {
- pinDoc.contentBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
+ pinDoc.presPinViewBounds = new List<number>([panX - pw / 2 / ps, panY - ph / 2 / ps, panX + pw / 2 / ps, panY + ph / 2 / ps]);
}
pinDoc.presPinViewX = panX;
pinDoc.presPinViewY = panY;
@@ -429,6 +444,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
}
+ static _navTimer: NodeJS.Timeout;
/**
* This method makes sure that cursor navigates to the element that
* has the option open and last in the group.
@@ -437,7 +453,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
* a new tab. If presCollection is undefined it will open the document
* on the right.
*/
- navigateToElement = async (curDoc: Doc) => {
+ navigateToActiveItem = () => {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null);
@@ -445,7 +461,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
const tab = CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === srcContext);
- this.turnOffEdit();
// Handles the setting of presCollection
if (includesDoc) {
//Case 1: Pres collection should not change as it is already the same
@@ -454,7 +469,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc.presCollection = srcContext;
}
const presStatus = this.rootDoc.presStatus;
- const selViewCache = Array.from(this._selectedArray);
+ const selViewCache = Array.from(this.selectedArray);
const dragViewCache = Array.from(this._dragArray);
const eleViewCache = Array.from(this._eleArray);
const self = this;
@@ -468,7 +483,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
self._eleArray.splice(0, self._eleArray.length, ...eleViewCache);
});
const openInTab = (doc: Doc, finished?: () => void) => {
- collectionDocView ? collectionDocView.props.addDocTab(doc, '') : this.props.addDocTab(doc, '');
+ (collectionDocView ?? this).props.addDocTab(doc, '');
this.layoutDoc.presCollection = targetDoc;
// this still needs some fixing
setTimeout(resetSelection, 500);
@@ -478,27 +493,38 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
finished?.();
}
};
+ PresBox.NavigateToTarget(targetDoc, activeItem, openInTab, srcContext, includesDoc || tab ? undefined : resetSelection);
+ };
+
+ static NavigateToTarget(targetDoc: Doc, activeItem: Doc, openInTab: any, srcContext: Doc, finished?: () => void) {
+ if (activeItem.presPinView && DocCast(targetDoc.context)?._currentFrame === undefined) {
+ const transTime = NumCast(activeItem.presTransition, 500);
+ const presTransitionTime = `all ${transTime}ms`;
+ targetDoc._dataTransition = presTransitionTime;
+ targetDoc.x = NumCast(activeItem.presX, NumCast(targetDoc.x));
+ targetDoc.y = NumCast(activeItem.presY, NumCast(targetDoc.y));
+ targetDoc.jitterRotation = NumCast(activeItem.presRot, NumCast(targetDoc.jitterRotation));
+ targetDoc.width = NumCast(activeItem.presWidth, NumCast(targetDoc.width));
+ targetDoc.height = NumCast(activeItem.presHeight, NumCast(targetDoc.height));
+ setTimeout(() => (targetDoc._dataTransition = undefined), transTime + 10);
+ }
// If openDocument is selected then it should open the document for the user
if (activeItem.openDocument) {
- LightboxView.SetLightboxDoc(targetDoc);
- // openInTab(targetDoc);
- } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
- LightboxView.SetLightboxDoc(undefined);
- await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
- } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
+ LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc);
+ } else if (targetDoc && activeItem.presMovement !== PresMovement.None) {
LightboxView.SetLightboxDoc(undefined);
- //awaiting jump so that new scale can be found, since jumping is async
- await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right
+ const zooming = activeItem.presMovement !== PresMovement.Pan;
+ DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, finished, undefined, true, NumCast(activeItem.presZoom));
}
// After navigating to the document, if it is added as a presPinView then it will
// adjust the pan and scale to that of the pinView when it was added.
if (activeItem.presPinView) {
- console.log(targetDoc.title);
- console.log('presPinView in PresBox.tsx:420');
- // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
- this.navigateToView(targetDoc, activeItem);
+ clearTimeout(PresBox._navTimer);
+ // targetDoc may or may not be displayed. this gets the first available document (or alias) view that matches targetDoc
+ const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
+ if (bestTarget) PresBox._navTimer = PresBox.restoreTargetDocView(bestTarget, activeItem);
}
- };
+ }
/**
* Uses the viewfinder to progressivize through the different views of a single collection.
@@ -705,8 +731,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc.presStatus = PresStatus.Edit;
clearTimeout(this._presTimer);
const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
- this.rootDoc.y = pt[1] + 10;
+ this.rootDoc.overlayX = pt[0] + (this.props.PanelWidth() - 250);
+ this.rootDoc.overlayY = pt[1] + 10;
this.rootDoc._height = 30;
this.rootDoc._width = 248;
Doc.AddDocToList(Doc.MyOverlayDocs, undefined, this.rootDoc);
@@ -756,27 +782,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
});
- setMovementName = action((movement: any, activeItem: Doc): string => {
- let output: string = 'none';
- switch (movement) {
- case PresMovement.Zoom:
- output = 'Pan & Zoom';
- break; //Pan and zoom
- case PresMovement.Pan:
- output = 'Pan';
- break; //Pan
- case PresMovement.Jump:
- output = 'Jump cut';
- break; //Jump Cut
- case PresMovement.None:
- output = 'None';
- break; //None
- default:
- output = 'Zoom';
- activeItem.presMovement = 'zoom';
- break; //default set as zoom
+ movementName = action((activeItem: Doc) => {
+ if (![PresMovement.Zoom, PresMovement.Pan, PresMovement.Jump, PresMovement.None].includes(StrCast(activeItem.presMovement) as any)) {
+ activeItem.presMovement = 'zoom';
}
- return output;
+ return StrCast(activeItem.presMovement);
});
whenChildContentsActiveChanged = action((isActive: boolean) => this.props.whenChildContentsActiveChanged((this._isChildActive = isActive)));
@@ -822,16 +832,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
/**
* For sorting the array so that the order is maintained when it is dropped.
*/
- @action
- sortArray = (): Doc[] => {
- return this.childDocs.filter(doc => this._selectedArray.has(doc));
- };
+ sortArray = () => this.childDocs.filter(doc => this.selectedArray.has(doc));
/**
* Method to get the list of selected items in the order in which they have been selected
*/
@computed get listOfSelected() {
- return Array.from(this._selectedArray).map((doc: Doc, index: any) => {
+ return Array.from(this.selectedArray).map((doc: Doc, index: any) => {
const curDoc = Cast(doc, Doc, null);
const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
if (curDoc && curDoc === this.activeItem)
@@ -866,33 +873,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//Regular click
@action
selectElement = async (doc: Doc) => {
- const context = Cast(doc.context, Doc, null);
this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
- if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
- else this.updateCurrentPresentation(context);
+ if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(DocCast(doc.context)), 0);
+ else this.updateCurrentPresentation(DocCast(doc.context));
};
//Command click
@action
multiSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
- if (!this._selectedArray.has(doc)) {
+ if (!this.selectedArray.has(doc)) {
this.addToSelectedArray(doc);
this._eleArray.push(ref);
this._dragArray.push(drag);
} else {
this.removeFromSelectedArray(doc);
- this.removeFromArray(this._eleArray, doc);
- this.removeFromArray(this._dragArray, doc);
+ this._eleArray.splice(this._eleArray.indexOf(ref));
+ this._dragArray.splice(this._dragArray.indexOf(drag));
}
this.selectPres();
};
- removeFromArray = (arr: any[], val: any) => {
- const index: number = arr.indexOf(val);
- const ret: any[] = arr.splice(index, 1);
- arr = ret;
- };
-
//Shift click
@action
shiftSelect = (doc: Doc, ref: HTMLElement, drag: HTMLElement) => {
@@ -925,9 +925,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
else this.regularSelect(doc, ref, drag, focus);
};
- static keyEventsWrapper = (e: KeyboardEvent) => {
- PresBox.Instance.keyEvents(e);
- };
+ static keyEventsWrapper = (e: KeyboardEvent) => PresBox.Instance.keyEvents(e);
// Key for when the presentaiton is active
@action
@@ -941,7 +939,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (this.layoutDoc.presStatus === 'edit') {
undoBatch(
action(() => {
- for (const doc of this._selectedArray) {
+ for (const doc of this.selectedArray) {
this.removeDocument(doc);
}
this.clearSelectedArray();
@@ -1028,13 +1026,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- getAllIndexes = (arr: Doc[], val: Doc): number[] => {
- const indexes = [];
- for (let i = 0; i < arr.length; i++) {
- arr[i] === val && indexes.push(i);
- }
- return indexes;
- };
+ getAllIndexes = (arr: Doc[], val: Doc) => arr.map((doc, i) => (doc === val ? i : -1)).filter(i => i !== -1);
// Adds the index in the pres path graphically
@computed get order() {
@@ -1153,7 +1145,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 10000) timeInMS = 10000;
- this._selectedArray.forEach(doc => (doc.presTransition = timeInMS));
+ this.selectedArray.forEach(doc => (doc.presTransition = timeInMS));
};
// Converts seconds to ms and updates presTransition
@@ -1161,8 +1153,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
let scale = Number(number) / 100;
if (change) scale += change;
if (scale < 0.01) scale = 0.01;
- if (scale > 1.5) scale = 1.5;
- this._selectedArray.forEach(doc => (doc.presZoom = scale));
+ if (scale > 1) scale = 1;
+ this.selectedArray.forEach(doc => (doc.presZoom = scale));
};
// Converts seconds to ms and updates presDuration
@@ -1171,100 +1163,43 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 20000) timeInMS = 20000;
- this._selectedArray.forEach(doc => (doc.presDuration = timeInMS));
+ this.selectedArray.forEach(doc => (doc.presDuration = timeInMS));
};
/**
* When the movement dropdown is changes
*/
@undoBatch
- updateMovement = action((movement: any, all?: boolean) => {
- (all ? this.childDocs : 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;
- }
- });
- });
+ updateMovement = action((movement: PresMovement, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presMovement = movement)));
@undoBatch
@action
updateHideBefore = (activeItem: Doc) => {
activeItem.presHideBefore = !activeItem.presHideBefore;
- this._selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore));
+ this.selectedArray.forEach(doc => (doc.presHideBefore = activeItem.presHideBefore));
};
@undoBatch
@action
updateHideAfter = (activeItem: Doc) => {
activeItem.presHideAfter = !activeItem.presHideAfter;
- this._selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter));
+ this.selectedArray.forEach(doc => (doc.presHideAfter = activeItem.presHideAfter));
};
@undoBatch
@action
updateOpenDoc = (activeItem: Doc) => {
activeItem.openDocument = !activeItem.openDocument;
- this._selectedArray.forEach(doc => {
- doc.openDocument = activeItem.openDocument;
- });
+ this.selectedArray.forEach(doc => (doc.openDocument = activeItem.openDocument));
};
@undoBatch
@action
- updateEffectDirection = (effect: any, all?: boolean) => {
- (all ? this.childDocs : this._selectedArray).forEach(doc => {
- const tagDoc = doc; // Cast(doc.presentationTargetDoc, Doc, null);
- switch (effect) {
- case PresEffect.Left:
- tagDoc.presEffectDirection = PresEffect.Left;
- break;
- case PresEffect.Right:
- tagDoc.presEffectDirection = PresEffect.Right;
- break;
- case PresEffect.Top:
- tagDoc.presEffectDirection = PresEffect.Top;
- break;
- case PresEffect.Bottom:
- tagDoc.presEffectDirection = PresEffect.Bottom;
- break;
- case PresEffect.Center:
- default:
- tagDoc.presEffectDirection = PresEffect.Center;
- break;
- }
- });
- };
+ updateEffectDirection = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffectDirection = effect));
@undoBatch
@action
- updateEffect = (effect: any, all?: boolean) => {
- (all ? this.childDocs : this._selectedArray).forEach(doc => {
- const tagDoc = doc; //Cast(doc.presentationTargetDoc, Doc, null);
- //prettier-ignore
- switch (effect) {
- default:
- case PresEffect.None: tagDoc.presEffect = PresEffect.None; break;
- 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;
- }
- });
- };
+ updateEffect = (effect: PresEffect, all?: boolean) => (all ? this.childDocs : this.selectedArray).forEach(doc => (doc.presEffect = effect));
_batch: UndoManager.Batch | undefined = undefined;
@@ -1273,6 +1208,49 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const targetDoc: Doc = this.targetDoc;
const isPresCollection: boolean = targetDoc === this.layoutDoc.presCollection;
const isPinWithView: boolean = BoolCast(activeItem.presPinView);
+ const presEffect = (effect: PresEffect) => (
+ <div className={`presBox-dropdownOption ${this.activeItem.presEffect === effect || (effect === PresEffect.None && !this.activeItem.presEffect) ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateEffect(effect)}>
+ {effect}
+ </div>
+ );
+ const presMovement = (movement: PresMovement) => (
+ <div className={`presBox-dropdownOption ${activeItem.presMovement === movement ? 'active' : ''}`} onPointerDown={StopEvent} onClick={() => this.updateMovement(movement)}>
+ {movement}
+ </div>
+ );
+ const presDirection = (diretion: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => {
+ const color = this.activeItem.presEffectDirection === diretion || (diretion === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black';
+ return (
+ <Tooltip title={<div className="dash-tooltip">{diretion}</div>}>
+ <div
+ style={{ ...opts, border: diretion === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }}
+ onClick={() => this.updateEffectDirection(diretion)}>
+ {icon ? <FontAwesomeIcon icon={icon as any} /> : null}
+ </div>
+ </Tooltip>
+ );
+ };
+ const inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => {
+ return (
+ <input
+ type="range"
+ step={step}
+ min={min}
+ max={max}
+ value={value}
+ className={`toolbar-slider ${active ? '' : 'none'}`}
+ onPointerDown={e => {
+ this._batch = UndoManager.StartBatch('pres slider');
+ e.stopPropagation();
+ }}
+ onPointerUp={() => this._batch?.end()}
+ onChange={e => {
+ e.stopPropagation();
+ change(e.target.value);
+ }}
+ />
+ );
+ };
if (activeItem && targetDoc) {
const type = targetDoc.type;
const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
@@ -1283,46 +1261,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
return (
<div
- className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`}
- onPointerDown={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
+ className={`presBox-ribbon ${this._transitionTools && this.layoutDoc.presStatus === PresStatus.Edit ? 'active' : ''}`}
+ onPointerDown={StopEvent}
+ onPointerUp={StopEvent}
onClick={action(e => {
e.stopPropagation();
- this.openMovementDropdown = false;
- this.openEffectDropdown = false;
+ this._openMovementDropdown = false;
+ this._openEffectDropdown = false;
})}>
<div className="ribbon-box">
Movement
- {isPresCollection || (isPresCollection && isPinWithView) ? (
- <div className="ribbon-property" style={{ marginLeft: 0, height: 25, textAlign: 'left', paddingLeft: 5, paddingRight: 5, fontSize: 10 }}>
- {this.scrollable ? 'Scroll to pinned view' : !isPinWithView ? 'No movement' : 'Pan & Zoom to pinned view'}
- </div>
- ) : (
- <div
- className="presBox-dropdown"
- onClick={action(e => {
- e.stopPropagation();
- this.openMovementDropdown = !this.openMovementDropdown;
- })}
- style={{ borderBottomLeftRadius: this.openMovementDropdown ? 0 : 5, border: this.openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
- {this.setMovementName(activeItem.presMovement, activeItem)}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this.openMovementDropdown ? Colors.MEDIUM_BLUE : '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)}>
- 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
+ className="presBox-dropdown"
+ onClick={action(e => {
+ e.stopPropagation();
+ this._openMovementDropdown = !this._openMovementDropdown;
+ })}
+ style={{ borderBottomLeftRadius: this._openMovementDropdown ? 0 : 5, border: this._openMovementDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ {this.movementName(activeItem)}
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openMovementDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={StopEvent} style={{ display: this._openMovementDropdown ? 'grid' : 'none' }}>
+ {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.None)}
+ {presMovement(PresMovement.Zoom)}
+ {presMovement(PresMovement.Pan)}
+ {isPresCollection || (isPresCollection && isPinWithView) ? null : presMovement(PresMovement.Jump)}
</div>
- )}
+ </div>
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
<div className="presBox-subheading">Zoom (% screen filled)</div>
<div className="ribbon-property">
@@ -1337,21 +1301,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- <input
- type="range"
- step="1"
- min="0"
- max="150"
- value={zoom}
- className={`toolbar-slider ${activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}
- id="toolbar-slider"
- onPointerDown={() => (this._batch = UndoManager.StartBatch('presZoom'))}
- onPointerUp={() => this._batch?.end()}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- this.setZoom(e.target.value);
- }}
- />
+ {inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
<div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? 'inline-flex' : 'none' }}>
<div className="presBox-subheading">Movement Speed</div>
<div className="ribbon-property">
@@ -1366,21 +1316,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- <input
- type="range"
- step="0.1"
- min="0.1"
- max="10"
- value={transitionSpeed}
- className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}
- id="toolbar-slider"
- onPointerDown={() => (this._batch = UndoManager.StartBatch('presTransition'))}
- onPointerUp={() => this._batch?.end()}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- this.setTransitionTime(e.target.value);
- }}
- />
+ {inputter('0.1', '0.1', '10', transitionSpeed, [PresMovement.Pan, PresMovement.Zoom].includes(activeItem.presMovement as any), this.setTransitionTime)}
<div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
<div className="slider-text">Fast</div>
<div className="slider-text">Medium</div>
@@ -1391,35 +1327,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
Visibility {'&'} Duration
<div className="ribbon-doubleButton">
{isPresCollection ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Hide before presented'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Hide before presented'}</div>}>
<div className={`ribbon-toggle ${activeItem.presHideBefore ? 'active' : ''}`} onClick={() => this.updateHideBefore(activeItem)}>
Hide before
</div>
</Tooltip>
)}
{isPresCollection ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Hide after presented'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Hide after presented'}</div>}>
<div className={`ribbon-toggle ${activeItem.presHideAfter ? 'active' : ''}`} onClick={() => this.updateHideAfter(activeItem)}>
Hide after
</div>
</Tooltip>
)}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Open in lightbox view'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Open in lightbox view'}</div>}>
<div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? Colors.LIGHT_BLUE : '' }} onClick={() => this.updateOpenDoc(activeItem)}>
Lightbox
</div>
@@ -1441,26 +1362,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- <input
- type="range"
- step="0.1"
- min="0.1"
- max="20"
- value={duration}
- style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'block' }}
- className={'toolbar-slider'}
- id="duration-slider"
- onPointerDown={() => {
- this._batch = UndoManager.StartBatch('presDuration');
- }}
- onPointerUp={() => {
- if (this._batch) this._batch.end();
- }}
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
- e.stopPropagation();
- this.setDurationTime(e.target.value);
- }}
- />
+ {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
<div className={'slider-headers'} style={{ display: targetDoc.type === DocumentType.AUDIO ? 'none' : 'grid' }}>
<div className="slider-text">Short</div>
<div className="slider-text">Medium</div>
@@ -1476,98 +1378,30 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
className="presBox-dropdown"
onClick={action(e => {
e.stopPropagation();
- this.openEffectDropdown = !this.openEffectDropdown;
+ this._openEffectDropdown = !this._openEffectDropdown;
})}
- style={{ borderBottomLeftRadius: this.openEffectDropdown ? 0 : 5, border: this.openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
+ style={{ borderBottomLeftRadius: this._openEffectDropdown ? 0 : 5, border: this._openEffectDropdown ? `solid 2px ${Colors.MEDIUM_BLUE}` : 'solid 1px black' }}>
{effect.toString()}
- <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this.openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
- <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this.openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
- <div
- className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.None || !this.activeItem.presEffect ? 'active' : ''}`}
- onPointerDown={e => e.stopPropagation()}
- onClick={() => this.updateEffect(PresEffect.None)}>
- None
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Fade ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Fade)}>
- Fade In
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Flip ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Flip)}>
- Flip
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Rotate ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Rotate)}>
- Rotate
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Bounce ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Bounce)}>
- Bounce
- </div>
- <div className={`presBox-dropdownOption ${this.activeItem.presEffect === PresEffect.Roll ? 'active' : ''}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateEffect(PresEffect.Roll)}>
- Roll
- </div>
+ <FontAwesomeIcon className="presBox-dropdownIcon" style={{ gridColumn: 2, color: this._openEffectDropdown ? Colors.MEDIUM_BLUE : 'black' }} icon={'angle-down'} />
+ <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} style={{ display: this._openEffectDropdown ? 'grid' : 'none' }} onPointerDown={e => e.stopPropagation()}>
+ {presEffect(PresEffect.None)}
+ {presEffect(PresEffect.Fade)}
+ {presEffect(PresEffect.Flip)}
+ {presEffect(PresEffect.Rotate)}
+ {presEffect(PresEffect.Bounce)}
+ {presEffect(PresEffect.Roll)}
</div>
</div>
<div className="ribbon-doubleButton" style={{ display: effect === 'None' ? 'none' : 'inline-flex' }}>
<div className="presBox-subheading">Effect direction</div>
- <div className="ribbon-property">{this.effectDirection}</div>
+ <div className="ribbon-property">{StrCast(this.activeItem.presEffectDirection)}</div>
</div>
<div className="effectDirection" style={{ display: effect === 'None' ? 'none' : 'grid', width: 40 }}>
- <Tooltip title={<div className="dash-tooltip">{'Enter from left'}</div>}>
- <div
- style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Left ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Left)}>
- <FontAwesomeIcon icon={'angle-right'} />
- </div>
- </Tooltip>
- <Tooltip title={<div className="dash-tooltip">{'Enter from right'}</div>}>
- <div
- style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Right ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Right)}>
- <FontAwesomeIcon icon={'angle-left'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from top'}</div>
- </>
- }>
- <div
- style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Top ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Top)}>
- <FontAwesomeIcon icon={'angle-down'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from bottom'}</div>
- </>
- }>
- <div
- style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: this.activeItem.presEffectDirection === PresEffect.Bottom ? Colors.LIGHT_BLUE : 'black', cursor: 'pointer' }}
- onClick={() => this.updateEffectDirection(PresEffect.Bottom)}>
- <FontAwesomeIcon icon={'angle-up'} />
- </div>
- </Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Enter from center'}</div>
- </>
- }>
- <div
- style={{
- gridColumn: 2,
- gridRow: 2,
- width: 10,
- height: 10,
- alignSelf: 'center',
- justifySelf: 'center',
- border: this.activeItem.presEffectDirection === PresEffect.Center || !this.activeItem.presEffectDirection ? `solid 2px ${Colors.LIGHT_BLUE}` : 'solid 2px black',
- borderRadius: '100%',
- cursor: 'pointer',
- }}
- onClick={() => this.updateEffectDirection(PresEffect.Center)}></div>
- </Tooltip>
+ {presDirection(PresEffect.Left, 'angle-right', 1, 2, {})}
+ {presDirection(PresEffect.Right, 'angle-left', 3, 2, {})}
+ {presDirection(PresEffect.Top, 'angle-down', 2, 1, {})}
+ {presDirection(PresEffect.Bottom, 'angle-up', 2, 3, {})}
+ {presDirection(PresEffect.Center, '', 2, 2, { width: 10, height: 10, alignSelf: 'center' })}
</div>
</div>
)}
@@ -1581,59 +1415,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
}
- @computed get effectDirection() {
- // prettier-ignore
- switch (this.activeItem.presEffectDirection) {
- case 'left': return 'Enter from left';
- case 'right': return 'Enter from right';
- case 'top': return'Enter from top';
- case 'bottom': return 'Enter from bottom';
- }
- return 'Enter from center';
- }
-
@undoBatch
@action
applyTo = (array: Doc[]) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- this.updateMovement(activeItem.presMovement, true);
- this.updateEffect(activeItem.presEffect, true);
- this.updateEffectDirection(activeItem.presEffectDirection, true);
- array.forEach(doc => {
- const curDoc = Cast(doc, Doc, null);
- const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
- if (tagDoc && targetDoc) {
- curDoc.presTransition = activeItem.presTransition;
- curDoc.presDuration = activeItem.presDuration;
- curDoc.presHideBefore = activeItem.presHideBefore;
- curDoc.presHideAfter = activeItem.presHideAfter;
- }
+ this.updateMovement(this.activeItem.presMovement as PresMovement, true);
+ this.updateEffect(this.activeItem.presEffect as PresEffect, true);
+ this.updateEffectDirection(this.activeItem.presEffectDirection as PresEffect, true);
+ const { presTransition, presDuration, presHideBefore, presHideAfter } = this.activeItem;
+ array.forEach(curDoc => {
+ curDoc.presTransition = presTransition;
+ curDoc.presDuration = presDuration;
+ curDoc.presHideBefore = presHideBefore;
+ curDoc.presHideAfter = presHideAfter;
});
};
- @computed get mediaStopSlides() {
- const activeItem: Doc = this.activeItem;
- const list = this.childDocs.map((doc, i) => {
- if (i > this.itemIndex) {
- return (
- <option>
- {i + 1}. {StrCast(doc.title)}
- </option>
- );
- }
- });
- return list;
- }
-
@computed get mediaOptionsDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
const clipStart: number = NumCast(activeItem.clipStart);
- const clipEnd: number = NumCast(activeItem.clipEnd);
- const duration = Math.round(NumCast(activeItem[`${Doc.LayoutFieldKey(activeItem)}-duration`]) * 10);
+ const clipEnd: number = NumCast(activeItem.clipEnd, NumCast(activeItem[Doc.LayoutFieldKey(activeItem) + '-duration']));
const mediaStopDocInd: number = NumCast(activeItem.mediaStopDoc);
- const mediaStopDocStr: string = mediaStopDocInd ? mediaStopDocInd + '. ' + this.childDocs[mediaStopDocInd - 1].title : '';
if (activeItem && targetDoc) {
return (
<div>
@@ -1649,9 +1451,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div id={'startTime'} className="slider-number" style={{ backgroundColor: Colors.LIGHT_GRAY }}>
<input
className="presBox-input"
- style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+ style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
type="number"
- value={NumCast(activeItem.presStartTime)}
+ value={NumCast(activeItem.presStartTime).toFixed(2)}
onKeyDown={e => e.stopPropagation()}
onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
activeItem.presStartTime = Number(e.target.value);
@@ -1675,9 +1477,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<input
className="presBox-input"
onKeyDown={e => e.stopPropagation()}
- style={{ textAlign: 'center', width: 30, height: 15, fontSize: 10 }}
+ style={{ textAlign: 'center', width: '100%', height: 15, fontSize: 10 }}
type="number"
- value={NumCast(activeItem.presEndTime)}
+ value={NumCast(activeItem.presEndTime).toFixed(2)}
onChange={action((e: React.ChangeEvent<HTMLInputElement>) => {
activeItem.presEndTime = Number(e.target.value);
})}
@@ -1695,13 +1497,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{ gridColumn: 1, gridRow: 1 }}
className={`toolbar-slider ${'end'}`}
id="toolbar-slider"
- onPointerDown={() => {
+ onPointerDown={e => {
this._batch = UndoManager.StartBatch('presEndTime');
const endBlock = document.getElementById('endTime');
if (endBlock) {
endBlock.style.color = Colors.LIGHT_GRAY;
endBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
}
+ e.stopPropagation();
}}
onPointerUp={() => {
this._batch?.end();
@@ -1725,13 +1528,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{ gridColumn: 1, gridRow: 1 }}
className={`toolbar-slider ${'start'}`}
id="toolbar-slider"
- onPointerDown={() => {
+ onPointerDown={e => {
this._batch = UndoManager.StartBatch('presStartTime');
const startBlock = document.getElementById('startTime');
if (startBlock) {
startBlock.style.color = Colors.LIGHT_GRAY;
startBlock.style.backgroundColor = Colors.MEDIUM_BLUE;
}
+ e.stopPropagation();
}}
onPointerUp={() => {
this._batch?.end();
@@ -1747,10 +1551,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}}
/>
</div>
- <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? '' : 'none'}`}>
- <div className="slider-text">{clipStart} s</div>
+ <div className="slider-headers">
+ <div className="slider-text">{clipStart.toFixed(2)} s</div>
<div className="slider-text"></div>
- <div className="slider-text">{clipEnd} s</div>
+ <div className="slider-text">{clipEnd.toFixed(2)} s</div>
</div>
</div>
<div className="ribbon-final-box">
@@ -1804,55 +1608,53 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get newDocumentToolbarDropdown() {
return (
- <div>
- <div
- className={'presBox-toolbar-dropdown'}
- style={{ display: this.newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
- onClick={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
- onPointerDown={e => e.stopPropagation()}>
- <div className="layout-container" style={{ height: 'max-content' }}>
- <div
- className="layout"
- style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'blank';
- this.createNewSlide(this.layout);
- })}
- />
- <div
- className="layout"
- style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'title';
- this.createNewSlide(this.layout);
- })}>
- <div className="title">Title</div>
- <div className="subtitle">Subtitle</div>
- </div>
- <div
- className="layout"
- style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'header';
- this.createNewSlide(this.layout);
- })}>
- <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
- Section header
- </div>
+ <div
+ className={'presBox-toolbar-dropdown'}
+ style={{ display: this._newDocumentTools && this.layoutDoc.presStatus === 'edit' ? 'inline-flex' : 'none' }}
+ onClick={e => e.stopPropagation()}
+ onPointerUp={e => e.stopPropagation()}
+ onPointerDown={e => e.stopPropagation()}>
+ <div className="layout-container" style={{ height: 'max-content' }}>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'blank';
+ this.createNewSlide(this.layout);
+ })}
+ />
+ <div
+ className="layout"
+ style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'title';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title">Title</div>
+ <div className="subtitle">Subtitle</div>
+ </div>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'header';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+ Section header
</div>
- <div
- className="layout"
- style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
- onClick={action(() => {
- this.layout = 'content';
- this.createNewSlide(this.layout);
- })}>
- <div className="title" style={{ alignSelf: 'center' }}>
- Title
- </div>
- <div className="content">Text goes here</div>
+ </div>
+ <div
+ className="layout"
+ style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }}
+ onClick={action(() => {
+ this.layout = 'content';
+ this.createNewSlide(this.layout);
+ })}>
+ <div className="title" style={{ alignSelf: 'center' }}>
+ Title
</div>
+ <div className="content">Text goes here</div>
</div>
</div>
</div>
@@ -1866,73 +1668,71 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get newDocumentDropdown() {
return (
- <div>
- <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
- <div className="ribbon-box">
- Slide Title: <br></br>
- <input
- className="ribbon-textInput"
- placeholder="..."
- type="text"
- name="fname"
- onChange={e => {
- e.stopPropagation();
- e.preventDefault();
- runInAction(() => (this.title = e.target.value));
- }}></input>
+ <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="ribbon-box">
+ Slide Title: <br></br>
+ <input
+ className="ribbon-textInput"
+ placeholder="..."
+ type="text"
+ name="fname"
+ onChange={e => {
+ e.stopPropagation();
+ e.preventDefault();
+ runInAction(() => (this.title = e.target.value));
+ }}></input>
+ </div>
+ <div className="ribbon-box">
+ Choose type:
+ <div className="ribbon-doubleButton">
+ <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ Text
+ </div>
+ <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
+ Freeform
+ </div>
</div>
- <div className="ribbon-box">
- Choose type:
- <div className="ribbon-doubleButton">
- <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? '' : Colors.LIGHT_BLUE }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
- Text
- </div>
- <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? Colors.LIGHT_BLUE : '' }} onClick={action(() => (this.addFreeform = !this.addFreeform))}>
- Freeform
+ </div>
+ <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
+ Preset layouts:
+ <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
+ <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
+ <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
+ <div className="title">Title</div>
+ <div className="subtitle">Subtitle</div>
+ </div>
+ <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
+ <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
+ Section header
</div>
</div>
- </div>
- <div className="ribbon-box" style={{ display: this.addFreeform ? 'grid' : 'none' }}>
- Preset layouts:
- <div className="layout-container" style={{ height: this.openLayouts ? 'max-content' : '75px' }}>
- <div className="layout" style={{ border: this.layout === 'blank' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'blank'))} />
- <div className="layout" style={{ border: this.layout === 'title' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'title'))}>
- <div className="title">Title</div>
- <div className="subtitle">Subtitle</div>
+ <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
+ <div className="title" style={{ alignSelf: 'center' }}>
+ Title
</div>
- <div className="layout" style={{ border: this.layout === 'header' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'header'))}>
- <div className="title" style={{ alignSelf: 'center', fontSize: 10 }}>
- Section header
- </div>
+ <div className="content">Text goes here</div>
+ </div>
+ <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
+ <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
+ Title
</div>
- <div className="layout" style={{ border: this.layout === 'content' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'content'))}>
- <div className="title" style={{ alignSelf: 'center' }}>
- Title
- </div>
- <div className="content">Text goes here</div>
+ <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
+ Column one text
</div>
- <div className="layout" style={{ border: this.layout === 'twoColumns' ? `solid 2px ${Colors.MEDIUM_BLUE}` : '' }} onClick={action(() => (this.layout = 'twoColumns'))}>
- <div className="title" style={{ alignSelf: 'center', gridColumn: '1/3' }}>
- Title
- </div>
- <div className="content" style={{ gridColumn: 1, gridRow: 2 }}>
- Column one text
- </div>
- <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
- Column two text
- </div>
+ <div className="content" style={{ gridColumn: 2, gridRow: 2 }}>
+ Column two text
</div>
</div>
- <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
- <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
- </div>
</div>
- <div className="ribbon-final-box">
- <div
- className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
- onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
- Create New Slide
- </div>
+ <div className="open-layout" onClick={action(() => (this.openLayouts = !this.openLayouts))}>
+ <FontAwesomeIcon style={{ transition: 'all 0.3s', transform: this.openLayouts ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'caret-down'} size={'lg'} />
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ <div
+ className={this.title !== '' && ((this.addFreeform && this.layout !== '') || !this.addFreeform) ? 'ribbon-final-button-hidden' : 'ribbon-final-button'}
+ onClick={() => this.createNewSlide(this.layout, this.title, this.addFreeform)}>
+ Create New Slide
</div>
</div>
</div>
@@ -1981,7 +1781,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Dropdown that appears when the user wants to begin presenting (either minimize or sidebar view)
@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 ${this._presentTools ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
<div
className="dropdown-play-button"
onClick={undoBatch(
@@ -2067,115 +1867,109 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const activeFontColor = targetDoc['pres-text-color'] ? StrCast(targetDoc['pres-text-color']) : 'Black';
const viewedFontColor = targetDoc['pres-text-viewed-color'] ? StrCast(targetDoc['pres-text-viewed-color']) : 'Black';
return (
- <div>
- <div
- className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`}
- onClick={e => e.stopPropagation()}
- onPointerUp={e => e.stopPropagation()}
- onPointerDown={e => e.stopPropagation()}>
- <div className="ribbon-box">
- {this.stringType} selected
- <div
- className="ribbon-doubleButton"
- style={{
- borderTop: 'solid 1px darkgrey',
- display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
- }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
- Contents
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
- Edit
- </div>
- </div>
- <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Active text color</div>
- <div
- className="ribbon-colorBox"
- style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
- onClick={action(() => {
- this.openActiveColorPicker = !this.openActiveColorPicker;
- })}></div>
+ <div className={`presBox-ribbon ${this._progressivizeTools && this.layoutDoc.presStatus === 'edit' ? 'active' : ''}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
+ <div className="ribbon-box">
+ {this.stringType} selected
+ <div
+ className="ribbon-doubleButton"
+ style={{
+ borderTop: 'solid 1px darkgrey',
+ display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
+ }}>
+ <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeChild}>
+ Contents
</div>
- {this.activeColorPicker}
- <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
- <div className="presBox-subheading">Viewed font color</div>
- <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
+ <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editProgressivize}>
+ Edit
</div>
- {this.viewedColorPicker}
+ </div>
+ <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
+ <div className="presBox-subheading">Active text color</div>
<div
- className="ribbon-doubleButton"
- style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
- Zoom
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
- Edit
- </div>
+ className="ribbon-colorBox"
+ style={{ backgroundColor: activeFontColor, height: 15, width: 15 }}
+ onClick={action(() => {
+ this.openActiveColorPicker = !this.openActiveColorPicker;
+ })}></div>
+ </div>
+ {this.activeColorPicker}
+ <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? 'inline-flex' : 'none' }}>
+ <div className="presBox-subheading">Viewed font color</div>
+ <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => (this.openViewedColorPicker = !this.openViewedColorPicker))}></div>
+ </div>
+ {this.viewedColorPicker}
+ <div
+ className="ribbon-doubleButton"
+ style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? 'inline-flex' : 'none' }}>
+ <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeZoom}>
+ Zoom
</div>
- <div
- className="ribbon-doubleButton"
- style={{
- borderTop: 'solid 1px darkgrey',
- display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
- }}>
- <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
- Scroll
- </div>
- <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
- Edit
- </div>
+ <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editZoomProgressivize}>
+ Edit
</div>
</div>
- <div className="ribbon-final-box">
- Frames
- <div className="ribbon-doubleButton">
- <div className="ribbon-frameSelector">
- <div
- key="back"
- title="back frame"
- className="backKeyframe"
- onClick={e => {
- e.stopPropagation();
- this.prevKeyframe(targetDoc, activeItem);
- }}>
- <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
- </div>
- <div
- key="num"
- title="toggle view all"
- className="numKeyframe"
- style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
- onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
- {NumCast(targetDoc._currentFrame)}
- </div>
- <div
- key="fwd"
- title="forward frame"
- className="fwdKeyframe"
- onClick={e => {
- e.stopPropagation();
- this.nextKeyframe(targetDoc, activeItem);
- }}>
- <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
- </div>
- </div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Last frame'}</div>
- </>
- }>
- <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
- </Tooltip>
+ <div
+ className="ribbon-doubleButton"
+ style={{
+ borderTop: 'solid 1px darkgrey',
+ display: targetDoc._viewType === 'stacking' || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? 'inline-flex' : 'none',
+ }}>
+ <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.progressivizeScroll}>
+ Scroll
</div>
- <div className="ribbon-frameList">
- {this.frameListHeader}
- {this.frameList}
+ <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? Colors.LIGHT_BLUE : '' }} onClick={this.editScrollProgressivize}>
+ Edit
</div>
- <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
- Play
+ </div>
+ </div>
+ <div className="ribbon-final-box">
+ Frames
+ <div className="ribbon-doubleButton">
+ <div className="ribbon-frameSelector">
+ <div
+ key="back"
+ title="back frame"
+ className="backKeyframe"
+ onClick={e => {
+ e.stopPropagation();
+ this.prevKeyframe(targetDoc, activeItem);
+ }}>
+ <FontAwesomeIcon icon={'caret-left'} size={'lg'} />
+ </div>
+ <div
+ key="num"
+ title="toggle view all"
+ className="numKeyframe"
+ style={{ color: targetDoc.keyFrameEditing ? 'white' : 'black', backgroundColor: targetDoc.keyFrameEditing ? Colors.MEDIUM_BLUE : Colors.LIGHT_BLUE }}
+ onClick={action(() => (targetDoc.keyFrameEditing = !targetDoc.keyFrameEditing))}>
+ {NumCast(targetDoc._currentFrame)}
+ </div>
+ <div
+ key="fwd"
+ title="forward frame"
+ className="fwdKeyframe"
+ onClick={e => {
+ e.stopPropagation();
+ this.nextKeyframe(targetDoc, activeItem);
+ }}>
+ <FontAwesomeIcon icon={'caret-right'} size={'lg'} />
+ </div>
</div>
+ <Tooltip
+ title={
+ <>
+ <div className="dash-tooltip">{'Last frame'}</div>
+ </>
+ }>
+ <div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div>
+ </Tooltip>
+ </div>
+ <div className="ribbon-frameList">
+ {this.frameListHeader}
+ {this.frameList}
+ </div>
+ <div className="ribbon-toggle" style={{ height: 20, backgroundColor: Colors.LIGHT_BLUE }} onClick={() => console.log(' TODO: play frames')}>
+ Play
</div>
</div>
</div>
@@ -2186,42 +1980,32 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
@action
switchActive = (color: ColorState) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const val = String(color.hex);
- targetDoc['pres-text-color'] = val;
+ this.targetDoc['pres-text-color'] = String(color.hex);
return true;
};
@undoBatch
@action
switchPresented = (color: ColorState) => {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const val = String(color.hex);
- targetDoc['pres-text-viewed-color'] = val;
+ this.targetDoc['pres-text-viewed-color'] = String(color.hex);
return true;
};
@computed get activeColorPicker() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
return !this.openActiveColorPicker ? null : (
<SketchPicker
onChange={this.switchActive}
presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={StrCast(targetDoc['pres-text-color'])}
+ color={StrCast(this.targetDoc['pres-text-color'])}
/>
);
}
@computed get viewedColorPicker() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
return !this.openViewedColorPicker ? null : (
<SketchPicker
onChange={this.switchPresented}
presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']}
- color={StrCast(targetDoc['pres-text-viewed-color'])}
+ color={StrCast(this.targetDoc['pres-text-viewed-color'])}
/>
);
}
@@ -2264,12 +2048,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//Toggle whether the user edits or not
@action
editScrollProgressivize = (e: React.MouseEvent) => {
- const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
if (!targetDoc.editScrollProgressivize) {
if (!targetDoc.scrollProgressivize) {
targetDoc.scrollProgressivize = true;
- activeItem.scrollProgressivize = true;
+ this.activeItem.scrollProgressivize = true;
}
targetDoc.editScrollProgressivize = true;
} else {
@@ -2281,8 +2064,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
progressivizeScroll = (e: React.MouseEvent) => {
e.stopPropagation();
- const activeItem: Doc = this.activeItem;
- activeItem.scrollProgressivize = !activeItem.scrollProgressivize;
+ this.activeItem.scrollProgressivize = !this.activeItem.scrollProgressivize;
const targetDoc: Doc = this.targetDoc;
targetDoc.scrollProgressivize = !targetDoc.scrollProgressivize;
// CollectionFreeFormDocumentView.setupScroll(targetDoc, NumCast(targetDoc._currentFrame));
@@ -2384,21 +2166,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
@observable
- toggleDisplayMovement = (doc: Doc) => {
- if (doc.displayMovement) doc.displayMovement = false;
- else doc.displayMovement = true;
- };
+ toggleDisplayMovement = (doc: Doc) => (doc.displayMovement = !doc.displayMovement);
@action
checkList = (doc: Doc, list: any): number => {
const x: List<number> = list;
- if (x && x.length >= NumCast(doc._currentFrame) + 1) {
+ if (x?.length >= NumCast(doc._currentFrame) + 1) {
return x[NumCast(doc._currentFrame)];
} else if (x) {
x.length = NumCast(doc._currentFrame) + 1;
x[NumCast(doc._currentFrame)] = x[NumCast(doc._currentFrame) - 1];
return x[NumCast(doc._currentFrame)];
- } else return 100;
+ }
+ return 100;
};
@computed get progressivizeChildDocs() {
@@ -2452,26 +2232,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@action
- nextAppearFrame = (doc: Doc, i: number): void => {
- // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- const appearFrame = Cast(doc.appearFrame, 'number', null);
- if (appearFrame === undefined) {
- doc.appearFrame = 0;
- }
- doc.appearFrame = appearFrame + 1;
+ nextAppearFrame = (doc: Doc, i: number) => {
+ doc.appearFrame = (Cast(doc.appearFrame, 'number', null) ?? 0) + 1;
this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
};
@action
- prevAppearFrame = (doc: Doc, i: number): void => {
- // const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
- // const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null);
- const appearFrame = Cast(doc.appearFrame, 'number', null);
- if (appearFrame === undefined) {
- doc.appearFrame = 0;
- }
- doc.appearFrame = Math.max(0, appearFrame - 1);
+ prevAppearFrame = (doc: Doc, i: number) => {
+ doc.appearFrame = Math.max(0, (Cast(doc.appearFrame, 'number', null) ?? 0) - 1);
this.updateOpacityList(doc['opacity-indexed'], NumCast(doc.appearFrame));
};
@@ -2500,31 +2268,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
- @computed get moreInfoDropdown() {
- return <div></div>;
- }
-
@computed
get toolbarWidth(): number {
- const width = this.props.PanelWidth();
- return width;
+ return this.props.PanelWidth();
}
@action
- toggleProperties = () => {
- if (SettingsManager.propertiesWidth > 0) {
- SettingsManager.propertiesWidth = 0;
- } else {
- SettingsManager.propertiesWidth = 250;
- }
- };
+ toggleProperties = () => (SettingsManager.propertiesWidth = SettingsManager.propertiesWidth > 0 ? 0 : 250);
@computed get toolbar() {
const propIcon = SettingsManager.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
const propTitle = SettingsManager.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.ActivePresentation;
const activeColor = Colors.LIGHT_BLUE;
const inactiveColor = Colors.WHITE;
return mode === CollectionViewType.Carousel3D ? null : (
@@ -2533,12 +2289,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={"plus"} />
<FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} />
</div></Tooltip> */}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'View paths'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'View paths'}</div>}>
<div
style={{ opacity: this.childDocs.length > 1 && this.layoutDoc.presCollection ? 1 : 0.3, color: this._pathBoolean ? Colors.MEDIUM_BLUE : 'white', width: isMini ? '100%' : undefined }}
className={'toolbar-button'}
@@ -2557,22 +2308,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</Tooltip>
<div className="toolbar-divider" /> */}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>
- </>
- }>
- <div className="toolbar-button" style={{ cursor: presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
- <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: presKeyEvents ? activeColor : inactiveColor }} />
+ <Tooltip title={<div className="dash-tooltip">{this._presKeyEvents ? 'Keys are active' : 'Keys are not active - click anywhere on the presentation trail to activate keys'}</div>}>
+ <div className="toolbar-button" style={{ cursor: this._presKeyEvents ? 'default' : 'pointer', position: 'absolute', right: 30, fontSize: 16 }}>
+ <FontAwesomeIcon className={'toolbar-thumbtack'} icon={'keyboard'} style={{ color: this._presKeyEvents ? activeColor : inactiveColor }} />
</div>
</Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{propTitle}</div>
- </>
- }>
+ <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: SettingsManager.propertiesWidth > 0 ? activeColor : inactiveColor }} />
</div>
@@ -2592,17 +2333,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
const isMini: boolean = this.toolbarWidth <= 100;
return (
- <div className="presBox-buttons" style={{ display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
+ <div className="presBox-buttons" style={{ background: Doc.ActivePresentation === this.rootDoc ? Colors.LIGHT_BLUE : undefined, display: !this.rootDoc._chromeHidden ? 'none' : undefined }}>
{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}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Stacking}>
List
</option>
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Tree}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Tree}>
Tree
</option>
{Doc.noviceMode ? null : (
- <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel3D}>
+ <option onPointerDown={StopEvent} value={CollectionViewType.Carousel3D}>
3D Carousel
</option>
)}
@@ -2623,11 +2364,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
{mode === CollectionViewType.Carousel3D || isMini ? null : (
<div
- className={`presBox-button-right ${this.presentTools ? 'active' : ''}`}
+ className={`presBox-button-right ${this._presentTools ? 'active' : ''}`}
onClick={action(() => {
- if (this.childDocs.length) this.presentTools = !this.presentTools;
+ if (this.childDocs.length) this._presentTools = !this._presentTools;
})}>
- <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this.presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
+ <FontAwesomeIcon className="dropdown" style={{ margin: 0, transform: this._presentTools ? 'rotate(180deg)' : 'rotate(0deg)' }} icon={'angle-down'} />
{this.presentDropdown}
</div>
)}
@@ -2639,16 +2380,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@action
- getList = (list: any): List<number> => {
- const x: List<number> = list;
- return x;
- };
+ getList = (list: any): List<number> => list;
@action
updateList = (list: any): List<number> => {
const targetDoc: Doc = this.targetDoc;
const x: List<number> = list;
- x.length + 1;
x[x.length - 1] = NumCast(targetDoc._scrollY);
return x;
};
@@ -2656,8 +2393,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
@action
newFrame = () => {
const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const type: string = StrCast(targetDoc.type);
+ const type: string = StrCast(this.targetDoc.type);
if (!activeItem.frameList) activeItem.frameList = new List<number>();
switch (type) {
case DocumentType.PDF || DocumentType.RTF || DocumentType.WEB:
@@ -2671,12 +2407,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="frameList-header">
&nbsp; Frames {this.panable ? <i>Panable</i> : this.scrollable ? <i>Scrollable</i> : null}
<div className={'frameList-headerButtons'}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Add frame by example'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Add frame by example'}</div>}>
<div
className={'headerButton'}
onClick={e => {
@@ -2686,12 +2417,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'plus'} onPointerDown={e => e.stopPropagation()} />
</div>
</Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Edit in collection'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Edit in collection'}</div>}>
<div
className={'headerButton'}
onClick={e => {
@@ -2707,27 +2433,24 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
@computed get frameList() {
- const activeItem: Doc = this.activeItem;
- const targetDoc: Doc = this.targetDoc;
- const frameList: List<number> = this.getList(activeItem.frameList);
- if (frameList) {
- const frameItems = frameList.map(value => <div className="framList-item"></div>);
- return <div className="frameList-container">{frameItems}</div>;
- } else return null;
+ const frameList: List<number> = this.getList(this.activeItem.frameList);
+ return !frameList ? null : (
+ <div className="frameList-container">
+ {frameList.map(value => (
+ <div className="framList-item" />
+ ))}
+ </div>
+ );
}
@computed get playButtonFrames() {
- const targetDoc: Doc = this.targetDoc;
- return (
- <>
- {this.targetDoc ? (
- <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
- <div>{NumCast(targetDoc._currentFrame)}</div>
- <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
- <div>{NumCast(targetDoc.lastFrame)}</div>
- </div>
- ) : null}
- </>
+ const targetDoc = this.targetDoc;
+ return !this.targetDoc ? null : (
+ <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? 'inline-flex' : 'none' }}>
+ <div>{NumCast(targetDoc._currentFrame)}</div>
+ <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
+ <div>{NumCast(targetDoc.lastFrame)}</div>
+ </div>
);
}
@@ -2737,35 +2460,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
// Case 1: There are still other frames and should go through all frames before going to next slide
return (
<div className="presPanelOverlay" style={{ display: this.layoutDoc.presStatus !== 'edit' ? 'inline-flex' : 'none' }}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Loop'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
<div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : 'white' }} onClick={() => (this.layoutDoc.presLoop = !this.layoutDoc.presLoop)}>
<FontAwesomeIcon icon={'redo-alt'} />
</div>
</Tooltip>
- <div className="presPanel-divider"></div>
+ <div className="presPanel-divider" />
<div
className="presPanel-button"
style={{ opacity: presStart ? 0.4 : 1 }}
- onClick={() => {
+ onClick={e => {
this.back();
if (this._presTimer) {
clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
}
+ e.stopPropagation();
}}>
<FontAwesomeIcon icon={'arrow-left'} />
</div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
<div className="presPanel-button" onClick={this.startOrPause}>
<FontAwesomeIcon icon={this.layoutDoc.presStatus === PresStatus.Autoplay ? 'pause' : 'play'} />
</div>
@@ -2773,23 +2487,19 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div
className="presPanel-button"
style={{ opacity: presEnd ? 0.4 : 1 }}
- onClick={() => {
+ onClick={e => {
this.next();
if (this._presTimer) {
clearTimeout(this._presTimer);
this.layoutDoc.presStatus = PresStatus.Manual;
}
+ e.stopPropagation();
}}>
<FontAwesomeIcon icon={'arrow-right'} />
</div>
<div className="presPanel-divider"></div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
- </>
- }>
- <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}>
+ <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
+ <div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.nextSlide(0)}>
<b>1</b>
</div>
</Tooltip>
@@ -2850,9 +2560,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
};
@action
- startMarqueeCreateSlide = () => {
- PresBox.startMarquee = true;
- };
+ startMarqueeCreateSlide = () => (PresBox.startMarquee = true);
AddToMap = (treeViewDoc: Doc, index: number[]): Doc[] => {
var indexNum = 0;
@@ -2882,23 +2590,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
sort = (treeViewMap: Map<Doc, number>) => [...treeViewMap.entries()].sort((a: [Doc, number], b: [Doc, number]) => (a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0)).map(kv => kv[0]);
render() {
- // calling this method for keyEvents
- this.isPres;
// needed to ensure that the childDocs are loaded for looking up fields
this.childDocs.slice();
const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
- const presKeyEvents: boolean = this.isPres && this._presKeyEventsActive && this.rootDoc === Doc.ActivePresentation;
const presEnd: boolean = !this.layoutDoc.presLoop && this.itemIndex === this.childDocs.length - 1;
const presStart: boolean = !this.layoutDoc.presLoop && this.itemIndex === 0;
- return DocListCast(Doc.MyOverlayDocs?.data).includes(this.rootDoc) ? (
- <div className="miniPres" onClick={e => e.stopPropagation()}>
- <div className="presPanelOverlay" style={{ display: 'inline-flex', height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Loop'}</div>
- </>
- }>
+ return this.props.addDocTab === returnFalse ? ( // bcz: hack!! - addDocTab === returnFalse only when this is being rendered by the OverlayView which means the doc is a mini player
+ <div className="miniPres" onClick={e => e.stopPropagation()} onPointerEnter={action(e => (this._forceKeyEvents = true))}>
+ <div
+ className="presPanelOverlay"
+ style={{ display: 'inline-flex', height: 30, background: Doc.ActivePresentation === this.rootDoc ? 'green' : '#323232', top: 0, zIndex: 3000000, boxShadow: this._presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
+ <Tooltip title={<div className="dash-tooltip">{'Loop'}</div>}>
<div
className="presPanel-button"
style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
@@ -2910,12 +2612,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}>
<FontAwesomeIcon icon={'arrow-left'} />
</div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? 'Pause' : 'Autoplay'}</div>}>
<div className="presPanel-button" onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}>
<FontAwesomeIcon icon={this.layoutDoc.presStatus === 'auto' ? 'pause' : 'play'} />
</div>
@@ -2924,12 +2621,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={'arrow-right'} />
</div>
<div className="presPanel-divider"></div>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Click to return to 1st slide'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">{'Click to return to 1st slide'}</div>}>
<div className="presPanel-button" style={{ border: 'solid 1px white' }} onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}>
<b>1</b>
</div>
@@ -2950,7 +2642,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
{this.toolbar}
{this.newDocumentToolbarDropdown}
<div className="presBox-listCont">
- <div className="Slide" style={{ height: `calc(100% - 30px)` }}>
+ <div className="Slide">
{mode !== CollectionViewType.Invalid ? (
<CollectionView
{...this.props}
@@ -2975,25 +2667,28 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
) : null}
</div>
- {
+ {/* {
// if the document type is a presentation, then the collection stacking view has a "+ new slide" button at the bottom of the stack
<Tooltip title={<div className="dash-tooltip">{'Click on document to pin to presentaiton or make a marquee selection to pin your desired view'}</div>}>
<button className="add-slide-button" onPointerDown={this.startMarqueeCreateSlide}>
+ NEW SLIDE
</button>
</Tooltip>
- }
+ } */}
</div>
</div>
);
}
+ static NavigateToDoc(bestTarget: Doc, activeItem: Doc) {
+ const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null);
+ const openInTab = (doc: Doc, finished?: () => void) => {
+ CollectionDockingView.AddSplit(doc, 'right');
+ finished?.();
+ };
+ PresBox.NavigateToTarget(bestTarget, activeItem, openInTab, srcContext);
+ }
}
ScriptingGlobals.add(function navigateToDoc(bestTarget: Doc, activeItem: Doc) {
- const srcContext = Cast(bestTarget.context, Doc, null) ?? Cast(Cast(bestTarget.annotationOn, Doc, null)?.context, Doc, null);
- const openInTab = (doc: Doc, finished?: () => void) => {
- CollectionDockingView.AddSplit(doc, 'right');
- finished?.();
- };
- DocumentManager.Instance.jumpToDocument(bestTarget, true, openInTab, srcContext ? [srcContext] : [], undefined, undefined, undefined, () => PresBox.navigateToDoc(bestTarget, activeItem, true), undefined, true, NumCast(activeItem.presZoom));
+ PresBox.NavigateToDoc(bestTarget, activeItem);
});
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
index 969f034a8..8a6c2a6dc 100644
--- a/src/client/views/nodes/trails/PresElementBox.scss
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -1,161 +1,159 @@
-$light-blue: #AEDDF8;
-$dark-blue: #5B9FDD;
+$light-blue: #aeddf8;
+$dark-blue: #5b9fdd;
$light-background: #ececec;
$slide-background: #d5dce2;
-$slide-active: #5B9FDD;
+$slide-active: #5b9fdd;
.presItem-container {
- cursor: grab;
- display: flex;
- grid-template-columns: 20px auto;
- font-family: Roboto;
- letter-spacing: normal;
- position: relative;
- pointer-events: all;
- width: 100%;
- height: 100%;
- font-weight: 400;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- align-items: center;
-
- // .presItem-number {
- // margin-top: 3.5px;
- // font-size: 12px;
- // font-weight: 700;
- // text-align: center;
- // justify-self: center;
- // align-self: flex-start;
- // position: relative;
- // display: inline-block;
- // overflow: hidden;
- // }
+ cursor: grab;
+ display: flex;
+ grid-template-columns: 20px auto;
+ font-family: Roboto;
+ letter-spacing: normal;
+ position: relative;
+ pointer-events: all;
+ width: 100%;
+ height: 100%;
+ font-weight: 400;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ align-items: center;
+ // .presItem-number {
+ // margin-top: 3.5px;
+ // font-size: 12px;
+ // font-weight: 700;
+ // text-align: center;
+ // justify-self: center;
+ // align-self: flex-start;
+ // position: relative;
+ // display: inline-block;
+ // overflow: hidden;
+ // }
}
.presItem-slide {
- position: relative;
- height: 100%;
- width: 100%;
- border-bottom: .5px solid grey;
- display: flex;
- justify-content: space-between;
- align-items: center;
- grid-template-rows: 16px 10px auto;
- grid-template-columns: max-content max-content max-content max-content auto;
+ position: relative;
+ height: 100%;
+ width: 100%;
+ border-bottom: 0.5px solid grey;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ grid-template-rows: 16px 10px auto;
+ grid-template-columns: max-content max-content max-content max-content auto;
- .presItem-name {
- display: flex;
- min-width: 20px;
- z-index: 300;
- top: 2px;
- align-self: center;
- font-size: 11px;
- font-family: Roboto;
- font-weight: 500;
- position: relative;
- padding-left: 10px;
- padding-right: 10px;
- letter-spacing: normal;
- width: max-content;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: pre;
- }
+ .presItem-name {
+ display: flex;
+ min-width: 20px;
+ z-index: 300;
+ top: 2px;
+ align-self: center;
+ font-size: 11px;
+ font-family: Roboto;
+ font-weight: 500;
+ position: relative;
+ padding-left: 10px;
+ padding-right: 10px;
+ letter-spacing: normal;
+ width: max-content;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: pre;
+ }
- .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;
- grid-row: 2;
- grid-column: 1/6;
- }
+ .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;
+ grid-row: 2;
+ grid-column: 1/6;
+ }
- .presItem-time {
- align-self: center;
- position: relative;
- padding-right: 10px;
- top: 1px;
- font-size: 10;
- font-weight: 300;
- font-family: Roboto;
- z-index: 300;
- letter-spacing: normal;
- }
+ .presItem-time {
+ align-self: center;
+ position: relative;
+ 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;
- width: auto;
- justify-content: center;
- margin: auto;
- margin-bottom: 2px;
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
- }
+ .presItem-embedded {
+ overflow: hidden;
+ grid-row: 3;
+ grid-column: 1/8;
+ position: relative;
+ display: flex;
+ width: auto;
+ justify-content: center;
+ margin: auto;
+ margin-bottom: 2px;
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+ }
- .presItem-embeddedMask {
- width: 100%;
- height: 100%;
- position: absolute;
- border-radius: 3px;
- top: 0;
- left: 0;
- z-index: 1;
- overflow: hidden;
- }
+ .presItem-embeddedMask {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ border-radius: 3px;
+ top: 0;
+ left: 0;
+ z-index: 1;
+ overflow: hidden;
+ }
+ .presItem-slideButtons {
+ display: flex;
+ grid-column: 7;
+ grid-row: 1/3;
+ width: max-content;
+ justify-self: right;
+ justify-content: flex-end;
- .presItem-slideButtons {
+ .slideButton {
+ cursor: pointer;
+ position: relative;
+ border-radius: 100px;
+ z-index: 300;
+ width: 18px;
+ height: 18px;
display: flex;
- grid-column: 7;
- grid-row: 1/3;
- width: max-content;
- justify-self: right;
- justify-content: flex-end;
-
- .slideButton {
- cursor: pointer;
- position: relative;
- border-radius: 100px;
- z-index: 300;
- width: 18px;
- height: 18px;
- display: flex;
- font-size: 12px;
- justify-self: center;
- align-self: center;
- background-color: rgba(0, 0, 0, 0.5);
- color: white;
- justify-content: center;
- align-items: center;
- transition: 0.2s;
- margin-right: 3px;
- }
+ font-size: 12px;
+ justify-self: center;
+ align-self: center;
+ background-color: rgba(0, 0, 0, 0.5);
+ color: white;
+ justify-content: center;
+ align-items: center;
+ transition: 0.2s;
+ margin-right: 3px;
+ }
- .slideButton:hover {
- background-color: rgba(0, 0, 0, 1);
- transform: scale(1.2);
- }
- }
+ .slideButton:hover {
+ background-color: rgba(0, 0, 0, 1);
+ transform: scale(1.2);
+ }
+ }
}
// .presItem-slide:hover {
@@ -194,7 +192,8 @@ $slide-active: #5B9FDD;
// }
.presItem-slide.active {
- box-shadow: 0 0 0px 2.5px $dark-blue;
+ //box-shadow: 0 0 0px 2.5px $dark-blue;
+ border: $dark-blue solid 2.5px;
}
.presItem-slide.group {
@@ -239,38 +238,38 @@ $slide-active: #5B9FDD;
}
.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;
+ 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%;
+ 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;
+ box-shadow: 0 0 0px 1.5px $dark-blue;
}
.expandButton {
@@ -306,4 +305,4 @@ $slide-active: #5B9FDD;
top: 1;
font-weight: 600;
font-size: 12;
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 91196ca21..e6d08cd53 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -3,7 +3,7 @@ import { Tooltip } from '@material-ui/core';
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from '../../../../fields/Doc';
-import { Id } from '../../../../fields/FieldSymbols';
+import { Copy, Id } from '../../../../fields/FieldSymbols';
import { List } from '../../../../fields/List';
import { Cast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../Utils';
@@ -24,6 +24,8 @@ import { PresBox } from './PresBox';
import './PresElementBox.scss';
import { PresMovement } from './PresEnums';
import React = require('react');
+import { InkField } from '../../../../fields/InkField';
+import { RichTextField } from '../../../../fields/RichTextField';
/**
* This class models the view a document added to presentation will have in the presentation.
* It involves some functionality for its buttons and options.
@@ -48,7 +50,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
return this.presBox.presStatus;
}
@computed get selectedArray() {
- return this.presBoxView?._selectedArray;
+ return this.presBoxView?.selectedArray;
}
@computed get presBoxView() {
const vpath = this.props.docViewPath();
@@ -79,9 +81,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
ScreenToLocalListTransform = (xCord: number, yCord: number) => [xCord, yCord];
@action
- presExpandDocumentClick = () => {
- this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton;
- };
+ presExpandDocumentClick = () => (this.rootDoc.presExpandInlineButton = !this.rootDoc.presExpandInlineButton);
embedHeight = (): number => 97;
// embedWidth = () => this.props.PanelWidth();
@@ -160,15 +160,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
));
return groupSlides;
}
- @computed get duration() {
- let durationInS: number;
- if (this.rootDoc.type === DocumentType.AUDIO || this.rootDoc.type === DocumentType.VID) {
- durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime);
- durationInS = Math.round(durationInS * 10) / 10;
- } else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
- else durationInS = 2;
- return 'D: ' + durationInS + 's';
- }
@computed get transition() {
let transitionInS: number;
@@ -320,6 +311,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
case DocumentType.RTF:
const scroll = targetDoc._scrollTop;
activeItem.presPinViewScroll = scroll;
+ if (targetDoc.type === DocumentType.RTF) {
+ activeItem.presData = targetDoc.text instanceof RichTextField ? targetDoc.text[Copy]() : targetDoc.text;
+ }
+ break;
+ case DocumentType.INK:
+ activeItem.presData = targetDoc.data instanceof InkField ? targetDoc.data[Copy]() : targetDoc.data;
break;
case DocumentType.VID:
case DocumentType.AUDIO:
@@ -337,6 +334,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
activeItem.presPinViewY = y;
activeItem.presPinViewScale = scale;
}
+
+ activeItem.presX = NumCast(targetDoc.x);
+ activeItem.presY = NumCast(targetDoc.y);
+ activeItem.presRot = NumCast(targetDoc.jitterRotation);
+ activeItem.presWidth = NumCast(targetDoc.width);
+ activeItem.presHeight = NumCast(targetDoc.height);
};
@computed get recordingIsInOverlay() {
@@ -381,7 +384,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
hideRecording = (e: React.MouseEvent, iconClick: boolean = false) => {
e.stopPropagation();
this.removeAllRecordingInOverlay();
-
// if (iconClick) PresElementBox.showVideo = false;
};
@@ -401,8 +403,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@undoBatch
@action
- startRecording = (activeItem: Doc) => {
- console.log('start recording', 'activeItem', activeItem);
+ startRecording = (e: React.MouseEvent, activeItem: Doc) => {
+ e.stopPropagation();
if (PresElementBox.videoIsRecorded(activeItem)) {
// if we already have an existing recording
this.showRecording(activeItem, true);
@@ -429,8 +431,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
activeItem.recording = recording;
// make recording box appear in the bottom right corner of the screen
- recording.x = window.innerWidth - recording[WidthSym]() - 20;
- recording.y = window.innerHeight - recording[HeightSym]() - 20;
+ recording.overlayX = window.innerWidth - recording[WidthSym]() - 20;
+ recording.overlayY = window.innerHeight - recording[HeightSym]() - 20;
Doc.AddDocToList(Doc.MyOverlayDocs, undefined, recording);
}
};
@@ -446,6 +448,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
@computed get mainItem() {
const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
+ const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres;
const toolbarWidth: number = this.toolbarWidth;
const showMore: boolean = this.toolbarWidth >= 300;
const miniView: boolean = this.toolbarWidth <= 110;
@@ -477,26 +480,18 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
onPointerOver={this.onPointerOver}
onPointerLeave={this.onPointerLeave}
onPointerDown={this.headerDown}>
- {/* {miniView ?
- // when width is LESS than 110 px
- <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
- {`${this.indexInPres + 1}.`}
- </div>
- :
- // when width is MORE than 110 px
- <div className="presItem-number">
- {`${this.indexInPres + 1}.`}
- </div>} */}
- {/* <div className="presItem-number">
- {`${this.indexInPres + 1}.`}
- </div> */}
- {miniView ? null : (
+ {miniView ? (
+ <div className={`presItem-miniSlide ${isSelected ? 'active' : ''}`} ref={this._dragRef}>
+ {`${this.indexInPres + 1}.`}
+ </div>
+ ) : (
<div
- ref={miniView ? null : this._dragRef}
- className={`presItem-slide ${isSelected ? 'active' : ''}`}
+ ref={this._dragRef}
+ className={`presItem-slide ${isCurrent ? 'active' : ''}`}
style={{
backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
- boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isSelected ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
+ //boxShadow: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? '0 0 0px 1.5px' + presBoxColor : undefined) : undefined,
+ border: presBoxColor && presBoxColor !== 'white' && presBoxColor !== 'transparent' ? (isCurrent ? presBoxColor + ' solid 2.5px' : undefined) : undefined,
}}>
<div
className="presItem-name"
@@ -510,79 +505,37 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
</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> */}
- <div className={'presItem-slideButtons'}>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Update view'}</div>
- </>
- }>
+ <div className="presItem-slideButtons">
+ <Tooltip title={<div className="dash-tooltip">Update view</div>}>
<div className="slideButton" onClick={() => this.updateView(targetDoc, activeItem)} style={{ fontWeight: 700, display: activeItem.presPinView ? 'flex' : 'none' }}>
V
</div>
</Tooltip>
-
- {this.recordingIsInOverlay ? (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Hide Recording'}</div>
- </>
- }>
- <div className="slideButton" onClick={e => this.hideRecording(e, true)} style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={'video-slash'} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- ) : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{`${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>
- </>
- }>
- <div
- className="slideButton"
- onClick={e => {
- e.stopPropagation();
- this.startRecording(activeItem);
- }}
- style={{ fontWeight: 700 }}>
- <FontAwesomeIcon icon={'video'} onPointerDown={e => e.stopPropagation()} />
- </div>
- </Tooltip>
- )}
-
- {this.indexInPres === 0 ? null : (
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}</div>
- </>
- }>
- <div
- className="slideButton"
- onClick={() => (activeItem.groupWithUp = !activeItem.groupWithUp)}
- style={{
- zIndex: 1000 - this.indexInPres,
- fontWeight: 700,
- backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined,
- height: activeItem.groupWithUp ? 53 : 18,
- transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined,
- }}>
- <div style={{ transform: activeItem.groupWithUp ? 'rotate(180deg) translate(0, -17.5px)' : 'rotate(0deg)' }}>
- <FontAwesomeIcon icon={'arrow-up'} onPointerDown={e => e.stopPropagation()} />
- </div>
+ {!Doc.noviceMode && <Tooltip title={<div className="dash-tooltip">{this.recordingIsInOverlay ? 'Hide Recording' : `${PresElementBox.videoIsRecorded(activeItem) ? 'Show' : 'Start'} recording`}</div>}>
+ <div className="slideButton" onClick={e => (this.recordingIsInOverlay ? this.hideRecording(e, true) : this.startRecording(e, activeItem))} style={{ fontWeight: 700 }}>
+ <FontAwesomeIcon icon={`video${this.recordingIsInOverlay ? '-slash' : ''}`} onPointerDown={e => e.stopPropagation()} />
+ </div>
+ </Tooltip>}
+ <Tooltip title={<div className="dash-tooltip">{activeItem.groupWithUp ? 'Ungroup' : 'Group with up'}</div>}>
+ <div
+ className="slideButton"
+ onClick={() => (activeItem.groupWithUp = !activeItem.groupWithUp)}
+ style={{
+ display: this.indexInPres === 0 ? 'none' : '',
+ zIndex: 1000 - this.indexInPres,
+ fontWeight: 700,
+ backgroundColor: activeItem.groupWithUp ? (presColorBool ? presBoxColor : Colors.MEDIUM_BLUE) : undefined,
+ height: activeItem.groupWithUp ? 53 : 18,
+ transform: activeItem.groupWithUp ? 'translate(0, -17px)' : undefined,
+ }}>
+ <div style={{ transform: activeItem.groupWithUp ? 'rotate(180deg) translate(0, -17.5px)' : 'rotate(0deg)' }}>
+ <FontAwesomeIcon icon={'arrow-up'} onPointerDown={e => e.stopPropagation()} />
</div>
- </Tooltip>
- )}
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}</div>
- </>
- }>
+ </div>
+ </Tooltip>
+ <Tooltip title={<div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? 'Minimize' : 'Expand'}</div>}>
<div
- className={'slideButton'}
+ className="slideButton"
onClick={e => {
e.stopPropagation();
this.presExpandDocumentClick();
@@ -590,18 +543,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
<FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? 'eye-slash' : 'eye'} onPointerDown={e => e.stopPropagation()} />
</div>
</Tooltip>
- <Tooltip
- title={
- <>
- <div className="dash-tooltip">{'Remove from presentation'}</div>
- </>
- }>
+ <Tooltip title={<div className="dash-tooltip">Remove from presentation</div>}>
<div className={'slideButton'} onClick={this.removeItem}>
<FontAwesomeIcon icon={'trash'} onPointerDown={e => e.stopPropagation()} />
</div>
</Tooltip>
</div>
- {/* <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div> */}
{this.renderEmbeddedInline}
</div>
)}
diff --git a/src/client/views/nodes/trails/PresEnums.ts b/src/client/views/nodes/trails/PresEnums.ts
index 93ab323fb..c6a222c3a 100644
--- a/src/client/views/nodes/trails/PresEnums.ts
+++ b/src/client/views/nodes/trails/PresEnums.ts
@@ -1,28 +1,28 @@
export enum PresMovement {
- Zoom = "zoom",
- Pan = "pan",
- Jump = "jump",
- None = "none",
+ Zoom = 'zoom',
+ Pan = 'pan',
+ Jump = 'jump',
+ None = 'none',
}
export enum PresEffect {
- Zoom = "Zoom",
- Lightspeed = "Lightspeed",
- Fade = "Fade in",
- Flip = "Flip",
- Rotate = "Rotate",
- Bounce = "Bounce",
- Roll = "Roll",
- None = "None",
- Left = "left",
- Right = "right",
- Center = "center",
- Top = "top",
- Bottom = "bottom"
+ Zoom = 'Zoom',
+ Lightspeed = 'Lightspeed',
+ Fade = 'Fade in',
+ Flip = 'Flip',
+ Rotate = 'Rotate',
+ Bounce = 'Bounce',
+ Roll = 'Roll',
+ None = 'None',
+ Left = 'Enter from left',
+ Right = 'Enter from right',
+ Center = 'Enter from center',
+ Top = 'Enter from Top',
+ Bottom = 'Enter from bottom',
}
export enum PresStatus {
- Autoplay = "auto",
- Manual = "manual",
- Edit = "edit"
-} \ No newline at end of file
+ Autoplay = 'auto',
+ Manual = 'manual',
+ Edit = 'edit',
+}