aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ChatBox/MessageComponent.scss10
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx11
-rw-r--r--src/client/views/nodes/ComparisonBox.scss2
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx142
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx1
-rw-r--r--src/client/views/nodes/DocumentView.tsx158
-rw-r--r--src/client/views/nodes/ImageBox.tsx5
-rw-r--r--src/client/views/nodes/PDFBox.tsx8
-rw-r--r--src/client/views/nodes/WebBox.tsx1
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx12
10 files changed, 192 insertions, 158 deletions
diff --git a/src/client/views/nodes/ChatBox/MessageComponent.scss b/src/client/views/nodes/ChatBox/MessageComponent.scss
new file mode 100644
index 000000000..6fcc0e5e7
--- /dev/null
+++ b/src/client/views/nodes/ChatBox/MessageComponent.scss
@@ -0,0 +1,10 @@
+MessageComponent-citation {
+ color: lightblue;
+ vertical-align: super;
+ font-size: smaller;
+}
+MessageComponent-file_path {
+ color: lightblue;
+ vertical-align: baseline;
+ font-size: inherit;
+}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 034a38e9c..ee67dd305 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -20,6 +20,11 @@ import { DocumentView, DocumentViewProps } from './DocumentView';
import { FieldViewProps } from './FieldView';
import { OpenWhere } from './OpenWhere';
+export enum GroupActive { // flags for whether a view is activate because of its relationship to a group
+ group = 'group', // this is a group that is activated because it's on an active canvas, but is not part of some other group
+ child = 'child', // this is a group child that is activated because its containing group is activated
+ inactive = 'inactive', // this is a group child but it is not active
+}
/// Ugh, typescript has no run-time way of iterating through the keys of an interface. so we need
/// manaully keep this list of keys in synch wih the fields of the freeFormProps interface
const freeFormPropsKeys = ['x', 'y', 'z', 'zIndex', 'rotation', 'opacity', 'backgroundColor', 'color', 'highlight', 'width', 'height', 'autoDim', 'transition'];
@@ -274,7 +279,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
if (this._props.isAnyChildContentActive()) return undefined;
const backColor = this.BackgroundColor;
const isGroup = this.dataDoc.isGroup && (!backColor || backColor === 'transparent');
- return isGroup ? (this._props.isDocumentActive?.() ? 'group' : this._props.isGroupActive?.() ? 'child' : 'inactive') : this._props.isGroupActive?.() ? 'child' : undefined;
+ return isGroup ? (this._props.isDocumentActive?.() ? GroupActive.group :
+ this._props.isGroupActive?.() ? GroupActive.child : GroupActive.inactive) :
+ this._props.isGroupActive?.() ? GroupActive.child : undefined; // prettier-ignore
};
localRotation = () => this._props.rotation;
render() {
@@ -313,6 +320,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
}
}
// eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) {
+ScriptingGlobals.add(function gotoFrame(doc: Doc, newFrame: number) {
CollectionFreeFormDocumentView.gotoKeyFrame(doc, newFrame);
});
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
index 093b9c004..08d9e6010 100644
--- a/src/client/views/nodes/ComparisonBox.scss
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -49,7 +49,6 @@
left: 0;
height: 100%;
overflow: hidden;
- transition: 200ms;
.beforeBox-cont {
height: 100%;
@@ -63,7 +62,6 @@
width: 3px;
display: inline-block;
background: white;
- transition: 200ms;
.slide-handle {
position: absolute;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index adb380f12..efaf6807a 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -30,41 +30,23 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return FieldView.LayoutString(ComparisonBox, fieldKey);
}
private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined];
+ private _closeRef = React.createRef<HTMLDivElement>();
+ @observable _inputValue = '';
+ @observable _outputValue = '';
+ @observable _loading = false;
+ @observable _errorMessage = '';
+ @observable _outputMessage = '';
+ @observable _animating = '';
+
constructor(props: FieldViewProps) {
super(props);
makeObservable(this);
}
- @observable inputValue = '';
- @observable outputValue = '';
- @observable loading = false;
- @observable errorMessage = '';
- @observable outputMessage = '';
-
- @action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
- this.inputValue = e.target.value;
- console.log(this.inputValue);
- };
-
- @observable _animating = '';
-
- @computed get clipWidth() {
- return NumCast(this.layoutDoc[this.clipWidthKey], 50);
- }
- get clipWidthKey() {
- return '_' + this._props.fieldKey + '_clipWidth';
- }
-
- @computed get clipHeight() {
- return NumCast(this.layoutDoc[this.clipHeightKey], 200);
- }
- get clipHeightKey() {
- return '_' + this._props.fieldKey + '_clipHeight';
- }
-
componentDidMount() {
this._props.setContentViewBox?.(this);
}
+
protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => {
this._disposers[disposerId]?.();
if (ele) {
@@ -72,7 +54,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
}
};
- private internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+ @computed get revealOp() { return this.layoutDoc[`_${this.fieldKey}_revealOp`] as ('flip'|'hover'|undefined); } // prettier-ignore
+ @computed get clipWidth() { return NumCast(this.layoutDoc[`_${this.fieldKey}_clipWidth`], 50); } // prettier-ignore
+ set clipWidth(width: number) { this.layoutDoc[`_${this.fieldKey}_clipWidth`] = width; } // prettier-ignore
+ @computed get useAlternate() { return this.layoutDoc[`_${this.fieldKey}_usePath`] === 'alternate'; } // prettier-ignore
+ set useAlternate(alt: boolean) { this.layoutDoc[`_${this.fieldKey}_usePath`] = alt ? 'alternate' : undefined; } // prettier-ignore
+
+ animateClipWidth = action((clipWidth: number, duration = 200 /* ms */) => {
+ this._animating = `all ${duration}ms`; // turn on clip animation transition, then turn it off at end of animation
+ setTimeout(action(() => { this._animating = ''; }), duration); // prettier-ignore
+ this.clipWidth = clipWidth;
+ });
+
+ internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
if (dropEvent.complete.docDragData) {
const { droppedDocuments } = dropEvent.complete.docDragData;
const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocuments, this.Document, (doc: Doc | Doc[]) => this.addDoc(toList(doc).lastElement(), fieldKey));
@@ -84,45 +78,34 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return undefined;
}, 'internal drop');
- private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
+ registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => {
if (e.button !== 2) {
setupMoveUpEvents(
this,
e,
this.onPointerMove,
emptyFunction,
- action((moveEv, doubleTap) => {
+ action((clickEv, doubleTap) => {
if (doubleTap) {
this._isAnyChildContentActive = true;
if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
+ // DocumentView.addViewRenderedCb(DocCast(this.dataDoc[this.fieldKey + '_1']), dv => {
+ // dv?.select(false);
+ // });
}
}),
- false,
+ true,
undefined,
- action(() => {
- if (this._isAnyChildContentActive) return;
- this._animating = 'all 200ms';
- // on click, animate slider movement to the targetWidth
- this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth();
- // this.layoutDoc[this.clipHeightKey] = (targetWidth * 100) / this._props.PanelHeight();
-
- setTimeout(
- action(() => {
- this._animating = '';
- }),
- 200
- );
- })
+ () => !this._isAnyChildContentActive && this.animateClipWidth((targetWidth * 100) / this._props.PanelWidth())
);
}
};
- @action
- private onPointerMove = ({ movementX }: PointerEvent) => {
+ onPointerMove = ({ movementX }: PointerEvent) => {
const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth();
- if (width && width > 5 && width < this._props.PanelWidth()) {
- this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth();
+ if (width > 5 && width < this._props.PanelWidth()) {
+ this.clipWidth = (width * 100) / this._props.PanelWidth();
}
return false;
};
@@ -180,8 +163,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
};
docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => {
- if (property === StyleProp.PointerEvents) return 'none';
- return this._props.styleProvider?.(doc, props, property);
+ switch (property) {
+ case StyleProp.PointerEvents: return 'none';
+ default: return this._props.styleProvider?.(doc, props, property);
+ } // prettier-ignore
};
moveDoc1 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true);
moveDoc2 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true);
@@ -220,36 +205,31 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
return layoutTemplateString;
};
- _closeRef = React.createRef<HTMLDivElement>();
-
/**
* Flips a flashcard to the alternate side for the user to view.
*/
flipFlashcard = () => {
- const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : undefined;
+ this.useAlternate = !this.useAlternate;
};
/**
* Changes the view option to hover for a flashcard.
*/
- hoverFlip = (side: string | undefined) => {
- if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side;
+ hoverFlip = (alternate: boolean) => {
+ if (this.revealOp === 'hover') this.useAlternate = alternate;
};
/**
* Creates the button used to flip the flashcards.
*/
@computed get overlayAlternateIcon() {
- const usepath = this.layoutDoc[`_${this._props.fieldKey}_usePath`];
return (
<Tooltip title={<div className="dash-tooltip">flip</div>}>
<div
className="formattedTextBox-alternateButton"
onPointerDown={e =>
setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => {
- console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]);
- if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') {
+ if (!this.revealOp || this.revealOp === 'flip') {
this.flipFlashcard();
console.log('Print Front of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text ?? ''));
console.log('Print Back of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text ?? ''));
@@ -257,8 +237,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
})
}
style={{
- background: usepath === 'alternate' ? 'white' : 'black',
- color: usepath === 'alternate' ? 'black' : 'white',
+ background: this.useAlternate ? 'white' : 'black',
+ color: this.useAlternate ? 'black' : 'white',
}}>
<FontAwesomeIcon icon="turn-up" size="sm" />
</div>
@@ -268,14 +248,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
@action handleRenderGPTClick = () => {
// Call the GPT model and get the output
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate';
- this.outputValue = '';
- if (this.inputValue) this.askGPT();
+ this.useAlternate = true;
+ this._outputValue = '';
+ if (this._inputValue) this.askGPT();
};
@action handleRenderClick = () => {
// Call the GPT model and get the output
- this.layoutDoc[`_${this._props.fieldKey}_usePath`] = undefined;
+ this.useAlternate = false;
};
/**
@@ -285,7 +265,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
askGPT = async (): Promise<string | undefined> => {
const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
- const queryText = questionText + ' UserAnswer: ' + this.inputValue + '. ' + rubricText;
+ const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText;
try {
const res = await gptAPICall(queryText, GPTCallType.QUIZ);
@@ -293,8 +273,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
console.error('GPT call failed');
return;
}
- this.outputValue = res;
- console.log(res);
+ this._outputValue = res;
} catch (err) {
console.error('GPT call failed');
}
@@ -355,7 +334,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
if (this.Document._layout_isFlashcard) {
- const side = this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 1 : 0;
+ const side = this.useAlternate ? 1 : 0;
// add text box to each side when comparison box is first created
if (!(this.dataDoc[this.fieldKey + '_0'] || this.dataDoc[this.fieldKey + '_0'] === 'empty')) {
@@ -383,17 +362,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
{/* {StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)} */}
<div className="input-box">
<textarea
- value={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? this.outputValue : this.inputValue}
- onChange={this.handleInputChange}
- readOnly={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate'}
+ value={this.useAlternate ? this._outputValue : this._inputValue}
+ onChange={action(e => {
+ this._inputValue = e.target.value;
+ })}
+ readOnly={this.useAlternate}
/>
</div>
- <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'none' : 'flex' }}>
+ <div className="submit-button" style={{ display: this.useAlternate ? 'none' : 'flex' }}>
<button type="button" onClick={this.handleRenderGPTClick}>
Submit
</button>
</div>
- <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'flex' : 'none' }}>
+ <div className="submit-button" style={{ display: this.useAlternate ? 'flex' : 'none' }}>
<button type="button" onClick={this.handleRenderClick}>
Edit Your Response
</button>
@@ -407,12 +388,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
<div
className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */
style={{ display: 'flex', flexDirection: 'column' }}
- onMouseEnter={() => {
- this.hoverFlip('alternate');
- }}
- onMouseLeave={() => {
- this.hoverFlip(undefined);
- }}>
+ onMouseEnter={() => this.hoverFlip(true)}
+ onMouseLeave={() => this.hoverFlip(false)}>
{displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)}
{this.overlayAlternateIcon}
</div>
@@ -430,9 +407,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
className="slide-bar"
style={{
left: `calc(${this.clipWidth + '%'} - 0.5px)`,
+ transition: this._animating,
cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined,
}}
- onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
+ onPointerDown={e => this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */
>
<div className="slide-handle" />
</div>
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index a1deb1625..d2e82284e 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -18,6 +18,7 @@ import { DocumentView } from '../../DocumentView';
import { DataVizView } from '../DataVizBox';
import './Chart.scss';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore
interface TableBoxProps {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7a1f94948..ce7cfa5f4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,6 +43,7 @@ import { ObserverJsxParser } from '../ObservableReactComponent';
import { PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { ViewBoxInterface } from '../ViewBoxInterface';
+import { GroupActive } from './CollectionFreeFormDocumentView';
import { DocumentContentsView } from './DocumentContentsView';
import { DocumentLinksButton } from './DocumentLinksButton';
import './DocumentView.scss';
@@ -52,7 +53,7 @@ import { OpenWhere, OpenWhereMod } from './OpenWhere';
import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { PresEffect, PresEffectDirection } from './trails/PresEnums';
import SpringAnimation from './trails/SlideEffect';
-import { SpringSettings, SpringType, springMappings } from './trails/SpringUtils';
+import { SpringType, springMappings } from './trails/SpringUtils';
interface Window {
MediaRecorder: MediaRecorder;
@@ -153,7 +154,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
@computed get disableClickScriptFunc() {
const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable;
- return (DocumentView.LongPress ||
+ return (SnappingManager.LongPress ||
onScriptDisable === 'always' ||
(onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))); // prettier-ignore
}
@@ -297,17 +298,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
e.stopPropagation();
};
onClick = action((e: React.MouseEvent | React.PointerEvent) => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
- const documentView = this._docView;
- if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
+ if (this._docView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
let stopPropagate = true;
let preventDefault = true;
- !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
const scriptProps = {
this: this.Document,
_readOnly_: false,
scriptContext: this._props.scriptContext,
- documentView,
+ documentView: this._docView,
clientX: e.clientX,
clientY: e.clientY,
shiftKey: e.shiftKey,
@@ -317,44 +316,39 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
};
if (this._doubleTap) {
const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick;
- if (this.onDoubleClickHdlr?.script) {
- UndoManager.RunInBatch(() => this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title);
- } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
- UndoManager.RunInBatch(() => this._props.addDocTab(this.Document, OpenWhere.lightboxAlways), 'double tap');
- DocumentView.DeselectAll();
- Doc.UnBrushDoc(this.Document);
- } else {
- this._singleClickFunc?.();
- }
+ undoable(() => {
+ if (this.onDoubleClickHdlr?.script) {
+ this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false);
+ } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') {
+ this._props.addDocTab(this.Document, OpenWhere.lightboxAlways);
+ DocumentView.DeselectAll();
+ Doc.UnBrushDoc(this.Document);
+ } else this._singleClickFunc?.();
+ }, 'on double click: ' + this.Document.title)();
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = undefined;
this._singleClickFunc = undefined;
} else {
- let clickFunc: undefined | (() => any);
- if (!this.disableClickScriptFunc && this.onClickHdlr?.script) {
- clickFunc = undoable(() => {
- this.onClickHdlr?.script.run(scriptProps, console.log).result?.select && this._props.select(false);
- }, 'click ' + this.Document.title);
- } else {
- // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
- if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) {
- stopPropagate = false;
- }
- preventDefault = false;
- }
- const sendToBack = e.altKey ? () => documentView._props.bringToFront?.(this.Document, true) : undefined;
+ const sendToBack = e.altKey ? () => this._props.bringToFront?.(this.Document, true) : undefined;
const selectFunc = () => {
+ !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document);
// selecting a view that is part of a template proxies the selection back to the root of the template
const templateRoot = !(e.ctrlKey || e.button > 0) && this._props.docViewPath?.().reverse().find(dv => !dv._props.TemplateDataDocument); // prettier-ignore
(templateRoot || this._docView)?.select(e.ctrlKey || e.shiftKey, e.metaKey);
};
- this._singleClickFunc = clickFunc ?? sendToBack ?? selectFunc;
- const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
- if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
+ const clickFunc = this.onClickFunc?.()?.script ? () => (this.onClickFunc?.()?.script.run(scriptProps, console.log).result as Opt<{ select: boolean }>)?.select && this._props.select(false) : undefined;
+ if (!clickFunc) {
+ // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
+ if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) stopPropagate = false;
+ preventDefault = false;
+ }
+ this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.title);
+ const waitForDblClick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
+ if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') {
this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300);
// eslint-disable-next-line no-use-before-define
- } else if (!DocumentView.LongPress) {
+ } else if (!SnappingManager.LongPress) {
this._singleClickFunc();
this._singleClickFunc = undefined;
}
@@ -365,9 +359,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
});
onPointerDown = (e: React.PointerEvent): void => {
- if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return;
+ if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return;
// eslint-disable-next-line no-use-before-define
- this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000);
+ this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000);
if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView;
this._downX = e.clientX;
@@ -418,7 +412,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected
}
// eslint-disable-next-line no-use-before-define
- if (DocumentView.LongPress) e.preventDefault();
+ if (SnappingManager.LongPress) e.preventDefault();
};
toggleFollowLink = undoable((): void => {
@@ -975,8 +969,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
* @returns a function that will wrap a JSX animation element wrapping any JSX element
*/
public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) {
- let dir = (presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) as PresEffectDirection;
- const transitionTime = presEffectDoc?.presentation_transition ? NumCast(presEffectDoc?.presentation_transition) : 500;
+ const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection;
+ const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null));
const effectProps = {
left: dir === PresEffectDirection.Left,
right: dir === PresEffectDirection.Right,
@@ -984,26 +978,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
bottom: dir === PresEffectDirection.Bottom,
opposite: true,
delay: 0,
- duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)),
+ duration,
};
const timing = StrCast(presEffectDoc?.presentation_effectTiming);
- let timingConfig: SpringSettings | undefined;
- if (timing) {
- timingConfig = JSON.parse(timing);
- }
-
- if (!timingConfig) {
- timingConfig = {
- type: SpringType.GENTLE,
- ...springMappings.gentle,
- };
- }
-
- if (!dir) {
- dir = PresEffectDirection.Center;
- }
-
+ const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? {
+ type: SpringType.GENTLE,
+ ...springMappings.gentle,
+ };
switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) {
case PresEffect.Expand: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Expand} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
case PresEffect.Flip: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Flip} springSettings={timingConfig}>{renderDoc}</SpringAnimation>
@@ -1085,15 +1067,16 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => Promise<void>;
public static linkCommonAncestor: (link: Doc) => DocumentView | undefined;
- // pin func
+ /**
+ * Pins a Doc to the current presentation trail. (see TabDocView for implementation)
+ */
public static PinDoc: (docIn: Doc | Doc[], pinProps: PinProps) => void;
- // gesture
- public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to.
- // media playing
- @observable public static CurrentlyPlaying: DocumentView[] = [];
+ /**
+ * The DocumentView below the cursor at the start of a gesture (that receives the pointerDown event). Used by GestureOverlay to determine the doc a gesture should apply to.
+ */
+ public static DownDocView: DocumentView | undefined;
public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore
- public ContentRef = React.createRef<HTMLDivElement>();
private _htmlOverlayEffect: Opt<Doc>;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _viewTimer: NodeJS.Timeout | undefined;
@@ -1124,7 +1107,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
@observable private _htmlOverlayText: Opt<string> = undefined;
@observable private _isHovering = false;
@observable private _selected = false;
- @observable public static LongPress = false;
+ @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing
@computed private get shouldNotScale() {
return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.();
@@ -1471,7 +1454,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
{!this.Document || !this._props.PanelWidth() ? null : (
<div
className="contentFittingDocumentView-previewDoc"
- ref={this.ContentRef}
style={{
transform: `translate(${this.centeringX}px, ${this.centeringY}px)`,
width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`,
@@ -1568,6 +1550,56 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
}
}
+export function ActiveFillColor(): string {
+ const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined;
+ return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, ""));
+} // prettier-ignore
+export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore
+export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore
+export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore
+export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore
+export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore
+export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore
+export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore
+export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore
+export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore
+export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore
+export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth); } // prettier-ignore
+
+export function SetActiveInkWidth(width: string): void {
+ !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width);
+}
+export function SetActiveBezierApprox(bezier: string): void {
+ ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier);
+}
+export function SetActiveInkColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
+}
+export function SetActiveIsInkMask(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
+}
+export function SetActiveInkHideTextLabels(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value);
+}
+export function SetActiveFillColor(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
+}
+export function SetActiveArrowStart(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowStart = value);
+}
+export function SetActiveArrowEnd(value: string) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value);
+}
+export function SetActiveArrowScale(value: number) {
+ ActiveInkPen() && (ActiveInkPen().activeArrowScale = value);
+}
+export function SetActiveDash(dash: string): void {
+ !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash);
+}
+export function SetEraserWidth(width: number): void {
+ ActiveInkPen() && (ActiveInkPen().eraserWidth = width);
+}
+
// eslint-disable-next-line prefer-arrow-callback
ScriptingGlobals.add(function DocFocusOrOpen(docIn: Doc, optionsIn?: FocusViewOptions, containingDoc?: Doc) {
return DocumentView.FocusOrOpen(docIn, optionsIn, containingDoc);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e4b3a1b9b..68c313480 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -448,6 +448,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
+ renderedPixelDimensions = async () => {
+ const { nativeWidth: width, nativeHeight: height } = await Networking.PostToServer('/inspectImage', { source: this.paths[0] });
+ return { width, height };
+ };
+
savedAnnotations = () => this._savedAnnotations;
render() {
TraceMobx();
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 7a89b143b..8db68ddfe 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -655,9 +655,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
else {
if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise);
- PDFBox.pdfpromise.get(href)?.then((pdf: any) => {
- PDFBox.pdfcache.set(href, (this._pdf = pdf));
- });
+ PDFBox.pdfpromise.get(href)?.then(
+ action((pdf: any) => {
+ PDFBox.pdfcache.set(href, (this._pdf = pdf));
+ })
+ );
}
}
return pdfView ?? this.renderTitleBox;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 8835ea5e7..da947face 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -45,6 +45,7 @@ import { LinkInfo } from './LinkDocPreview';
import { OpenWhere } from './OpenWhere';
import './WebBox.scss';
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const { CreateImage } = require('./WebBoxRenderer');
@observer
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9f2a9b8e1..5b435e44a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -87,9 +87,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
public static LiveTextUndo: UndoManager.Batch | undefined; // undo batch when typing a new text note into a collection
static _globalHighlightsCache: string = '';
static _globalHighlights = new ObservableSet<string>(['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items']);
- static _highlightStyleSheet: any = addStyleSheet();
- static _bulletStyleSheet: any = addStyleSheet();
- static _userStyleSheet: any = addStyleSheet();
+ static _highlightStyleSheet = addStyleSheet();
+ static _bulletStyleSheet = addStyleSheet();
+ static _userStyleSheet = addStyleSheet();
static _hadSelection: boolean = false;
private _selectionHTML: string | undefined;
private _sidebarRef = React.createRef<SidebarAnnos>();
@@ -384,7 +384,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
}
} else {
- const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data!;
+ const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data;
if (jsonstring) {
const json = JSON.parse(jsonstring);
json.selection = state.toJSON().selection;
@@ -1925,11 +1925,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
setHeight={this.setSidebarHeight}
/>
) : (
- <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.()!, false), true)}>
+ <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.(), false), true)}>
<ComponentTag
// eslint-disable-next-line react/jsx-props-no-spreading
{...this._props}
- ref={this._sidebarTagRef as any}
+ ref={this._sidebarTagRef}
setContentView={emptyFunction}
NativeWidth={returnZero}
NativeHeight={returnZero}