aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts2
-rw-r--r--src/client/util/DocumentManager.ts8
-rw-r--r--src/client/util/LinkManager.ts3
-rw-r--r--src/client/views/DocumentButtonBar.tsx2
-rw-r--r--src/client/views/GlobalKeyHandler.ts4
-rw-r--r--src/client/views/PreviewCursor.tsx2
-rw-r--r--src/client/views/collections/CollectionSubView.tsx5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx4
-rw-r--r--src/client/views/nodes/ColorBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx9
-rw-r--r--src/client/views/nodes/PDFBox.scss2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss58
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx49
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx7
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts30
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts2
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts2
-rw-r--r--src/client/views/pdf/Annotation.tsx5
-rw-r--r--src/client/views/pdf/PDFMenu.tsx1
-rw-r--r--src/client/views/pdf/PDFViewer.tsx53
-rw-r--r--src/server/ApiManagers/PDFManager.ts7
21 files changed, 157 insertions, 100 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index aed523fa4..0fc58c39d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -533,6 +533,8 @@ export namespace Docs {
const dataDoc = MakeDataDelegate(proto, protoProps, data, fieldKey);
const viewDoc = Doc.MakeDelegate(dataDoc, delegId);
+ proto.links = ComputedField.MakeFunction("links(self)");
+
viewDoc.author = Doc.CurrentUserEmail;
viewDoc.type !== DocumentType.LINK && DocUtils.MakeLinkToActiveAudio(viewDoc);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 78c05f572..40d6b039a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -130,7 +130,7 @@ export class DocumentManager {
willZoom: boolean, // whether to zoom doc to take up most of screen
createViewFunc = DocumentManager.addRightSplit, // how to create a view of the doc if it doesn't exist
docContext?: Doc, // context to load that should contain the target
- linkId?: string, // link that's being followed
+ linkDoc?: Doc, // link that's being followed
closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there
originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
finished?: () => void
@@ -140,7 +140,7 @@ export class DocumentManager {
const highlight = () => {
const finalDocView = getFirstDocView(targetDoc);
if (finalDocView) {
- finalDocView.layoutDoc.scrollToLinkID = linkId;
+ finalDocView.layoutDoc.scrollToLinkID = linkDoc?.[Id];
Doc.linkFollowHighlight(finalDocView.props.Document);
}
};
@@ -195,7 +195,7 @@ export class DocumentManager {
const finalDocView = getFirstDocView(targetDoc);
const finalDocContextView = getFirstDocView(targetDocContext);
setTimeout(() => // if not, wait a bit to see if the context can be loaded (e.g., a PDF). wait interval heurisitic tries to guess how we're animating based on what's just become visible
- this.jumpToDocument(targetDoc, willZoom, createViewFunc, undefined, linkId, true, undefined, finished), // pass true this time for closeContextIfNotFound
+ this.jumpToDocument(targetDoc, willZoom, createViewFunc, undefined, linkDoc, true, undefined, finished), // pass true this time for closeContextIfNotFound
finalDocView ? 0 : finalDocContextView ? 250 : 2000); // so call jump to doc again and if the doc isn't found, it will be created.
}, 0);
}
@@ -224,7 +224,7 @@ export class DocumentManager {
containerDoc.currentTimecode = targetTimecode;
const targetContext = await target?.context as Doc;
const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
- DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc[Id], undefined, doc, finished);
+ DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "onRight"), finished), targetNavContext, linkDoc, undefined, doc, finished);
} else {
finished?.();
}
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 47b2541bd..438f3eb9b 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -70,6 +70,9 @@ export class LinkManager {
const protomatch2 = Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, null));
return protomatch1 || protomatch2 || Doc.AreProtosEqual(link, anchor);
});
+ DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).map(anno => {
+ related.push(...LinkManager.Instance.getAllRelatedLinks(anno));
+ })
return related;
}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 49c15f764..fcaea0f0b 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -271,7 +271,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
const considerPush = isText && this.considerGoogleDocsPush;
return <div className="documentButtonBar">
<div className="documentButtonBar-button">
- <DocumentLinksButton View={this.view0!} />
+ <DocumentLinksButton View={this.view0!} AlwaysOn={true} />
</div>
<div className="documentButtonBar-button">
{this.templateButton}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 7bc8cf6a7..e3546dece 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -15,11 +15,11 @@ import { SelectionManager } from "../util/SelectionManager";
import SharingManager from "../util/SharingManager";
import { undoBatch, UndoManager } from "../util/UndoManager";
import { CollectionDockingView } from "./collections/CollectionDockingView";
-import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView";
import { DocumentDecorations } from "./DocumentDecorations";
import { MainView } from "./MainView";
import { DocumentView } from "./nodes/DocumentView";
import { DocumentLinksButton } from "./nodes/DocumentLinksButton";
+import PDFMenu from "./pdf/PDFMenu";
const modifiers = ["control", "meta", "shift", "alt"];
type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise<KeyControlInfo>;
@@ -264,7 +264,7 @@ export default class KeyManager {
}
break;
case "c":
- if (DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) {
+ if (!PDFMenu.Instance.Active && DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) {
const bds = DocumentDecorations.Instance.Bounds;
const pt = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2);
const text = `__DashCloneId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":");
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index e27f6b95a..1ab99881d 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -9,6 +9,7 @@ import { Transform } from "../util/Transform";
import { DocServer } from '../DocServer';
import { undoBatch } from '../util/UndoManager';
import { NumCast } from '../../fields/Types';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
@observer
export class PreviewCursor extends React.Component<{}> {
@@ -81,6 +82,7 @@ export class PreviewCursor extends React.Component<{}> {
e.stopPropagation();
} else {
// creates text document
+ FormattedTextBox.PasteOnLoad = e;
undoBatch(() => PreviewCursor._addLiveTextDoc(Docs.Create.TextDocument("", {
_width: 500,
limitHeight: 400,
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 00d6d59c8..570f9375e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -19,6 +19,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager";
import { DocComponent } from "../DocComponent";
import { FieldViewProps } from "../nodes/FieldView";
import React = require("react");
+import * as rp from 'request-promise';
export interface CollectionViewProps extends FieldViewProps {
addDocument: (document: Doc | Doc[]) => boolean;
@@ -400,9 +401,9 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const item = e.dataTransfer.items[i];
if (item.kind === "string" && item.type.includes("uri")) {
const stringContents = await new Promise<string>(resolve => item.getAsString(resolve));
- const type = "html";// (await rp.head(Utils.CorsProxy(stringContents)))["content-type"];
+ const type = (await rp.head(Utils.CorsProxy(stringContents)))["content-type"];
if (type) {
- const doc = await DocUtils.DocumentFromType(type, stringContents, options);
+ const doc = await DocUtils.DocumentFromType(type, Utils.CorsProxy(stringContents), options);
doc && generatedDocuments.push(doc);
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1e2f54e28..2e543f137 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1383,9 +1383,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onPointerDown={this.onPointerDown}
onPointerMove={this.onCursorMove}
onDrop={this.onExternalDrop.bind(this)}
- onDragOver={e => {
- e.preventDefault();
- }}
+ onDragOver={e => e.preventDefault()}
onContextMenu={this.onContextMenu}
style={{
pointerEvents: this.backgroundEvents ? "all" : undefined,
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index d6d9a8cfd..137b387c0 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -39,7 +39,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
if (view.props.LayoutTemplate?.() || view.props.LayoutTemplateString) { // this situation typically occurs when you have a link dot
targetDoc.backgroundColor = Doc.UserDoc().backgroundColor; // bcz: don't know how to change the color of an inline template...
}
- else if (StrCast(Doc.Layout(view.props.Document).layout).includes("FormattedTextBox") && FormattedTextBox.HadSelection) {
+ else if (StrCast(Doc.Layout(view.props.Document).layout).includes("FormattedTextBox") && window.getSelection()?.toString() !== "") {
Doc.Layout(view.props.Document)[Doc.LayoutFieldKey(view.props.Document) + "-color"] = Doc.UserDoc().backgroundColor;
} else {
Doc.Layout(view.props.Document)._backgroundColor = Doc.UserDoc().backgroundColor; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index ef900fff6..4f4f12521 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -17,6 +17,7 @@ export const Flyout = higflyout.default;
interface DocumentLinksButtonProps {
View: DocumentView;
Offset?: number[];
+ AlwaysOn?: boolean;
}
@observer
export class DocumentLinksButton extends React.Component<DocumentLinksButtonProps, {}> {
@@ -80,17 +81,17 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
@computed
get linkButton() {
const links = DocListCast(this.props.View.props.Document.links);
- return !links.length || links[0].hidden ? (null) :
- <div title="Drag(create link) Tap(view links)" ref={this._linkButton} style={{ position: "absolute", left: this.props.Offset?.[0] }}>
+ return (!links.length || links[0].hidden) && !this.props.AlwaysOn ? (null) :
+ <div title="Drag(create link) Tap(view links)" ref={this._linkButton} style={{ minWidth: 20, minHeight: 20, position: "absolute", left: this.props.Offset?.[0] }}>
<div className={"documentLinksButton"} style={{ backgroundColor: DocumentLinksButton.StartLink ? "transparent" : "" }}
onPointerDown={this.onLinkButtonDown}
onPointerLeave={action(() => LinkDocPreview.LinkInfo = undefined)}
- onPointerEnter={action(e => LinkDocPreview.LinkInfo = {
+ onPointerEnter={action(e => links.length && (LinkDocPreview.LinkInfo = {
addDocTab: this.props.View.props.addDocTab,
linkSrc: this.props.View.props.Document,
linkDoc: links[0],
Location: [e.clientX, e.clientY + 20]
- })} >
+ }))} >
{links.length ? links.length : <FontAwesomeIcon className="documentdecorations-icon" icon="link" size="sm" />}
</div>
{DocumentLinksButton.StartLink && DocumentLinksButton.StartLink !== this.props.View ? <div className={"documentLinksButton-endLink"} onPointerDown={this.completeLink} /> : (null)}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 3e09fe519..f55c4f7d6 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -1,7 +1,7 @@
.pdfBox,
.pdfBox-interactive {
display: inline-block;
- position: absolute;
+ position: relative;
height: 100%;
width: 100%;
overflow: hidden;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 20e13a599..678494b27 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -305,37 +305,37 @@ footnote::after {
margin-left: 1em;
font-family: inherit;
}
- .bullet { p {display: inline; font-family: inherit} margin-left: 0; }
- .bullet1 { p {display: inline; font-family: inherit} }
- .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p {display: inline; font-family: inherit} font-size: smaller; }
-
- .decimal1-ol { counter-reset: deci1; p {display: inline; font-family: inherit} margin-left: 0; }
- .decimal2-ol { counter-reset: deci2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1em;}
- .decimal3-ol { counter-reset: deci3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
- .decimal4-ol { counter-reset: deci4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3em;}
- .decimal5-ol { counter-reset: deci5; p {display: inline; font-family: inherit} font-size: smaller; }
- .decimal6-ol { counter-reset: deci6; p {display: inline; font-family: inherit} font-size: smaller; }
- .decimal7-ol { counter-reset: deci7; p {display: inline; font-family: inherit} font-size: smaller; }
-
- .multi1-ol { counter-reset: multi1; p {display: inline; font-family: inherit} margin-left: 0; padding-left: 1.2em }
- .multi2-ol { counter-reset: multi2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1.4em;}
- .multi3-ol { counter-reset: multi3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
- .multi4-ol { counter-reset: multi4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
+ .bullet { p {display: inline-block; font-family: inherit} margin-left: 0; }
+ .bullet1 { p {display: inline-block; font-family: inherit} }
+ .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p {display: inline-block; font-family: inherit} font-size: smaller; }
+
+ .decimal1-ol { counter-reset: deci1; p {display: inline-block; font-family: inherit} margin-left: 0; }
+ .decimal2-ol { counter-reset: deci2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 1em;}
+ .decimal3-ol { counter-reset: deci3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2em;}
+ .decimal4-ol { counter-reset: deci4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3em;}
+ .decimal5-ol { counter-reset: deci5; p {display: inline-block; font-family: inherit} font-size: smaller; }
+ .decimal6-ol { counter-reset: deci6; p {display: inline-block; font-family: inherit} font-size: smaller; }
+ .decimal7-ol { counter-reset: deci7; p {display: inline-block; font-family: inherit} font-size: smaller; }
+
+ .multi1-ol { counter-reset: multi1; p {display: inline-block; font-family: inherit} margin-left: 0; padding-left: 1.2em }
+ .multi2-ol { counter-reset: multi2; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 1.4em;}
+ .multi3-ol { counter-reset: multi3; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 2em;}
+ .multi4-ol { counter-reset: multi4; p {display: inline-block; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
- .bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; margin-left: -1em; width: 1em; content:" " }
-
- .decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
- .decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
- .decimal3:before { transition: 0.5s;counter-increment: deci3; display: inline-block; margin-left: -2.85em;width: 2.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) ". "; }
- .decimal4:before { transition: 0.5s;counter-increment: deci4; display: inline-block; margin-left: -3.85em;width: 3.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) ". "; }
- .decimal5:before { transition: 0.5s;counter-increment: deci5; display: inline-block; margin-left: -2em; width: 5em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ". "; }
- .decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; }
- .decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; }
+ .bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; vertical-align: top; margin-left: -1em; width: 1em; content:" " }
+
+ .decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; vertical-align: top; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
+ .decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; vertical-align: top; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
+ .decimal3:before { transition: 0.5s;counter-increment: deci3; display: inline-block; vertical-align: top; margin-left: -2.85em;width: 2.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) ". "; }
+ .decimal4:before { transition: 0.5s;counter-increment: deci4; display: inline-block; vertical-align: top; margin-left: -3.85em;width: 3.85em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) ". "; }
+ .decimal5:before { transition: 0.5s;counter-increment: deci5; display: inline-block; vertical-align: top; margin-left: -2em; width: 5em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) ". "; }
+ .decimal6:before { transition: 0.5s;counter-increment: deci6; display: inline-block; vertical-align: top; margin-left: -2em; width: 6em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) ". "; }
+ .decimal7:before { transition: 0.5s;counter-increment: deci7; display: inline-block; vertical-align: top; margin-left: -2em; width: 7em; content: counter(deci1) "."counter(deci2) "."counter(deci3) "."counter(deci4) "."counter(deci5) "."counter(deci6) "."counter(deci7) ". "; }
- .multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
- .multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
- .multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
- .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
+ .multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; vertical-align: top; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
+ .multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; vertical-align: top; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
+ .multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; vertical-align: top; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
+ .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; vertical-align: top; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
}
.formattedTextBox-inner-rounded-selected,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index cdf231985..135ab8cbc 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { isEqual } from "lodash";
import { action, computed, IReactionDisposer, Lambda, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { baseKeymap } from "prosemirror-commands";
+import { baseKeymap, selectAll } from "prosemirror-commands";
import { history } from "prosemirror-history";
import { inputRules } from 'prosemirror-inputrules';
import { keymap } from "prosemirror-keymap";
@@ -102,6 +102,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public static FocusedBox: FormattedTextBox | undefined;
public static SelectOnLoad = "";
+ public static PasteOnLoad: ClipboardEvent | undefined;
public static SelectOnLoadChar = "";
public static IsFragment(html: string) {
return html.indexOf("data-pm-slice") !== -1;
@@ -275,6 +276,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const end = this._editorView.state.doc.nodeSize - 2;
this._editorView.dispatch(this._editorView.state.tr.removeMark(0, end, mark).removeMark(0, end, activeMark));
}
+ if (FormattedTextBox.PasteOnLoad) {
+ const pdfDocId = FormattedTextBox.PasteOnLoad.clipboardData?.getData("dash/pdfOrigin");
+ const pdfRegionId = FormattedTextBox.PasteOnLoad.clipboardData?.getData("dash/pdfRegion");
+ FormattedTextBox.PasteOnLoad = undefined;
+ setTimeout(() => pdfDocId && pdfRegionId && this.addPdfReference(pdfDocId, pdfRegionId, undefined), 10);
+ }
}
adoptAnnotation = (start: number, end: number, mark: Mark) => {
const view = this._editorView!;
@@ -726,7 +733,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
const marks = [...node.marks];
const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.link);
- return linkIndex !== -1 && marks[linkIndex].attrs.allRefs.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined;
+ return linkIndex !== -1 && marks[linkIndex].attrs.allHrefs.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined;
};
let start = 0;
@@ -857,8 +864,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
const cbe = event as ClipboardEvent;
- const pdfDocId = cbe.clipboardData && cbe.clipboardData.getData("dash/pdfOrigin");
- const pdfRegionId = cbe.clipboardData && cbe.clipboardData.getData("dash/pdfRegion");
+ const pdfDocId = cbe.clipboardData?.getData("dash/pdfOrigin");
+ const pdfRegionId = cbe.clipboardData?.getData("dash/pdfRegion");
+ return pdfDocId && pdfRegionId && this.addPdfReference(pdfDocId, pdfRegionId, slice) ? true : false;
+ }
+
+ addPdfReference = (pdfDocId: string, pdfRegionId: string, slice?: Slice) => {
+ const view = this._editorView!;
if (pdfDocId && pdfRegionId) {
DocServer.GetRefField(pdfDocId).then(pdfDoc => {
DocServer.GetRefField(pdfRegionId).then(pdfRegion => {
@@ -866,17 +878,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
setTimeout(async () => {
const targetField = Doc.LayoutFieldKey(pdfDoc);
const targetAnnotations = await DocListCastAsync(pdfDoc[DataSym][targetField + "-annotations"]);// bcz: better to have the PDF's view handle updating its own annotations
- targetAnnotations?.push(pdfRegion);
+ if (targetAnnotations) targetAnnotations.push(pdfRegion);
+ else Doc.AddDocToList(pdfDoc[DataSym], targetField + "-annotations", pdfRegion);
});
const link = DocUtils.MakeLink({ doc: this.rootDoc }, { doc: pdfRegion }, "PDF pasted");
if (link) {
- cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
const linkId = link[Id];
- const frag = addMarkToFrag(slice.content, (node: Node) => addLinkMark(node, StrCast(pdfDoc.title), linkId));
- slice = new Slice(frag, slice.openStart, slice.openEnd);
- const tr = view.state.tr.replaceSelection(slice);
- view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+ const quote = view.state.schema.nodes.blockquote.create();
+ quote.content = addMarkToFrag(slice?.content || view.state.doc.content, (node: Node) => addLinkMark(node, StrCast(pdfDoc.title), linkId));
+ const newSlice = new Slice(Fragment.from(quote), slice?.openStart || 0, slice?.openEnd || 0);
+ if (slice) {
+ view.dispatch(view.state.tr.replaceSelection(newSlice).scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+ } else {
+ selectAll(view.state, (tx: Transaction) => view.dispatch(tx.replaceSelection(newSlice).scrollIntoView()));
+
+ }
}
}
});
@@ -898,7 +915,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
const marks = [...node.marks];
const linkIndex = marks.findIndex(mark => mark.type.name === "link");
- const link = view.state.schema.mark(view.state.schema.marks.link, { href: Utils.prepend(`/doc/${linkId}`), location: "onRight", title: title, docref: true });
+ const allHrefs = [{ href: Utils.prepend(`/doc/${linkId}`), title, linkId }];
+ const link = view.state.schema.mark(view.state.schema.marks.link, { allHrefs, location: "onRight", title, docref: true });
marks.splice(linkIndex === -1 ? 0 : linkIndex, 1, link);
return node.mark(marks);
}
@@ -933,7 +951,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
- //applyDevTools.applyDevTools(this._editorView);
+ !Doc.UserDoc().noviceMode && applyDevTools.applyDevTools(this._editorView);
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
const { state: { tr }, dispatch } = this._editorView;
@@ -1193,6 +1211,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
+ ondrop = (eve: React.DragEvent) => {
+ 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.
+ }
onscrolled = (ev: React.UIEvent) => {
this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop;
}
@@ -1281,7 +1302,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
})}
>
- <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !this.props.isSelected() ? "none" : undefined }} onScroll={this.onscrolled} ref={this._scrollRef}>
+ <div className={`formattedTextBox-outer`} ref={this._scrollRef}
+ style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !this.props.isSelected() ? "none" : undefined }}
+ onScroll={this.onscrolled} onDrop={this.ondrop} >
<div className={`formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
style={{
padding: `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 0d8e22251..90f2c0aa6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -177,11 +177,12 @@ export class FormattedTextBoxComment {
// this checks if the selection is a hyperlink. If so, it displays the target doc's text for internal links, and the url of the target for external links.
if (set === "none" && state.selection.$from) {
nbef = findStartOfMark(state.selection.$from, view, findLinkMark);
- const naft = findEndOfMark(state.selection.$from, view, findLinkMark);
+ const naft = findEndOfMark(state.selection.$from, view, findLinkMark) || nbef;
let child: any = null;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node));
- const mark = child && findLinkMark(child.marks);
- const href = mark?.attrs.allHrefs.find((item: { href: string }) => item.href)?.href || forceUrl;
+ child = child || (nbef && state.selection.$from.nodeBefore);
+ const mark = child ? findLinkMark(child.marks) : undefined;
+ const href = (!mark?.attrs.docref || naft === nbef) && mark?.attrs.allHrefs.find((item: { href: string }) => item.href)?.href || forceUrl;
if (forceUrl || (href && child && nbef && naft && mark?.attrs.showPreview)) {
FormattedTextBoxComment.tooltipText.textContent = "external => " + href;
(FormattedTextBoxComment.tooltipText as any).href = href;
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 9c91d8007..0abaf3df6 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -1,4 +1,4 @@
-import { chainCommands, exitCode, joinDown, joinUp, lift, selectParentNode, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn, newlineInCode } from "prosemirror-commands";
+import { chainCommands, exitCode, joinDown, joinUp, lift, deleteSelection, joinBackward, selectNodeBackward, setBlockType, splitBlockKeepMarks, toggleMark, wrapIn, newlineInCode } from "prosemirror-commands";
import { liftTarget } from "prosemirror-transform";
import { redo, undo } from "prosemirror-history";
import { undoInputRule } from "prosemirror-inputrules";
@@ -12,6 +12,7 @@ import { Doc, DataSym } from "../../../../fields/Doc";
import { FormattedTextBox } from "./FormattedTextBox";
import { Id } from "../../../../fields/FieldSymbols";
import { Docs } from "../../../documents/Documents";
+import { update } from "lodash";
const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
@@ -43,7 +44,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
//History commands
bind("Mod-z", undo);
- bind("Backspace", undoInputRule);
bind("Shift-Mod-z", redo);
!mac && bind("Mod-y", redo);
@@ -175,6 +175,25 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
}
});
+ var backspace = chainCommands(deleteSelection, joinBackward, selectNodeBackward);
+ bind("Backspace", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => {
+ if (!deleteSelection(state, (tx: Transaction<Schema<any, any>>) => {
+ dispatch(updateBullets(tx, schema));
+ })) {
+ if (!joinBackward(state, (tx: Transaction<Schema<any, any>>) => {
+ dispatch(updateBullets(tx, schema));
+ })) {
+ if (!selectNodeBackward(state, (tx: Transaction<Schema<any, any>>) => {
+ dispatch(updateBullets(tx, schema));
+ })) {
+ return false;
+ }
+ }
+ }
+ return true;
+ });
+
+ //newlineInCode, createParagraphNear, liftEmptyBlock, splitBlock
//command to break line
bind("Enter", (state: EditorState<S>, dispatch: (tx: Transaction<Schema<any, any>>) => void) => {
if (addTextOnRight(false)) return true;
@@ -190,7 +209,12 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
const marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
const cr = state.selection.$from.node().textContent.endsWith("\n");
if (cr || !newlineInCode(state, dispatch)) {
- if (!splitListItem(schema.nodes.list_item)(state, dispatch)) {
+ if (!splitListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
+ const tx3 = updateBullets(tx2, schema);
+ marks && tx3.ensureMarks([...marks]);
+ marks && tx3.setStoredMarks([...marks]);
+ dispatch(tx3);
+ })) {
if (!splitBlockKeepMarks(state, (tx3: Transaction) => {
splitMetadata(marks, tx3);
if (!liftListItem(schema.nodes.list_item)(tx3, dispatch as ((tx: Transaction<Schema<any, any>>) => void))) {
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 1de211f28..b09ac0678 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -38,7 +38,7 @@ export const marks: { [index: string]: MarkSpec } = {
const targetids = node.attrs.allHrefs.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.targetId, "");
const linkids = node.attrs.allHrefs.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.linkId, "");
return node.attrs.docref && node.attrs.title ?
- ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, class: "prosemirror-attribution", title: `${node.attrs.title}` }, node.attrs.title], ["br"]] :
+ ["div", ["span", `"`], ["span", 0], ["span", `"`], ["br"], ["a", { ...node.attrs, href: node.attrs.allHrefs[0].href, class: "prosemirror-attribution" }, node.attrs.title], ["br"]] :
node.attrs.allHrefs.length === 1 ?
["a", { ...node.attrs, class: linkids, targetids, title: `${node.attrs.title}`, href: node.attrs.allHrefs[0].href }, 0] :
["div", { class: "prosemirror-anchor" },
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 0a867912f..afb1f57b7 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -302,7 +302,7 @@ export const nodes: { [index: string]: NodeSpec } = {
mapStyle: { default: "decimal" }, // "decimal", "multi", "bullet"
visibility: { default: true }
},
- content: 'paragraph block*',
+ content: 'paragraph+ | (paragraph ordered_list)',
parseDOM: [{
tag: "li", getAttrs(dom: any) {
return { mapStyle: dom.getAttribute("data-mapStyle"), bulletStyle: dom.getAttribute("data-bulletStyle") };
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index cb6a15f36..d29b638e6 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -8,7 +8,6 @@ import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
import { DocumentManager } from "../../util/DocumentManager";
import PDFMenu from "./PDFMenu";
import "./Annotation.scss";
-import { DocumentView } from "../nodes/DocumentView";
interface IAnnotationProps {
anno: Doc;
@@ -19,7 +18,9 @@ interface IAnnotationProps {
fieldKey: string;
}
-export default class Annotation extends React.Component<IAnnotationProps> {
+@observer
+export default
+ class Annotation extends React.Component<IAnnotationProps> {
render() {
return DocListCast(this.props.anno.annotations).map(a => (
<RegionAnnotation {...this.props} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />));
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index a641bce67..6dcf5cce6 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -26,6 +26,7 @@ export default class PDFMenu extends AntimodeMenu {
public AddTag: (key: string, value: string) => boolean = returnFalse;
public PinToPres: () => void = unimplementedFunction;
public Marquee: { left: number; top: number; width: number; height: number; } | undefined;
+ public get Active() { return this._opacity ? true : false; }
constructor(props: Readonly<{}>) {
super(props);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 50ffd57fe..bd74e0dd0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,5 +1,6 @@
import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
+const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
import * as Pdfjs from "pdfjs-dist";
import "pdfjs-dist/web/pdf_viewer.css";
import { Dictionary } from "typescript-collections";
@@ -41,7 +42,10 @@ export const pageSchema = createSchema({
serachMatch: "boolean"
});
-pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
+//pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
+// The workerSrc property shall be specified.
+pdfjsLib.GlobalWorkerOptions.workerSrc = "https://unpkg.com/pdfjs-dist@2.4.456/build/pdf.worker.min.js";
+
type PdfDocument = makeInterface<[typeof documentSchema, typeof pageSchema]>;
const PdfDocument = makeInterface(documentSchema, pageSchema);
@@ -80,7 +84,6 @@ interface IViewerProps {
export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocument>(PdfDocument) {
static _annotationStyle: any = addStyleSheet();
@observable private _pageSizes: { width: number, height: number }[] = [];
- @observable private _annotations: Doc[] = [];
@observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
@observable private _script: CompiledScript = CompileScript("return true") as CompiledScript;
@observable private Index: number = -1;
@@ -112,17 +115,14 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
private _downY: number = 0;
private _coverPath: any;
private _viewerIsSetup = false;
+ private _lastSearch: string = "";
@computed get allAnnotations() {
- return DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]).filter(
- anno => this._script.run({ this: anno }, console.log, true).result);
- }
-
- @computed get nonDocAnnotations() {
- return this._annotations.filter(anno => this._script.run({ this: anno }, console.log, true).result);
+ return DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]).
+ filter(anno => this._script.run({ this: anno }, console.log, true).result);
}
+ @computed get nonDocAnnotations() { return this.allAnnotations.filter(a => a.annotations); }
- _lastSearch: string = "";
componentDidMount = async () => {
// change the address to be the file address of the PNG version of each page
// file address of the pdf
@@ -148,7 +148,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
runInAction(() => this._showWaiting = this._showCover = true);
this.props.startupLive && this.setupPdfJsViewer();
- this._mainCont.current!.scrollTop = this.layoutDoc._scrollTop || 0;
+ this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0);
this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => {
if (search) {
this.search(Doc.SearchQuery(), true);
@@ -231,25 +231,19 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
await this.initialLoad();
this._scrollTopReactionDisposer = reaction(() => Cast(this.layoutDoc._scrollTop, "number", null),
- (stop) => (stop !== undefined && this.layoutDoc._scrollY === undefined) && (this._mainCont.current!.scrollTop = stop), { fireImmediately: true });
-
- this._annotationReactionDisposer = reaction(
- () => DocListCast(this.dataDoc[this.props.fieldKey + "-annotations"]),
- annotations => annotations?.length && (this._annotations = annotations),
+ (stop) => (stop !== undefined && this.layoutDoc._scrollY === undefined && this._mainCont.current) && (this._mainCont.current.scrollTop = stop),
{ fireImmediately: true });
this._filterReactionDisposer = reaction(
- () => ({ scriptField: Cast(this.Document.filterScript, ScriptField), annos: this._annotations.slice() }),
- action(({ scriptField, annos }: { scriptField: FieldResult<ScriptField>, annos: Doc[] }) => {
+ () => Cast(this.Document.filterScript, ScriptField),
+ action(scriptField => {
const oldScript = this._script.originalScript;
- this._script = scriptField && scriptField.script.compiled ? scriptField.script : CompileScript("return true") as CompiledScript;
+ this._script = scriptField?.script.compiled ? scriptField.script : CompileScript("return true") as CompiledScript;
if (this._script.originalScript !== oldScript) {
this.Index = -1;
}
- annos.forEach(d => d.opacity = this._script.run({ this: d }, console.log, 1).result ? 1 : 0);
}),
- { fireImmediately: true }
- );
+ { fireImmediately: true });
this.createPdfViewer();
}
@@ -270,16 +264,18 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
}
document.removeEventListener("copy", this.copy);
document.addEventListener("copy", this.copy);
- document.addEventListener("pagesinit", this.pagesinit);
- document.addEventListener("pagerendered", action(() => this._showCover = this._showWaiting = false));
+ const eventBus = new PDFJSViewer.EventBus(true);
+ eventBus._on("pagesinit", this.pagesinit);
+ eventBus._on("pagerendered", action(() => this._showCover = this._showWaiting = false));
const pdfLinkService = new PDFJSViewer.PDFLinkService();
- const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService });
+ const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
this._pdfViewer = new PDFJSViewer.PDFViewer({
container: this._mainCont.current,
viewer: this._viewer.current,
linkService: pdfLinkService,
findController: pdfFindController,
renderer: "canvas",
+ eventBus
});
pdfLinkService.setViewer(this._pdfViewer);
pdfLinkService.setDocument(this.props.pdf, null);
@@ -403,7 +399,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
if (!searchString) {
fwd ? this.nextAnnotation() : this.prevAnnotation();
}
- else if (this._pdfViewer._pageViewsReady) {
+ else if (this._pdfViewer.pageViewsReady) {
this._pdfViewer.findController.executeCommand('findagain', {
caseSensitive: false,
findPrevious: !fwd,
@@ -503,7 +499,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
const annoBox = document.createElement("div");
annoBox.className = "pdfViewer-annotationBox";
// transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * scaleY / this._zoomed + this._mainCont.current.scrollTop).toString();
+ 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();
@@ -656,8 +652,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@computed get annotationLayer() {
TraceMobx();
return <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.Document._nativeHeight), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
- {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
- <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)}
+ {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
+ <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)
+ }
</div>;
}
overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts
index d2a9e9cce..e028d628d 100644
--- a/src/server/ApiManagers/PDFManager.ts
+++ b/src/server/ApiManagers/PDFManager.ts
@@ -2,6 +2,7 @@ import ApiManager, { Registration } from "./ApiManager";
import { Method } from "../RouteManager";
import RouteSubscriber from "../RouteSubscriber";
import { existsSync, createReadStream, createWriteStream } from "fs";
+const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
import * as Pdfjs from 'pdfjs-dist';
import { createCanvas } from "canvas";
const imageSize = require("probe-image-size");
@@ -51,11 +52,13 @@ async function getOrCreateThumbnail(coreFilename: string, pageNum: number, res:
}
async function CreateThumbnail(coreFilename: string, pageNum: number, res: express.Response, subtree?: string) {
- const sourcePath = resolve(pathToDirectory(Directory.pdfs), `${subtree ?? ""}${coreFilename}.pdf`);
+ const part1 = subtree ?? "";
+ const filename = `${part1}${coreFilename}.pdf`;
+ const sourcePath = resolve(pathToDirectory(Directory.pdfs), filename);
const documentProxy = await Pdfjs.getDocument(sourcePath).promise;
const factory = new NodeCanvasFactory();
const page = await documentProxy.getPage(pageNum);
- const viewport = page.getViewport(1 as any);
+ const viewport = page.getViewport({ scale: 1, rotation: 0, dontFlip: false });
const { canvas, context } = factory.create(viewport.width, viewport.height);
const renderContext = {
canvasContext: context,