diff options
Diffstat (limited to 'src')
24 files changed, 98 insertions, 89 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b32cbd3d0..df08345f9 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -280,7 +280,7 @@ export namespace Docs { }], [DocumentType.WEB, { layout: { view: WebBox, dataField: defaultDataKey }, - options: { _height: 300 } + options: { _height: 300, scrollHeight: 100000, _fitWidth: true } }], [DocumentType.COL, { layout: { view: CollectionView, dataField: defaultDataKey }, @@ -304,7 +304,7 @@ export namespace Docs { }], [DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, - options: { _curPage: 1 } + options: { _curPage: 1, _fitWidth: true } }], [DocumentType.IMPORT, { layout: { view: DirectoryImportBox, dataField: defaultDataKey }, @@ -764,11 +764,16 @@ export namespace Docs { } export function PdfDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(new URL(url)), options); + const pdfProto = Prototypes.get(DocumentType.PDF); + pdfProto._fitWidth = true; // backward compatibility -- can be removed after db is reset + return InstanceFromProto(pdfProto, new PdfField(new URL(url)), options); } export function WebDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, { _fitWidth: true, _chromeStatus: url ? "disabled" : "enabled", isAnnotating: false, _lockedTransform: true, ...options }); + const webProto = Prototypes.get(DocumentType.WEB); + webProto.scrollHeight = 100000; // backward compatibility -- can be removed after db is reset + webProto._fitWidth = true; // backward compatibility -- can be removed after db is reset + return InstanceFromProto(webProto, url ? new WebField(new URL(url)) : undefined, { _chromeStatus: url ? "disabled" : "enabled", isAnnotating: false, _lockedTransform: true, ...options }); } export function HtmlDocument(html: string, options: DocumentOptions = {}) { @@ -1110,7 +1115,6 @@ export namespace DocUtils { } if (type.indexOf("pdf") !== -1) { ctor = Docs.Create.PdfDocument; - if (!options._fitWidth) options._fitWidth = true; if (!options._width) options._width = 400; if (!options._height) options._height = options._width * 1200 / 927; } @@ -1131,7 +1135,7 @@ export namespace DocUtils { }); } ctor = Docs.Create.WebDocument; - options = { ...options, _fitWidth: true, _width: 400, _height: 512, title: path, }; + options = { ...options, _width: 400, _height: 512, title: path, }; } return ctor ? ctor(path, options) : undefined; } diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c4f7744ce..f3fec9ae6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -444,7 +444,7 @@ export class CurrentUserUtils { { _width: 250, _height: 250, title: "container", system: true, cloneFieldFilter: new List<string>(["system"]) }); } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, _fitWidth: true, isTemplateDoc: true, _height: 512, _width: 400, useCors: true, system: true, cloneFieldFilter: new List<string>(["system"]) }); + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "webpage", _nativeWidth: 850, isTemplateDoc: true, _height: 512, _width: 400, useCors: true, system: true, cloneFieldFilter: new List<string>(["system"]) }); } if (doc.activeMobileMenu === undefined) { this.setupActiveMobileMenu(doc); diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 7a449b882..8ddfce772 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -21,7 +21,7 @@ export namespace Hypothesis { export const getSourceWebDoc = async (uri: string) => { const result = await findWebDoc(uri); console.log(result ? "existing doc found" : "existing doc NOT found"); - return result || Docs.Create.WebDocument(uri, { title: uri, _fitWidth: true, _nativeWidth: 850, _height: 512, _width: 400, useCors: true }); // create and return a new Web doc with given uri if no matching docs are found + return result || Docs.Create.WebDocument(uri, { title: uri, _nativeWidth: 850, _height: 512, _width: 400, useCors: true }); // create and return a new Web doc with given uri if no matching docs are found }; diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index a2bd0aad9..eeef94d74 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -155,7 +155,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV e.preventDefault(); let googleDoc = await Cast(dataDoc.googleDoc, Doc); if (!googleDoc) { - const options = { _width: 600, _fitWidth: true, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, useCors: false }; + const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, useCors: false }; googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 8df7f7eef..19b23af13 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -6,7 +6,7 @@ import { InkData, InkField, InkTool } from "../../fields/InkField"; import { makeInterface } from "../../fields/Schema"; import { Cast, StrCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; -import { setupMoveUpEvents } from "../../Utils"; +import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { InteractionUtils } from "../util/InteractionUtils"; import { Scripting } from "../util/Scripting"; @@ -87,6 +87,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume } } + onPointerDown = (e: React.PointerEvent) => { + this.props.isSelected(true) && setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e: PointerEvent, doubleTap: boolean | undefined) => { + doubleTap && InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = true); + })); + } public static MaskDim = 50000; render() { @@ -196,6 +201,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset", overflow: "visible", }} + onPointerDown={this.onPointerDown} onContextMenu={() => { const cm = ContextMenu.Instance; if (cm) { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index ac61dd1d8..5b57ad19f 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -49,7 +49,7 @@ export class PreviewCursor extends React.Component<{}> { else if (re.test(plain)) { const url = plain; undoBatch(() => PreviewCursor._addDocument(Docs.Create.WebDocument(url, { - title: url, _fitWidth: true, _width: 500, _height: 300, useCors: true, x: newPoint[0], y: newPoint[1] + title: url, _width: 500, _height: 300, useCors: true, x: newPoint[0], y: newPoint[1] })))(); } else if (plain.startsWith("__DashDocId(") || plain.startsWith("__DashCloneId(")) { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 4413d28f5..9a836313c 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -153,7 +153,7 @@ export class PropertiesButtons extends React.Component<{}, {}> { e.preventDefault(); let googleDoc = await Cast(dataDoc.googleDoc, Doc); if (!googleDoc) { - const options = { _width: 600, _fitWidth: true, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, useCors: false }; + const options = { _width: 600, _nativeWidth: 960, _nativeHeight: 800, isAnnotating: false, useCors: false }; googleDoc = Docs.Create.WebDocument(googleDocUrl, options); dataDoc.googleDoc = googleDoc; } diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss index df63288f1..94001730c 100644 --- a/src/client/views/StyleProvider.scss +++ b/src/client/views/StyleProvider.scss @@ -3,7 +3,7 @@ width: 20; height: 20; position: absolute; - right: -5; + right: -25; top: -5; background: transparent; pointer-events: all; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 26cb4d156..287bc56c2 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -268,7 +268,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: } }); } else { - this.addDocument(Docs.Create.WebDocument(href, { ...options, _fitWidth: true, title: href })); + this.addDocument(Docs.Create.WebDocument(href, { ...options, title: href })); } } else if (text) { this.addDocument(Docs.Create.TextDocument(text, { ...options, _showTitle: StrCast(Doc.UserDoc().showTitle), _width: 100, _height: 25 })); @@ -385,7 +385,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: console.log("Adding ..."); const newDoc = Docs.Create.WebDocument(uriList.split("#annotations:")[0], {// clean hypothes.is URLs that reference a specific annotation (eg. https://en.wikipedia.org/wiki/Cartoon#annotations:t7qAeNbCEeqfG5972KR2Ig) ...options, - _fitWidth: true, title: uriList.split("#annotations:")[0], _width: 400, _height: 512, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 258e839d0..9ef37ecc2 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -89,7 +89,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque const [x, y] = this.Transform.transformPoint(this._downX, this._downY); if (e.key === "?") { cm.setDefaultItem("?", (str: string) => this.props.addDocTab( - Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _fitWidth: true, _width: 400, x, y, _height: 512, _nativeWidth: 850, isAnnotating: false, title: "bing", useCors: true }), "add:right")); + Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 400, x, y, _height: 512, _nativeWidth: 850, isAnnotating: false, title: "bing", useCors: true }), "add:right")); cm.displayMenu(this._downX, this._downY); e.stopPropagation(); diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index d6cefa5b0..19ef03a31 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -127,9 +127,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { @undoBatch @action - deleteLink = (): void => { + deleteLink = (e: React.PointerEvent): void => { this.props.linkDoc.linksToAnnotation && Hypothesis.deleteLink(this.props.linkDoc, this.props.sourceDoc, this.props.destinationDoc); LinkManager.Instance.deleteLink(this.props.linkDoc); + e.stopPropagation(); runInAction(() => { LinkDocPreview.LinkInfo = undefined; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 546eca427..c5c47b463 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -389,9 +389,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"); @@ -897,7 +895,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { if (this.nativeHeight) { return Math.min(this.props.PanelHeight(), this.props.Document._fitWidth ? - Math.max(NumCast(this.props.Document._height), NumCast((this.props.Document.scrollHeight as number) * this.props.PanelWidth() / this.nativeWidth, this.props.PanelHeight())) : + 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 ); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 47fa25951..649fe8f40 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -83,7 +83,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD if (!selected) { this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); this._savedAnnotations.clear(); - AnchorMenu.Instance.fadeOut(true); } }, { fireImmediately: true }); 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 55a9818ad..6354c677e 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -195,7 +195,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD if (!selected) { this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); this._savedAnnotations.clear(); - AnchorMenu.Instance.fadeOut(true); } }, { fireImmediately: true }); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c9c4ed159..69f797880 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -161,7 +161,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum if (!selected) { this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); this._savedAnnotations.clear(); - AnchorMenu.Instance.fadeOut(true); } }, { fireImmediately: true }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index f9982f747..ac5ea66ff 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -59,7 +59,7 @@ 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'; @@ -85,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; } @@ -211,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); @@ -254,42 +291,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp let unchanged = true; const effectiveAcl = GetEffectiveAcl(this.dataDoc); - if (!this._editorView.state.selection.empty) { - runInAction(() => { - 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); - AnchorMenu.Instance.jumpTo(Math.min(coordsT.left, coordsB.left), Math.max(coordsT.bottom, coordsB.bottom)); - } + 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\""); @@ -658,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" }); @@ -999,7 +1002,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._disposers.selected = reaction(() => this.props.isSelected(), action((selected) => { this._recording = false; - AnchorMenu.Instance.fadeOut(true); if (RichTextMenu.Instance?.view === this._editorView && !selected) { RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined); } @@ -1296,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 8867595ff..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); 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> : <> diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index e2bd5a73d..d1fdc6c44 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -1,7 +1,7 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; -import { action, computed, observable } from "mobx"; +import { action, computed, observable, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { ColorState } from "react-color"; import { Doc, Opt } from "../../../fields/Doc"; @@ -9,6 +9,7 @@ import { returnFalse, setupMoveUpEvents, unimplementedFunction, Utils } from ".. import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu"; import { ButtonDropdown } from "../nodes/formattedText/RichTextMenu"; import "./AnchorMenu.scss"; +import { SelectionManager } from "../../util/SelectionManager"; @observer export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { @@ -58,6 +59,14 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { AnchorMenu.Instance._canFade = false; } + _disposer: IReactionDisposer | undefined; + componentDidMount() { + this._disposer = reaction(() => SelectionManager.Views(), + selected => { + AnchorMenu.Instance.fadeOut(true); + }); + } + pointerDown = (e: React.PointerEvent) => { setupMoveUpEvents(this, e, (e: PointerEvent) => { this.StartDrag(e, this._commentCont.current!); diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 85dd65901..cd32c2c3a 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -67,8 +67,8 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> { } componentWillUnmount() { - this._brushDisposer && this._brushDisposer(); - this._reactionDisposer && this._reactionDisposer(); + this._brushDisposer?.(); + this._reactionDisposer?.(); } @undoBatch @@ -83,8 +83,8 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> { DocListCast(group.annotations).forEach(anno => anno.delete = true); } - AnchorMenu.Instance.fadeOut(true); + this.props.select(false); } @undoBatch diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f2052d454..fa97bde3f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -137,7 +137,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu if (!selected) { this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); this._savedAnnotations.keys().forEach(k => this._savedAnnotations.setValue(k, [])); - AnchorMenu.Instance.fadeOut(true); } (SelectionManager.Views().length === 1) && this.setupPdfJsViewer(); }, @@ -389,7 +388,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu } else { // clear out old marquees and initialize menu for new selection AnchorMenu.Instance.Status = "marquee"; - AnchorMenu.Instance.fadeOut(true); this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove())); this._savedAnnotations.clear(); this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "pdfAnnotation", { "pointer-events": "none" }); diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 65f9e40ff..2183d2172 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -57,7 +57,7 @@ export class Uploader extends React.Component<ImageUploadProps> { doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 2: File is a PDF document } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, _fitWidth: true, title: name }); + doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); // Case 3: File is another document type (most likely Image) } else { doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name }); |