aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-03-09 20:56:29 -0500
committerbobzel <zzzman@gmail.com>2021-03-09 20:56:29 -0500
commit9e04c57cab8095277398cbcee6fa4ebd904dcf85 (patch)
treef6076f1fefcb2693d33f84759da83703ebf2468b /src
parent524806c57b5582c6ed8893d38d79c55603ced834 (diff)
changed field unchanged -> googleDocUnchanged. cleaned up some other code.
Diffstat (limited to 'src')
-rw-r--r--src/client/views/DocumentButtonBar.tsx6
-rw-r--r--src/client/views/PropertiesButtons.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx138
-rw-r--r--src/client/views/pdf/Annotation.tsx17
-rw-r--r--src/client/views/pdf/PDFViewer.tsx109
5 files changed, 117 insertions, 159 deletions
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index a9cd7b4a9..5ebf29603 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -131,7 +131,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const title = (() => {
switch (this.openHover) {
default:
- case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+ case UtilityButtonState.Default: return `${!dataDoc?.googleDocUnchanged ? "Pull from" : "Fetch"} Google Docs`;
case UtilityButtonState.OpenRight: return "Open in Right Split";
case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
}
@@ -167,7 +167,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
this.clearPullColor();
DocumentButtonBar.hasPulledHack = false;
targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
- dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+ dataDoc.googleDocUnchanged && runInAction(() => this.isAnimatingFetch = true);
}
}}>
<FontAwesomeIcon className="documentdecorations-icon" size="sm"
@@ -175,7 +175,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
icon={(() => {
switch (this.openHover) {
default:
- case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+ case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch;
case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
case UtilityButtonState.OpenExternally: return "share";
}
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index e418a6f3c..bf72dbdba 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -131,7 +131,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
const title = (() => {
switch (this.openHover) {
default:
- case UtilityButtonState.Default: return `${!dataDoc?.unchanged ? "Pull from" : "Fetch"} Google Docs`;
+ case UtilityButtonState.Default: return `${!dataDoc?.googleDocUnchanged ? "Pull from" : "Fetch"} Google Docs`;
case UtilityButtonState.OpenRight: return "Open in Right Split";
case UtilityButtonState.OpenExternally: return "Open in new Browser Tab";
}
@@ -165,7 +165,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
this.clearPullColor();
PropertiesButtons.hasPulledHack = false;
targetDoc[Pulls] = NumCast(targetDoc[Pulls]) + 1;
- dataDoc.unchanged && runInAction(() => this.isAnimatingFetch = true);
+ dataDoc.googleDocUnchanged && runInAction(() => this.isAnimatingFetch = true);
}
}}>
<FontAwesomeIcon className="documentdecorations-icon" size="lg" color="black"
@@ -173,7 +173,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
icon={(() => {
switch (this.openHover) {
default:
- case UtilityButtonState.Default: return dataDoc.unchanged === false ? (this.pullIcon as any) : fetch;
+ case UtilityButtonState.Default: return dataDoc.googleDocUnchanged === false ? (this.pullIcon as any) : fetch;
case UtilityButtonState.OpenRight: return "arrow-alt-circle-right";
case UtilityButtonState.OpenExternally: return "share";
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 29f6e2bd8..89df7a98a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -15,7 +15,7 @@ import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, Wid
import { documentSchema } from '../../../../fields/documentSchemas';
import applyDevTools = require("prosemirror-dev-tools");
import { removeMarkWithAttrs } from "./prosemirrorPatches";
-import { Id, Copy } from '../../../../fields/FieldSymbols';
+import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { PrefetchProxy } from '../../../../fields/Proxy';
import { RichTextField } from "../../../../fields/RichTextField";
@@ -90,8 +90,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public static get DefaultLayout() {
return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
}
- public static CanAnnotate = true;
public static Instance: FormattedTextBox;
+ static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
+ static _highlightStyleSheet: any = addStyleSheet();
+ static _bulletStyleSheet: any = addStyleSheet();
+ static _userStyleSheet: any = addStyleSheet();
+ static _canAnnotate = true;
+ static _hadSelection: boolean = false;
+ public static LiveTextUndo: UndoManager.Batch | undefined;
public ProseRef?: HTMLDivElement;
public get EditorView() { return this._editorView; }
public get SidebarKey() { return this.fieldKey + "-sidebar"; }
@@ -111,6 +117,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
private _focusSpeed: Opt<number>;
private _keymap: any = 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 _forceDownNode: Node | undefined;
+ private _downEvent: any;
+ private _downX = 0;
+ private _downY = 0;
+ private _break = false;
@computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
@computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
@@ -121,10 +133,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@computed get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
@computed get _recording() { return this.dataDoc?.audioState === "recording"; }
set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
+ @computed get config() {
+ this._keymap = buildKeymap(schema, this.props);
+ this._rules = new RichTextRules(this.props.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(editorView); } })
+ ]
+ };
+ }
public static FocusedBox: FormattedTextBox | undefined;
- public static SelectOnLoad = "";
public static PasteOnLoad: ClipboardEvent | undefined;
+ public static SelectOnLoad = "";
public static SelectOnLoadChar = "";
public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; }
public static GetHref(html: string): string {
@@ -314,7 +342,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
// needs a better API for taking in a set of words with target documents instead of just one target
- public hyperlinkTerms = (terms: string[], target: Doc) => {
+ hyperlinkTerms = (terms: string[], target: Doc) => {
if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
const res1 = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
let tr = this._editorView.state.tr;
@@ -334,7 +362,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView.dispatch(tr);
}
}
- public highlightSearchTerms = (terms: string[], backward: boolean) => {
+ highlightSearchTerms = (terms: string[], backward: boolean) => {
if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
@@ -363,7 +391,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- public unhighlightSearchTerms = () => {
+ unhighlightSearchTerms = () => {
if (window.screen.width < 600) null;
else if (this._editorView && (this._editorView as any).docView) {
const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
@@ -409,7 +437,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
target._fitToBox = true;
const node = schema.nodes.dashDoc.create({
width: target[WidthSym](), height: target[HeightSym](),
- title: "dashDoc", docid: target[Id],
+ title: "dashDoc",
+ docid: target[Id],
float: "right"
});
const view = this._editorView!;
@@ -463,7 +492,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return ret;
}
- static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
updateHighlights = () => {
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) {
@@ -548,7 +576,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: `${FormattedTextBox._canAnnotate ? "Hide" : "Show"} Annotation Bar`, event: () => FormattedTextBox._canAnnotate = !FormattedTextBox._canAnnotate, icon: "expand-arrows-alt" });
uicontrols.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, 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" });
@@ -637,26 +665,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- @computed get config() {
- this._keymap = buildKeymap(schema, this.props);
- this._rules = new RichTextRules(this.props.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(editorView); } })
- ]
- };
- }
-
makeLinkAnchor(anchorDoc?: Doc, location?: string, targetHref?: string, title?: string) {
const state = this._editorView?.state;
if (state) {
@@ -761,7 +769,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
instance => {
if (instance) {
this.pullFromGoogleDoc(this.checkState);
- this.dataDoc[GoogleRef] && this.dataDoc.unchanged && runInAction(() => instance.isAnimatingFetch = true);
+ this.dataDoc[GoogleRef] && this.dataDoc.googleDocUnchanged && runInAction(() => instance.isAnimatingFetch = true);
}
}
);
@@ -791,7 +799,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
() => {
if (!DocumentButtonBar.hasPulledHack) {
DocumentButtonBar.hasPulledHack = true;
- this.pullFromGoogleDoc(this.dataDoc.unchanged ? this.checkState : this.updateState);
+ this.pullFromGoogleDoc(this.dataDoc.googleDocUnchanged ? this.checkState : this.updateState);
}
}
);
@@ -866,7 +874,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
response && (this.dataDoc[GoogleRef] = response.documentId);
const pushSuccess = response !== undefined && !("errors" in response);
- dataDoc.unchanged = pushSuccess;
+ dataDoc.googleDocUnchanged = pushSuccess;
DocumentButtonBar.Instance.startPushOutcome(pushSuccess);
}
};
@@ -911,7 +919,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}, 0);
dataDoc.title = exportState.title;
this.dataDoc["title-custom"] = true;
- dataDoc.unchanged = true;
+ dataDoc.googleDocUnchanged = true;
} else {
delete dataDoc[GoogleRef];
}
@@ -923,7 +931,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc);
const equalTitles = dataDoc.title === exportState.title;
const unchanged = equalContent && equalTitles;
- dataDoc.unchanged = unchanged;
+ dataDoc.googleDocUnchanged = unchanged;
DocumentButtonBar.Instance.setPullState(unchanged);
}
}
@@ -1100,11 +1108,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
}
- _downEvent: any;
- _downX = 0;
- _downY = 0;
- _break = false;
- _collapsed = false;
onPointerDown = (e: React.PointerEvent): void => {
if ((e.target as any).tagName === "AUDIOTAG") {
e.preventDefault();
@@ -1152,9 +1155,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
document.removeEventListener("pointerup", this.onSelectEnd);
document.removeEventListener("pointermove", this.onSelectMove);
}
-
onPointerUp = (e: React.PointerEvent): void => {
- if (!this._editorView?.state.selection.empty && FormattedTextBox.CanAnnotate) this.setupAnchorMenu();
+ if (!this._editorView?.state.selection.empty && FormattedTextBox._canAnnotate) this.setupAnchorMenu();
if (!this._downEvent) return;
this._downEvent = false;
if (!(e.nativeEvent as any).formattedHandled && this.active(true)) {
@@ -1171,7 +1173,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
e.stopPropagation();
}
}
-
@action
onDoubleClick = (e: React.MouseEvent): void => {
FormattedTextBoxComment.textBox = this;
@@ -1191,7 +1192,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
e.stopPropagation();
}
}
-
@action
onFocused = (e: React.FocusEvent): void => {
FormattedTextBox.FocusedBox = this;
@@ -1223,12 +1223,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
e.stopPropagation();
}
}
-
- static _highlightStyleSheet: any = addStyleSheet();
- static _bulletStyleSheet: any = addStyleSheet();
- static _userStyleSheet: any = addStyleSheet();
- _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
- _forceDownNode: Node | undefined;
onClick = (e: React.MouseEvent): void => {
if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) {
this._forceDownNode = undefined;
@@ -1264,7 +1258,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._forceUncollapse = !(this._editorView!.root as any).getSelection().isCollapsed;
this._forceDownNode = (this._editorView!.state.selection as NodeSelection)?.node;
}
-
// 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, downNode: Node | undefined = undefined, selectOrderedList: boolean = false) {
this._forceUncollapse = false;
@@ -1314,24 +1307,20 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
view.root.addEventListener("mouseup", view.mouseDown.up);
}
}
-
- public startUndoTypingBatch() {
+ startUndoTypingBatch() {
!this._undoTyping && (this._undoTyping = UndoManager.StartBatch("undoTyping"));
}
-
public endUndoTypingBatch() {
const wasUndoing = this._undoTyping;
this._undoTyping?.end();
this._undoTyping = undefined;
return wasUndoing;
}
- public static LiveTextUndo: UndoManager.Batch | undefined;
- public static HadSelection: boolean = false;
onBlur = (e: any) => {
if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
}
- FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
+ FormattedTextBox._hadSelection = window.getSelection()?.toString() !== "";
this.endUndoTypingBatch();
FormattedTextBox.LiveTextUndo?.end();
@@ -1350,7 +1339,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._lastText = curText;
}
}
-
onKeyDown = (e: React.KeyboardEvent) => {
// single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container)
if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) {
@@ -1372,29 +1360,27 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._rules!.EnteringStyle = false;
}
e.stopPropagation();
- if (e.key === "Escape") {
- this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from)));
- (document.activeElement as any).blur?.();
- SelectionManager.DeselectAll();
- RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
- } else {
- if (e.key === "Tab" || e.key === "Enter") {
- if (e.key === "Enter") this.insertTime();
- e.preventDefault();
- }
- if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
- const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
- this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({})).addStoredMark(mark));
- }
- this.startUndoTypingBatch();
+ 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?.();
+ SelectionManager.DeselectAll();
+ RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
+ return;
+ case "Enter": this.insertTime();
+ case "Tab": e.preventDefault(); break;
+ default: if (this._lastTimedMark?.attrs.userid === Doc.CurrentUserEmail) break;
+ case " ":
+ this._editorView!.dispatch(this._editorView!.state.tr.removeStoredMark(schema.marks.user_mark.create({}))
+ .addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
}
+ this.startUndoTypingBatch();
}
-
- ondrop = (eve: React.DragEvent) => {
+ ondrop = (e: React.DragEvent) => {
this._editorView!.dispatch(updateBullets(this._editorView!.state.tr, this._editorView!.state.schema));
- eve.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
+ e.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
}
- onScroll = (ev: React.UIEvent) => {
+ onScroll = (e: React.UIEvent) => {
if (!LinkDocPreview.LinkInfo && this._scrollRef.current) {
this._ignoreScroll = true;
this.layoutDoc._scrollTop = this._scrollRef.current.scrollTop;
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 913cfdcc2..05d81f40f 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,7 +1,7 @@
import React = require("react");
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
import { Id } from "../../../fields/FieldSymbols";
import { List } from "../../../fields/List";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
@@ -21,16 +21,11 @@ interface IAnnotationProps extends FieldViewProps {
export
class Annotation extends React.Component<IAnnotationProps> {
render() {
- return DocListCast(this.props.anno.textInlineAnnotations).map(a =>
- <RegionAnnotation {...this.props} showInfo={this.props.showInfo} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />);
+ return DocListCast(this.props.anno.textInlineAnnotations).map(a => <RegionAnnotation {...this.props} document={a} key={a[Id]} />);
}
}
interface IRegionAnnotationProps extends IAnnotationProps {
- x: number;
- y: number;
- width: number;
- height: number;
document: Doc;
}
@observer
@@ -96,10 +91,10 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
render() {
return (<div className="pdfAnnotation" onPointerEnter={() => this.props.showInfo(this.props.anno)} onPointerLeave={() => this.props.showInfo(undefined)} onPointerDown={this.onPointerDown} ref={this._mainCont}
style={{
- top: this.props.y,
- left: this.props.x,
- width: this.props.width,
- height: this.props.height,
+ left: NumCast(this.props.document.x),
+ top: NumCast(this.props.document.y),
+ width: NumCast(this.props.document._width),
+ height: NumCast(this.props.document._height),
opacity: this._brushed ? 0.5 : undefined,
backgroundColor: this._brushed ? "orange" : StrCast(this.props.document.backgroundColor),
}} >
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 28d7b0954..73aea9737 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -8,8 +8,7 @@ import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { InkTool } from "../../../fields/InkField";
import { createSchema, makeInterface } from "../../../fields/Schema";
-import { ScriptField } from "../../../fields/ScriptField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast, ScriptCast } from "../../../fields/Types";
import { PdfField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from "../../../Utils";
@@ -66,12 +65,12 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@observable private _pageSizes: { width: number, height: number }[] = [];
@observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
@observable private _script: CompiledScript = CompileScript("return true") as CompiledScript;
- @observable private Index: number = -1;
@observable private _marqueeing: number[] | undefined;
@observable private _showWaiting = true;
@observable private _showCover = false;
@observable private _zoomed = 1;
@observable private _overlayAnnoInfo: Opt<Doc>;
+ @observable private Index: number = -1;
private _pdfViewer: any;
private _styleRule: any; // stylesheet rule for making hyperlinks clickable
@@ -89,7 +88,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
private _viewerIsSetup = false;
private _ignoreScroll = false;
private _initialScroll: Opt<number>;
- private _smoothScrolling = true;
+ private _forcedScroll = true;
@computed get allAnnotations() {
return DocUtils.FilterDocs(DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]), this.props.docFilters(), this.props.docRangeFilters(), undefined);
@@ -158,12 +157,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
copy = (e: ClipboardEvent) => {
if (this.active() && e.clipboardData) {
- //const annoDoc = this.makeAnnotationDocument("rgba(3,144,152,0.3)"); // copied text markup color (blueish)
- //if (annoDoc) {
e.clipboardData.setData("text/plain", this._selectionText);
- // e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
- // e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
- //}
e.preventDefault();
}
}
@@ -174,12 +168,13 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) =>
this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => {
+ const page0or180 = page.rotate === 0 || page.rotate === 180;
this._pageSizes.splice(i, 1, {
- width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]),
- height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0])
+ width: (page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1]),
+ height: (page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0])
});
- i === this.props.pdf.numPages - 1 && this.props.loaded?.((page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]),
- (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]), i);
+ i === this.props.pdf.numPages - 1 && this.props.loaded?.((page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1]),
+ (page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0]), i);
}))));
this.Document.scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72;
}
@@ -207,13 +202,13 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
setupPdfJsViewer = async () => {
if (this._viewerIsSetup) return;
- else this._viewerIsSetup = true;
+ this._viewerIsSetup = true;
this._showWaiting = true;
this.props.setPdfViewer(this);
await this.initialLoad();
this._disposers.filterScript = reaction(
- () => Cast(this.Document.filterScript, ScriptField),
+ () => ScriptCast(this.Document.filterScript),
action(scriptField => {
const oldScript = this._script.originalScript;
this._script = scriptField?.script.compiled ? scriptField.script : CompileScript("return true") as CompiledScript;
@@ -234,25 +229,23 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
document.removeEventListener("pagesinit", this.pagesinit);
var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : "";
this._disposers.scroll = reaction(
- () => NumCast(this.Document._scrollTop),
+ () => Math.abs(NumCast(this.Document._scrollTop)),
(pos) => {
if (!this._ignoreScroll) {
(this._showCover || this._showWaiting) && this.setupPdfJsViewer();
const viewTrans = quickScroll ?? StrCast(this.Document._viewTransition);
- const delay = this._mainCont.current ? 0 : 250; // wait for mainCont and try again to scroll
const durationMiliStr = viewTrans.match(/([0-9]*)ms/);
const durationSecStr = viewTrans.match(/([0-9.]*)s/);
const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
+ this._forcedScroll = true;
if (duration) {
- this._smoothScrolling = true;
setTimeout(() => {
- this._mainCont.current && smoothScroll(duration, this._mainCont.current, Math.abs(pos || 0));
- setTimeout(() => this._smoothScrolling = false, duration);
- }, delay);
+ this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos);
+ setTimeout(() => this._forcedScroll = false, duration);
+ }, this._mainCont.current ? 0 : 250); // wait for mainCont and try again to scroll
} else {
- this._smoothScrolling = true;
- this._mainCont.current?.scrollTo({ top: Math.abs(pos || 0) });
- this._smoothScrolling = false;
+ this._mainCont.current?.scrollTo({ top: pos });
+ this._forcedScroll = false;
}
}
},
@@ -267,8 +260,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
createPdfViewer() {
if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
+ console.log("PDFViewer- I guess we got here");
if (this._retries < 5) {
this._retries++;
+ console.log("PDFViewer- retry num:" + this._retries);
setTimeout(() => this.createPdfViewer(), 1000);
}
return;
@@ -277,9 +272,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
document.addEventListener("copy", this.copy);
const eventBus = new PDFJSViewer.EventBus(true);
eventBus._on("pagesinit", this.pagesinit);
- eventBus._on("pagerendered", action(() => {
- this._showWaiting = false;
- }));
+ eventBus._on("pagerendered", action(() => this._showWaiting = false));
const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus });
const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
this._pdfViewer = new PDFJSViewer.PDFViewer({
@@ -324,8 +317,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
onScroll = (e: React.UIEvent<HTMLElement>) => {
- if (this._mainCont.current && !this._smoothScrolling) {
- this._ignoreScroll = true;
+ if (this._mainCont.current && !this._forcedScroll) {
+ this._ignoreScroll = true; // the pdf scrolled, so we need to tell the Doc to scroll but we don't want the doc to then try to set the PDF scroll pos (which would interfere with the smooth scroll animation)
if (!LinkDocPreview.LinkInfo) {
this.layoutDoc._scrollTop = this._mainCont.current.scrollTop;
}
@@ -343,32 +336,24 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
return index;
}
-
@action
search = (searchString: string, fwd: boolean, clear: boolean = false) => {
+ const findOpts = {
+ caseSensitive: false,
+ findPrevious: !fwd,
+ highlightAll: true,
+ phraseSearch: true,
+ query: searchString
+ };
if (clear) {
this._pdfViewer?.findController.executeCommand('reset', { query: "" });
} else if (!searchString) {
fwd ? this.nextAnnotation() : this.prevAnnotation();
} else if (this._pdfViewer?.pageViewsReady) {
- this._pdfViewer.findController.executeCommand('findagain', {
- caseSensitive: false,
- findPrevious: !fwd,
- highlightAll: true,
- phraseSearch: true,
- query: searchString
- });
+ this._pdfViewer.findController.executeCommand('findagain', findOpts);
}
else if (this._mainCont.current) {
- const executeFind = () => {
- this._pdfViewer.findController.executeCommand('find', {
- caseSensitive: false,
- findPrevious: !fwd,
- highlightAll: true,
- phraseSearch: true,
- query: searchString
- });
- };
+ const executeFind = () => this._pdfViewer.findController.executeCommand('find', findOpts);
this._mainCont.current.addEventListener("pagesloaded", executeFind);
this._mainCont.current.addEventListener("pagerendered", executeFind);
}
@@ -376,7 +361,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
onPointerDown = (e: React.PointerEvent): void => {
- const hit = document.elementFromPoint(e.clientX, e.clientY);
+ // const hit = document.elementFromPoint(e.clientX, e.clientY);
// bcz: Change. drag selecting requires that preventDefault is NOT called. This used to happen in DocumentView,
// but that's changed, so this shouldn't be needed.
// if (hit && hit.localName === "span" && this.annotationsActive(true)) { // drag selecting text stops propagation
@@ -414,11 +399,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
this.props.select(false);
}
- @action
- onSelectMove = (e: PointerEvent): void => {
- // if (e.target && (e.target as any).parentElement === this._mainCont.current)
- e.stopPropagation();
- }
+ onSelectMove = (e: PointerEvent) => e.stopPropagation();
@action
onSelectEnd = (e: PointerEvent): void => {
@@ -429,8 +410,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
const sel = window.getSelection();
if (sel?.type === "Range") {
- const selRange = sel.getRangeAt(0);
- this.createTextAnnotation(sel, selRange);
+ this.createTextAnnotation(sel, sel.getRangeAt(0));
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
}
}
@@ -442,18 +422,16 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
const clientRects = selRange.getClientRects();
for (let i = 0; i < clientRects.length; i++) {
const rect = clientRects.item(i);
- if (rect) {
+ if (rect && rect.width !== this._mainCont.current.clientWidth) {
const scaleX = this._mainCont.current.offsetWidth / boundingRect.width;
- if (rect.width !== this._mainCont.current.clientWidth) {
- const annoBox = document.createElement("div");
- annoBox.className = "marqueeAnnotator-annotationBox";
- // transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * scaleX / this._zoomed + this._mainCont.current.scrollTop).toString();
- annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / this._zoomed).toString();
- annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / this._zoomed).toString();
- annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / this._zoomed).toString();
- this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
- }
+ const annoBox = document.createElement("div");
+ annoBox.className = "marqueeAnnotator-annotationBox";
+ // transforms the positions from screen onto the pdf div
+ annoBox.style.top = ((rect.top - boundingRect.top) * scaleX / this._zoomed + this._mainCont.current.scrollTop).toString();
+ annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / this._zoomed).toString();
+ annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / this._zoomed).toString();
+ annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / this._zoomed).toString();
+ this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
}
}
}
@@ -509,7 +487,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
@computed get annotationLayer() {
- TraceMobx();
return <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.Document), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
{this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
<Annotation {...this.props} fieldKey={this.fieldKey + "-annotations"} showInfo={this.showInfo} dataDoc={this.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)