aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DocumentManager.ts2
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx7
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/linking/LinkEditor.tsx74
-rw-r--r--src/client/views/nodes/DocumentView.scss2
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx86
-rw-r--r--src/fields/Doc.ts7
9 files changed, 136 insertions, 49 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index a60c1ed6b..00f6bc40a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -233,7 +233,7 @@ export class DocumentManager {
}
}
if (focusView) {
- !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox
+ !noSelect && Doc.linkFollowHighlight(focusView.rootDoc, undefined, targetDoc); //TODO:glr make this a setting in PresBox
if (originatingDoc?.followLinkAudio) DocumentManager.playAudioAnno(focusView.rootDoc);
const doFocus = (forceDidFocus: boolean) =>
focusView.focus(originalTarget ?? targetDoc, {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 987bfc23d..392b4eeeb 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -484,6 +484,7 @@ export class MainView extends React.Component {
}
globalPointerDown = action((e: PointerEvent) => {
+ runInAction(() => (Doc.HighlightBrush.linkFollowEffect = undefined));
AudioBox.Enabled = true;
const targets = document.elementsFromPoint(e.x, e.y);
if (targets.length) {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 92319d080..434466505 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -452,7 +452,7 @@ export class CollectionDockingView extends CollectionSubView() {
.map(id => DocServer.GetCachedRefField(id))
.filter(f => f)
.map(f => f as Doc);
- const changesMade = this.props.Document.dockcingConfig !== json;
+ const changesMade = this.props.Document.dockingConfig !== json;
if (changesMade && !this._flush) {
UndoManager.RunInBatch(() => {
this.props.Document.dockingConfig = json;
@@ -507,7 +507,12 @@ export class CollectionDockingView extends CollectionSubView() {
action(() => {
//if (confirm('really close this?')) {
if ((!stack.parent.isRoot && !stack.parent.parent.isRoot) || stack.parent.contentItems.length > 1) {
+ const batch = UndoManager.StartBatch('close stack');
stack.remove();
+ setTimeout(() => {
+ this.stateChanged();
+ batch.end();
+ });
} else {
alert('cant delete the last stack');
}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7bc273d7d..b66dc0aa2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -111,7 +111,7 @@ export function CollectionSubView<X>(moreProps?: X) {
rawdocs = rootDoc && !this.props.isAnnotationOverlay ? [Doc.GetProto(rootDoc)] : [];
}
- const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate).map(d => d as Doc);
+ const docs = rawdocs.filter(d => !(d instanceof Promise) && GetEffectiveAcl(Doc.GetProto(d)) !== AclPrivate && !d.unrendered).map(d => d as Doc);
const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 3e8867c50..d90a91ab7 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -3,13 +3,14 @@ import { Tooltip } from '@material-ui/core';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, NumListCast, StrListCast, Field } from '../../../fields/Doc';
-import { DateCast, StrCast, Cast, BoolCast } from '../../../fields/Types';
+import { DateCast, StrCast, Cast, BoolCast, DocCast, NumCast } from '../../../fields/Types';
import { LinkManager } from '../../util/LinkManager';
import { undoBatch } from '../../util/UndoManager';
import './LinkEditor.scss';
import { LinkRelationshipSearch } from './LinkRelationshipSearch';
import React = require('react');
import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils';
+import { PresBox, PresEffect } from '../nodes/trails';
interface LinkEditorProps {
sourceDoc: Doc;
@@ -24,6 +25,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
@observable zoomFollow = BoolCast(this.props.sourceDoc.followLinkZoom);
@observable audioFollow = BoolCast(this.props.sourceDoc.followLinkAudio);
@observable openDropdown: boolean = false;
+ @observable openEffectDropdown: boolean = false;
@observable private buttonColor: string = '';
@observable private relationshipButtonColor: string = '';
@observable private relationshipSearchVisibility: string = 'none';
@@ -295,6 +297,61 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
);
}
+ @computed get sourceAnchor() {
+ const ldoc = this.props.linkDoc;
+ if (this.props.sourceDoc !== ldoc.anchor1 && this.props.sourceDoc !== ldoc.anchor2) {
+ if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor1).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor1);
+ if (Doc.AreProtosEqual(DocCast(DocCast(ldoc.anchor2).annotationOn), this.props.sourceDoc)) return DocCast(ldoc.anchor2);
+ }
+ return this.props.sourceDoc;
+ }
+ @action
+ changeEffectDropdown = () => {
+ this.openEffectDropdown = !this.openEffectDropdown;
+ };
+
+ @undoBatch
+ changeEffect = action((follow: string) => {
+ this.openEffectDropdown = false;
+ this.sourceAnchor.presEffect = follow;
+ });
+
+ @computed
+ get effectDropdown() {
+ return (
+ <div className="linkEditor-followingDropdown">
+ <div className="linkEditor-followingDropdown-label">Transition Effect:</div>
+ <div className="linkEditor-followingDropdown-dropdown">
+ <div className="linkEditor-followingDropdown-header" onPointerDown={this.changeEffectDropdown}>
+ {StrCast(this.sourceAnchor.presEffect, 'default')}
+ <FontAwesomeIcon className="linkEditor-followingDropdown-icon" icon={this.openEffectDropdown ? 'chevron-up' : 'chevron-down'} size={'lg'} />
+ </div>
+ <div className="linkEditor-followingDropdown-optionsList" style={{ display: this.openEffectDropdown ? '' : 'none' }}>
+ {[
+ PresEffect.None,
+ PresEffect.Zoom,
+ PresEffect.Lightspeed,
+ PresEffect.Fade,
+ PresEffect.Flip,
+ PresEffect.Rotate,
+ PresEffect.Bounce,
+ PresEffect.Roll,
+ PresEffect.Left,
+ PresEffect.Right,
+ PresEffect.Center,
+ PresEffect.Top,
+ PresEffect.Bottom,
+ ].map(effect => (
+ <div className="linkEditor-followingDropdown-option" onPointerDown={() => this.changeEffect(effect.toString())}>
+ {effect.toString()}
+ </div>
+ ))}
+ </div>
+ </div>
+ </div>
+ );
+ }
+
autoMove = (e: React.PointerEvent) => {
setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(action(() => (this.props.linkDoc.linkAutoMove = !this.props.linkDoc.linkAutoMove))));
};
@@ -348,7 +405,6 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
</>
) : null}
</div>
-
{this.editDescription}
{this.editRelationship}
{this.editZoomFollow}
@@ -390,6 +446,20 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
</Tooltip>
</div>
{this.followingDropdown}
+ {this.effectDropdown}
+ {PresBox.inputter('0.1', '0.1', '10', NumCast(this.sourceAnchor.presTransition) / 1000, true, (val: string) => PresBox.SetTransitionTime(val, (timeInMS: number) => (this.sourceAnchor.presTransition = timeInMS)))}
+ <div
+ className={'slider-headers'}
+ style={{
+ display: 'grid',
+ justifyContent: 'space-between',
+ width: '100%',
+ gridTemplateColumns: 'auto auto auto',
+ }}>
+ <div className="slider-text">Fast</div>
+ <div className="slider-text">Medium</div>
+ <div className="slider-text">Slow</div>
+ </div>{' '}
</div>
);
}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 01188d3fa..abf6e37ab 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -28,7 +28,7 @@
transition: outline 0.3s linear;
// background: $white; //overflow: hidden;
- transform-origin: left top;
+ transform-origin: center;
&.minimized {
width: 30px;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index dc468cf89..fb07f1033 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -2,7 +2,7 @@ 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, trace } from 'mobx';
-import { observer } from 'mobx-react';
+import { observer, renderReporter } from 'mobx-react';
import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt, StrListCast, WidthSym } from '../../../fields/Doc';
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
@@ -1394,7 +1394,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined,
});
- const animRenderDoc = PresBox.Instance?.isActiveItemTarget(this.layoutDoc) ? PresBox.AnimationEffect(renderDoc, PresBox.Instance.activeItem) : renderDoc;
+ const animRenderDoc = Doc.IsHighlighted(this.rootDoc) || PresBox.Instance?.isActiveItemTarget(this.layoutDoc) ? PresBox.AnimationEffect(renderDoc, PresBox.Instance?.activeItem ?? Doc.HighlightBrush.linkFollowEffect, this.rootDoc) : renderDoc;
return (
<div
className={`${DocumentView.ROOT_DIV} docView-hack`}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 10f2dc016..7235481e0 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -34,6 +34,7 @@ import { FieldView, FieldViewProps } from '../FieldView';
import { ScriptingBox } from '../ScriptingBox';
import './PresBox.scss';
import { PresEffect, PresMovement, PresStatus } from './PresEnums';
+import { map } from 'bluebird';
const { Howl } = require('howler');
export interface PinProps {
@@ -67,17 +68,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
* @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
*/
- public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc) {
+ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Doc, root: Doc) {
const effectProps = {
- left: presEffectDoc.presEffectDirection === PresEffect.Left,
- right: presEffectDoc.presEffectDirection === PresEffect.Right,
- top: presEffectDoc.presEffectDirection === PresEffect.Top,
- bottom: presEffectDoc.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: NumCast(presEffectDoc.presTransition),
+ delay: 0,
+ duration: Cast(presEffectDoc?.presTransition, 'number', null),
};
//prettier-ignore
- switch (StrCast(presEffectDoc.presEffect)) {
+ switch (StrCast(presEffectDoc?.presEffect)) {
default:
case PresEffect.None: return renderDoc;
case PresEffect.Zoom: return <Zoom {...effectProps}>{renderDoc}</Zoom>;
@@ -386,7 +388,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinDataTypes.dataannos) {
const fkey = Doc.LayoutFieldKey(bestTarget);
- Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List<Doc>(DocListCast(activeItem.presAnnotations));
+ Doc.GetProto(bestTarget)[fkey + '-annotations'] = new List<Doc>([...DocListCast(bestTarget[fkey + '-annotations']).filter(doc => doc.unrendered), ...DocListCast(activeItem.presAnnotations)]);
}
if (pinDataTypes.dataview && activeItem.presData !== undefined) {
const fkey = Doc.LayoutFieldKey(bestTarget);
@@ -465,7 +467,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
if (pinProps.pinData.dataannos) {
const fkey = Doc.LayoutFieldKey(targetDoc);
- pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']));
+ pinDoc.presAnnotations = new List<Doc>(DocListCast(Doc.GetProto(targetDoc)[fkey + '-annotations']).filter(doc => !doc.unrendered));
}
if (pinProps.pinData.textview) pinDoc.presData = targetDoc[Doc.LayoutFieldKey(targetDoc)] instanceof ObjectField ? (targetDoc[Doc.LayoutFieldKey(targetDoc)] as ObjectField)[Copy]() : targetDoc.text;
if (pinProps.pinData.scrollable) pinDoc.presPinViewScroll = targetDoc._scrollTop;
@@ -1095,12 +1097,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
getPaths = (collection: Doc) => this.paths; // needs to be smarter and figure out the paths to draw for this specific collection. or better yet, draw everything in an overlay layer instad of within a collection
// Converts seconds to ms and updates presTransition
- setTransitionTime = (number: String, change?: number) => {
+ public static SetTransitionTime = (number: String, setter: (timeInMS: number) => void, change?: number) => {
let timeInMS = Number(number) * 1000;
if (change) timeInMS += change;
if (timeInMS < 100) timeInMS = 100;
if (timeInMS > 10000) timeInMS = 10000;
- this.selectedArray.forEach(doc => (doc.presTransition = timeInMS));
+ setter(timeInMS);
+ };
+ setTransitionTime = (number: String, change?: number) => {
+ PresBox.SetTransitionTime(number, (timeInMS: number) => this.selectedArray.forEach(doc => (doc.presTransition = timeInMS)), change);
};
// Converts seconds to ms and updates presTransition
@@ -1165,6 +1170,28 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
_batch: UndoManager.Batch | undefined = undefined;
+ public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void) => {
+ let batch: any;
+ return (
+ <input
+ type="range"
+ step={step}
+ min={min}
+ max={max}
+ value={value}
+ className={`toolbar-slider ${active ? '' : 'none'}`}
+ onPointerDown={e => {
+ batch = UndoManager.StartBatch('pres slider');
+ e.stopPropagation();
+ }}
+ onPointerUp={() => batch?.end()}
+ onChange={e => {
+ e.stopPropagation();
+ change(e.target.value);
+ }}
+ />
+ );
+ };
@computed get transitionDropdown() {
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
@@ -1180,39 +1207,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
{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';
+ const presDirection = (direction: PresEffect, icon: string, gridColumn: number, gridRow: number, opts: object) => {
+ const color = this.activeItem.presEffectDirection === direction || (direction === PresEffect.Center && !this.activeItem.presEffectDirection) ? Colors.LIGHT_BLUE : 'black';
return (
- <Tooltip title={<div className="dash-tooltip">{diretion}</div>}>
+ <Tooltip title={<div className="dash-tooltip">{direction}</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)}>
+ style={{ ...opts, border: direction === PresEffect.Center ? `solid 2px ${color}` : undefined, borderRadius: '100%', cursor: 'pointer', gridColumn, gridRow, justifySelf: 'center', color }}
+ onClick={() => this.updateEffectDirection(direction)}>
{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;
@@ -1263,7 +1269,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- {inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
+ {PresBox.inputter('0', '1', '100', zoom, activeItem.presMovement === PresMovement.Zoom, this.setZoom)}
<div className="ribbon-doubleButton" style={{ display: 'inline-flex' }}>
<div className="presBox-subheading">Transition Speed</div>
<div className="ribbon-property">
@@ -1278,7 +1284,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- {inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)}
+ {PresBox.inputter('0.1', '0.1', '10', transitionSpeed, true, this.setTransitionTime)}
<div className={'slider-headers'}>
<div className="slider-text">Fast</div>
<div className="slider-text">Medium</div>
@@ -1331,7 +1337,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
</div>
</div>
</div>
- {inputter('0.1', '0.1', '20', duration, targetDoc.type !== DocumentType.AUDIO, this.setDurationTime)}
+ {PresBox.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>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 70cb10970..75801b68c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1263,11 +1263,15 @@ export namespace Doc {
export function linkFollowUnhighlight() {
Doc.UnhighlightAll();
document.removeEventListener('pointerdown', linkFollowUnhighlight);
+ runInAction(() => (HighlightBrush.linkFollowEffect = undefined));
}
let _lastDate = 0;
- export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true) {
+ export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true, presEffect?: Doc) {
linkFollowUnhighlight();
+ // runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = undefined));
+ // setTimeout(() => runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect)));
+ runInAction(() => presEffect && (HighlightBrush.linkFollowEffect = presEffect));
(destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs));
document.removeEventListener('pointerdown', linkFollowUnhighlight);
document.addEventListener('pointerdown', linkFollowUnhighlight);
@@ -1277,6 +1281,7 @@ export namespace Doc {
export class HighlightBrush {
@observable HighlightedDoc: Map<Doc, boolean> = new Map();
+ @observable static linkFollowEffect: Doc | undefined;
}
const highlightManager = new HighlightBrush();
export function IsHighlighted(doc: Doc) {