aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/MarqueeAnnotator.tsx21
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx6
-rw-r--r--src/client/views/nodes/ImageBox.tsx6
-rw-r--r--src/client/views/nodes/VideoBox.tsx16
-rw-r--r--src/client/views/nodes/WebBox.tsx48
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx260
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx10
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx91
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx4
-rw-r--r--src/client/views/pdf/PDFViewer.tsx34
10 files changed, 213 insertions, 283 deletions
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index c18ac6738..8aed34d24 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -27,7 +27,7 @@ export interface MarqueeAnnotatorProps {
containerOffset?: () => number[];
marqueeContainer: HTMLDivElement;
docView: () => DocumentView;
- savedAnnotations: () => ObservableMap<number, HTMLDivElement[]>;
+ savedAnnotations: () => ObservableMap<number, (HTMLDivElement& { marqueeing?: boolean})[]>;
selectionText: () => string;
annotationLayer: HTMLDivElement;
addDocument: (doc: Doc) => boolean;
@@ -41,7 +41,7 @@ export interface MarqueeAnnotatorProps {
export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorProps> {
private _start: { x: number; y: number } = { x: 0, y: 0 };
- constructor(props: any) {
+ constructor(props: MarqueeAnnotatorProps) {
super(props);
makeObservable(this);
}
@@ -60,13 +60,13 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
});
@undoBatch
- makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap<number, HTMLDivElement[]>): Opt<Doc> => {
+ makeAnnotationDocument = (color: string, isLinkButton?: boolean, savedAnnotations?: ObservableMap<number, (HTMLDivElement& { marqueeing?: boolean})[]>): Opt<Doc> => {
const savedAnnoMap = savedAnnotations?.values() && Array.from(savedAnnotations?.values()).length ? savedAnnotations : this.props.savedAnnotations();
if (savedAnnoMap.size === 0) return undefined;
const savedAnnos = Array.from(savedAnnoMap.values())[0];
const doc = this.props.Document;
const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1);
- if (savedAnnos.length && (savedAnnos[0] as any).marqueeing) {
+ if (savedAnnos.length && savedAnnos[0].marqueeing) {
const anno = savedAnnos[0];
const containerOffset = this.props.containerOffset?.() || [0, 0];
const marqueeAnno = Docs.Create.FreeformDocument([], {
@@ -86,8 +86,9 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
const textRegionAnno = Docs.Create.ConfigDocument({
annotationOn: this.props.Document,
- text: this.props.selectionText() as any, // text want an RTFfield, but strings are acceptable, too.
- text_html: this.props.selectionText() as any,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ text: this.props.selectionText() as any, // text wants an RTFfield, but strings are acceptable, too.
+ text_html: this.props.selectionText(),
backgroundColor: 'transparent',
presentation_duration: 2100,
presentation_transition: 500,
@@ -136,7 +137,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
return annotationDoc as Doc;
};
- public static previewNewAnnotation = action((savedAnnotations: ObservableMap<number, HTMLDivElement[]>, annotationLayer: HTMLDivElement, div: HTMLDivElement, page: number) => {
+ public static previewNewAnnotation = action((savedAnnotations: ObservableMap<number, (HTMLDivElement& { marqueeing?: boolean})[]>, annotationLayer: HTMLDivElement & { marqueeing?: boolean}, div: HTMLDivElement, page: number) => {
div.style.backgroundColor = '#ACCEF7';
div.style.opacity = '0.5';
annotationLayer.append(div);
@@ -264,17 +265,17 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
if (!this.isEmpty && marqueeStyle) {
// configure and show the annotation/link menu if a the drag region is big enough
// copy the temporary marquee to allow for multiple selections (not currently available though).
- const copy = document.createElement('div');
+ const copy: (HTMLDivElement & {marqueeing?: boolean}) = document.createElement('div');
const scale = (this.props.scaling?.() || 1) * NumCast(this.props.Document._freeform_scale, 1);
['border', 'opacity', 'top', 'left', 'width', 'height'].forEach(prop => {
- copy.style[prop as any] = marqueeStyle[prop as any];
+ copy.style[prop as unknown as number] = marqueeStyle[prop as unknown as number]; // bcz: hack to get around TS type checking for array index with strings
});
copy.className = 'marqueeAnnotator-annotationBox';
copy.style.top = parseInt(marqueeStyle.top.toString().replace('px', '')) / scale + this.props.scrollTop + 'px';
copy.style.left = parseInt(marqueeStyle.left.toString().replace('px', '')) / scale + 'px';
copy.style.width = parseInt(marqueeStyle.width.toString().replace('px', '')) / scale + 'px';
copy.style.height = parseInt(marqueeStyle.height.toString().replace('px', '')) / scale + 'px';
- (copy as any).marqueeing = true;
+ copy.marqueeing = true;
MarqueeAnnotator.previewNewAnnotation(this.props.savedAnnotations(), this.props.annotationLayer, copy, this.props.getPageFromScroll?.(this.top) || 0);
AnchorMenu.Instance.jumpTo(x, y);
}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 4d5f15a3e..baf8693ca 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -50,7 +50,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
sidebarAddDoc: ((doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean) | undefined;
crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined;
@observable _marqueeing: number[] | undefined = undefined;
- @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @observable _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean})[]>();
constructor(props: FieldViewProps) {
super(props);
@@ -376,8 +376,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
- const target = e.target as any;
- if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) {
+ const target = e.target as HTMLElement;
+ if (e.target && (target.className.includes('endOfContent') || (target.parentElement?.className !== 'textLayer' && target.parentElement?.parentElement?.className !== 'textLayer'))) {
/* empty */
} else {
// if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 68c313480..ce7552047 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -73,7 +73,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
- @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @observable _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean})[]>();
@observable _curSuffix = '';
@observable _error = '';
@observable _isHovering = false; // flag to switch between primary and alternate images on hover
@@ -356,7 +356,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get content() {
TraceMobx();
- const backColor = DashColor(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) ?? Colors.WHITE);
+ const backColor = DashColor(this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string ?? Colors.WHITE);
const backAlpha = backColor.red() === 0 && backColor.green() === 0 && backColor.blue() === 0 ? backColor.alpha() : 1;
const srcpath = this.layoutDoc.hideImage ? '' : this.paths[0];
const fadepath = this.layoutDoc.hideImage ? '' : this.paths.lastElement();
@@ -456,7 +456,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
savedAnnotations = () => this._savedAnnotations;
render() {
TraceMobx();
- const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
+ const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string;
const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / (this._props.NativeDimScaling?.() || 1)}px` : borderRad;
return (
<div
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fe7600fa3..1f285b300 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1,4 +1,3 @@
-/* eslint-disable jsx-a11y/media-has-caption */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
@@ -59,8 +58,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _marqueeref = React.createRef<MarqueeAnnotator>();
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); // outermost div
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
- private _playRegionTimer: any = null; // timeout for playback
- private _controlsFadeTimer: any = null; // timeout for controls fade
+ private _playRegionTimer: NodeJS.Timeout | undefined; // timeout for playback
+ private _controlsFadeTimer: NodeJS.Timeout | undefined; // timeout for controls fade
private _ffref = React.createRef<CollectionFreeFormView>();
constructor(props: FieldViewProps) {
@@ -142,7 +141,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
switch (e.key) {
case 'ArrowLeft':
case 'ArrowRight':
- clearTimeout(this._controlsFadeTimer);
+ this._controlsFadeTimer && clearTimeout(this._controlsFadeTimer);
this._scrubbing = true;
this._controlsFadeTimer = setTimeout(
action(() => {
@@ -217,7 +216,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._playTimer = undefined;
this.updateTimecode();
if (!this._finished) {
- clearTimeout(this._playRegionTimer); // if paused in the middle of playback, prevents restart on next play
+ this._playRegionTimer && clearTimeout(this._playRegionTimer); // if paused in the middle of playback, prevents restart on next play
}
this._playRegionTimer = undefined;
};
@@ -420,7 +419,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._videoRef = vref;
if (vref) {
this._videoRef!.ontimeupdate = this.updateTimecode;
- // @ts-ignore
// vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen);
this._disposers.reactionDisposer?.();
this._disposers.reactionDisposer = reaction(
@@ -469,7 +467,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
runInAction(() => {
this._screenCapture = !this._screenCapture;
});
- this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
+ this._videoRef!.srcObject = !this._screenCapture ? null : await (navigator.mediaDevices).getDisplayMedia({ video: true });
},
icon: 'expand-arrows-alt',
});
@@ -877,7 +875,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return (
<div className="videoBox-stackPanel" style={{ transition: this.transition, height: `${100 - this.heightPercent}%`, display: this.heightPercent === 100 ? 'none' : '' }}>
<CollectionStackedTimeline
- ref={action((r: any) => {
+ ref={action((r: CollectionStackedTimeline) => {
this._stackedTimeline = r;
})}
// eslint-disable-next-line react/jsx-props-no-spreading
@@ -968,7 +966,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options));
savedAnnotations = () => this._savedAnnotations;
render() {
- const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding);
+ const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string;
const borderRadius = borderRad?.includes('px') ? `${Number(borderRad.split('px')[0]) / this.scaling()}px` : borderRad;
return (
<div
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index da947face..be7e0f483 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/control-has-associated-label */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { htmlToText } from 'html-to-text';
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
@@ -67,7 +65,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _sidebarRef = React.createRef<SidebarAnnos>();
private _searchRef = React.createRef<HTMLInputElement>();
private _searchString = '';
- private _scrollTimer: any;
+ private _scrollTimer: NodeJS.Timeout | undefined;
private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
@observable private _webUrl = ''; // url of the src parameter of the embedded iframe but not necessarily the rendered page - eg, when following a link, the rendered page changes but we don't want the src parameter to also change as that would cause an unnecessary re-render.
@@ -85,7 +83,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._marqueeing = val;
}
@observable private _iframe: HTMLIFrameElement | null = null;
- @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @observable private _savedAnnotations = new ObservableMap<number, (HTMLDivElement& { marqueeing?: boolean})[]>();
@observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight);
@computed get _url() {
return this.webField?.toString() || '';
@@ -361,8 +359,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return anchor;
};
- _textAnnotationCreator: (() => ObservableMap<number, HTMLDivElement[]>) | undefined;
- savedAnnotationsCreator: () => ObservableMap<number, HTMLDivElement[]> = () => this._textAnnotationCreator?.() || this._savedAnnotations;
+ _textAnnotationCreator: (() => ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean})[]>) | undefined;
+ savedAnnotationsCreator: () => ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean})[]> = () => this._textAnnotationCreator?.() || this._savedAnnotations;
@action
iframeMove = (e: PointerEvent) => {
@@ -399,7 +397,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
.transformPoint(e.clientX, e.clientY - NumCast(this.layoutDoc.layout_scrollTop));
if (!this._marqueeref.current?.isEmpty) this._marqueeref.current?.onEnd(theclick[0], theclick[1]);
else {
- if (!(e.target as any)?.tagName?.includes('INPUT')) this.finishMarquee(theclick[0], theclick[1]);
+ if (!(e.target as HTMLElement)?.tagName?.includes('INPUT')) this.finishMarquee(theclick[0], theclick[1]);
this._getAnchor = AnchorMenu.Instance?.GetAnchor;
this.marqueeing = undefined;
}
@@ -430,7 +428,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._setPreviewCursor?.(e.clientX, e.clientY, false, true, this.Document);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
- if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) {
+ const target = e.target as HTMLElement;
+ if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) {
if (e.button !== 2) this.marqueeing = [e.clientX, e.clientY];
e.preventDefault();
}
@@ -470,7 +469,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
.transformPoint(e.clientX, e.clientY - NumCast(this.layoutDoc.layout_scrollTop));
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
const word = getWordAtPoint(e.target, e.clientX, e.clientY);
- if (!word && !(e.target as any)?.className?.includes('rangeslider') && !(e.target as any)?.onclick && !(e.target as any)?.parentNode?.onclick) {
+ const target = e.target as HTMLElement;
+ if (!word && !target?.className?.includes('rangeslider') && !target?.onclick && !target?.parentElement?.onclick) {
this.marqueeing = theclick;
this._marqueeref.current?.onInitiateSelection(this.marqueeing);
this._iframe?.contentDocument?.addEventListener('pointermove', this.iframeMove);
@@ -479,16 +479,16 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
isFirefox = () => 'InstallTrigger' in window; // navigator.userAgent.indexOf("Chrome") !== -1;
- addWebStyleSheet(document: any, styleType: string = 'text/css') {
+ addWebStyleSheet(document: Document | null | undefined, styleType: string = 'text/css') {
if (document) {
const style = document.createElement('style');
style.type = styleType;
const sheets = document.head.appendChild(style);
- return (sheets as any).sheet;
+ return sheets.sheet;
}
return undefined;
}
- addWebStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
+ addWebStyleSheetRule(sheet: CSSStyleSheet | null | undefined, selector: string, css: {[key:string]: string}, selectorPrefix = '.') {
const propText =
typeof css === 'string'
? css
@@ -498,7 +498,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
}
- _iframetimeout: any = undefined;
+ _iframetimeout: NodeJS.Timeout|undefined = undefined;
@observable _warning = 0;
@action
iframeLoaded = () => {
@@ -520,7 +520,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (requrlraw !== this._url.toString()) {
if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
const matches = requrlraw.match(/[^a-zA-z]q=[^&]*/g);
- const newsearch = matches?.lastElement()!;
+ const newsearch = matches?.lastElement() || "";
if (matches) {
requrlraw = requrlraw.substring(0, requrlraw.indexOf(newsearch));
for (let i = 1; i < Array.from(matches)?.length; i++) {
@@ -570,8 +570,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
undoBatch(
action((e: MouseEvent) => {
let eleHref = '';
- for (let ele = e.target as any; ele; ele = ele.parentElement) {
- eleHref = (typeof ele.href === 'string' ? ele.href : ele.href?.baseVal) || ele.parentElement?.href || eleHref;
+ for (let ele = e.target as HTMLElement | Element | null; ele; ele = ele.parentElement) {
+ if (ele instanceof HTMLAnchorElement) {
+ eleHref = (typeof ele.href === 'string' ? ele.href : eleHref) || (ele.parentElement && ("href" in ele.parentElement) ? ele.parentElement.href as string: eleHref);
+ }
}
const origin = this.webField?.origin;
if (eleHref && origin) {
@@ -850,10 +852,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return (
<span
className="webBox-htmlSpan"
- ref={action((r: any) => {
+ ref={action((r: HTMLSpanElement) => {
if (r) {
this._scrollHeight = DivHeight(r);
- this.lighttext = Array.from(r.children).some((c: any) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE);
+ this.lighttext = Array.from(r.children).some((c: Element) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE);
}
})}
contentEditable
@@ -1001,7 +1003,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
_innerCollectionView: CollectionFreeFormView | undefined;
zoomScaling = () => this._innerCollectionView?.zoomScaling() ?? 1;
- setInnerContent = (component: ViewBoxInterface<any>) => {
+ setInnerContent = (component: ViewBoxInterface<FieldViewProps>) => {
this._innerCollectionView = component as CollectionFreeFormView;
};
@@ -1083,7 +1085,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get webpage() {
TraceMobx();
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
- const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as any);
+ const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as "none" | "all" | "visiblePainted" | undefined)
const scale = previewScale * (this._props.NativeDimScaling?.() || 1);
return (
<div
@@ -1154,7 +1156,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter];
opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [ClientUtils.OpaqueBackgroundFilter])];
- childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc)) return 'none';
}
@@ -1168,7 +1170,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
render() {
TraceMobx();
const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
- const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as any);
+ const pointerEvents = this.layoutDoc._lockedPosition ? 'none' : (this._props.pointerEvents?.() as 'none' | 'all' | 'visiblePainted' | undefined);
const scale = previewScale * (this._props.NativeDimScaling?.() || 1);
return (
<div
@@ -1178,7 +1180,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
pointerEvents: this.pointerEvents(), //
position: SnappingManager.IsDragging ? 'absolute' : undefined,
}}>
- <div className="webBox-background" style={{ backgroundColor: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) }} />
+ <div className="webBox-background" style={{ backgroundColor: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string }} />
<div
className="webBox-container"
style={{
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b0c6120d4..39e237986 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,9 +1,8 @@
/* eslint-disable no-use-before-define */
-/* eslint-disable jsx-a11y/no-static-element-interactions */
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
-import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction } from 'mobx';
import { observer } from 'mobx-react';
import { baseKeymap, selectAll } from 'prosemirror-commands';
import { history } from 'prosemirror-history';
@@ -60,7 +59,7 @@ import { LinkInfo } from '../LinkDocPreview';
import { OpenWhere } from '../OpenWhere';
import './FormattedTextBox.scss';
import { findLinkMark, FormattedTextBoxComment } from './FormattedTextBoxComment';
-import { buildKeymap, updateBullets } from './ProsemirrorExampleTransfer';
+import { buildKeymap, KeyMap, updateBullets } from './ProsemirrorExampleTransfer';
import { removeMarkWithAttrs } from './prosemirrorPatches';
import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu';
import { RichTextRules } from './RichTextRules';
@@ -91,12 +90,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
static _bulletStyleSheet = addStyleSheet();
static _userStyleSheet = addStyleSheet();
static _hadSelection: boolean = false;
+ private _oldWheel: HTMLDivElement | null = null;
private _selectionHTML: string | undefined;
private _sidebarRef = React.createRef<SidebarAnnos>();
private _sidebarTagRef = React.createRef<React.Component>();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _scrollRef: HTMLDivElement | null = null;
- private _editorView: Opt<EditorView>;
+ private _editorView: Opt<EditorView & { TextView?: FormattedTextBox|undefined}>;
public _applyingChange: string = '';
private _inDrop = false;
private _finishingLink = false;
@@ -108,79 +108,40 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
private _recordingStart: number = 0;
private _ignoreScroll = false;
private _focusSpeed: Opt<number>;
- private _keymap: any = undefined;
+ private _keymap: KeyMap | undefined = undefined;
private _rules: RichTextRules | undefined;
private _forceUncollapse = true; // if the cursor doesn't move between clicks, then the selection will disappear for some reason. This flags the 2nd click as happening on a selection which allows bullet points to toggle
private _break = true;
public ProseRef?: HTMLDivElement;
- public get EditorView() {
- return this._editorView;
- }
- public get SidebarKey() {
- return this.fieldKey + '_sidebar';
- }
- @computed get allSidebarDocs() {
- return DocListCast(this.dataDoc[this.SidebarKey]);
- }
-
- @computed get noSidebar() {
- return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar;
- }
- @computed get layout_sidebarWidthPercent() {
- return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
- }
- @computed get sidebarColor() {
- return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4'));
- }
- @computed get layout_autoHeight() {
- return (this._props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this._props.ignoreAutoHeight;
- }
- @computed get textHeight() {
- return NumCast(this.dataDoc[this.fieldKey + '_height']);
- }
- @computed get scrollHeight() {
- return NumCast(this.dataDoc[this.fieldKey + '_scrollHeight']);
- }
- @computed get sidebarHeight() {
- return !this.sidebarWidth() ? 0 : NumCast(this.dataDoc[this.SidebarKey + '_height']);
- }
- @computed get titleHeight() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) || 0;
- }
- @computed get layout_autoHeightMargins() {
- return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins);
- }
- @computed get _recordingDictation() {
- return this.dataDoc?.mediaState === mediaState.Recording;
- }
- set _recordingDictation(value) {
- !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined);
- }
+ set _recordingDictation(value) { !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined); }
+ @computed get _recordingDictation() { return this.dataDoc?.mediaState === mediaState.Recording; } // prettier-ignore
+ @computed get allSidebarDocs() { return DocListCast(this.dataDoc[this.SidebarKey]); } // prettier-ignore
+ @computed get noSidebar() { return this.DocumentView?.()._props.hideDecorationTitle || this._props.noSidebar || this.Document._layout_noSidebar; } // prettier-ignore
+ @computed get layout_sidebarWidthPercent() { return this._showSidebar ? '20%' : StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); } // prettier-ignore
+ @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.fieldKey + '_backgroundColor'], '#e4e4e4')); } // prettier-ignore
+ @computed get layout_autoHeight() { return (this._props.forceAutoHeight || this.layoutDoc._layout_autoHeight) && !this._props.ignoreAutoHeight; } // prettier-ignore
+ @computed get textHeight() { return NumCast(this.dataDoc[this.fieldKey + '_height']); } // prettier-ignore
+ @computed get scrollHeight() { return NumCast(this.dataDoc[this.fieldKey + '_scrollHeight']); } // prettier-ignore
+ @computed get sidebarHeight() { return !this.sidebarWidth() ? 0 : NumCast(this.dataDoc[this.SidebarKey + '_height']); } // prettier-ignore
+ @computed get titleHeight() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) as number || 0; } // prettier-ignore
+ @computed get layout_autoHeightMargins() { return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins); } // prettier-ignore
@computed get config() {
this._keymap = buildKeymap(schema, this._props);
this._rules = new RichTextRules(this.Document, this);
- return {
- schema,
- plugins: [
- inputRules(this._rules.inpRules),
- this.richTextMenuPlugin(),
- history(),
- keymap(this._keymap),
- keymap(baseKeymap),
- new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }),
- new Plugin({
- view(/* editorView */) {
- return new FormattedTextBoxComment();
- },
- }),
- ],
- };
+ return { schema,
+ plugins: [
+ inputRules(this._rules.inpRules),
+ this.richTextMenuPlugin(),
+ history(),
+ keymap(this._keymap),
+ keymap(baseKeymap),
+ new Plugin({ props: { attributes: { class: 'ProseMirror-example-setup-style' } } }),
+ new Plugin({ view: () => new FormattedTextBoxComment() }),
+ ] };
}
- // State for GPT
- @observable
- private gptRes: string = '';
-
+ public get EditorView() { return this._editorView; }
+ public get SidebarKey() { return this.fieldKey + '_sidebar'; }
public makeAIFlashcards: () => void = unimplementedFunction;
public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
@@ -205,9 +166,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (state && a1 && a2 && this._editorView) {
this.removeDocument(a1);
this.removeDocument(a2);
- let allFoundLinkAnchors: any[] = [];
- state.doc.nodesBetween(0, state.doc.nodeSize - 2, (node: any /* , pos: number, parent: any */) => {
- const foundLinkAnchors = findLinkMark(node.marks)?.attrs.allAnchors.filter((a: any) => a.anchorId === a1[Id] || a.anchorId === a2[Id]) || [];
+ let allFoundLinkAnchors: { href: string; title: string; anchorId: string }[] = [];
+ state.doc.nodesBetween(0, state.doc.nodeSize - 2, (node: Node /* , pos: number, parent: any */) => {
+ const foundLinkAnchors = findLinkMark(node.marks)?.attrs.allAnchors.filter((a: { href: string; title: string; anchorId: string }) => a.anchorId === a1[Id] || a.anchorId === a2[Id]) || [];
allFoundLinkAnchors = foundLinkAnchors.length ? foundLinkAnchors : allFoundLinkAnchors;
return true;
});
@@ -255,7 +216,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const target = this._sidebarRef.current?.anchorMenuClick(anchor);
if (target) {
anchor.followLinkAudio = true;
- let stopFunc: any;
+ let stopFunc: () => void = emptyFunction;
const targetData = target[DocData];
targetData.mediaState = mediaState.Recording;
DictationManager.recordAudioAnnotation(targetData, Doc.LayoutFieldKey(target), stop => { stopFunc = stop }); // prettier-ignore
@@ -273,10 +234,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
});
};
- AnchorMenu.Instance.Highlight = undoable((color: string) => {
- this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight');
- return undefined;
- }, 'highlght text');
+ AnchorMenu.Instance.Highlight = undoable((color: string) => this._editorView?.state && RichTextMenu.Instance?.setFontField(color, 'fontHighlight'), 'highlght text');
AnchorMenu.Instance.onMakeAnchor = () => this.getAnchor(true);
AnchorMenu.Instance.StartCropDrag = unimplementedFunction;
/**
@@ -292,7 +250,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.DocumentView?.()!, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
+ const docView = this.DocumentView?.();
+ docView && DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, () => this.getAnchor(true), targetCreator), e.pageX, e.pageY);
});
AnchorMenu.Instance.setSelectedText(window.getSelection()?.toString() ?? '');
@@ -345,7 +304,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if ([AclEdit, AclAdmin, AclSelfEdit, AclAugment].includes(effectiveAcl)) {
const accumTags = [] as string[];
- state.tr.doc.nodesBetween(0, state.doc.content.size, (node: any /* , pos: number, parent: any */) => {
+ state.tr.doc.nodesBetween(0, state.doc.content.size, (node: Node /* , pos: number, parent: any */) => {
if (node.type === schema.nodes.dashField && node.attrs.fieldKey.startsWith('#')) {
accumTags.push(node.attrs.fieldKey);
}
@@ -410,8 +369,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
});
if (this._editorView && linkTime) {
const { state } = this._editorView;
- const { path } = state.selection.$from as any;
- if (linkAnchor && path[path.length - 3].type !== state.schema.nodes.code_block) {
+ const node = state.selection.$from.node();
+ if (linkAnchor && node.type !== state.schema.nodes.code_block) {
const time = linkTime + Date.now() / 1000 - this._recordingStart / 1000;
this._break = false;
const { from } = state.selection;
@@ -476,7 +435,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
* function of a freeform view that is driven by the text box's text. The include directive will copy the code of the published
* document into the code being evaluated.
*/
- hyperlinkTerm = (trIn: any, target: Doc, newAutoLinks: Set<Doc>) => {
+ hyperlinkTerm = (trIn: Transaction, target: Doc, newAutoLinks: Set<Doc>) => {
let tr = trIn;
const editorView = this._editorView;
if (editorView && !Doc.AreProtosEqual(target, this.Document)) {
@@ -493,7 +452,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
) {
const splitter = editorView.state.schema.marks.splitter.create({ id: Utils.GenerateGuid() });
tr = tr.addMark(sel.from, sel.to, splitter);
- tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number /* , parent: any */) => {
+ tr.doc.nodesBetween(sel.from, sel.to, (node: Node, pos: number /* , parent: any */) => {
if (node.firstChild === null && !node.marks.find((m: Mark) => m.type.name === schema.marks.noAutoLinkAnchor.name) && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
alink =
alink ??
@@ -646,15 +605,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
if (node.isBlock) {
// tslint:disable-next-line: prefer-for-of
- for (let i = 0; i < (context.content as any).content.length; i++) {
- const result = this.getNodeEndpoints((context.content as any).content[i], node);
+ for (let i = 0; i < context.content.childCount; i++) {
+ const result = this.getNodeEndpoints(context.content.child(i), node);
if (result) {
return {
from: result.from + offset + (context.type.name === 'doc' ? 0 : 1),
to: result.to + offset + (context.type.name === 'doc' ? 0 : 1),
};
}
- offset += (context.content as any).content[i].nodeSize;
+ offset += context.content.child(i).nodeSize;
}
}
return null;
@@ -818,8 +777,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
specificContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
- let target = e.target as any; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
- while (target && !target.dataset?.targethrefs) target = target.parentElement;
+ let target:Element|HTMLElement|null = e.target as HTMLElement; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
+ while (target && (!(target instanceof HTMLElement) || !target.dataset?.targethrefs)) target = target.parentElement;
const editor = this._editorView;
if (editor && target && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) {
const hrefs = (target.dataset?.targethrefs as string)
@@ -1107,7 +1066,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
});
const href = targetHref ?? Doc.localServerPath(anchor);
if (anchor !== anchorDoc && addAsAnnotation) this.addDocument(anchor);
- tr.doc.nodesBetween(selection.from, selection.to, (node: any, pos: number /* , parent: any */) => {
+ tr.doc.nodesBetween(selection.from, selection.to, (node: Node, pos: number /* , parent: any */) => {
if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) {
const allAnchors = [{ href, title, anchorId: anchor[Id] }];
allAnchors.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.linkAnchor.name)?.attrs.allAnchors ?? []));
@@ -1184,17 +1143,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
this._didScroll = false; // assume we don't need to scroll. if we do, this will get set to true in handleScrollToSelextion when we dispatch the setSelection below
if (this._editorView && textAnchorId) {
- const editor = this._editorView;
- const ret = findAnchorFrag(editor.state.doc.content, editor);
+ const { state } = this._editorView;
+ const ret = findAnchorFrag(state.doc.content, this._editorView);
- const content = (ret.frag as any)?.content;
- if ((ret.frag.size || (content?.length && content[0].type === this._editorView.state.schema.nodes.dashDoc) || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
+ const firstChild = ret.frag.childCount ? ret.frag.child(0) : undefined;
+ if (ret.start >= 0 && (ret.frag.size || (firstChild && [state.schema.nodes.dashDoc, state.schema.nodes.audioTag].includes(firstChild.type)))) {
!options.instant && (this._focusSpeed = focusSpeed);
- let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
+ let selection = TextSelection.near(state.doc.resolve(ret.start)); // default to near the start
if (ret.frag.firstChild) {
- selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
+ selection = TextSelection.between(state.doc.resolve(ret.start), state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
}
- editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
+ this._editorView.dispatch(state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
const escAnchorId = textAnchorId[0] >= '0' && textAnchorId[0] <= '9' ? `\\3${textAnchorId[0]} ${textAnchorId.substr(1)}` : textAnchorId;
addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' });
setTimeout(() => {
@@ -1405,41 +1364,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let el = elIn;
while (el && el !== document.body) {
if (getComputedStyle(el).display === 'none') return false;
- el = el.parentNode as any;
+ el = el.parentElement;
}
return true;
}
richTextMenuPlugin() {
- const self = this;
- return new Plugin({
- view(newView) {
- runInAction(() => {
- self._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView);
- });
+ return new Plugin({view : action((newView: EditorView) => {
+ this._props.rootSelected?.() && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView);
return new RichTextMenuPlugin({ editorProps: this._props });
- },
- });
- }
+ })});
+ };
_didScroll = false;
_scrollStopper: undefined | (() => void);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
setupEditor(config: any, fieldKey: string) {
const curText = Cast(this.dataDoc[this.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.fieldKey]);
const rtfField = Cast((!curText && this.layoutDoc[this.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
- const self = this;
this._editorView?.destroy();
this._editorView = new EditorView(this.ProseRef, {
state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config),
handleScrollToSelection: editorView => {
const docPos = editorView.coordsAtPos(editorView.state.selection.to);
- const viewRect = self._ref.current!.getBoundingClientRect();
- const scrollRef = self._scrollRef;
+ const viewRect = this._ref.current!.getBoundingClientRect();
+ const scrollRef = this._scrollRef;
const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined;
const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined;
if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) {
const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE);
- const scrollPos = scrollRef.scrollTop + shift * self.ScreenToLocalBoxXf().Scale;
+ const scrollPos = scrollRef.scrollTop + shift * this.ScreenToLocalBoxXf().Scale;
if (this._focusSpeed !== undefined) {
setTimeout(() => {
scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed || 0, scrollRef, scrollPos, 'ease', this._scrollStopper));
@@ -1470,7 +1424,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
});
}
}
- (this._editorView as any).TextView = this;
+ this._editorView.TextView = this;
}
const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, Doc.SelectOnLoad) && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()));
@@ -1548,18 +1502,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
onPointerDown = (e: React.PointerEvent): void => {
- if ((e.nativeEvent as any).handledByInnerReactInstance) {
- return; // e.stopPropagation();
- }
- (e.nativeEvent as any).handledByInnerReactInstance = true;
-
if (this.Document.forceActive) e.stopPropagation();
this.tryUpdateScrollHeight(); // if a doc a fitWidth doc is being viewed in different embedContainer (eg freeform & lightbox), then it will have conflicting heights. so when the doc is clicked on, we want to make sure it has the appropriate height for the selected view.
- if ((e.target as any).tagName === 'AUDIOTAG') {
+ const target = e.target as HTMLElement;
+ if (target.tagName === 'AUDIOTAG') {
e.preventDefault();
e.stopPropagation();
- const timecode = Number((e.target as any)?.dataset?.timecode);
- DocServer.GetRefField((e.target as any)?.dataset?.audioid || 0).then(anchor => {
+ const timecode = Number(target.dataset?.timecode);
+ DocServer.GetRefField(target.dataset?.audioid || "").then(anchor => {
if (anchor instanceof Doc) {
// const timecode = NumCast(anchor.timecodeToShow, 0);
const audiodoc = anchor.annotationOn as Doc;
@@ -1583,7 +1533,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
// stop propagation if not in sidebar, otherwise nested boxes will lose focus to outer boxes.
e.stopPropagation(); // if the text box's content is active, then it consumes all down events
document.addEventListener('pointerup', this.onSelectEnd);
- (this.ProseRef?.children?.[0] as any).focus();
+ (this.ProseRef?.children?.[0] as HTMLElement).focus();
}
}
if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
@@ -1599,10 +1549,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const state = this.EditorView?.state;
if (state && this.ProseRef?.children[0].className.includes('-focused') && this._props.isContentActive() && !e.button) {
if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
- let clickTarget = e.target as any; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
- for (let { target } = e as any; target && !target.dataset?.targethrefs; target = target.parentElement);
- while (clickTarget && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement;
- FormattedTextBoxComment.update(this, this.EditorView!, undefined, clickTarget?.dataset?.targethrefs, clickTarget?.dataset.linkdoc, clickTarget?.dataset.nopreview === 'true');
+ let clickTarget:HTMLElement|Element|null = e.target as HTMLElement; // hrefs are stored on the dataset of the <a> node that wraps the hyerlink <span>
+ for (let target:HTMLElement|Element|null = clickTarget as HTMLElement; target instanceof HTMLElement && !target.dataset?.targethrefs; target = target.parentElement);
+ while (clickTarget instanceof HTMLElement && !clickTarget.dataset?.targethrefs) clickTarget = clickTarget.parentElement;
+ const dataset = clickTarget instanceof HTMLElement ? clickTarget?.dataset : undefined;
+ FormattedTextBoxComment.update(this, this.EditorView!, undefined, dataset?.targethrefs, dataset?.linkdoc, dataset?.nopreview === 'true');
}
};
@action
@@ -1626,27 +1577,24 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
setFocus = (ipos?: number) => {
const pos = ipos ?? (this._editorView?.state.selection.$from.pos || 1);
setTimeout(() => this._editorView?.dispatch(this._editorView.state.tr.setSelection(TextSelection.near(this._editorView.state.doc.resolve(pos)))), 100);
- setTimeout(() => (this.ProseRef?.children?.[0] as any).focus(), 200);
+ setTimeout(() => (this.ProseRef?.children?.[0] as HTMLElement).focus(), 200);
};
@action
onFocused = (e: React.FocusEvent): void => {
// applyDevTools.applyDevTools(this._editorView);
- this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this._props, this.layoutDoc);
e.stopPropagation();
};
onClick = (e: React.MouseEvent): void => {
if (!this._props.isContentActive()) return;
- if ((e.nativeEvent as any).handledByInnerReactInstance) {
- e.stopPropagation();
- return;
- }
- if (!this._forceUncollapse || (this._editorView!.root as any).getSelection().isCollapsed) {
+ const editorView = this._editorView;
+ const editorRoot = editorView?.root instanceof Document ?editorView.root : undefined;
+ if (editorView && (!this._forceUncollapse || editorRoot?.getSelection()?.isCollapsed)) {
// this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text.
- const pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
- const node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text)
- if (pcords && node?.type === this._editorView!.state.schema.nodes.dashComment) {
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pcords.pos + 2)));
+ const pcords = editorView.posAtCoords({ left: e.clientX, top: e.clientY });
+ const node = pcords && editorView.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text)
+ if (pcords && node?.type === editorView.state.schema.nodes.dashComment) {
+ this._editorView!.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, pcords.pos + 2)));
e.preventDefault();
}
if (!node && this.ProseRef) {
@@ -1654,19 +1602,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
const boundsRect = lastNode?.getBoundingClientRect();
if (e.clientX > boundsRect.left && e.clientX < boundsRect.right && e.clientY > boundsRect.bottom) {
// if we clicked below the last prosemirror div, then set the selection to be the end of the document
- this._editorView?.focus();
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, this._editorView!.state.doc.content.size)));
+ editorView.focus();
+ editorView.dispatch(editorView.state.tr.setSelection(TextSelection.create(editorView.state.doc, editorView.state.doc.content.size)));
}
- } else if (node && [this._editorView!.state.schema.nodes.ordered_list, this._editorView!.state.schema.nodes.listItem].includes(node.type) && node !== (this._editorView!.state.selection as NodeSelection)?.node && pcords) {
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(NodeSelection.create(this._editorView!.state.doc, pcords.pos)));
+ } else if (node && [editorView.state.schema.nodes.ordered_list, editorView.state.schema.nodes.listItem].includes(node.type) && node !== (editorView.state.selection as NodeSelection)?.node && pcords) {
+ editorView.dispatch(editorView.state.tr.setSelection(NodeSelection.create(editorView.state.doc, pcords.pos)));
}
}
- if (this._props.rootSelected?.()) {
+ if (editorView && this._props.rootSelected?.()) {
// if text box is selected, then it consumes all click events
- (e.nativeEvent as any).handledByInnerReactInstance = true;
- this.hitBulletTargets(e.clientX, e.clientY, !this._editorView?.state.selection.empty || this._forceUncollapse, false, e.shiftKey);
+ e.stopPropagation();
+ this.hitBulletTargets(e.clientX, e.clientY, !editorView.state.selection.empty || this._forceUncollapse, false, e.shiftKey);
}
- this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed;
+ this._forceUncollapse = !editorRoot?.getSelection()?.isCollapsed;
};
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean, selectOrderedList: boolean = false) {
@@ -1682,9 +1630,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
let $olistPos = this._editorView?.state.doc.resolve(olistPos);
let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
if (olistNode?.type === this._editorView?.state.schema.nodes.list_item) {
- if ($olistPos && ($olistPos as any).path.length > 3) {
+ if ($olistPos && $olistPos.depth) {
olistNode = $olistPos.parent;
- $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]);
+ $olistPos = this._editorView?.state.doc.resolve($olistPos.start($olistPos.depth - 1));
}
}
const maxSize = this._editorView?.state.doc.content.size ?? 0;
@@ -1715,7 +1663,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
@action
- onBlur = (e: any) => {
+ onBlur = (e: React.FocusEvent) => {
if (this.ProseRef?.children[0] !== e.nativeEvent.target) return;
if (!(this.EditorView?.state.selection instanceof NodeSelection) || this.EditorView.state.selection.node.type !== this.EditorView.state.schema.nodes.footnote) {
const stordMarks = this._editorView?.state.storedMarks?.slice();
@@ -1780,7 +1728,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
switch (e.key) {
case 'Escape':
this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
- (document.activeElement as any).blur?.();
+ (document.activeElement as HTMLElement).blur?.();
DocumentView.DeselectAll();
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, undefined);
return;
@@ -1886,7 +1834,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
TraceMobx();
const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
const color = !annotated ? Colors.WHITE : Colors.BLACK;
- const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : ''));
+ const backgroundColor = !annotated ? (this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK) : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.WidgetColor + (annotated ? ':annotated' : '')) as string;
return !annotated && (!this._props.isContentActive() || SnappingManager.IsDragging || Doc.ActiveTool !== InkTool.None) ? null : (
<div
@@ -1903,6 +1851,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
@computed get sidebarCollection() {
const renderComponent = (tag: string) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const ComponentTag: any = tag === CollectionViewType.Tree ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView;
return ComponentTag === CollectionStackingView ? (
<SidebarAnnos
@@ -2029,19 +1978,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
e.stopPropagation();
}
};
- _oldWheel: any;
- @computed get fontColor() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor);
- }
- @computed get fontSize() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize);
- }
- @computed get fontFamily() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily);
- }
- @computed get fontWeight() {
- return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontWeight);
- }
+ @computed get fontColor() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontColor) as string; } // prettier-ignore
+ @computed get fontSize() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontSize) as string; } // prettier-ignore
+ @computed get fontFamily() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontFamily) as string; } // prettier-ignore
+ @computed get fontWeight() { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FontWeight) as string; }// prettier-ignore
render() {
TraceMobx();
const scale = this._props.NativeDimScaling?.() || 1;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 01c46edeb..37a96fc37 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -1,4 +1,4 @@
-import { Mark, ResolvedPos } from 'prosemirror-model';
+import { Mark, Node, ResolvedPos } from 'prosemirror-model';
import { EditorState } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import { ClientUtils } from '../../../../ClientUtils';
@@ -73,7 +73,7 @@ export class FormattedTextBoxComment {
FormattedTextBoxComment.textBox = undefined;
FormattedTextBoxComment.tooltip.style.display = 'none';
}
- public static saveMarkRegion(textBox: any, start: number, end: number, mark: Mark) {
+ public static saveMarkRegion(textBox: FormattedTextBox, start: number, end: number, mark: Mark) {
FormattedTextBoxComment.textBox = textBox;
FormattedTextBoxComment.startUserMarkRegion = start;
FormattedTextBoxComment.endUserMarkRegion = end;
@@ -87,7 +87,7 @@ export class FormattedTextBoxComment {
const start = view.coordsAtPos(state.selection.from - nbef);
const end = view.coordsAtPos(state.selection.from - nbef);
// The box in which the tooltip is positioned, to use as base
- const box = (document.getElementsByClassName('mainView-container') as any)[0].getBoundingClientRect();
+ const box = document.getElementsByClassName('mainView-container')[0].getBoundingClientRect();
// Find a center-ish x position from the selection endpoints (when crossing lines, end may be more to the left)
const left = Math.max((start.left + end.left) / 2, start.left + 3);
FormattedTextBoxComment.tooltip.style.left = left - box.left + 'px';
@@ -118,8 +118,8 @@ export class FormattedTextBoxComment {
const nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
const naft = findEndOfMark(state.selection.$from, view, findOtherUserMark);
const noselection = state.selection.$from === state.selection.$to;
- let child: any = null;
- state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any /* , pos: number, parent: any */) => {
+ let child: Node | undefined;
+ state.doc.nodesBetween(state.selection.from, state.selection.to, (node: Node /* , pos: number, parent: any */) => {
!child && node.marks.length && (child = node);
});
const mark = child && findOtherUserMark(child.marks);
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index a612f3c65..247b7c097 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react';
import { lift, wrapIn } from 'prosemirror-commands';
import { Mark, MarkType } from 'prosemirror-model';
import { wrapInList } from 'prosemirror-schema-list';
-import { EditorState, NodeSelection, TextSelection } from 'prosemirror-state';
+import { EditorState, NodeSelection, TextSelection, Transaction } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
@@ -17,7 +17,7 @@ import { ObservableReactComponent } from '../../ObservableReactComponent';
import { DocumentView } from '../DocumentView';
import { EquationBox } from '../EquationBox';
import { FieldViewProps } from '../FieldView';
-import { FormattedTextBox } from './FormattedTextBox';
+import { FormattedTextBox, FormattedTextBoxProps } from './FormattedTextBox';
import { updateBullets } from './ProsemirrorExampleTransfer';
import './RichTextMenu.scss';
import { schema } from './schema_rts';
@@ -35,8 +35,8 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
private _linkToRef = React.createRef<HTMLInputElement>();
layoutDoc: Doc | undefined;
- @observable public view?: EditorView = undefined;
- public editorProps: FieldViewProps | undefined;
+ @observable public view?: EditorView & { TextView ?: FormattedTextBox } = undefined;
+ public editorProps: FieldViewProps | AntimodeMenuProps |undefined;
public _brushMap: Map<string, Set<Mark>> = new Map();
@@ -114,17 +114,17 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
_disposer: IReactionDisposer | undefined;
componentDidMount() {
- this._disposer = reaction(
- () => DocumentView.Selected().slice(),
- () => this.updateMenu(undefined, undefined, undefined, undefined)
- );
+ // this._disposer = reaction(
+ // () => DocumentView.Selected().slice(),
+ // () => this.updateMenu(undefined, undefined, undefined, undefined)
+ // );
}
componentWillUnmount() {
this._disposer?.();
}
@action
- public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: any, layoutDoc: Doc | undefined) {
+ public updateMenu(view: EditorView | undefined, lastState: EditorState | undefined, props: FormattedTextBoxProps|AntimodeMenuProps|undefined, layoutDoc: Doc | undefined) {
if (this._linkToRef.current?.getBoundingClientRect().width) {
return;
}
@@ -158,7 +158,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle));
}
- setMark = (mark: Mark, state: EditorState, dispatch: any, dontToggle: boolean = false) => {
+ setMark = (mark: Mark, state: EditorState, dispatch: (tr:Transaction) => void, dontToggle: boolean = false) => {
if (mark) {
const newPos = state.selection.$anchor.node()?.type === schema.nodes.ordered_list ? state.selection.from : state.selection.from;
const node = (state.selection as NodeSelection).node ?? (newPos >= 0 ? state.doc.nodeAt(newPos) : undefined);
@@ -177,17 +177,18 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
toggleMark(mark.type, mark.attrs)(state, dispatch);
}
}
- this.updateMenu(this.view, undefined, undefined, this.layoutDoc);
+ // this.updateMenu(this.view, undefined, undefined, this.layoutDoc);
}
};
// finds font sizes and families in selection
- getActiveAlignment() {
+ getActiveAlignment = () => {
if (this.view && this.TextView?._props.rootSelected?.()) {
- const { path } = this.view.state.selection.$from as any;
- 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) {
- return path[i].attrs.align || 'left';
+ const from = this.view.state.selection.$from;
+ for (let i = from.depth; i >= 0; i--) {
+ const node = from.node(i);
+ if (node.type === this.view.state.schema.nodes.paragraph || node.type === this.view.state.schema.nodes.heading) {
+ return node.attrs.align || 'left';
}
}
}
@@ -195,7 +196,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
// finds font sizes and families in selection
- getActiveListStyle() {
+ getActiveListStyle = () => {
const state = this.view?.state;
if (state) {
const pos = state.selection.$anchor;
@@ -321,7 +322,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
if (this.view) {
const mark = this.view.state.schema.mark(this.view.state.schema.marks.noAutoLinkAnchor);
this.setMark(mark, this.view.state, this.view.dispatch, false);
- this.TextView.autoLink();
+ this.TextView?.autoLink();
this.view.focus();
}
};
@@ -350,7 +351,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
};
setFontField = (value: string, fontField: 'fontSize' | 'fontFamily' | 'fontColor' | 'fontHighlight') => {
- if (this.view) {
+ if (this.TextView && this.view) {
const { text, paragraph } = this.view.state.schema.nodes;
const selNode = this.view.state.selection.$anchor.node();
if (this.view.state.selection.from === 1 && this.view.state.selection.empty && [undefined, text, paragraph].includes(selNode?.type)) {
@@ -360,11 +361,11 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const attrs: { [key: string]: string } = {};
attrs[fontField] = value;
const fmark = this.view?.state.schema.marks['pF' + fontField.substring(1)].create(attrs);
- this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
+ this.setMark(fmark, this.view.state, (tx: Transaction) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
this.view.focus();
} else {
Doc.UserDoc()[fontField] = value;
- this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
+ // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
}
};
@@ -383,17 +384,17 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
marks && tx2.setStoredMarks([...marks]);
this.view.dispatch(tx2);
} else
- !wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => {
+ !wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: Transaction) => {
const tx3 = updateBullets(tx2, schema, newMapStyle, this.view!.state.selection.from - 1, this.view!.state.selection.to + 1);
marks && tx3.ensureMarks([...marks]);
marks && tx3.setStoredMarks([...marks]);
this.view!.dispatch(tx3);
});
this.view.focus();
- this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
+ // this.updateMenu(this.view, undefined, this.props, this.layoutDoc);
};
- insertSummarizer(state: EditorState, dispatch: any) {
+ insertSummarizer(state: EditorState, dispatch: (tr:Transaction) => void) {
if (state.selection.empty) return false;
const mark = state.schema.marks.summarize.create();
const { tr } = state;
@@ -407,7 +408,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
vcenterToggle = () => {
this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered);
};
- align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => {
+ align = (view: EditorView, dispatch: (tr:Transaction) => void, alignment: 'left' | 'right' | 'center') => {
if (this.TextView?._props.rootSelected?.()) {
let { tr } = view.state;
view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos) => {
@@ -423,7 +424,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
};
- paragraphSetup(state: EditorState, dispatch: any, field: 'inset' | 'indent', value?: 0 | 10 | -10) {
+ paragraphSetup(state: EditorState, dispatch: (tr:Transaction) => void, field: 'inset' | 'indent', value?: 0 | 10 | -10) {
let { tr } = state;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => {
if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
@@ -439,9 +440,9 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return true;
}
- insertBlockquote(state: EditorState, dispatch: any) {
- const { path } = state.selection.$from as any;
- if (path.length > 6 && path[path.length - 6].type === schema.nodes.blockquote) {
+ insertBlockquote(state: EditorState, dispatch: (tr:Transaction) => void) {
+ const node = state.selection.$from.depth ? state.selection.$from.node(state.selection.$from.depth-1): undefined;
+ if (node?.type === schema.nodes.blockquote) {
lift(state, dispatch);
} else {
wrapIn(schema.nodes.blockquote)(state, dispatch);
@@ -449,7 +450,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return true;
}
- insertHorizontalRule(state: EditorState, dispatch: any) {
+ insertHorizontalRule(state: EditorState, dispatch: (tr:Transaction) => void) {
dispatch(state.tr.replaceSelectionWith(state.schema.nodes.horizontal_rule.create()).scrollIntoView());
return true;
}
@@ -497,7 +498,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
get TextView() {
- return (this.view as any)?.TextView as FormattedTextBox;
+ return this.view?.TextView;
}
get TextViewFieldKey() {
return this.TextView?._props.fieldKey;
@@ -512,11 +513,9 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
createLinkButton() {
- const self = this;
-
- function onLinkChange(e: React.ChangeEvent<HTMLInputElement>) {
- self.TextView?.endUndoTypingBatch();
- UndoManager.RunInBatch(() => self.setCurrentLink(e.target.value), 'link change');
+ const onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ this.TextView?.endUndoTypingBatch();
+ UndoManager.RunInBatch(() => this.setCurrentLink(e.target.value), 'link change');
}
const link = this.currentLink ? this.currentLink : '';
@@ -524,7 +523,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
const button = (
<Tooltip title={<div className="dash-tooltip">set hyperlink</div>} placement="bottom">
{
- // eslint-disable-next-line jsx-a11y/control-has-associated-label
<button type="button" className="antimodeMenu-button color-preview-button">
<FontAwesomeIcon icon="link" size="lg" />
</button>
@@ -589,7 +587,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
// TODO: should check for valid URL
@undoBatch
makeLinkToURL = (target: string) => {
- ((this.view as any)?.TextView as FormattedTextBox).makeLinkAnchor(undefined, 'onRadd:rightight', target, target);
+ this.TextView?.makeLinkAnchor(undefined, 'onRadd:rightight', target, target);
};
@undoBatch
@@ -597,12 +595,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
if (this.view) {
const linkAnchor = this.view.state.selection.$from.nodeAfter?.marks.find(m => m.type === this.view!.state.schema.marks.linkAnchor);
if (linkAnchor) {
- const allAnchors = linkAnchor.attrs.allAnchors.slice();
- this.TextView.RemoveAnchorFromSelection(allAnchors);
+ const allAnchors = (linkAnchor.attrs.allAnchors as { href: string; title: string; linkId: string; targetId: string; }[]).slice();
+ this.TextView?.RemoveAnchorFromSelection(allAnchors);
// bcz: Argh ... this will remove the link from the document even it's anchored somewhere else in the text which happens if only part of the anchor text was selected.
allAnchors
- .filter((aref: any) => aref?.href.indexOf(Doc.localServerPath()) === 0)
- .forEach((aref: any) => {
+ .filter(aref => aref?.href.indexOf(Doc.localServerPath()) === 0)
+ .forEach(aref => {
const anchorId = aref.href.replace(Doc.localServerPath(), '').split('?')[0];
anchorId && DocServer.GetRefField(anchorId).then(linkDoc => Doc.DeleteLink?.(linkDoc as Doc));
});
@@ -629,7 +627,7 @@ export class ButtonDropdown extends ObservableReactComponent<ButtonDropdownProps
@observable private showDropdown: boolean = false;
private ref: HTMLDivElement | null = null;
- constructor(props: any) {
+ constructor(props: ButtonDropdownProps) {
super(props);
makeObservable(this);
}
@@ -683,7 +681,6 @@ export class ButtonDropdown extends ObservableReactComponent<ButtonDropdownProps
<>
{this._props.button}
{
- // eslint-disable-next-line jsx-a11y/control-has-associated-label
<button type="button" className="dropdown-button antimodeMenu-button" key="antimodebutton" onPointerDown={this.onDropdownClick}>
<FontAwesomeIcon icon="caret-down" size="sm" />
</button>
@@ -697,12 +694,12 @@ export class ButtonDropdown extends ObservableReactComponent<ButtonDropdownProps
}
interface RichTextMenuPluginProps {
- editorProps: any;
+ editorProps: FormattedTextBoxProps;
}
export class RichTextMenuPlugin extends React.Component<RichTextMenuPluginProps> {
// eslint-disable-next-line react/no-unused-class-component-methods
- update(view: EditorView, lastState: EditorState | undefined) {
- RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, (view as any).TextView?.layoutDoc);
+ update(view: EditorView & {TextView ?: FormattedTextBox}, lastState: EditorState | undefined) {
+ RichTextMenu.Instance?.updateMenu(view, lastState, this.props.editorProps, view.TextView?.layoutDoc);
}
render() {
return null;
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 2f6824466..03585a8b7 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -25,7 +25,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
private _commentRef = React.createRef<HTMLDivElement>();
private _cropRef = React.createRef<HTMLDivElement>();
- constructor(props: any) {
+ constructor(props: AntimodeMenuProps) {
super(props);
makeObservable(this);
AnchorMenu.Instance = this;
@@ -50,7 +50,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public OnAudio: (e: PointerEvent) => void = unimplementedFunction;
public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction;
- public Highlight: (color: string) => Opt<Doc> = (/* color: string */) => undefined;
+ public Highlight: (color: string) => void = emptyFunction;
public GetAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = emptyFunction;
public Delete: () => void = unimplementedFunction;
public PinToPres: () => void = unimplementedFunction;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fa5e5cedb..1279563ef 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/no-static-element-interactions */
-/* eslint-disable jsx-a11y/click-events-have-key-events */
import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as Pdfjs from 'pdfjs-dist';
@@ -64,13 +62,13 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
}
@observable _pageSizes: { width: number; height: number }[] = [];
- @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @observable _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean})[]>();
@observable _textSelecting = true;
@observable _showWaiting = true;
@observable Index: number = -1;
- private _pdfViewer: any;
- private _styleRule: any; // stylesheet rule for making hyperlinks clickable
+ private _pdfViewer!: PDFJSViewer.PDFViewer;
+ private _styleRule: number | undefined; // stylesheet rule for making hyperlinks clickable
private _retries = 0; // number of times tried to create the PDF viewer
private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void);
private _marqueeref = React.createRef<MarqueeAnnotator>();
@@ -107,7 +105,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
});
this.setupPdfJsViewer();
this._mainCont.current?.addEventListener('scroll', e => {
- (e.target as any).scrollLeft = 0;
+ (e.target as HTMLElement).scrollLeft = 0;
});
this._disposers.layout_autoHeight = reaction(
@@ -211,18 +209,12 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
};
pagesinit = () => {
- if (this._pdfViewer._setDocumentViewerElement?.offsetParent) {
- runInAction(() => {
- this._pdfViewer.currentScaleValue = this._props.layoutDoc._freeform_scale = 1;
- });
- this.gotoPage(NumCast(this._props.Document._layout_curPage, 1));
- }
document.removeEventListener('pagesinit', this.pagesinit);
let quickScroll: { loc?: string; easeFunc?: 'ease' | 'linear' } | undefined = { loc: this._initialScroll ? this._initialScroll.loc?.toString() : '', easeFunc: this._initialScroll ? this._initialScroll.easeFunc : undefined };
this._disposers.scale = reaction(
() => NumCast(this._props.layoutDoc._freeform_scale, 1),
scale => {
- this._pdfViewer.currentScaleValue = scale;
+ this._pdfViewer.currentScaleValue = scale+"";
},
{ fireImmediately: true }
);
@@ -321,7 +313,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
}
};
- @observable private _scrollTimer: any = undefined;
+ @observable private _scrollTimer: NodeJS.Timeout | undefined = undefined;
onScroll = () => {
if (this._mainCont.current && !this._forcedScroll) {
@@ -330,7 +322,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
this._props.layoutDoc._layout_scrollTop = this._mainCont.current.scrollTop;
}
this._ignoreScroll = false;
- if (this._scrollTimer) clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio
+ this._scrollTimer && clearTimeout(this._scrollTimer); // wait until a scrolling pause, then create an anchor to audio
this._scrollTimer = setTimeout(() => {
CreateLinkToActiveAudio(() => this._props.pdfBox.getAnchor(true)!, false);
this._scrollTimer = undefined;
@@ -390,8 +382,8 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
this._props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this.isAnnotating = true;
- const target = e.target as any;
- if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) {
+ const target = e.target as HTMLElement;
+ if (e.target && (target.className.includes('endOfContent') || (target.parentElement?.className !== 'textLayer' && target.parentElement?.parentElement?.className !== 'textLayer'))) {
this._textSelecting = false;
} else {
// if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
@@ -491,7 +483,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
e.stopPropagation();
if (e.ctrlKey) {
const curScale = Number(this._pdfViewer.currentScaleValue);
- this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000));
+ this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000)) + "";
this._props.layoutDoc._freeform_scale = Number(this._pdfViewer.currentScaleValue);
}
}
@@ -520,7 +512,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1);
transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter];
opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [ClientUtils.OpaqueBackgroundFilter])];
- childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none';
const isInk = doc.layout_isSvg && !props?.LayoutTemplateString;
@@ -531,11 +523,11 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
};
childPointerEvents = () => (this._props.isContentActive() !== false ? 'all' : 'none');
- renderAnnotations = (childFilters: () => string[], mixBlendMode?: any, display?: string) => (
+ renderAnnotations = (childFilters: () => string[], mixBlendMode?: 'hard-light' | 'multiply', display?: string) => (
<div
className="pdfViewerDash-overlay"
style={{
- mixBlendMode: mixBlendMode,
+ mixBlendMode,
display: display,
pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
}}>