aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/documents/Documents.ts3
-rw-r--r--src/client/util/LinkManager.ts15
-rw-r--r--src/client/util/RichTextSchema.tsx3
-rw-r--r--src/client/util/TooltipTextMenu.tsx25
-rw-r--r--src/client/views/linking/LinkFollowBox.tsx8
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx80
6 files changed, 53 insertions, 81 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 079ff00db..4ae770e25 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -638,9 +638,6 @@ export namespace DocUtils {
});
}
export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", sourceContext?: Doc, id?: string, anchored1?: boolean) {
- // if (LinkManager.Instance.doesLinkExist(source, target)) return undefined;
- if (LinkManager.Instance.doesNormalLinkExist(source, target) && description !== "in-text link being created") return undefined; // normal describes the type of link attempting to be created
- // if normal link already exists and !normal (in text link is not being created) then return
let sv = DocumentManager.Instance.getDocumentView(source);
if (sv && sv.props.ContainingCollectionDoc === target) return;
if (target === CurrentUserUtils.UserDocument) return undefined;
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index b285b967b..8a668e8d8 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -238,21 +238,6 @@ export class LinkManager {
return index !== -1;
}
- // checks if a normal link (i.e. no in-text link) exists with given anchors
- public doesNormalLinkExist(anchor1: Doc, anchor2: Doc): boolean {
- let allLinks = LinkManager.Instance.getAllLinks();
- let index = allLinks.findIndex(linkDoc => {
- if ((Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor2)) ||
- (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor1))) {
- console.log("guid: " + linkDoc.guid);
- }
- return (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor2) && linkDoc.guid === undefined) ||
- (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor1) && linkDoc.guid === undefined);
- });
- return index !== -1;
- }
-
-
// finds the opposite anchor of a given anchor in a link
//TODO This should probably return undefined if there isn't an opposite anchor
//TODO This should also await the return value of the anchor so we don't filter out promises
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index ea31671ac..9d5ccffe9 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -253,8 +253,7 @@ export const marks: { [index: string]: MarkSpec } = {
href: {},
location: { default: null },
title: { default: null },
- guid: { default: null },
- docref: { default: false }
+ docref: { default: false } // flags whether the linked text comes from a document within Dash. If so, an attribution label is appended after the text
},
inclusive: false,
parseDOM: [{
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index c84d98df9..987bc4f58 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -302,16 +302,16 @@ export class TooltipTextMenu {
{
handlers: {
dragComplete: action(() => {
- let linkDoc = dragData.linkDocument;
- let guid = Utils.GenerateGuid();
- let proto = Doc.GetProto(linkDoc);
- if (proto && docView) {
- proto.sourceContext = docView.props.ContainingCollectionDoc;
- }
- linkDoc.guid = guid;
- let text = this.makeLink(Utils.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab", guid);
- if (linkDoc instanceof Doc && linkDoc.anchor2 instanceof Doc) {
- proto.title = text === "" ? proto.title : text + " to " + linkDoc.anchor2.title; // TODODO open to more descriptive descriptions of following in text link
+ if (dragData.linkDocument) {
+ let linkDoc = dragData.linkDocument;
+ let proto = Doc.GetProto(linkDoc);
+ if (proto && docView) {
+ proto.sourceContext = docView.props.ContainingCollectionDoc;
+ }
+ let text = this.makeLink(linkDoc, ctrlKey ? "onRight" : "inTab");
+ if (linkDoc instanceof Doc && linkDoc.anchor2 instanceof Doc) {
+ proto.title = text === "" ? proto.title : text + " to " + linkDoc.anchor2.title; // TODODO open to more descriptive descriptions of following in text link
+ }
}
}),
},
@@ -398,9 +398,10 @@ export class TooltipTextMenu {
// let link = state.schema.mark(state.schema.marks.link, { href: target, location: location });
// }
- makeLink = (target: string, location: string, guid?: string): string => {
+ makeLink = (targetDoc: Doc, location: string): string => {
+ let target = Utils.prepend("/doc/" + targetDoc[Id]);
let node = this.view.state.selection.$from.nodeAfter;
- let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location, guid: guid });
+ let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location, guid: targetDoc[Id] });
this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link));
this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link));
node = this.view.state.selection.$from.nodeAfter;
diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx
index 1280ae28b..cad404d1f 100644
--- a/src/client/views/linking/LinkFollowBox.tsx
+++ b/src/client/views/linking/LinkFollowBox.tsx
@@ -243,7 +243,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
let proto = Doc.GetProto(LinkFollowBox.linkDoc);
let targetContext = await Cast(proto.targetContext, Doc);
let sourceContext = await Cast(proto.sourceContext, Doc);
- let guid = StrCast(LinkFollowBox.linkDoc.guid);
+ let guid = StrCast(LinkFollowBox.linkDoc[Id]);
const shouldZoom = options ? options.shouldZoom : false;
let dockingFunc = (document: Doc) => { (this._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
@@ -255,12 +255,10 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, document => dockingFunc(sourceContext!));
if (LinkFollowBox.sourceDoc && LinkFollowBox.destinationDoc) {
if (guid) {
- LinkFollowBox.destinationDoc.guid = guid;
+ let views = DocumentManager.Instance.getDocumentViews(jumpToDoc);
+ views.length && (views[0].props.Document.scrollToLinkID = guid);
} else {
jumpToDoc.linkHref = Utils.prepend("/doc/" + StrCast(LinkFollowBox.linkDoc[Id]));
- let newguid = Utils.GenerateGuid();
- LinkFollowBox.linkDoc.guid = newguid;
- LinkFollowBox.destinationDoc.guid = newguid;
}
}
}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 53f28ac00..0a8b841a9 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -80,6 +80,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
private _nodeClicked: any;
private _undoTyping?: UndoManager.Batch;
private _searchReactionDisposer?: Lambda;
+ private _guidReactionDisposer: Opt<IReactionDisposer>;
private _reactionDisposer: Opt<IReactionDisposer>;
private _textReactionDisposer: Opt<IReactionDisposer>;
private _heightReactionDisposer: Opt<IReactionDisposer>;
@@ -139,66 +140,50 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
}
- this.props.Document.guid = undefined;
- this.props.Document.linkHref = undefined;
-
- reaction(
- () => StrCast(this.props.Document.guid),
- async (guid) => {
- let start = -1;
- let href = this.props.Document.linkHref;
-
- if (this._editorView && guid) {
- let editor = this._editorView;
- let ret = findLinkFrag(editor.state.doc.content, editor);
-
- if (ret.frag.size > 2) {
- let tr;
- if (ret.frag.firstChild) {
- let between = TextSelection.between(editor.state.doc.resolve(ret.start + 2), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize));
- tr = editor.state.tr.setSelection(between);
- } else {
- let near = TextSelection.near(editor.state.doc.resolve(ret.start));
- tr = editor.state.tr.setSelection(near);
- }
-
- editor.focus();
- editor.dispatch(tr.scrollIntoView());
- editor.dispatch(tr.scrollIntoView()); // bcz: sometimes selection doesn't fully scroll into view on smaller text boxes <5 lines visibility -- hopefully avoidable by ppl just not using small boxes...?
-
- this.props.Document.guid = undefined;
- this.props.Document.linkHref = undefined;
- }
- }
-
- function findLinkFrag(frag: Fragment, editor: EditorView) {
+ this._guidReactionDisposer = reaction(
+ () => StrCast(this.props.Document.scrollToLinkID),
+ async (scrollToLinkID) => {
+ let findLinkFrag = (frag: Fragment, editor: EditorView) => {
const nodes: Node[] = [];
frag.forEach((node, index) => {
let examinedNode = findLinkNode(node, editor);
- if (examinedNode && examinedNode.textContent !== "") {
+ if (examinedNode && examinedNode.textContent) {
nodes.push(examinedNode);
start += index;
}
});
return { frag: Fragment.fromArray(nodes), start: start };
}
- function findLinkNode(node: Node, editor: EditorView) {
+ let findLinkNode = (node: Node, editor: EditorView) => {
if (!node.isText) {
const content = findLinkFrag(node.content, editor);
return node.copy(content.frag);
}
const marks = [...node.marks];
- const linkIndex = marks.findIndex(mark => mark.type.name === "link");
- if (linkIndex !== -1) {
- if (guid === marks[linkIndex].attrs.guid) {
- return node;
- } else if (href && href === marks[linkIndex].attrs.href) { // retroactively fixing old in-text links by adding guid
- marks[linkIndex].attrs.guid = guid;
- return node;
+ const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.link);
+ return linkIndex !== -1 && scrollToLinkID === marks[linkIndex].attrs.href.replace(/.*\/doc\//, "") ? node : undefined;
+ }
+
+ let start = -1;
+
+ if (this._editorView && scrollToLinkID) {
+ let editor = this._editorView;
+ let ret = findLinkFrag(editor.state.doc.content, editor);
+
+ if (ret.frag.size > 2 && ((!this.props.isOverlay && !this.props.isSelected()) || (this.props.isSelected() && this.props.isOverlay))) {
+ let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
+ if (ret.frag.firstChild) {
+ selection = TextSelection.between(editor.state.doc.resolve(ret.start + 2), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
}
+ editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
+ const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
+ setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0);
+ setTimeout(() => this.unhighlightSearchTerms(), 2000);
+
+ this.props.Document.scrollToLinkID = undefined;
}
- return undefined;
}
+
}
);
}
@@ -759,6 +744,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._editorView && this._editorView.destroy();
this._editorView = new EditorView(this._proseRef, {
state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
+ handleScrollToSelection: (editorView) => {
+ let ref = editorView.domAtPos(editorView.state.selection.from);
+ let r1 = (ref.node as any).getBoundingClientRect();
+ let r3 = self._ref.current!.getBoundingClientRect();
+ self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale;
+ return true;
+ },
dispatchTransaction: this.dispatchTransaction,
nodeViews: {
image(node, view, getPos) { return new ImageResizeView(node, view, getPos, self.props.addDocTab); },
@@ -799,6 +791,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
componentWillUnmount() {
+ this._guidReactionDisposer && this._guidReactionDisposer();
this._rulesReactionDisposer && this._rulesReactionDisposer();
this._reactionDisposer && this._reactionDisposer();
this._proxyReactionDisposer && this._proxyReactionDisposer();
@@ -823,7 +816,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let ctrlKey = e.ctrlKey;
if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
let href = (e.target as any).href;
- let guid = (e.target as any).guid;
let location: string;
if ((e.target as any).attributes.location) {
location = (e.target as any).attributes.location.value;