aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/apis/hypothesis/HypothesisUtils.ts111
-rw-r--r--src/client/views/MainView.tsx43
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx7
-rw-r--r--src/client/views/nodes/DocumentLinksButton.tsx38
5 files changed, 103 insertions, 98 deletions
diff --git a/src/client/apis/hypothesis/HypothesisUtils.ts b/src/client/apis/hypothesis/HypothesisUtils.ts
index 855964bf6..5c6e4d31d 100644
--- a/src/client/apis/hypothesis/HypothesisUtils.ts
+++ b/src/client/apis/hypothesis/HypothesisUtils.ts
@@ -1,15 +1,45 @@
import { StrCast, Cast } from "../../../fields/Types";
import { SearchUtil } from "../../util/SearchUtil";
-import { action } from "mobx";
+import { action, runInAction } from "mobx";
import { Doc } from "../../../fields/Doc";
import { DocumentType } from "../../documents/DocumentTypes";
-import { Docs } from "../../documents/Documents";
+import { Docs, DocUtils } from "../../documents/Documents";
import { SelectionManager } from "../../util/SelectionManager";
+import { WebField } from "../../../fields/URLField";
+import { DocumentManager } from "../../util/DocumentManager";
+import { DocumentLinksButton } from "../../views/nodes/DocumentLinksButton";
+import { LinkManager } from "../../util/LinkManager";
+import { TaskCompletionBox } from "../../views/nodes/TaskCompletedBox";
+import { Utils } from "../../../Utils";
+import { LinkDescriptionPopup } from "../../views/nodes/LinkDescriptionPopup";
+import { Id } from "../../../fields/FieldSymbols";
export namespace Hypothesis {
+ // Return web doc with the given uri, or create and create a new doc with the given uri
+ export const getSourceWebDoc = async (uri: string) => {
+ const currentDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+ console.log(Cast(currentDoc.data, WebField)?.url.href === uri, uri, Cast(currentDoc.data, WebField)?.url.href);
+ if (Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the current doc is the source, only resort to Search otherwise
+
+ const results: Doc[] = [];
+ await SearchUtil.Search("web", true).then(action(async (res: SearchUtil.DocSearchResult) => {
+ const docs = await Promise.all(res.docs.map(async doc => (await Cast(doc.extendsDoc, Doc)) || doc));
+ const filteredDocs = docs.filter(doc =>
+ doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data
+ );
+ filteredDocs.forEach(doc => console.log("web docs:", doc.title, Cast(doc.data, WebField)?.url.href));
+ filteredDocs.forEach(doc => { uri === Cast(doc.data, WebField)?.url.href && results.push(doc); }); // TODO check history? imperfect matches?
+ }));
+
+ results.forEach(doc => console.log(doc.title, StrCast(doc.data)));
+
+ return results.length ? results[0] : Docs.Create.WebDocument(uri, { _nativeWidth: 850, _nativeHeight: 962, _width: 600, UseCors: true }); // create and return a new Web doc with given uri if no matching docs are found
+ };
+
// Send Hypothes.is client request to edit an annotation to add a Dash hyperlink
export const makeLink = async (title: string, url: string, annotationId: string) => {
+ console.log("SEND addLink");
const newHyperlink = `[${title}\n](${url})`;
document.dispatchEvent(new CustomEvent<{ newHyperlink: string, id: string }>("addLink", {
detail: { newHyperlink: newHyperlink, id: annotationId },
@@ -25,22 +55,56 @@ export namespace Hypothesis {
}));
};
- // Construct an URL which will automatically scroll the web page to a specific annotation's position
- export const makeAnnotationUrl = (annotationId: string, baseUrl: string) => {
- console.log("baseUrl", baseUrl, annotationId);
- return `${baseUrl}#annotations:${annotationId}`;
- };
+ // listen for event from Hypothes.is plugin to link an annotation to Dash
+ export const linkListener = async (e: any) => {
+ const annotationId: string = e.detail.id;
+ const annotationUri: string = e.detail.uri;
+ const sourceDoc: Doc = await getSourceWebDoc(annotationUri);
+
+ if (!DocumentLinksButton.StartLink) { // start link if there were none already started
+ runInAction(() => {
+ DocumentLinksButton.AnnotationId = annotationId;
+ DocumentLinksButton.AnnotationUri = annotationUri;
+ DocumentLinksButton.StartLink = sourceDoc;
+ });
+ } else if (!Doc.AreProtosEqual(sourceDoc, DocumentLinksButton.StartLink)) { // if a link has already been started, complete the link to the sourceDoc
+ console.log("completing link", sourceDoc.title);
+ runInAction(() => {
+ DocumentLinksButton.AnnotationId = annotationId;
+ DocumentLinksButton.AnnotationUri = annotationUri;
+ });
+
+ const linkDoc = DocUtils.MakeLink({ doc: DocumentLinksButton.StartLink }, { doc: sourceDoc }, DocumentLinksButton.AnnotationId ? "hypothes.is annotation" : "long drag");
+ LinkManager.currentLink = linkDoc;
- // Extract username from Hypothe.is's userId format
- export const extractUsername = (userid: string) => {
- const regex = new RegExp('(?<=\:)(.*?)(?=\@)/');
- return regex.exec(userid)![0];
+ Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
+ Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
+ Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
+ makeLink(StrCast(DocumentLinksButton.StartLink.title), Utils.prepend("/doc/" + DocumentLinksButton.StartLink[Id]), StrCast(DocumentLinksButton.AnnotationId)); // update and link placeholder annotation
+
+ runInAction(() => {
+ if (linkDoc) {
+ TaskCompletionBox.textDisplayed = "Link Created";
+ TaskCompletionBox.popupX = screenX;
+ TaskCompletionBox.popupY = screenY - 133;
+ TaskCompletionBox.taskCompleted = true;
+
+ if (LinkDescriptionPopup.showDescriptions === "ON" || !LinkDescriptionPopup.showDescriptions) {
+ LinkDescriptionPopup.popupX = screenX;
+ LinkDescriptionPopup.popupY = screenY - 100;
+ LinkDescriptionPopup.descriptionPopup = true;
+ }
+ setTimeout(action(() => { TaskCompletionBox.taskCompleted = false; }), 2500);
+ }
+ });
+ }
};
- // Return corres
- export const getSourceWebDoc = async (uri: string) => {
+ // Return web doc with the given uri, or create and create a new doc with the given uri
+ export const getSourceWebDocView = async (uri: string) => {
const currentDoc = SelectionManager.SelectedDocuments()[0].props.Document;
- if (StrCast(currentDoc.data) === uri) return currentDoc; // always check first whether the current doc is the source, only resort to Search otherwise
+ console.log(Cast(currentDoc.data, WebField)?.url.href === uri, uri, Cast(currentDoc.data, WebField)?.url.href);
+ if (Cast(currentDoc.data, WebField)?.url.href === uri) return currentDoc; // always check first whether the current doc is the source, only resort to Search otherwise
const results: Doc[] = [];
await SearchUtil.Search("web", true).then(action(async (res: SearchUtil.DocSearchResult) => {
@@ -48,12 +112,23 @@ export namespace Hypothesis {
const filteredDocs = docs.filter(doc =>
doc.author === Doc.CurrentUserEmail && doc.type === DocumentType.WEB && doc.data
);
- filteredDocs.forEach(doc => { uri === StrCast(doc.data) && results.push(doc); }); // TODO check history? imperfect matches?
+ filteredDocs.forEach(doc => console.log("web docs:", doc.title, Cast(doc.data, WebField)?.url.href));
+ filteredDocs.forEach(doc => { uri === Cast(doc.data, WebField)?.url.href && results.push(doc); }); // TODO check history? imperfect matches?
}));
- results.forEach(doc => console.log(doc.title, StrCast(doc.data)));
+ results.forEach(doc => {
+ const docView = DocumentManager.Instance.getFirstDocumentView(doc);
+ if (docView) {
+ console.log(doc.title, StrCast(doc.data));
+ return docView;
+ }
+ });
+
+ return undefined;
+ };
- return results.length ? results[0] : Docs.Create.WebDocument(uri, { _nativeWidth: 850, _nativeHeight: 962, _width: 600 }); // create and return a new Web doc with given uri if no matching docs are found
+ export const createInvisibleDoc = (uri: string) => {
+ const newDoc = Docs.Create.WebDocument(uri, { _nativeWidth: 0, _nativeHeight: 0, _width: 0, UseCors: true });
};
export const scrollToAnnotation = (annotationId: string) => {
@@ -71,7 +146,7 @@ export namespace Hypothesis {
detail: annotationId,
bubbles: true
}));
- }, 200);
+ }, 250);
document.addEventListener('scrollSuccess', onSuccess); // listen for success message from client
setTimeout(() => !success && clearTimeout(interval), 10000); // give up if no success after 10s
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 954b8b998..5c34233b4 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -104,47 +104,7 @@ export class MainView extends React.Component {
}
});
});
- document.addEventListener("linkAnnotationToDash", async (e: any) => { // listen for event from Hypothes.is plugin to link an annotation to Dash
- const annotationId = e.detail.id;
- const annotationUri = e.detail.uri;
- const sourceDoc = await Hypothesis.getSourceWebDoc(annotationUri);
- console.log("sourceDoc: ", sourceDoc.title);
-
- if (!DocumentLinksButton.StartLink) { // starts link only if there are none already started (else, a listener in DocumentLinksButton will handle link completion)
- runInAction(() => {
- DocumentLinksButton.AnnotationId = annotationId;
- DocumentLinksButton.AnnotationUri = annotationUri;
- DocumentLinksButton.StartLink = sourceDoc;
- });
- } else { // if a link's already started in Dash, send event to DocumentLinksButton tofinish the link to the annotation
- document.dispatchEvent(new CustomEvent<{ id: string, uri: string, sourceDoc: Doc }>("completeLinkToAnnotation", {
- detail: {
- id: annotationId,
- uri: annotationUri,
- sourceDoc: sourceDoc
- },
- bubbles: true
- }));
- }
- });
-
- // reaction(() => SelectionManager.SelectedDocuments(), selected => {
- // console.log("selection changed");
- // const selectedWebDocs = selected.map(docView => docView.props.Document).filter(doc => doc.type === DocumentType.WEB);
- // const urls = selectedWebDocs.map(doc => Cast(doc.data, WebField)?.url.href).filter(url => url !== undefined);
- // console.log("urls", urls);
-
- // const frame = document.getElementById('hyp_sidebar') as HTMLIFrameElement;
- // console.log("contentwindow?", frame.contentDocument);
- // if (frame.contentWindow) {
- // frame.contentWindow.postMessage("hello sidebar", window.origin);
- // }
-
- // document.dispatchEvent(new CustomEvent('showAnnotations', {
- // detail: urls,
- // bubbles: true
- // }));
- // });
+ document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener);
}
componentWillUnMount() {
@@ -152,6 +112,7 @@ export class MainView extends React.Component {
window.removeEventListener("pointerdown", this.globalPointerDown);
window.removeEventListener("pointerup", this.globalPointerUp);
window.removeEventListener("paste", KeyManager.Instance.paste as any);
+ document.removeEventListener("linkAnnotationToDash", Hypothesis.linkListener);
}
constructor(props: Readonly<{}>) {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 764758eee..c3d81bda4 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -74,7 +74,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
if (e.key === "?") {
ContextMenu.Instance.setDefaultItem("?", (str: string) => {
const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, {
- _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 800, isAnnotating: false,
+ _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 850, isAnnotating: false,
title: "bing", UseCors: true
});
this.props.addDocTab(textDoc, "onRight");
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 8503bcbeb..40a16961a 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -11,7 +11,7 @@ import { ContextMenu } from '../ContextMenu';
import './LinkMenuItem.scss';
import React = require("react");
import { DocumentManager } from '../../util/DocumentManager';
-import { setupMoveUpEvents, emptyFunction, Utils } from '../../../Utils';
+import { setupMoveUpEvents, emptyFunction, Utils, simulateMouseClick } from '../../../Utils';
import { DocumentView } from '../nodes/DocumentView';
import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
import { LinkDocPreview } from '../nodes/LinkDocPreview';
@@ -20,6 +20,7 @@ import { Id } from '../../../fields/FieldSymbols';
import { Tooltip } from '@material-ui/core';
import { DocumentType } from '../../documents/DocumentTypes';
import { undoBatch } from '../../util/UndoManager';
+import { WebField } from '../../../fields/URLField';
library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp, faPencilAlt, faEyeSlash);
@@ -156,7 +157,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
const linkDoc = this.props.linkDoc;
if (linkDoc.followLinkLocation === "openExternal" && this.props.destinationDoc.type === DocumentType.WEB) {
- window.open(Hypothesis.makeAnnotationUrl(StrCast(linkDoc.annotationId), StrCast(linkDoc.annotationUri)), '_blank');
+ window.open(`${StrCast(linkDoc.annotationUri)}#annotations:${StrCast(linkDoc.annotationId)}`, '_blank');
return;
}
@@ -244,7 +245,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
<FontAwesomeIcon className="destination-icon" icon={destinationIcon} size="sm" /></div>
<p className="linkMenu-destination-title"
onPointerDown={this.followDefault}>
- {this.props.linkDoc.linksToAnnotation ? "Annotation in" : ""} {title}
+ {this.props.linkDoc.linksToAnnotation && Cast(this.props.destinationDoc.data, WebField)?.url.href === this.props.linkDoc.annotationUri ? "Annotation in" : ""} {title}
</p>
</div>
{this.props.linkDoc.description !== "" ? <p className="linkMenu-description">
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index be7c3e135..3736cd3b2 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -40,35 +40,6 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
@observable public static AnnotationId: string | undefined;
@observable public static AnnotationUri: string | undefined;
- componentDidMount() {
- document.addEventListener("completeLinkToAnnotation", this.onLinkFromAnnotation);
- }
-
- componentWillUnmount() {
- document.removeEventListener("completeLinkToAnnotation", this.onLinkFromAnnotation);
- }
-
- @action
- onLinkFromAnnotation = async (e: any) => {
- const annotationId: string = e.detail.id;
- const annotationUri: string = e.detail.uri;
- const sourceDoc: Doc = e.detail.sourceDoc;
-
- // DocumentLinksButton.StartLink && this.props.View.props.Document.type === DocumentType.WEB && console.log(
- // sourceDoc.title,
- // this.props.View.props.Document.title,
- // sourceDoc.data,
- // this.props.View.props.Document.data,
- // Doc.AreProtosEqual(sourceDoc, this.props.View.props.Document));
-
- if (Doc.AreProtosEqual(sourceDoc, this.props.View.props.Document) && sourceDoc !== DocumentLinksButton.StartLink) {
- DocumentLinksButton.AnnotationId = annotationId;
- DocumentLinksButton.AnnotationUri = annotationUri;
- this.finishLinkClick(500, 100);
- console.log("completed link from annotation");
- }
- }
-
@action @undoBatch
onLinkButtonMoved = (e: PointerEvent) => {
if (this.props.InMenu && this.props.StartLink) {
@@ -181,15 +152,12 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
setTimeout(action(() => DocumentLinksButton.StartLink!._link = this.props.View._link = undefined), 0);
LinkManager.currentLink = linkDoc;
- // if the link is to a Hypothes.is annotation
- if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) {
- // figure out whether the StartLink doc or the current doc is the one to be linked to the annotation (the one NOT containing the annotation)
- const toBeLinked: Doc = DocumentLinksButton.AnnotationUri === Cast(DocumentLinksButton.StartLink.data, WebField)?.url.href ?
- this.props.View.props.Document : DocumentLinksButton.StartLink;
+ if (DocumentLinksButton.AnnotationId && DocumentLinksButton.AnnotationUri) { // if linking from a Hypothes.is annotation
+ const targetDoc = this.props.View.props.Document;
Doc.GetProto(linkDoc as Doc).linksToAnnotation = true;
Doc.GetProto(linkDoc as Doc).annotationId = DocumentLinksButton.AnnotationId;
Doc.GetProto(linkDoc as Doc).annotationUri = DocumentLinksButton.AnnotationUri;
- Hypothesis.makeLink(StrCast(toBeLinked.title), Utils.prepend("/doc/" + toBeLinked[Id]), DocumentLinksButton.AnnotationId); // update and link placeholder annotation
+ Hypothesis.makeLink(StrCast(targetDoc.title), Utils.prepend("/doc/" + targetDoc[Id]), DocumentLinksButton.AnnotationId); // edit annotation to add a Dash hyperlink to the linked doc
}
runInAction(() => {