diff options
author | bobzel <zzzman@gmail.com> | 2020-09-17 10:46:27 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2020-09-17 10:46:27 -0400 |
commit | 80bbbb3842cb89949d2b949ce8f5a2ed3921b112 (patch) | |
tree | 0041374a63f80325060a47dc0a259c750e526792 | |
parent | 5dc5009da8018d79620a42b75833d5b4335e0f56 (diff) |
fixed deleting text links to work when there are multiple links in the same linkAnchor mark. addressed problem with text getting a negative height when its resized to fit content in a preview window when its also displayed in freeform.
5 files changed, 59 insertions, 49 deletions
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index de50deee7..87c620d6d 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -445,7 +445,7 @@ export class SharingManager extends React.Component<{}> { const commonKeys = intersection(...docs.map(doc => this.layoutDocAcls ? doc?.[AclSym] && Object.keys(doc[AclSym]) : doc?.[DataSym]?.[AclSym] && Object.keys(doc[DataSym][AclSym]))); // the list of users shared with - const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`ACL-${user.email.replace('.', '_')}`) : true).map(({ user, notificationDoc }) => { + const userListContents: (JSX.Element | null)[] = users.filter(({ user }) => docs.length > 1 ? commonKeys.includes(`ACL-${user.email.replace('.', '_')}`) : true).map(({ user, notificationDoc, userColor }) => { const userKey = `ACL-${user.email.replace('.', '_')}`; const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[userKey] === docs[0]?.[AclSym]?.[userKey] : doc?.[DataSym]?.[AclSym]?.[userKey] === docs[0]?.[DataSym]?.[AclSym]?.[userKey]); const permissions = uniform ? StrCast(targetDoc?.[userKey]) : "-multiple-"; @@ -461,7 +461,7 @@ export class SharingManager extends React.Component<{}> { <select className={"permissions-dropdown"} value={permissions} - onChange={e => this.setInternalSharing({ user, notificationDoc }, e.currentTarget.value)} + onChange={e => this.setInternalSharing({ user, notificationDoc, userColor }, e.currentTarget.value)} > {this.sharingOptions(uniform)} </select> diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 188ed03da..83012bab5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1233,7 +1233,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp FormattedTextBoxComment.textBox = this; const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY }); !this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0)))); - FormattedTextBoxComment.update(editor, undefined, (e.target as any)?.className === "prosemirror-dropdownlink" ? (e.target as any).href : ""); + const target = (e.target as any).parentElement; // hrefs are store don the database of the <a> node that wraps the hyerlink <span> + FormattedTextBoxComment.update(editor, undefined, target?.dataset?.targethrefs); } (e.nativeEvent as any).formattedHandled = true; @@ -1487,7 +1488,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp @action tryUpdateHeight(limitHeight?: number) { let scrollHeight = this.ProseRef?.scrollHeight || 0; - if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation + if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation scrollHeight = scrollHeight * NumCast(this.layoutDoc._viewScale, 1); if (limitHeight && scrollHeight > limitHeight) { scrollHeight = limitHeight; @@ -1506,18 +1507,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, 10); } else { try { - // let ele = this._boxRef.current; - // while (ele && ele.className !== "documentView-contentsView") ele = ele.parentElement as any; - // if (ele) { - // const docHeight = Number(getComputedStyle(ele).height.replace("px", "")); - // const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", "")); - // const outer = docHeight - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0); - // this.rootDoc._height = newHeight + outer; - // this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined; - // } const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", "")); const outer = this.rootDoc[HeightSym]() - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0); - this.rootDoc._height = newHeight + outer; + this.rootDoc._height = newHeight + Math.max(0, outer); this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined; } catch (e) { console.log("Error in tryUpdateHeight"); } } diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 1bf885636..249aca812 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Tooltip } from "@material-ui/core"; -import { action } from "mobx"; +import { action, observable } from "mobx"; import { Mark, ResolvedPos } from "prosemirror-model"; import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; @@ -23,6 +23,7 @@ import { FormattedTextBox } from "./FormattedTextBox"; import './FormattedTextBoxComment.scss'; import { schema } from "./schema_rts"; import React = require("react"); +import { observer } from "mobx-react"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -60,6 +61,7 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark // this view appears when clicking on text that has a hyperlink which is configured to show a preview of its target. // this will also display metadata information about text when the view is configured to display things like other people who authored text. // + export class FormattedTextBoxComment { static tooltip: HTMLElement; static tooltipText: HTMLElement; @@ -72,6 +74,13 @@ export class FormattedTextBoxComment { static _deleteRef: Opt<HTMLDivElement | null>; static _followRef: Opt<HTMLDivElement | null>; + static _nextRef: Opt<HTMLDivElement | null>; + + static _lastState?: EditorState; + static _lastView?: EditorView; + + @observable static _hrefInd = 0; + static _hrefs: string[] | undefined = []; constructor(view: any) { if (!FormattedTextBoxComment.tooltip) { @@ -101,6 +110,8 @@ export class FormattedTextBoxComment { if (linkDoc.author) { if (FormattedTextBoxComment._deleteRef?.contains(e.target as any)) { this.deleteLink(); + } else if (FormattedTextBoxComment._nextRef?.contains(e.target as any)) { + FormattedTextBoxComment.showPreview(FormattedTextBoxComment._lastView!, FormattedTextBoxComment._lastState, FormattedTextBoxComment._hrefs?.[(++FormattedTextBoxComment._hrefInd) % FormattedTextBoxComment._hrefs?.length]) } else { FormattedTextBoxComment.linkDoc = undefined; if (linkDoc.type !== DocumentType.LINK) { @@ -128,7 +139,6 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.linkDoc ? LinkManager.Instance.deleteLink(FormattedTextBoxComment.linkDoc) : null; LinkDocPreview.LinkInfo = undefined; DocumentLinksButton.EditLink = undefined; - //FormattedTextBoxComment.tooltipText = undefined; FormattedTextBoxComment.Hide(); }); @@ -164,14 +174,20 @@ export class FormattedTextBoxComment { } static update(view: EditorView, lastState?: EditorState, forceUrl: string = "") { - const state = view.state; // Don't do anything if the document/selection didn't change - if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) { + if (!forceUrl && lastState?.doc.eq(view.state.doc) && lastState?.selection.eq(view.state.selection)) { return; } + FormattedTextBoxComment._lastState = lastState; + FormattedTextBoxComment._lastView = view; + FormattedTextBoxComment._hrefs = forceUrl ? forceUrl.trim().split(" ") : undefined; + FormattedTextBoxComment._hrefInd = 0; FormattedTextBoxComment.linkDoc = undefined; + FormattedTextBoxComment.showPreview(view, lastState, FormattedTextBoxComment._hrefs?.[FormattedTextBoxComment._hrefInd]); + } + static showPreview(view: EditorView, lastState?: EditorState, forceUrl: string = "") { + const state = view.state; const textBox = FormattedTextBoxComment.textBox; if (!textBox || !textBox.props) { return; @@ -209,7 +225,7 @@ export class FormattedTextBoxComment { state.doc.nodesBetween(state.selection.from, state.selection.to, (node: any, pos: number, parent: 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.allLinks.find((item: { href: string }) => item.href)?.href || forceUrl; + const href = forceUrl || (!mark?.attrs.docref || naft === nbef) && mark?.attrs.allLinks.find((item: { href: string }) => item.href)?.href; if (forceUrl || (href && child && nbef && naft && mark?.attrs.showPreview)) { try { ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); @@ -245,34 +261,35 @@ export class FormattedTextBoxComment { if (target?.author) { FormattedTextBoxComment.showCommentbox("", view, nbef); - const title = StrCast(target.title).length > 16 ? - StrCast(target.title).substr(0, 16) + "..." : target.title; - + const title = StrCast(target.title).length > 16 ? StrCast(target.title).substr(0, 16) + "..." : target.title; const docPreview = <div className="FormattedTextBoxComment"> <div className="FormattedTextBoxComment-info"> <div className="FormattedTextBoxComment-title"> {title} - {FormattedTextBoxComment.linkDoc.description !== "" ? <p className="FormattedTextBoxComment-description"> - {StrCast(FormattedTextBoxComment.linkDoc.description)}</p> : null} + {FormattedTextBoxComment.linkDoc.description === "" ? (null) : + <p className="FormattedTextBoxComment-description"> {StrCast(FormattedTextBoxComment.linkDoc.description)}</p>} </div> <div className="wrapper" style={{ float: "right" }}> + {(FormattedTextBoxComment._hrefs?.length || 0) <= 1 ? (null) : <Tooltip title={<><div className="dash-tooltip">Next Link</div></>} placement="top"> + <div className="FormattedTextBoxComment-button" ref={(r) => this._nextRef = r}> + <FontAwesomeIcon className="FormattedTextBoxComment-fa-icon" icon="chevron-right" color="white" size="sm" /> + </div> + </Tooltip>} <Tooltip title={<><div className="dash-tooltip">Delete Link</div></>} placement="top"> - <div className="FormattedTextBoxComment-button" - ref={(r) => this._deleteRef = r}> - <FontAwesomeIcon className="FormattedTextBoxComment-fa-icon" icon="trash" color="white" - size="sm" /></div> + <div className="FormattedTextBoxComment-button" ref={(r) => this._deleteRef = r}> + <FontAwesomeIcon className="FormattedTextBoxComment-fa-icon" icon="trash" color="white" size="sm" /> + </div> </Tooltip> <Tooltip title={<><div className="dash-tooltip">Follow Link</div></>} placement="top"> - <div className="FormattedTextBoxComment-button" - ref={(r) => this._followRef = r}> - <FontAwesomeIcon className="FormattedTextBoxComment-fa-icon" icon="arrow-right" color="white" - size="sm" /> + <div className="FormattedTextBoxComment-button" ref={(r) => this._followRef = r}> + <FontAwesomeIcon className="FormattedTextBoxComment-fa-icon" icon="arrow-right" color="white" size="sm" /> </div> </Tooltip> - </div> </div> + </div> + </div> <div className="FormattedTextBoxComment-preview-wrapper"> <ContentFittingDocumentView Document={target} @@ -304,8 +321,6 @@ export class FormattedTextBoxComment { </div> </div>; - - FormattedTextBoxComment.showCommentbox("", view, nbef); ReactDOM.render(docPreview, FormattedTextBoxComment.tooltipText); diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index 066ceb5c8..cca7ea013 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -36,20 +36,21 @@ export const marks: { [index: string]: MarkSpec } = { }], toDOM(node: any) { const targetids = node.attrs.allLinks.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.targetId, ""); + const targethrefs = node.attrs.allLinks.reduce((p: string, item: { href: string, title: string, targetId: string, linkId: string }) => p + " " + item.href, ""); const linkids = node.attrs.allLinks.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, href: node.attrs.allLinks[0].href, class: "prosemirror-attribution" }, node.attrs.title], ["br"]] : - node.attrs.allLinks.length === 1 ? - ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}`, href: node.attrs.allLinks[0].href, style: `text-decoration: ${linkids === " " ? "underline" : undefined}` }, 0] : - ["div", { class: "prosemirror-anchor" }, - ["span", { class: "prosemirror-linkBtn" }, - ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}` }, 0], - ["input", { class: "prosemirror-hrefoptions" }], - ], - ["div", { class: "prosemirror-links" }, ...node.attrs.allLinks.map((item: { href: string, title: string }) => - ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title] - )] - ]; + //node.attrs.allLinks.length === 1 ? + ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, "data-targethrefs": targethrefs, title: `${node.attrs.title}`, href: node.attrs.allLinks[0].href, style: `text-decoration: ${linkids === " " ? "underline" : undefined}` }, 0]; + // ["div", { class: "prosemirror-anchor" }, + // ["span", { class: "prosemirror-linkBtn" }, + // ["a", { ...node.attrs, class: linkids, "data-targetids": targetids, title: `${node.attrs.title}` }, 0], + // ["input", { class: "prosemirror-hrefoptions" }], + // ], + // ["div", { class: "prosemirror-links" }, ...node.attrs.allLinks.map((item: { href: string, title: string }) => + // ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title] + // )] + // ]; } }, diff --git a/src/client/views/nodes/formattedText/prosemirrorPatches.js b/src/client/views/nodes/formattedText/prosemirrorPatches.js index 0969ea4ef..746c93868 100644 --- a/src/client/views/nodes/formattedText/prosemirrorPatches.js +++ b/src/client/views/nodes/formattedText/prosemirrorPatches.js @@ -146,7 +146,9 @@ function isInSetWithAttrs(mark, set, attrs) { for (var i = 0; i < set.length; i++) { if (set[i].type == mark) { if (Array.from(Object.keys(attrs)).reduce((p, akey) => { - return p && JSON.stringify(set[i].attrs[akey]) === JSON.stringify(attrs[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))) + return false; }, true)) { return set[i]; } @@ -178,7 +180,7 @@ function removeMarkWithAttrs(tr, from, to, mark, attrs) { var style = toRemove[i], found$1 = (void 0); for (var j = 0; j < matched.length; j++) { var m = matched[j]; - if (m.step == step - 1 && style.eq(matched[j].style)) { found$1 = m; } + if (m.step == step - 1 /*&& style.eq(matched[j].style)*/) { found$1 = m; } // bcz: not sure what this is even trying to do, but style.eq doesn't seem to exist anymore } if (found$1) { found$1.to = end; |