aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-02-10 00:48:40 -0500
committerbobzel <zzzman@gmail.com>2021-02-10 00:48:40 -0500
commit7fedb7f75829269e46da5eaeb3b58166f9ab2126 (patch)
treebcadae8e02776dc328200dcdf18003103cad2a88 /src
parent46b569203a3890657ce799aa6b649cfc8bb431f2 (diff)
fixes for removing individual overlapping textanchors in a textBox. Hopefully near final cleanup of linkDocPreview and FormattedTextComment
Diffstat (limited to 'src')
-rw-r--r--src/client/views/linking/LinkMenuItem.tsx2
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx2
-rw-r--r--src/client/views/nodes/LinkDocPreview.scss3
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx100
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx5
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx103
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts5
-rw-r--r--src/client/views/nodes/formattedText/prosemirrorPatches.js18
8 files changed, 103 insertions, 135 deletions
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 2bc2bc6a4..53a7ae9ab 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -140,7 +140,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
<div ref={this._drag} className="linkMenu-name" //title="drag to view target. click to customize."
onPointerLeave={LinkDocPreview.Clear}
onPointerEnter={e => this.props.linkDoc && LinkDocPreview.SetLinkInfo({
- docprops: this.props.docView.props,
+ docProps: this.props.docView.props,
linkSrc: this.props.sourceDoc,
linkDoc: this.props.linkDoc,
showHeader: false,
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 7a4209563..db5414069 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -137,7 +137,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`}
onPointerLeave={LinkDocPreview.Clear}
onPointerEnter={e => LinkDocPreview.SetLinkInfo({
- docprops: this.props,
+ docProps: this.props,
linkSrc: linkSource,
linkDoc: this.rootDoc,
showHeader: true,
diff --git a/src/client/views/nodes/LinkDocPreview.scss b/src/client/views/nodes/LinkDocPreview.scss
index abbb8cdf0..b7aeaa072 100644
--- a/src/client/views/nodes/LinkDocPreview.scss
+++ b/src/client/views/nodes/LinkDocPreview.scss
@@ -19,6 +19,9 @@
height: 37px;
white-space: pre;
+ .linkDocPreview-buttonBar {
+ float: right;
+ }
.linkDocPreview-title {
padding-right: 4px;
float: left;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 463719824..576d1d15b 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -13,11 +13,12 @@ import { Transform } from "../../util/Transform";
import { DocumentView, DocumentViewSharedProps } from "./DocumentView";
import './LinkDocPreview.scss';
import React = require("react");
+import { undoBatch } from '../../util/UndoManager';
interface LinkDocPreviewProps {
linkDoc?: Doc;
linkSrc?: Doc;
- docprops: DocumentViewSharedProps;
+ docProps: DocumentViewSharedProps;
location: number[];
hrefs?: string[];
showHeader?: boolean;
@@ -34,25 +35,24 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
@observable _linkSrc: Opt<Doc>;
@observable _toolTipText = "";
@observable _hrefInd = 0;
- @observable _linkTarget: Opt<Doc>;
- @action componentDidUpdate(props: any) {
- if (props.linkSrc !== this.props.linkSrc ||
- props.linkDoc !== this.props.linkDoc ||
- props.hrefs !== this.props.hrefs) {
- this._linkTarget = this.props.linkDoc;
- this._linkSrc = this.props.linkSrc;
- this._linkDoc = this.props.linkDoc;
- this._toolTipText = "";
- this.updatePreview();
- }
- }
- @action componentDidMount() {
- this._linkTarget = this.props.linkDoc;
+ @action init() {
+ var linkTarget = this.props.linkDoc;
this._linkSrc = this.props.linkSrc;
this._linkDoc = this.props.linkDoc;
+ const anchor1 = this._linkDoc?.anchor1 as Doc;
+ const anchor2 = this._linkDoc?.anchor2 as Doc;
+ if (anchor1 && anchor2) {
+ linkTarget = Doc.AreProtosEqual(anchor1, this._linkSrc) || Doc.AreProtosEqual(anchor1?.annotationOn as Doc, this._linkSrc) ? anchor2 : anchor1;
+ }
+ this._targetDoc = linkTarget?.annotationOn as Doc ?? linkTarget;
this._toolTipText = "";
- this.updatePreview();
+ }
+ componentDidUpdate(props: any) {
+ if (props.linkSrc !== this.props.linkSrc || props.linkDoc !== this.props.linkDoc || props.hrefs !== this.props.hrefs) this.init();
+ }
+ componentDidMount() {
+ this.init();
document.addEventListener("pointerdown", this.onPointerDown);
}
@@ -62,66 +62,46 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
}
onPointerDown = (e: PointerEvent) => {
- !this._infoRef.current?.contains(e.target as any) && LinkDocPreview.Clear();
+ !this._infoRef.current?.contains(e.target as any) && LinkDocPreview.Clear(); // close preview when not clicking anywhere other than the info bar of the preview
}
- updatePreview() {
- const linkDoc = this.props.linkDoc;
- const linkSrc = this.props.linkSrc;
+ @computed get href() {
if (this.props.hrefs?.length) {
const href = this.props.hrefs[this._hrefInd];
- if (href.indexOf(Utils.prepend("/doc/")) !== 0) {
+ if (href.indexOf(Utils.prepend("/doc/")) !== 0) { // link to a web page URL -- try to show a preview
if (href.startsWith("https://en.wikipedia.org/wiki/")) {
wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(action(summary => this._toolTipText = summary.substring(0, 500))));
} else {
- runInAction(() => this._toolTipText = "external => " + href);
+ setTimeout(action(() => this._toolTipText = "url => " + href));
}
- } else {
+ } else { // hyperlink to a document .. decode doc id and retrieve from the server. this will trigger vals() being invalidated
const anchorDoc = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
- anchorDoc && DocServer.GetRefField(anchorDoc).then(action(async anchor => {
+ anchorDoc && DocServer.GetRefField(anchorDoc).then(action(anchor => {
if (anchor instanceof Doc && DocListCast(anchor.links).length) {
this._linkDoc = DocListCast(anchor.links)[0];
this._linkSrc = anchor;
- const targetanchor = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
- runInAction(async () => {
- this._linkTarget = targetanchor;
- const target = this._linkTarget?.annotationOn ? await DocCastAsync(this._linkTarget.annotationOn) : this._linkTarget;
- runInAction(() => {
- this._toolTipText = "";
- this._targetDoc = target;
- });
- });
+ const linkTarget = LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc);
+ this._targetDoc = linkTarget?.annotationOn as Doc ?? linkTarget;
+ this._toolTipText = "";
}
}));
}
- } else if (linkDoc) {
- const anchor1 = linkDoc.anchor1 as Doc;
- const anchor2 = linkDoc.anchor2 as Doc;
- runInAction(async () => {
- this._linkTarget = Doc.AreProtosEqual(anchor1, linkSrc) || Doc.AreProtosEqual(anchor1.annotationOn as Doc, linkSrc) ? anchor2 : anchor1;
- const target = this._linkTarget?.annotationOn ? await DocCastAsync(this._linkTarget.annotationOn) : this._linkTarget;
- runInAction(() => {
- this._toolTipText = "";
- this._targetDoc = target;
- });
- });
+ return href;
}
+ return undefined;
}
deleteLink = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => this._linkDoc ? LinkManager.Instance.deleteLink(this._linkDoc) : null));
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(() => this._linkDoc && LinkManager.Instance.deleteLink(this._linkDoc)));
}
nextHref = (e: React.PointerEvent) => {
- setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => {
- this._hrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1);
- this.updatePreview();
- }));
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, action(() => this._hrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1)));
}
followLink = (e: React.PointerEvent) => {
if (this._linkDoc && this._linkSrc) {
- LinkManager.FollowLink(this._linkDoc, this._linkSrc, this.props.docprops, false);
+ LinkManager.FollowLink(this._linkDoc, this._linkSrc, this.props.docProps, false);
} else if (this.props.hrefs?.length) {
- this.props.docprops?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _width: 200, _height: 400, useCors: true }), "add:right");
+ this.props.docProps?.addDocTab(Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _width: 200, _height: 400, useCors: true }), "add:right");
}
}
width = () => Math.min(225, NumCast(this._targetDoc?.[WidthSym](), 225));
@@ -133,13 +113,12 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
{StrCast(this._targetDoc.title).length > 16 ? StrCast(this._targetDoc.title).substr(0, 16) + "..." : this._targetDoc.title}
<p className="linkDocPreview-description"> {StrCast(this._linkDoc.description)}</p>
</div>
- <div className="wrapper" style={{ float: "right" }}>
- {(this.props.hrefs?.length || 0) <= 1 ? (null) :
- <Tooltip title={<div className="dash-tooltip">Next Link</div>} placement="top">
- <div className="linkDocPreview-button" onPointerDown={this.nextHref}>
- <FontAwesomeIcon className="linkDocPreview-fa-icon" icon="chevron-right" color="white" size="sm" />
- </div>
- </Tooltip>}
+ <div className="linkDocPreview-buttonBar" >
+ <Tooltip title={<div className="dash-tooltip">Next Link</div>} placement="top">
+ <div className="linkDocPreview-button" style={{ background: (this.props.hrefs?.length || 0) <= 1 ? "gray" : "green" }} onPointerDown={this.nextHref}>
+ <FontAwesomeIcon className="linkDocPreview-fa-icon" icon="chevron-right" color="white" size="sm" />
+ </div>
+ </Tooltip>
<Tooltip title={<div className="dash-tooltip">Delete Link</div>} placement="top">
<div className="linkDocPreview-button" onPointerDown={this.deleteLink}>
@@ -151,6 +130,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
}
@computed get docPreview() {
+ const href = this.href; // needs to be here to trigger lookup of web pages and docs on server
return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? (null) :
<div className="linkDocPreview-inner">
{!this.props.showHeader ? (null) : this.previewHeader}
@@ -163,8 +143,8 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
Document={this._targetDoc!}
moveDocument={returnFalse}
rootSelected={returnFalse}
- styleProvider={this.props.docprops?.styleProvider}
- layerProvider={this.props.docprops?.layerProvider}
+ styleProvider={this.props.docProps?.styleProvider}
+ layerProvider={this.props.docProps?.layerProvider}
docViewPath={emptyPath}
ScreenToLocalTransform={Transform.Identity}
parentActive={returnFalse}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index fece45e18..2434bee40 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -177,6 +177,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
if (allFoundLinkAnchors.length) {
this._editorView.dispatch(removeMarkWithAttrs(state.tr, 0, state.doc.nodeSize - 2, state.schema.marks.linkAnchor, { allAnchors: allFoundLinkAnchors }));
+
+ this.setupEditor(this.config, this.fieldKey);
}
}
}
@@ -186,6 +188,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const state = this._editorView?.state;
if (state && this._editorView) {
this._editorView.dispatch(removeMarkWithAttrs(state.tr, state.selection.from, state.selection.to, state.schema.marks.link, { allAnchors }));
+ this.setupEditor(this.config, this.fieldKey);
}
}
@@ -1233,7 +1236,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
- // !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;
@@ -1376,6 +1378,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
onFocused = (e: React.FocusEvent): void => {
FormattedTextBox.FocusedBox = this;
this.tryUpdateHeight();
+ //applyDevTools.applyDevTools(this._editorView);
// see if we need to preserve the insertion point
const prosediv = this.ProseRef?.children?.[0] as any;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index e4a1e0f1b..89df5e246 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -1,9 +1,7 @@
import { Mark, ResolvedPos } from "prosemirror-model";
import { EditorState } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
-import { Doc, DocListCast } from "../../../../fields/Doc";
-import { Utils } from "../../../../Utils";
-import { DocServer } from "../../../DocServer";
+import { Doc } from "../../../../fields/Doc";
import { LinkDocPreview } from "../LinkDocPreview";
import { FormattedTextBox } from "./FormattedTextBox";
import './FormattedTextBoxComment.scss';
@@ -37,54 +35,51 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark
export class FormattedTextBoxComment {
static tooltip: HTMLElement;
static tooltipText: HTMLElement;
- static start: number;
- static end: number;
- static mark: Mark;
+ static startUserMarkRegion: number;
+ static endUserMarkRegion: number;
+ static userMark: Mark;
static textBox: FormattedTextBox | undefined;
constructor(view: any) {
if (!FormattedTextBoxComment.tooltip) {
- FormattedTextBoxComment.tooltip = document.createElement("div");
- FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip";
- FormattedTextBoxComment.tooltip.style.display = "none";
- FormattedTextBoxComment.tooltipText = document.createElement("div");
- FormattedTextBoxComment.tooltipText.className = "FormattedTextBox-tooltipText";
- FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipText);
- FormattedTextBoxComment.tooltip.onpointerdown = (e: PointerEvent) => {
- const textBox = FormattedTextBoxComment.textBox;
- false && FormattedTextBoxComment.start !== undefined && textBox?.adoptAnnotation(
- FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
+ const tooltip = FormattedTextBoxComment.tooltip = document.createElement("div");
+ const tooltipText = FormattedTextBoxComment.tooltipText = document.createElement("div");
+ tooltip.className = "FormattedTextBox-tooltip";
+ tooltipText.className = "FormattedTextBox-tooltipText";
+ tooltip.style.display = "none";
+ tooltip.appendChild(tooltipText);
+ tooltip.onpointerdown = (e: PointerEvent) => {
+ const { textBox, startUserMarkRegion, endUserMarkRegion, userMark } = FormattedTextBoxComment;
+ false && startUserMarkRegion !== undefined && textBox?.adoptAnnotation(startUserMarkRegion, endUserMarkRegion, userMark);
e.stopPropagation();
e.preventDefault();
};
- document.getElementById("root")?.appendChild(FormattedTextBoxComment.tooltip);
+ document.getElementById("root")?.appendChild(tooltip);
}
}
public static Hide() {
FormattedTextBoxComment.textBox = undefined;
FormattedTextBoxComment.tooltip.style.display = "none";
}
- public static SetState(textBox: any, start: number, end: number, mark: Mark) {
+ public static saveMarkRegion(textBox: any, start: number, end: number, mark: Mark) {
FormattedTextBoxComment.textBox = textBox;
- FormattedTextBoxComment.start = start;
- FormattedTextBoxComment.end = end;
- FormattedTextBoxComment.mark = mark;
+ FormattedTextBoxComment.startUserMarkRegion = start;
+ FormattedTextBoxComment.endUserMarkRegion = end;
+ FormattedTextBoxComment.userMark = mark;
FormattedTextBoxComment.tooltip.style.display = "";
}
- static showCommentbox(set: string, view: EditorView, nbef: number) {
+ static showCommentbox(view: EditorView, nbef: number) {
const state = view.state;
- if (set !== "none") {
- // These are in screen coordinates
- const start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef);
- // The box in which the tooltip is positioned, to use as base
- const box = (document.getElementsByClassName("mainView-container") as any)[0].getBoundingClientRect();
- // Find a center-ish x position from the selection endpoints (when crossing lines, end may be more to the left)
- const left = Math.max((start.left + end.left) / 2, start.left + 3);
- FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px";
- FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px";
- }
- FormattedTextBoxComment.tooltip.style.display = set;
+ // These are in screen coordinates
+ const start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef);
+ // The box in which the tooltip is positioned, to use as base
+ const box = (document.getElementsByClassName("mainView-container") as any)[0].getBoundingClientRect();
+ // Find a center-ish x position from the selection endpoints (when crossing lines, end may be more to the left)
+ const left = Math.max((start.left + end.left) / 2, start.left + 3);
+ FormattedTextBoxComment.tooltip.style.left = (left - box.left) + "px";
+ FormattedTextBoxComment.tooltip.style.bottom = (box.bottom - start.top) + "px";
+ FormattedTextBoxComment.tooltip.style.display = "";
}
static update(view: EditorView, lastState?: EditorState, hrefs: string = "") {
@@ -96,7 +91,6 @@ export class FormattedTextBoxComment {
static setupPreview(view: EditorView, textBox: FormattedTextBox, hrefs?: string[]) {
const state = view.state;
// this section checks to see if the insertion point is over text entered by a different user. If so, it sets ths comment text to indicate the user and the modification date
- var hide = true;
if (state.selection.$from) {
const nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
const naft = findEndOfMark(state.selection.$from, view, findOtherUserMark);
@@ -105,43 +99,26 @@ export class FormattedTextBoxComment {
state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: any) => !child && node.marks.length && (child = node));
const mark = child && findOtherUserMark(child.marks);
if (mark && child && (nbef || naft) && (!mark.attrs.opened || noselection)) {
- FormattedTextBoxComment.SetState(textBox, state.selection.$from.pos - nbef, state.selection.$from.pos + naft, mark);
+ FormattedTextBoxComment.saveMarkRegion(textBox, state.selection.$from.pos - nbef, state.selection.$from.pos + naft, mark);
}
if (mark && child && ((nbef && naft) || !noselection)) {
FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " on " + (new Date(mark.attrs.modified * 1000)).toLocaleString();
- FormattedTextBoxComment.showCommentbox("", view, nbef);
- hide = false;
- }
+ FormattedTextBoxComment.showCommentbox(view, nbef);
+ } else FormattedTextBoxComment.Hide();
}
+
// 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 (hide && state.selection.$from) {
+ if (state.selection.$from && hrefs) {
const nbef = findStartOfMark(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) => !child && node.marks.length && (child = node));
- child = child || (nbef && state.selection.$from.nodeBefore);
- const mark = child ? findLinkMark(child.marks) : undefined;
- const href = (!mark?.attrs.docref || naft === nbef) && mark?.attrs.allAnchors.find((item: { href: string }) => item.href)?.href;
- if ((href && child && nbef && naft && mark?.attrs.showPreview)) {
- const showPreview = (link?: Doc) => {
- return LinkDocPreview.SetLinkInfo({
- docprops: textBox.props.docViewPath.lastElement().props,
- linkSrc: textBox.props.Document,
- linkDoc: link,
- location: ((pos) => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - nbef)),
- hrefs,
- showHeader: true
- });
- }
- const anchorDoc = href.indexOf(Utils.prepend("/doc/")) === 0 ? href.replace(Utils.prepend("/doc/"), "").split("?")[0] : undefined;
- if (anchorDoc) {
- DocServer.GetRefField(anchorDoc).then(anchor => anchor instanceof Doc && showPreview(DocListCast(anchor.links)[0]));
- } else if (hrefs?.length) {
- showPreview()
- }
- }
+ nbef && naft && LinkDocPreview.SetLinkInfo({
+ docProps: textBox.props,
+ linkSrc: textBox.rootDoc,
+ location: ((pos) => [pos.left, pos.top + 25])(view.coordsAtPos(state.selection.from - nbef)),
+ hrefs,
+ showHeader: true
+ });
}
- if (hide) FormattedTextBoxComment.Hide();
}
destroy() { }
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index aceba0387..655ee7e44 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -23,7 +23,6 @@ export const marks: { [index: string]: MarkSpec } = {
linkAnchor: {
attrs: {
allAnchors: { default: [] as { href: string, title: string, anchorId: string }[] },
- showPreview: { default: true },
location: { default: null },
title: { default: null },
docref: { default: false } // flags whether the linked text comes from a document within Dash. If so, an attribution label is appended after the text
@@ -32,8 +31,8 @@ export const marks: { [index: string]: MarkSpec } = {
parseDOM: [{
tag: "a[href]", getAttrs(dom: any) {
return {
- allAnchors: [{ href: dom.getAttribute("shref"), title: dom.getAttribute("title"), anchorId: dom.getAttribute("class") }],
location: dom.getAttribute("location"),
+ title: dom.getAttribute("title")
};
}
}],
@@ -47,7 +46,7 @@ export const marks: { [index: string]: MarkSpec } = {
href: node.attrs.allAnchors[0].href,
}, node.attrs.title], ["br"]] :
//node.attrs.allLinks.length === 1 ?
- ["a", { ...node.attrs, class: anchorids, "data-targethrefs": targethrefs, title: node.attrs.title, href: node.attrs.allAnchors[0]?.href, style: `text-decoration: "underline"` }, 0];
+ ["a", { class: anchorids, "data-targethrefs": targethrefs, title: node.attrs.title, location: node.attrs.location, style: `text-decoration: underline` }, 0];
// ["div", { class: "prosemirror-anchor" },
// ["span", { class: "prosemirror-linkBtn" },
// ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}` }, 0],
diff --git a/src/client/views/nodes/formattedText/prosemirrorPatches.js b/src/client/views/nodes/formattedText/prosemirrorPatches.js
index 746c93868..5bc323a4d 100644
--- a/src/client/views/nodes/formattedText/prosemirrorPatches.js
+++ b/src/client/views/nodes/formattedText/prosemirrorPatches.js
@@ -143,17 +143,21 @@ function wrappingInputRule(regexp, nodeType, getAttrs, joinPredicate, customWith
// :: ([Mark]) → ?Mark
// Tests whether there is a mark of this type in the given set.
function isInSetWithAttrs(mark, set, attrs) {
+ var markAllAnchors = attrs.allAnchors !== undefined ? Array.from(attrs.allAnchors.map(al => al.anchorId)) : [];
for (var i = 0; i < set.length; i++) {
if (set[i].type == mark) {
- if (Array.from(Object.keys(attrs)).reduce((p, akey) => {
+ return Array.from(Object.keys(attrs)).reduce((p, akey) => {
if (p && JSON.stringify(set[i].attrs[akey]) === JSON.stringify(attrs[akey])) return true;
- set[i].attrs.allLinks = Array.from(set[i].attrs.allLinks).filter(a => !Array.from(attrs.allLinks.map(al => al.targetId)).includes(a.targetId) || !Array.from(attrs.allLinks.map(al => al.linkId).includes(a.linkId)))
+ // bcz: hack to allow special case of anchors in Dash to be removed from a mark which has multiple
+ if (set[i].attrs.allAnchors !== undefined) {
+ set[i].attrs.allAnchors = set[i].attrs.allAnchors.filter(a => !markAllAnchors.includes(a.anchorId));
+ if (set[i].attrs.allAnchors.length) return undefined;
+ }
return false;
- }, true)) {
- return set[i];
- }
+ }, true);
}
}
+ return undefined;
};
// :: (number, number, ?union<Mark, MarkType>) → this
@@ -170,7 +174,9 @@ function removeMarkWithAttrs(tr, from, to, mark, attrs) {
step++;
var toRemove = null;
if (mark) {
- if (isInSetWithAttrs(mark, node.marks, attrs)) { toRemove = [mark]; }
+ const inset = isInSetWithAttrs(mark, node.marks, attrs);
+ if (inset === true) { toRemove = [mark]; }
+ // if (inset === undefined) { console.log("lightened") } // anchorids were removed from the mark, but the mark wasn't removed since there are still anchorsids left
} else {
toRemove = node.marks;
}