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/DocumentView.tsx18
-rw-r--r--src/client/views/nodes/ImageBox.scss10
-rw-r--r--src/client/views/nodes/ImageBox.tsx42
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx2
-rw-r--r--src/client/views/nodes/VideoBox.tsx35
-rw-r--r--src/client/views/nodes/WebBox.tsx257
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx46
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx4
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts2
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx27
10 files changed, 186 insertions, 257 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6371ae5fb..6217f473f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -386,9 +386,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}, console.log);
undoBatch(func)();
} else if (!Doc.IsSystem(this.props.Document)) {
- if (this.props.Document.type === DocumentType.INK) {
- InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = true);
- } else if (this.props.Document.type !== DocumentType.LABEL) {
+ if (this.props.Document.type !== DocumentType.LABEL) {
UndoManager.RunInBatch(() => {
const fullScreenDoc = Cast(this.props.Document._fullScreenView, Doc, null) || this.props.Document;
this.props.addDocTab(fullScreenDoc, "add");
@@ -550,10 +548,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
"linking to document tabs not yet supported. Drop link on document content.");
return;
}
+ if (de.complete.annoDragData) de.complete.annoDragData.annotationDocument = de.complete.annoDragData.annotationDocCreator();
const linkSource = de.complete.annoDragData ? de.complete.annoDragData.annotationDocument : de.complete.linkDragData ? de.complete.linkDragData.linkSourceDocument : undefined;
if (linkSource && linkSource !== this.props.Document) {
e.stopPropagation();
- de.complete.linkDocument = DocUtils.MakeLink({ doc: linkSource }, { doc: this._componentView?.getAnchor() || this.rootDoc }, "link", undefined, undefined, undefined, [de.x, de.y]);
+ const dropDoc = this._componentView?.getAnchor() || this.rootDoc;
+ if (de.complete.annoDragData) de.complete.annoDragData.dropDocument = dropDoc;
+ de.complete.linkDocument = DocUtils.MakeLink({ doc: linkSource }, { doc: dropDoc }, "link", undefined, undefined, undefined, [de.x, de.y]);
}
}
@@ -873,10 +874,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
@computed get panelWidth() { return this.nativeWidth ? this.nativeWidth * this.nativeScaling : this.props.PanelWidth(); }
@computed get panelHeight() {
if (this.nativeHeight) {
- if (this.props.Document._fitWidth) {
- return Math.min(this.props.PanelHeight(), NumCast(this.props.Document.scrollHeight, this.props.PanelHeight()));
- }
- return Math.min(this.props.PanelHeight(), this.nativeHeight * this.nativeScaling);
+ return Math.min(this.props.PanelHeight(),
+ this.props.Document._fitWidth ?
+ Math.max(NumCast(this.props.Document._height), NumCast(((this.props.Document.scrollHeight || 0) as number) * this.props.PanelWidth() / this.nativeWidth, this.props.PanelHeight())) :
+ this.nativeHeight * this.nativeScaling
+ );
}
return this.props.PanelHeight();
}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index c1b95b308..41055e2db 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -5,6 +5,16 @@
position: relative;
transform-origin: top left;
+
+ .imageBox-annotationLayer {
+ position: absolute;
+ transform-origin: left top;
+ top: 0;
+ width: 100%;
+ pointer-events: none;
+ mix-blend-mode: multiply; // bcz: makes text fuzzy!
+ }
+
.imageBox-fader {
pointer-events: inherit;
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b0e7f4ce5..649fe8f40 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -27,6 +27,10 @@ import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
import React = require("react");
import { StyleProp } from '../StyleProvider';
+import { AnchorMenu } from '../pdf/AnchorMenu';
+import { Dictionary } from 'typescript-collections';
+import { MarqueeAnnotator } from '../MarqueeAnnotator';
+import { Annotation } from '../pdf/Annotation';
const path = require('path');
const { Howl } = require('howler');
@@ -63,7 +67,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
private _dropDisposer?: DragManager.DragDropDisposer;
- private _pathDisposer?: IReactionDisposer;
+ private _disposers: { [name: string]: IReactionDisposer } = {};
@observable private _audioState = 0;
@observable static _showControls: boolean;
@observable uploadIcon = uploadIcons.idle;
@@ -74,7 +78,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
}
componentDidMount() {
- this._pathDisposer = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
+ this._disposers.selection = reaction(() => this.props.isSelected(),
+ selected => {
+ if (!selected) {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.clear();
+ }
+ },
+ { fireImmediately: true });
+ this._disposers.path = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
action(({ nativeSize, width }) => {
if (!this.layoutDoc._height) {
this.layoutDoc._height = width * nativeSize.nativeHeight / nativeSize.nativeWidth;
@@ -84,7 +96,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
}
componentWillUnmount() {
- this._pathDisposer?.();
+ Object.values(this._disposers).forEach(disposer => disposer?.());
}
@undoBatch
@@ -356,7 +368,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`;
}
- return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget}>
+ return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget} onPointerDown={this.marqueeDown}>
<div className="imageBox-fader" >
<img key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={srcpath}
@@ -402,11 +414,28 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.ycenter);
contentFunc = () => [this.content];
+ private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+ private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+ @observable _marqueeing: number[] | undefined;
+ @observable _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
+ @computed get annotationLayer() {
+ return <div className="imageBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer} />;
+ }
+ @action
+ marqueeDown = (e: React.PointerEvent) => {
+ if (!e.altKey && e.button === 0 && this.active(true)) this._marqueeing = [e.clientX, e.clientY];
+ }
+ @action
+ finishMarquee = () => {
+ this._marqueeing = undefined;
+ this.props.select(true);
+ }
+
render() {
TraceMobx();
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / (this.props.scaling?.() || 1)}px` : borderRad;
- return (<div className={`imageBox`} onContextMenu={this.specificContextMenu}
+ return (<div className={`imageBox`} onContextMenu={this.specificContextMenu} ref={this._mainCont}
style={{
width: this.props.PanelWidth() ? undefined : `100%`,
height: this.props.PanelWidth() ? undefined : `100%`,
@@ -437,6 +466,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
whenActiveChanged={this.whenActiveChanged}>
{this.contentFunc}
</CollectionFreeFormView>
+ {this.annotationLayer}
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
+ <MarqueeAnnotator rootDoc={this.rootDoc} down={this._marqueeing} scaling={this.props.scaling} addDocument={this.addDocument} finishMarquee={this.finishMarquee} savedAnnotations={this._savedAnnotations} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />}
</div >);
}
}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 07b2b6338..7934dba8e 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -76,7 +76,7 @@ export class LinkDocPreview extends React.Component<Props> {
if (this.props.linkDoc && this.props.linkSrc) {
LinkManager.FollowLink(this.props.linkDoc, this.props.linkSrc, this.props.docprops, false);
} else if (this.props.href) {
- this.props.docprops?.addDocTab(Docs.Create.WebDocument(this.props.href, { _fitWidth: true, title: this.props.href, _width: 200, _height: 400, useCors: true }), "add:right");
+ this.props.docprops?.addDocTab(Docs.Create.WebDocument(this.props.href, { title: this.props.href, _width: 200, _height: 400, useCors: true }), "add:right");
}
}
width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 67e8d74b3..2ac105545 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -225,6 +225,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
}
componentDidMount() {
+ this._disposers.selection = reaction(() => this.props.isSelected(),
+ selected => {
+ if (!selected) {
+ this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
+ this._savedAnnotations.clear();
+ }
+ },
+ { fireImmediately: true });
this._disposers.videoStart = reaction(
() => this.Document._videoStart,
(videoStart) => {
@@ -743,17 +751,29 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
screenToLocalTransform = () => this.props.ScreenToLocalTransform();
contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
+
+ @computed get annotationLayer() {
+ return <div className="imageBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer} />;
+ }
+
+ marqueeDown = action((e: React.PointerEvent) => {
+ if (!e.altKey && e.button === 0 && this.active(true)) this._marqueeing = [e.clientX, e.clientY];
+ })
+
+ finishMarquee = action(() => {
+ this._marqueeing = undefined;
+ this.props.select(true);
+ })
+
render() {
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / (this.props.scaling?.() || 1)}px` : borderRad;
- return (<div className="videoBox" onContextMenu={this.specificContextMenu}
+ return (<div className="videoBox" onContextMenu={this.specificContextMenu} ref={this._mainCont}
style={{
- width: "100%",
- height: "100%",
pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
borderRadius
}} >
- <div className="videoBox-viewer" >
+ <div className="videoBox-viewer" onPointerDown={this.marqueeDown}>
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
forceScaling={true}
fieldKey={this.annotationKey}
@@ -771,6 +791,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
{this.contentFunc}
</CollectionFreeFormView>
</div>
+<<<<<<< HEAD
+=======
+ {this.uIButtons}
+ {this.annotationLayer}
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
+ <MarqueeAnnotator rootDoc={this.rootDoc} down={this._marqueeing} scaling={this.props.scaling} addDocument={this.addDocumentWithTimestamp} finishMarquee={this.finishMarquee} savedAnnotations={this._savedAnnotations} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />}
+>>>>>>> 10b759d2bd09af3a8e8a4effbc8fd2312dd873d2
</div >);
}
}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 7fb14b0cc..69f797880 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,9 +1,10 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from '@material-ui/core';
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Dictionary } from "typescript-collections";
import * as WebRequest from 'web-request';
-import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin, DataSym, HeightSym, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
@@ -12,9 +13,9 @@ import { List } from "../../../fields/List";
import { listSpec, makeInterface } from "../../../fields/Schema";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { WebField } from "../../../fields/URLField";
-import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
-import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue, OmitKeys, smoothScroll } from "../../../Utils";
-import { Docs, DocUtils } from "../../documents/Documents";
+import { TraceMobx } from "../../../fields/util";
+import { emptyFunction, OmitKeys, returnOne, smoothScroll, Utils } from "../../../Utils";
+import { Docs } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
import { ImageUtils } from "../../util/Import & Export/ImageUtils";
import { undoBatch } from "../../util/UndoManager";
@@ -24,15 +25,11 @@ import { ContextMenuProps } from "../ContextMenuItem";
import { ViewBoxAnnotatableComponent } from "../DocComponent";
import { DocumentDecorations } from "../DocumentDecorations";
import { Annotation } from "../pdf/Annotation";
-import { PDFMenu } from "../pdf/PDFMenu";
-import { PdfViewerMarquee } from "../pdf/PDFViewer";
+import { AnchorMenu } from "../pdf/AnchorMenu";
import { FieldView, FieldViewProps } from './FieldView';
import "./WebBox.scss";
-import "../pdf/PDFViewer.scss";
import React = require("react");
-import { Tooltip } from '@material-ui/core';
-import { CurrentUserUtils } from '../../util/CurrentUserUtils';
-import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import { MarqueeAnnotator } from "../MarqueeAnnotator";
const htmlToText = require("html-to-text");
type WebDocument = makeInterface<[typeof documentSchema]>;
@@ -40,32 +37,22 @@ const WebDocument = makeInterface(documentSchema);
@observer
export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocument>(WebDocument) {
-
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
- static _annotationStyle: any = addStyleSheet();
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); }
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
- private _startX: number = 0;
- private _startY: number = 0;
- @observable private _marqueeX: number = 0;
- @observable private _marqueeY: number = 0;
- @observable private _marqueeWidth: number = 0;
- @observable private _marqueeHeight: number = 0;
- @observable private _marqueeing: boolean = false;
+ private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
+ private _disposers: { [name: string]: IReactionDisposer } = {};
+ private _longPressSecondsHack?: NodeJS.Timeout;
+ private _outerRef = React.createRef<HTMLDivElement>();
+ private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
+ private _iframeDragRef = React.createRef<HTMLDivElement>();
+ @observable private _marqueeing: number[] | undefined;
@observable private _url: string = "hello";
@observable private _pressX: number = 0;
@observable private _pressY: number = 0;
@observable private _iframe: HTMLIFrameElement | null = null;
@observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
- private _selectionReactionDisposer?: IReactionDisposer;
- private _scrollReactionDisposer?: IReactionDisposer;
- private _scrollTopReactionDisposer?: IReactionDisposer;
- private _moveReactionDisposer?: IReactionDisposer;
- private _longPressSecondsHack?: NodeJS.Timeout;
- private _outerRef = React.createRef<HTMLDivElement>();
- private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
- private _iframeDragRef = React.createRef<HTMLDivElement>();
- private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean) => void);
+
get scrollHeight() { return this.webpage?.scrollHeight || 1000; }
get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) !== "enabled"; }
set _collapsed(value) { this.layoutDoc._chromeStatus = !value ? "enabled" : "disabled"; }
@@ -99,8 +86,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
this.webpage.scrollLeft = NumCast(this.layoutDoc._scrollLeft);
}
}
- this._scrollReactionDisposer?.();
- this._scrollReactionDisposer = reaction(() => ({ scrollY: this.layoutDoc._scrollY, scrollX: this.layoutDoc._scrollX }),
+ this._disposers.scrollReaction?.();
+ this._disposers.scrollReaction = reaction(() => ({ scrollY: this.layoutDoc._scrollY, scrollX: this.layoutDoc._scrollX }),
({ scrollY, scrollX }) => {
const delay = this._outerRef.current ? 0 : 250; // wait for mainCont and try again to scroll
const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
@@ -118,7 +105,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
},
{ fireImmediately: true }
);
- this._scrollTopReactionDisposer = reaction(() => this.layoutDoc._scrollTop,
+ this._disposers.scrollTop = reaction(() => this.layoutDoc._scrollTop,
scrollTop => {
const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
const duration = durationStr ? Number(durationStr[1]) : 1000;
@@ -166,15 +153,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
const urlField = Cast(this.dataDoc[this.props.fieldKey], WebField);
runInAction(() => this._url = urlField?.url.toString() || "");
- this._moveReactionDisposer = reaction(() => this.layoutDoc.x || this.layoutDoc.y,
+ this._disposers.scrollMove = reaction(() => this.layoutDoc.x || this.layoutDoc.y,
() => this.updateScroll(this.layoutDoc._scrollLeft, this.layoutDoc._scrollTop));
- this._selectionReactionDisposer = reaction(() => this.props.isSelected(),
+ this._disposers.selection = reaction(() => this.props.isSelected(),
selected => {
if (!selected) {
this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, []));
- PDFMenu.Instance.fadeOut(true);
+ this._savedAnnotations.clear();
}
},
{ fireImmediately: true });
@@ -202,18 +188,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
componentWillUnmount() {
- this._moveReactionDisposer?.();
- this._selectionReactionDisposer?.();
- this._scrollTopReactionDisposer?.();
- this._scrollReactionDisposer?.();
+ Object.values(this._disposers).forEach(disposer => disposer?.());
document.removeEventListener("pointerup", this.onLongPressUp);
document.removeEventListener("pointermove", this.onLongPressMove);
this._iframe?.removeEventListener('wheel', this.iframeWheel);
}
- onUrlDragover = (e: React.DragEvent) => {
- e.preventDefault();
- }
+ onUrlDragover = (e: React.DragEvent) => { e.preventDefault(); }
@undoBatch
@action
@@ -256,6 +237,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
urlHash(s: string) {
return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
}
+
@action
submitURL = () => {
if (!this._url.startsWith("http")) this._url = "http://" + this._url;
@@ -283,9 +265,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
onValueKeyDown = async (e: React.KeyboardEvent) => {
- if (e.key === "Enter") {
- this.submitURL();
- }
+ if (e.key === "Enter") this.submitURL();
e.stopPropagation();
}
@@ -300,22 +280,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
_ignore = 0;
- onPreWheel = (e: React.WheelEvent) => {
- this._ignore = e.timeStamp;
- }
- onPrePointer = (e: React.PointerEvent) => {
- this._ignore = e.timeStamp;
- }
+ onPreWheel = (e: React.WheelEvent) => { this._ignore = e.timeStamp; }
+ onPrePointer = (e: React.PointerEvent) => { this._ignore = e.timeStamp; }
onPostPointer = (e: React.PointerEvent) => {
- if (this._ignore !== e.timeStamp) {
- e.stopPropagation();
- }
+ if (this._ignore !== e.timeStamp) e.stopPropagation();
}
onPostWheel = (e: React.WheelEvent) => {
- if (this._ignore !== e.timeStamp) {
- e.stopPropagation();
- }
+ if (this._ignore !== e.timeStamp) e.stopPropagation();
}
onLongPressDown = (e: React.PointerEvent) => {
@@ -431,7 +403,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
@computed
get urlContent() {
-
const field = this.dataDoc[this.props.fieldKey];
let view;
if (field instanceof HtmlField) {
@@ -449,6 +420,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
return view;
}
+
@computed
get content() {
const view = this.urlContent;
@@ -458,7 +430,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
return (<>
<div className={"webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
style={{
- width: `${100 / scale}%`,
+ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / scale}%`,
height: `${100 / scale}%`,
transform: `scale(${scale})`
}}
@@ -476,25 +448,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
</>);
}
-
-
@computed get allAnnotations() { return DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]); }
@computed get nonDocAnnotations() { return this.allAnnotations.filter(a => a.annotations); }
- @undoBatch
- @action
- makeAnnotationDocument = (color: string): Opt<Doc> => {
- if (this._savedAnnotations.size() === 0) return undefined;
- const anno = this._savedAnnotations.values()[0][0];
- const annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: color, annotationOn: this.props.Document, title: "Annotation on " + this.Document.title });
- if (anno.style.left) annoDoc.x = parseInt(anno.style.left);
- if (anno.style.top) annoDoc.y = NumCast(this.layoutDoc._scrollTop) + parseInt(anno.style.top);
- if (anno.style.height) annoDoc._height = parseInt(anno.style.height);
- if (anno.style.width) annoDoc._width = parseInt(anno.style.width);
- anno.remove();
- this._savedAnnotations.clear();
- return annoDoc;
- }
@computed get annotationLayer() {
TraceMobx();
return <div className="webBox-annotationLayer" style={{ height: Doc.NativeHeight(this.Document) || undefined }} ref={this._annotationLayer}>
@@ -503,153 +459,20 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
}
</div>;
}
- @action
- createAnnotation = (div: HTMLDivElement, page: number) => {
- if (this._annotationLayer.current) {
- if (div.style.top) {
- div.style.top = (parseInt(div.style.top)).toString();
- }
- this._annotationLayer.current.append(div);
- div.style.backgroundColor = "#ACCEF7";
- div.style.opacity = "0.5";
- const savedPage = this._savedAnnotations.getValue(page);
- if (savedPage) {
- savedPage.push(div);
- this._savedAnnotations.setValue(page, savedPage);
- }
- else {
- this._savedAnnotations.setValue(page, [div]);
- }
- }
- }
@action
- highlight = (color: string) => {
- // creates annotation documents for current highlights
- const effectiveAcl = GetEffectiveAcl(this.props.Document[DataSym]);
- const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) ? this.makeAnnotationDocument(color.replace(/[0-9.]*\)/, "0.3)")) : undefined;
- annotationDoc && this.addDocument?.(annotationDoc);
- return annotationDoc ?? undefined;
- }
- /**
- * This is temporary for creating annotations from highlights. It will
- * start a drag event and create or put the necessary info into the drag event.
- */
- @action
- startDrag = async (e: PointerEvent, ele: HTMLElement) => {
- e.preventDefault();
- e.stopPropagation();
-
- const targetDoc = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.props.Document.title, 0, 0, 125, 125);
- FormattedTextBox.SelectOnLoad = targetDoc[Id];
- const annotationDoc = this.highlight("rgba(173, 216, 230, 0.35)"); // hyperlink color
- if (annotationDoc) {
- DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
- dragComplete: e => {
- if (!e.aborted && e.annoDragData && !e.linkDocument) {
- e.linkDocument = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
- annotationDoc.isLinkButton = true;
- annotationDoc.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.props.Document;
- }
- }
- });
- }
- }
- @action
onMarqueeDown = (e: React.PointerEvent) => {
- this._marqueeing = false;
if (!e.altKey && e.button === 0 && this.active(true)) {
- // clear out old marquees and initialize menu for new selection
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
- PDFMenu.Instance.Status = "pdf";
- PDFMenu.Instance.fadeOut(true);
- this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
- this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, []));
- if ((e.target as any)?.parentElement.className === "textLayer") {
- // start selecting text if mouse down on textLayer spans
- }
- else if (this._mainCont.current) {
- // set marquee x and y positions to the spatially transformed position
- const nheight = Doc.NativeHeight(this.Document) || 1;
- const nwidth = Doc.NativeWidth(this.Document) || 1;
- const boundingRect = this._mainCont.current.getBoundingClientRect();
- const boundingHeight = nheight / nwidth * boundingRect.width;
- this._startX = (e.clientX - boundingRect.left) / boundingRect.width * nwidth;
- this._startY = (e.clientY - boundingRect.top) / boundingHeight * nheight;
- this._marqueeHeight = this._marqueeWidth = 0;
- this._marqueeing = true;
- }
- document.removeEventListener("pointermove", this.onSelectMove);
- document.addEventListener("pointermove", this.onSelectMove);
- document.removeEventListener("pointerup", this.onSelectEnd);
- document.addEventListener("pointerup", this.onSelectEnd);
- }
- }
- @action
- onSelectMove = (e: PointerEvent): void => {
- if (this._marqueeing && this._mainCont.current) {
- // transform positions and find the width and height to set the marquee to
- const boundingRect = this._mainCont.current.getBoundingClientRect();
- const boundingHeight = (Doc.NativeHeight(this.Document) || 1) / (Doc.NativeWidth(this.Document) || 1) * boundingRect.width;
- const curX = (e.clientX - boundingRect.left) / boundingRect.width * (Doc.NativeWidth(this.Document) || 1);
- const curY = (e.clientY - boundingRect.top) / boundingHeight * (Doc.NativeHeight(this.Document) || 1);
- this._marqueeWidth = curX - this._startX;
- this._marqueeHeight = curY - this._startY;
- this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
- this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
- this._marqueeWidth = Math.abs(this._marqueeWidth);
- this._marqueeHeight = Math.abs(this._marqueeHeight);
- e.stopPropagation();
- e.preventDefault();
- }
- else if (e.target && (e.target as any).parentElement === this._mainCont.current) {
- e.stopPropagation();
+ this._marqueeing = [e.clientX, e.clientY];
}
}
@action
- onSelectEnd = (e: PointerEvent): void => {
- clearStyleSheetRules(WebBox._annotationStyle);
- this._savedAnnotations.clear();
- if (this._marqueeWidth > 10 || this._marqueeHeight > 10) {
- const marquees = this._mainCont.current!.getElementsByClassName("pdfViewerDash-dragAnnotationBox");
- if (marquees?.length) { // copy the marquee and convert it to a permanent annotation.
- const style = (marquees[0] as HTMLDivElement).style;
- const copy = document.createElement("div");
- copy.style.left = style.left;
- copy.style.top = style.top;
- copy.style.width = style.width;
- copy.style.height = style.height;
- copy.style.border = style.border;
- copy.style.opacity = style.opacity;
- (copy as any).marqueeing = true;
- copy.className = "webBox-annotationBox";
- this.createAnnotation(copy, 0);
- }
-
- if (!e.ctrlKey) {
- PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight };
- }
- PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
- }
- //this._marqueeing = false;
-
- if (PDFMenu.Instance.Highlighting) {// when highlighter has been toggled when menu is pinned, we auto-highlight immediately on mouse up
- this.highlight("rgba(245, 230, 95, 0.616)"); // yellowish highlight color for highlighted text (should match PDFMenu's highlight color)
- }
- else {
- PDFMenu.Instance.StartDrag = this.startDrag;
- PDFMenu.Instance.Highlight = this.highlight;
- }
- document.removeEventListener("pointermove", this.onSelectMove);
- document.removeEventListener("pointerup", this.onSelectEnd);
+ finishMarquee = () => {
+ this._marqueeing = undefined;
+ this.props.select(true);
}
- marqueeWidth = () => this._marqueeWidth;
- marqueeHeight = () => this._marqueeHeight;
- marqueeX = () => this._marqueeX;
- marqueeY = () => this._marqueeY;
- marqueeing = () => this._marqueeing;
+
scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop));
render() {
const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false;
@@ -662,9 +485,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
{this.content}
<div className={"webBox-outerContent"} ref={this._outerRef}
style={{
- width: `${100 / scale}%`,
- height: `${100 / scale}%`,
- transform: `scale(${scale})`,
+ width: `${100 / scale}%`, height: `${100 / scale}%`, transform: `scale(${scale})`,
pointerEvents: this.layoutDoc.isAnnotating && !inactiveLayer ? "all" : "none"
}}
onWheel={e => {
@@ -707,9 +528,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
</div>
</div>
{this.annotationLayer}
- <PdfViewerMarquee isMarqueeing={this.marqueeing} width={this.marqueeWidth} height={this.marqueeHeight} x={this.marqueeX} y={this.marqueeY} />
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
+ <MarqueeAnnotator rootDoc={this.rootDoc} down={this._marqueeing} scaling={this.props.scaling} addDocument={this.addDocument} finishMarquee={this.finishMarquee} savedAnnotations={this._savedAnnotations} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} />}
</div >
-
{this.props.isSelected() ? this.editToggleBtn() : null}
</div>);
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c129d0204..ac5ea66ff 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -59,11 +59,13 @@ import { FormattedTextBoxComment, formattedTextBoxCommentPlugin, findLinkMark }
import React = require("react");
import { LinkManager } from '../../../util/LinkManager';
import { CollectionStackingView } from '../../collections/CollectionStackingView';
-import { CollectionViewType, CollectionViewProps } from '../../collections/CollectionView';
+import { CollectionViewType } from '../../collections/CollectionView';
import { SnappingManager } from '../../../util/SnappingManager';
import { LinkDocPreview } from '../LinkDocPreview';
import { SubCollectionViewProps } from '../../collections/CollectionSubView';
import { StyleProp } from '../../StyleProvider';
+import { AnchorMenu } from '../../pdf/AnchorMenu';
+import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
export interface FormattedTextBoxProps {
makeLink?: () => Opt<Doc>; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text
@@ -83,6 +85,7 @@ type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, da
export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
+ public static CanAnnotate = true;
public static Instance: FormattedTextBox;
public ProseRef?: HTMLDivElement;
public get EditorView() { return this._editorView; }
@@ -209,6 +212,42 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this.linkOnDeselect.clear();
}
+ @action
+ setupAnchorMenu = () => {
+ AnchorMenu.Instance.Status = "marquee";
+ AnchorMenu.Instance.Highlight = action((color: string) => {
+ this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch);
+ return undefined;
+ });
+ /**
+ * This function is used by the PDFmenu to create an anchor highlight and a new linked text annotation.
+ * It also initiates a Drag/Drop interaction to place the text annotation.
+ */
+ AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const targetCreator = () => {
+ const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.rootDoc.title, 0, 0, 100, 100);
+ FormattedTextBox.SelectOnLoad = target[Id];
+ return target;
+ }
+
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.rootDoc, () => this.rootDoc, targetCreator), e.pageX, e.pageY, {
+ dragComplete: e => {
+ if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) {
+ e.linkDocument = DocUtils.MakeLink({ doc: e.annoDragData.annotationDocument }, { doc: e.annoDragData.dropDocument }, "hyperlink", "link to note");
+ e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.rootDoc;
+ }
+ e.linkDocument && e.annoDragData?.dropDocument && this.makeLinkToSelection(e.linkDocument[Id], "a link", "add:right", e.annoDragData.dropDocument[Id]);
+ e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument
+ }
+ });
+ });
+ const coordsT = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
+ const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
+ this.props.isSelected(true) && AnchorMenu.Instance.jumpTo(Math.min(coordsT.left, coordsB.left), Math.max(coordsT.bottom, coordsB.bottom));
+ }
+
dispatchTransaction = (tx: Transaction) => {
let timeStamp;
clearTimeout(timeStamp);
@@ -252,6 +291,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
let unchanged = true;
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
+ if (!this._editorView.state.selection.empty && FormattedTextBox.CanAnnotate) this.setupAnchorMenu();
+
const removeSelection = (json: string | undefined) => {
return json?.indexOf("\"storedMarks\"") === -1 ? json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
};
@@ -619,6 +660,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const uicontrols: ContextMenuProps[] = [];
+ uicontrols.push({ description: `${FormattedTextBox.CanAnnotate ? "Hide" : "Show"} Annotation Bar`, event: () => FormattedTextBox.CanAnnotate = !FormattedTextBox.CanAnnotate, icon: "expand-arrows-alt" });
uicontrols.push({ description: `${this.layoutDoc._showAudio ? "Hide" : "Show"} Dictation Icon`, event: () => this.layoutDoc._showAudio = !this.layoutDoc._showAudio, icon: "expand-arrows-alt" });
uicontrols.push({ description: "Show Highlights...", noexpand: true, subitems: highlighting, icon: "hand-point-right" });
!Doc.UserDoc().noviceMode && uicontrols.push({ description: `Create TimeStamp When ${this.layoutDoc._timeStampOnEnter ? "Pause" : "Enter"}`, event: () => this.layoutDoc._timeStampOnEnter = !this.layoutDoc._timeStampOnEnter, icon: "expand-arrows-alt" });
@@ -1256,9 +1298,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
componentWillUnmount() {
+ Object.values(this._disposers).forEach(disposer => disposer?.());
this.endUndoTypingBatch();
this.unhighlightSearchTerms();
- Object.values(this._disposers).forEach(disposer => disposer?.());
this._editorView?.destroy();
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 038a91aa3..5371bd10a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -121,7 +121,7 @@ export class FormattedTextBoxComment {
}
}
} else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
- textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _fitWidth: true, _width: 200, _height: 400, useCors: true }), "add:right");
+ textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, useCors: true }), "add:right");
}
keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation(
FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
@@ -255,7 +255,7 @@ export class FormattedTextBoxComment {
docTarget && DocServer.GetRefField(docTarget).then(async linkDoc => {
if (linkDoc instanceof Doc) {
(FormattedTextBoxComment.tooltipText as any).href = href;
- FormattedTextBoxComment.linkDoc = DocListCast(textBox.props.Document.links).find(link => link.anchor1 === textBox.props.Document || link.anchor2 === textBox.props.Document ? link : undefined) || linkDoc;
+ FormattedTextBoxComment.linkDoc = linkDoc;
const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc);
const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
if (anchor !== target && anchor && target) {
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index cb5823e86..8d9d36580 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -135,7 +135,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey
//Command to create a new Tab with a PDF of all the command shortcuts
bind("Mod-/", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
- const newDoc = Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _fitWidth: true, _width: 300, _height: 300 });
+ const newDoc = Docs.Create.PdfDocument(Utils.prepend("/assets/cheat-sheet.pdf"), { _width: 300, _height: 300 });
props.addDocTab(newDoc, "add:right");
});
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 07439825f..992194e2b 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -56,7 +56,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable private activeListType: string = "";
@observable private activeAlignment: string = "left";
- @observable private brushIsEmpty: boolean = true;
@observable private brushMarks: Set<Mark> = new Set();
@observable private showBrushDropdown: boolean = false;
@@ -600,7 +599,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
createBrushButton() {
const self = this;
- function onBrushClick(e: React.PointerEvent) {
+ const onBrushClick = (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
self.TextView.endUndoTypingBatch();
@@ -622,8 +621,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
//onPointerDown={onBrushClick}
const button = <Tooltip title={<div className="dash-tooltip">style brush</div>} placement="bottom">
-
- <button className="antimodeMenu-button" style={this.brushMarks?.size > 0 ? { backgroundColor: "121212" } : {}}>
+ <button className="antimodeMenu-button" onClick={onBrushClick} style={this.brushMarks?.size > 0 ? { backgroundColor: "121212" } : {}}>
<FontAwesomeIcon icon="paint-roller" size="lg" style={{ transitionProperty: "transform", transitionDuration: "0.1s", transform: `rotate(${this.brushMarks?.size > 0 ? 45 : 0}deg)` }} />
</button>
</Tooltip>;
@@ -636,13 +634,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
</div>;
return (
- <ButtonDropdown view={this.view} key={"brush dropdown"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} />
+ <ButtonDropdown view={this.view} key={"brush dropdown"} button={button} openDropdownOnButton={false} dropdownContent={dropdownContent} />
);
}
@action
clearBrush() {
- RichTextMenu.Instance.brushIsEmpty = true;
RichTextMenu.Instance.brushMarks = new Set();
}
@@ -650,26 +647,22 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
fillBrush(state: EditorState<any>, dispatch: any) {
if (!this.view) return;
- if (this.brushIsEmpty) {
+ if (!Array.from(this.brushMarks.keys()).length) {
const selected_marks = this.getMarksInSelection(this.view.state);
if (selected_marks.size >= 0) {
this.brushMarks = selected_marks;
- this.brushIsEmpty = !this.brushIsEmpty;
}
}
else {
const { from, to, $from } = this.view.state.selection;
if (!this.view.state.selection.empty && $from && $from.nodeAfter) {
- if (this.brushMarks && to - from > 0) {
+ if (to - from > 0) {
this.view.dispatch(this.view.state.tr.removeMark(from, to));
Array.from(this.brushMarks).filter(m => m.type !== schema.marks.user_mark).forEach((mark: Mark) => {
this.setMark(mark, this.view!.state, this.view!.dispatch);
});
}
}
- else {
- this.brushIsEmpty = !this.brushIsEmpty;
- }
}
}
@@ -817,8 +810,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
<button className="remove-button" onPointerDown={e => this.deleteLink()}>Remove link</button>
</div>;
- return <ButtonDropdown view={this.view} key={"link button"} button={button} dropdownContent={dropdownContent}
- openDropdownOnButton={true} link={true} />;
+ return <ButtonDropdown view={this.view} key={"link button"} button={button} dropdownContent={dropdownContent} openDropdownOnButton={true} link={true} />;
}
async getTextLinkTargetTitle() {
@@ -1027,6 +1019,7 @@ interface ButtonDropdownProps {
openDropdownOnButton?: boolean;
link?: boolean;
pdf?: boolean;
+
}
@observer
@@ -1071,9 +1064,11 @@ export class ButtonDropdown extends React.Component<ButtonDropdownProps> {
return (
<div className="button-dropdown-wrapper" ref={node => this.ref = node}>
{!this.props.pdf ?
- <div className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.onDropdownClick}>
+ <div className="antimodeMenu-button dropdown-button-combined" onPointerDown={this.props.openDropdownOnButton ? this.onDropdownClick : undefined}>
{this.props.button}
- <div style={{ marginTop: "-8.5" }}><FontAwesomeIcon icon="caret-down" size="sm" /></div>
+ <div style={{ marginTop: "-8.5", position: "relative" }} onPointerDown={!this.props.openDropdownOnButton ? this.onDropdownClick : undefined}>
+ <FontAwesomeIcon icon="caret-down" size="sm" />
+ </div>
</div>
:
<>