From 1b65063a3cce0123215c914af6328a8a81ece33f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 13 Jun 2020 20:53:31 -0400 Subject: fixed text sidebar when text is scaled. started to add multiple links to a text selection --- .../nodes/formattedText/FormattedTextBoxComment.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx') diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 59a6045ab..dde7cc0c1 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -115,7 +115,7 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = ""); } - static update(view: EditorView, lastState?: EditorState) { + 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) && @@ -160,25 +160,26 @@ export class FormattedTextBoxComment { 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); - if (mark && child && nbef && naft && mark.attrs.showPreview) { - FormattedTextBoxComment.tooltipText.textContent = "external => " + mark.attrs.href; - (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; - if (mark.attrs.href.startsWith("https://en.wikipedia.org/wiki/")) { - wiki().page(mark.attrs.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500))); + const href = mark?.attrs.href || forceUrl; + if (forceUrl || (href && child && nbef && naft && mark?.attrs.showPreview)) { + FormattedTextBoxComment.tooltipText.textContent = "external => " + href; + (FormattedTextBoxComment.tooltipText as any).href = href; + if (href.startsWith("https://en.wikipedia.org/wiki/")) { + wiki().page(href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500))); } else { FormattedTextBoxComment.tooltipText.style.whiteSpace = "pre"; FormattedTextBoxComment.tooltipText.style.overflow = "hidden"; } - if (mark.attrs.href.indexOf(Utils.prepend("/doc/")) === 0) { + if (href.indexOf(Utils.prepend("/doc/")) === 0) { FormattedTextBoxComment.tooltipText.textContent = "target not found..."; (FormattedTextBoxComment.tooltipText as any).href = ""; - const docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; + const docTarget = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; try { ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); } catch (e) { } docTarget && DocServer.GetRefField(docTarget).then(async linkDoc => { if (linkDoc instanceof Doc) { - (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; + (FormattedTextBoxComment.tooltipText as any).href = href; FormattedTextBoxComment.linkDoc = linkDoc; const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ? Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc)) || linkDoc); const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor; -- cgit v1.2.3-70-g09d2 From e2423815ef608f35fdb9c1625d7de0bf5a5fe206 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 13 Jun 2020 23:19:27 -0400 Subject: fixes to make link lines work correctly with text anchors that have more than one link. fixed problem making a text link anchor by adding dummy mark to split the selection first. --- .../CollectionFreeFormLinkView.tsx | 11 ++++++--- .../views/nodes/formattedText/FormattedTextBox.tsx | 24 ++++++++++--------- .../formattedText/FormattedTextBoxComment.tsx | 2 +- .../formattedText/ProsemirrorExampleTransfer.ts | 1 - .../views/nodes/formattedText/RichTextMenu.tsx | 8 +++---- src/client/views/nodes/formattedText/marks_rts.ts | 27 ++++++++++++++-------- src/fields/RichTextUtils.ts | 2 +- 7 files changed, 45 insertions(+), 30 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index f3fc04752..8ab00bb29 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -46,10 +46,15 @@ export class CollectionFreeFormLinkView extends React.Component ele.getAttribute("targetids")?.includes(AanchorId)); + const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId)); if (!targetBhyperlink) { this.props.A.props.Document[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100; this.props.A.props.Document[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 95d36c994..ffab1d1e1 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -583,20 +583,22 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }; } - makeLinkToSelection(linkDocId: string, title: string, location: string, targetId: string) { - if (this._editorView) { - const href = Utils.prepend("/doc/" + linkDocId); - const sel = this._editorView.state.selection; - let tr = this._editorView!.state.tr; - sel.from !== sel.to && this._editorView.state.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { - if (node.firstChild === null) { - const allHrefs = [{ href, title }]; + makeLinkToSelection(linkId: string, title: string, location: string, targetId: string) { + const state = this._editorView?.state; + if (state) { + const href = Utils.prepend("/doc/" + linkId); + const sel = state.selection; + const splitter = state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); + let tr = state.tr.addMark(sel.from, sel.to, splitter); + sel.from !== sel.to && tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { + if (node.firstChild === null && node.marks.find((m: Mark) => m.type.name === schema.marks.splitter.name)) { + const allHrefs = [{ href, title, targetId, linkId }]; allHrefs.push(...(node.marks.find((m: Mark) => m.type.name === schema.marks.link.name)?.attrs.allHrefs ?? [])); - const link = this._editorView!.state.schema.marks.link.create({ href, allHrefs, title, location, linkId: linkDocId, targetId }); + const link = state.schema.marks.link.create({ href, allHrefs, title, location, linkId, targetId }); tr = tr.addMark(pos, pos + node.nodeSize, link); } }); - this._editorView.dispatch(tr); + this._editorView!.dispatch(tr.removeMark(sel.from, sel.to, splitter)); } } componentDidMount() { @@ -704,7 +706,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 && scrollToLinkID === marks[linkIndex].attrs.href.replace(/.*\/doc\//, "") ? node : undefined; + return linkIndex !== -1 && marks[linkIndex].attrs.allRefs.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? node : undefined; }; let start = 0; diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index dde7cc0c1..7513c881d 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -160,7 +160,7 @@ export class FormattedTextBoxComment { 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.href || forceUrl; + const href = 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 0e3e7f91e..77b93b9d2 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -6,7 +6,6 @@ import { liftListItem, sinkListItem } from "./prosemirrorPatches.js"; import { splitListItem, wrapInList, } from "prosemirror-schema-list"; import { EditorState, Transaction, TextSelection } from "prosemirror-state"; import { SelectionManager } from "../../../util/SelectionManager"; -import { Docs } from "../../../documents/Documents"; import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types"; import { Doc } from "../../../../fields/Doc"; import { FormattedTextBox } from "./FormattedTextBox"; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index fd1b26208..03d393cde 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -631,7 +631,7 @@ export default class RichTextMenu extends AntimodeMenu { const node = this.view.state.selection.$from.nodeAfter; const link = node && node.marks.find(m => m.type.name === "link"); if (link) { - const href = link.attrs.href; + const href = link.attrs.allHrefs.length > 0 ? link.attrs.allHrefs[0].href : undefined; if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; @@ -677,7 +677,7 @@ export default class RichTextMenu extends AntimodeMenu { const node = this.view.state.selection.$from.nodeAfter; const link = node && node.marks.find(m => m.type === this.view!.state.schema.marks.link); - const href = link!.attrs.href; + const href = link!.attrs.allHrefs.length > 0 ? link!.attrs.allHrefs[0].href : undefined; if (href) { if (href.indexOf(Utils.prepend("/doc/")) === 0) { const linkclicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0]; @@ -705,8 +705,8 @@ export default class RichTextMenu extends AntimodeMenu { let startIndex = $start.index(); let endIndex = $start.indexAfter(); - while (startIndex > 0 && $start.parent.child(startIndex - 1).marks.filter(m => m.type === mark && m.attrs.href === href).length) startIndex--; - while (endIndex < $start.parent.childCount && $start.parent.child(endIndex).marks.filter(m => m.type === mark && m.attrs.href === href).length) endIndex++; + while (startIndex > 0 && $start.parent.child(startIndex - 1).marks.filter(m => m.type === mark && m.attrs.allHrefs.find((item: { href: string }) => item.href === href)).length) startIndex--; + while (endIndex < $start.parent.childCount && $start.parent.child(endIndex).marks.filter(m => m.type === mark && m.attrs.allHrefs.find((item: { href: string }) => item.href === href)).length) endIndex++; let startPos = $start.start(); let endPos = startPos; diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index b42fa6755..9c279a88f 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -9,15 +9,20 @@ const codeDOM: DOMOutputSpecArray = ["code", 0]; // :: Object [Specs](#model.MarkSpec) for the marks in the schema. export const marks: { [index: string]: MarkSpec } = { + splitter: { + attrs: { + id: { default: "" } + }, + toDOM(node: any) { + return ["div", { className: "dummy" }, 0]; + } + }, // :: MarkSpec A link. Has `href` and `title` attributes. `title` // defaults to the empty string. Rendered and parsed as an `` // element. link: { attrs: { - href: {}, - allHrefs: { default: [] as { href: string, title: string }[] }, - targetId: { default: "" }, - linkId: { default: "" }, + allHrefs: { default: [] as { href: string, title: string, linkId: string, targetId: string }[] }, showPreview: { default: true }, location: { default: null }, title: { default: null }, @@ -26,20 +31,24 @@ export const marks: { [index: string]: MarkSpec } = { inclusive: false, parseDOM: [{ tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), location: dom.getAttribute("location"), title: dom.getAttribute("title"), targetId: dom.getAttribute("id") }; + return { allHrefs: [{ href: dom.getAttribute("href"), title: dom.getAttribute("title"), linkId: dom.getAttribute("linkids"), targetId: dom.getAttribute("targetids") }], location: dom.getAttribute("location"), }; } }], toDOM(node: any) { + 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"]] : node.attrs.allHrefs.length === 1 ? - ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0] : + ["a", { ...node.attrs, class: linkids, targetids, title: `${node.attrs.title}`, href: node.attrs.allHrefs[0].href }, 0] : ["div", { class: "prosemirror-anchor" }, ["button", { class: "prosemirror-linkBtn" }, - ["a", { ...node.attrs, id: node.attrs.linkId + node.attrs.targetId, title: `${node.attrs.title}` }, 0], - ["input", { class: "fa fa-caret-down prosemirror-hrefoptions" }], + ["a", { ...node.attrs, class: linkids, targetids, title: `${node.attrs.title}` }, 0], + ["input", { class: "prosemirror-hrefoptions" }], ], - ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title])] + ["div", { class: "prosemirror-links" }, ...node.attrs.allHrefs.map((item: { href: string, title: string }) => + ["a", { class: "prosemirror-dropdownlink", href: item.href }, item.title] + )] ] } }, diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts index f81ec8c6d..66959882d 100644 --- a/src/fields/RichTextUtils.ts +++ b/src/fields/RichTextUtils.ts @@ -392,7 +392,7 @@ export namespace RichTextUtils { const { attrs } = mark; switch (converted) { case "link": - let url = attrs.href; + let url = attrs.allHrefs.length ? attrs.allHrefs[0].href : ""; const delimiter = "/doc/"; const alreadyShared = "?sharing=true"; if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) { -- cgit v1.2.3-70-g09d2 From 182aef3ef47a3005e1b8a60bad8195769ce07733 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 15 Jun 2020 18:00:25 -0400 Subject: fixed acls for text hyperlinks (mostly) by not allowing links to be traversed --- src/client/DocServer.ts | 7 +++- src/client/views/nodes/DocumentView.tsx | 14 ++++++- .../formattedText/FormattedTextBoxComment.tsx | 46 +++++++++++++--------- src/fields/Doc.ts | 20 ++-------- 4 files changed, 49 insertions(+), 38 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c6b3fa61f..c7dfb0b23 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,6 +1,6 @@ import * as io from 'socket.io-client'; import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message"; -import { Opt, Doc } from '../fields/Doc'; +import { Opt, Doc, fetchProto } from '../fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../fields/RefField'; @@ -244,7 +244,10 @@ export namespace DocServer { return cached; } else { // CACHED => great, let's just return the cached field we have - return Promise.resolve(cached); + return Promise.resolve(cached).then(field => { + (field instanceof Doc) && fetchProto(field); + return field; + }); } }; const _GetCachedRefFieldImpl = (id: string): Opt => { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 35bf5344e..8a067b806 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -687,7 +687,18 @@ export class DocumentView extends DocComponent(Docu @undoBatch @action setAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => { - this.layoutDoc.ACL = this.dataDoc.ACL = acl; + this.dataDoc.ACL = this.props.Document.ACL = acl; + DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => { + if (d.author === Doc.CurrentUserEmail) d.ACL = acl; + const data = d[DataSym]; + if (data && data.author === Doc.CurrentUserEmail) data.ACL = acl; + }); + } + @undoBatch + @action + testAcl = (acl: "readOnly" | "addOnly" | "ownerOnly") => { + this.dataDoc.author = this.props.Document.author = "ADMIN"; + this.dataDoc.ACL = this.props.Document.ACL = acl; DocListCast(this.dataDoc[Doc.LayoutFieldKey(this.dataDoc)]).map(d => { if (d.author === Doc.CurrentUserEmail) d.ACL = acl; const data = d[DataSym]; @@ -758,6 +769,7 @@ export class DocumentView extends DocComponent(Docu moreItems.push({ description: "Make Add Only", event: () => this.setAcl("addOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make Read Only", event: () => this.setAcl("readOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make Private", event: () => this.setAcl("ownerOnly"), icon: "concierge-bell" }); + moreItems.push({ description: "Test Private", event: () => this.testAcl("ownerOnly"), icon: "concierge-bell" }); moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 7513c881d..5ac173602 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -84,11 +84,13 @@ export class FormattedTextBoxComment { const keep = e.target && (e.target as any).type === "checkbox" ? true : false; const textBox = FormattedTextBoxComment.textBox; if (FormattedTextBoxComment.linkDoc && !keep && textBox) { - if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { - textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); - } else { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, - (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + if (FormattedTextBoxComment.linkDoc.author) { + if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) { + textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "inTab" : "onRight"); + } else { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : followLinkLocation)); + } } } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400, UseCors: true }), "onRight"); @@ -115,6 +117,23 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = ""); } + static showCommentbox(set: string, view: EditorView, nbef: number) { + const state = view.state; + if (set !== "none") { + // These are in screen coordinates + // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to); + 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 && (FormattedTextBoxComment.tooltip.style.display = set); + } + static update(view: EditorView, lastState?: EditorState, forceUrl: string = "") { const state = view.state; // Don't do anything if the document/selection didn't change @@ -186,7 +205,8 @@ export class FormattedTextBoxComment { if (anchor !== target && anchor && target) { target._scrollY = NumCast(anchor?.y); } - if (target) { + if (target?.author) { + FormattedTextBoxComment.showCommentbox("", view, nbef); ReactDOM.render( { - if (proto.author !== Doc.CurrentUserEmail) { - if (proto.ACL === "ownerOnly") { - proto[AclSym] = doc[AclSym] = AclPrivate; - return undefined; - } else if (proto.ACL === "readOnly") { - proto[AclSym] = doc[AclSym] = AclReadonly; - } else if (proto.ACL === "addOnly") { - proto[AclSym] = doc[AclSym] = AclAddonly; - } - } - }); - return proto; + if (doc.proto instanceof Promise) { + doc.proto.then(proto => fetchProto(proto)); + return doc.proto; } } -- cgit v1.2.3-70-g09d2 From 997035dfaf78ec0bcb4ec1b85e2e3f7dae410ca0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 16 Jun 2020 12:40:21 -0400 Subject: cleaned up some of the prosemirror plugin views. --- .../nodes/formattedText/DashDocCommentView.tsx | 38 +++--- .../views/nodes/formattedText/DashFieldView.tsx | 7 +- .../views/nodes/formattedText/FootnoteView.tsx | 17 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 8 +- .../formattedText/FormattedTextBoxComment.tsx | 7 +- .../views/nodes/formattedText/RichTextSchema.tsx | 96 +------------- .../views/nodes/formattedText/SummaryView.tsx | 144 +++++++-------------- 7 files changed, 86 insertions(+), 231 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx') diff --git a/src/client/views/nodes/formattedText/DashDocCommentView.tsx b/src/client/views/nodes/formattedText/DashDocCommentView.tsx index 2d4e360a8..ad204f3df 100644 --- a/src/client/views/nodes/formattedText/DashDocCommentView.tsx +++ b/src/client/views/nodes/formattedText/DashDocCommentView.tsx @@ -4,6 +4,10 @@ import { Doc } from "../../../../fields/Doc"; import { DocServer } from "../../../DocServer"; import React = require("react"); + +// creates an inline comment in a note when '>>' is typed. +// the comment sits on the right side of the note and vertically aligns with its anchor in the text. +// the comment can be toggled on/off with the '<-' text anchor. export class DashDocCommentView { _fieldWrapper: HTMLDivElement; // container for label and value @@ -19,11 +23,7 @@ export class DashDocCommentView { this._fieldWrapper.onkeyup = function (e: any) { e.stopPropagation(); }; this._fieldWrapper.onmousedown = function (e: any) { e.stopPropagation(); }; - ReactDOM.render(, this._fieldWrapper); + ReactDOM.render(, this._fieldWrapper); (this as any).dom = this._fieldWrapper; } @@ -35,12 +35,11 @@ export class DashDocCommentView { } interface IDashDocCommentViewInternal { - node: any; + docid: string; view: any; getPos: any; } - export class DashDocCommentViewInternal extends React.Component{ constructor(props: IDashDocCommentViewInternal) { @@ -51,18 +50,14 @@ export class DashDocCommentViewInternal extends React.Component dashDoc instanceof Doc && Doc.linkFollowUnhighlight()); + DocServer.GetRefField(this.props.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowUnhighlight()); e.preventDefault(); e.stopPropagation(); }; onPointerEnterCollapsed(e: any) { - DocServer.GetRefField(this.props.node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc, false)); + DocServer.GetRefField(this.props.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc, false)); e.preventDefault(); e.stopPropagation(); }; @@ -75,7 +70,7 @@ export class DashDocCommentViewInternal extends React.Component { - expand && DocServer.GetRefField(this.props.node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); + expand && DocServer.GetRefField(this.props.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); try { this.props.view.dispatch(this.props.view.state.tr.setSelection(TextSelection.create(this.props.view.state.tr.doc, this.props.getPos() + (expand ? 2 : 1)))); } catch (e) { } }, 0); } @@ -87,16 +82,17 @@ export class DashDocCommentViewInternal extends React.Component { // search forward in the prosemirror doc for the attached dashDocNode that is the target of the comment anchor - for (let i = this.props.getPos() + 1; i < this.props.view.state.doc.content.size; i++) { - const m = this.props.view.state.doc.nodeAt(i); - if (m && m.type === this.props.view.state.schema.nodes.dashDoc && m.attrs.docid === this.props.node.attrs.docid) { + const state = this.props.view.state; + for (let i = this.props.getPos() + 1; i < state.doc.content.size; i++) { + const m = state.doc.nodeAt(i); + if (m && m.type === state.schema.nodes.dashDoc && m.attrs.docid === this.props.docid) { return { node: m, pos: i, hidden: m.attrs.hidden } as { node: any, pos: number, hidden: boolean }; } } - const dashDoc = this.props.view.state.schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: this.props.node.attrs.docid, float: "right" }); - this.props.view.dispatch(this.props.view.state.tr.insert(this.props.getPos() + 1, dashDoc)); - setTimeout(() => { try { this.props.view.dispatch(this.props.view.state.tr.setSelection(TextSelection.create(this.props.view.state.tr.doc, this.props.getPos() + 2))); } catch (e) { } }, 0); + const dashDoc = state.schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: this.props.docid, float: "right" }); + this.props.view.dispatch(state.tr.insert(this.props.getPos() + 1, dashDoc)); + setTimeout(() => { try { this.props.view.dispatch(state.tr.setSelection(TextSelection.create(state.tr.doc, this.props.getPos() + 2))); } catch (e) { } }, 0); return undefined; }; @@ -104,7 +100,7 @@ export class DashDocCommentViewInternal extends React.Component, this._fieldWrapper); (this as any).dom = this._fieldWrapper; } - destroy() { - ReactDOM.unmountComponentAtNode(this._fieldWrapper); - } + destroy() { ReactDOM.unmountComponentAtNode(this._fieldWrapper); } selectNode() { } - } + interface IDashFieldViewInternal { fieldKey: string; docid: string; diff --git a/src/client/views/nodes/formattedText/FootnoteView.tsx b/src/client/views/nodes/formattedText/FootnoteView.tsx index 1d21f2ae9..1683cc972 100644 --- a/src/client/views/nodes/formattedText/FootnoteView.tsx +++ b/src/client/views/nodes/formattedText/FootnoteView.tsx @@ -28,15 +28,11 @@ export class FootnoteView { } selectNode() { - const attrs = { ...this.node.attrs }; - attrs.visibility = true; this.dom.classList.add("ProseMirror-selectednode"); if (!this.innerView) this.open(); } deselectNode() { - const attrs = { ...this.node.attrs }; - attrs.visibility = false; this.dom.classList.remove("ProseMirror-selectednode"); if (this.innerView) this.close(); } @@ -78,7 +74,7 @@ export class FootnoteView { }) as any } }); - setTimeout(() => this.innerView && this.innerView.docView.setSelection(0, 0, this.innerView.root, true), 0); + setTimeout(() => this.innerView?.docView.setSelection(0, 0, this.innerView.root, true), 0); } ignore = (e: PointerEvent) => { @@ -88,13 +84,11 @@ export class FootnoteView { toggle = () => { if (this.innerView) this.close(); - else { - this.open(); - } + else this.open(); } close() { - this.innerView && this.innerView.destroy(); + this.innerView?.destroy(); this.innerView = null; this.dom.textContent = ""; } @@ -106,8 +100,7 @@ export class FootnoteView { if (!tr.getMeta("fromOutside")) { const outerTr = this.outerView.state.tr, offsetMap = StepMap.offset(this.getPos() + 1); for (const transaction of transactions) { - const steps = transaction.steps; - for (const step of steps) { + for (const step of transaction.steps) { outerTr.step(step.map(offsetMap)); } } @@ -139,7 +132,7 @@ export class FootnoteView { } stopEvent(event: any) { - return this.innerView && this.innerView.dom.contains(event.target); + return this.innerView?.dom.contains(event.target); } ignoreMutation() { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 99cd503ec..ba36a1618 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -35,8 +35,8 @@ import buildKeymap from "./ProsemirrorExampleTransfer"; import RichTextMenu from './RichTextMenu'; import { RichTextRules } from "./RichTextRules"; -import { DashDocView } from "./DashDocView"; -// import { DashDocView } from "./RichTextSchema"; +//import { DashDocView } from "./DashDocView"; +import { DashDocView } from "./RichTextSchema"; import { DashDocCommentView } from "./DashDocCommentView"; import { DashFieldView } from "./DashFieldView"; @@ -903,9 +903,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, dispatchTransaction: this.dispatchTransaction, nodeViews: { - dashComment(node, view, getPos) { console.log("rendering dashComment"); return new DashDocCommentView(node, view, getPos); }, - dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); }, + dashComment(node, view, getPos) { return new DashDocCommentView(node, view, getPos); }, dashDoc(node, view, getPos) { return new DashDocView(node, view, getPos, self); }, + dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); }, summary(node, view, getPos) { return new SummaryView(node, view, getPos); }, ordered_list(node, view, getPos) { return new OrderedListView(); }, footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); } diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 5ac173602..000b3c2e5 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -50,7 +50,9 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark return after; } - +// 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; @@ -235,9 +237,6 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip.style.width = NumCast(target._width) ? `${NumCast(target._width)}` : "100%"; FormattedTextBoxComment.tooltip.style.height = NumCast(target._height) ? `${NumCast(target._height)}` : "100%"; } - // let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field. probably need an 'overviewLayout' and then just display the target Document .... - // let text = ext && StrCast(ext.text); - // ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title))); } }); } diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index 79abfa995..05557e22a 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -1,95 +1,20 @@ -import { IReactionDisposer, observable, reaction, runInAction } from "mobx"; -import { baseKeymap, toggleMark } from "prosemirror-commands"; -import { redo, undo } from "prosemirror-history"; -import { keymap } from "prosemirror-keymap"; -import { DOMOutputSpecArray, Fragment, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model"; -import { bulletList, listItem, orderedList } from 'prosemirror-schema-list'; -import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-state"; -import { StepMap } from "prosemirror-transform"; -import { EditorView } from "prosemirror-view"; +import { IReactionDisposer, reaction } from "mobx"; +import { NodeSelection } from "prosemirror-state"; import * as ReactDOM from 'react-dom'; -import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../../../fields/Doc"; +import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc"; import { Id } from "../../../../fields/FieldSymbols"; -import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; -import { listSpec } from "../../../../fields/Schema"; -import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; import { ComputedField } from "../../../../fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../../fields/Types"; -import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../../../Utils"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types"; +import { emptyFunction, returnEmptyString, returnFalse, returnZero, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; -import { CollectionViewType } from "../../collections/CollectionView"; +import { Transform } from "../../../util/Transform"; import { DocumentView } from "../DocumentView"; import { FormattedTextBox } from "./FormattedTextBox"; -import { DocumentManager } from "../../../util/DocumentManager"; -import { Transform } from "../../../util/Transform"; import React = require("react"); - -// export class DashDocCommentView { -// _collapsed: HTMLElement; -// _view: any; -// constructor(node: any, view: any, getPos: any) { - -// console.log("DashDocCommentView constructor"); - -// //moved -// this._collapsed = document.createElement("span"); -// this._collapsed.className = "formattedTextBox-inlineComment"; -// this._collapsed.id = "DashDocCommentView-" + node.attrs.docid; -// this._view = view; -// //moved -// const targetNode = () => { // search forward in the prosemirror doc for the attached dashDocNode that is the target of the comment anchor -// for (let i = getPos() + 1; i < view.state.doc.content.size; i++) { -// const m = view.state.doc.nodeAt(i); -// if (m && m.type === view.state.schema.nodes.dashDoc && m.attrs.docid === node.attrs.docid) { -// return { node: m, pos: i, hidden: m.attrs.hidden } as { node: any, pos: number, hidden: boolean }; -// } -// } -// const dashDoc = view.state.schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: node.attrs.docid, float: "right" }); -// view.dispatch(view.state.tr.insert(getPos() + 1, dashDoc)); -// setTimeout(() => { try { view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.tr.doc, getPos() + 2))); } catch (e) { } }, 0); -// return undefined; -// }; -// //moved -// this._collapsed.onpointerdown = (e: any) => { -// e.stopPropagation(); -// }; -// //moved -// this._collapsed.onpointerup = (e: any) => { -// const target = targetNode(); -// if (target) { -// const expand = target.hidden; -// const tr = view.state.tr.setNodeMarkup(target.pos, undefined, { ...target.node.attrs, hidden: target.node.attrs.hidden ? false : true }); -// view.dispatch(tr.setSelection(TextSelection.create(tr.doc, getPos() + (expand ? 2 : 1)))); // update the attrs -// setTimeout(() => { -// expand && DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); -// try { view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.tr.doc, getPos() + (expand ? 2 : 1)))); } catch (e) { } -// }, 0); -// } -// e.stopPropagation(); -// }; -// //moved -// this._collapsed.onpointerenter = (e: any) => { -// DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc, false)); -// e.preventDefault(); -// e.stopPropagation(); -// }; -// //moved -// this._collapsed.onpointerleave = (e: any) => { -// DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowUnhighlight()); -// e.preventDefault(); -// e.stopPropagation(); -// }; - -// (this as any).dom = this._collapsed; -// } -// //moved -// selectNode() { } -// } - export class DashDocView { _dashSpan: HTMLDivElement; _outer: HTMLElement; @@ -132,10 +57,6 @@ export class DashDocView { this._dashSpan.style.whiteSpace = "normal"; this._dashSpan.onpointerleave = () => { - - console.log("DashDocView_dashSpan.onpointerleave"); // SMM - console.log("DashDocCommentView-id=", node.attrs.docid); // SMM - const ele = document.getElementById("DashDocCommentView-" + node.attrs.docid); if (ele) { (ele as HTMLDivElement).style.backgroundColor = ""; @@ -143,9 +64,6 @@ export class DashDocView { }; this._dashSpan.onpointerenter = () => { - console.log("DashDocView_dashSpan.onpointerenter"); // SMM - console.log("DashDocCommentView-id=", node.attrs.docid); // SMM - const ele = document.getElementById("DashDocCommentView-" + node.attrs.docid); if (ele) { (ele as HTMLDivElement).style.backgroundColor = "orange"; @@ -208,7 +126,7 @@ export class DashDocView { this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px"; this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray")); }, { fireImmediately: true }); - + const doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => { ReactDOM.unmountComponentAtNode(this._dashSpan); diff --git a/src/client/views/nodes/formattedText/SummaryView.tsx b/src/client/views/nodes/formattedText/SummaryView.tsx index e5328496c..922285bd0 100644 --- a/src/client/views/nodes/formattedText/SummaryView.tsx +++ b/src/client/views/nodes/formattedText/SummaryView.tsx @@ -1,108 +1,45 @@ -import { IReactionDisposer, observable, computed, action } from "mobx"; -import { Fragment, Node, Slice } from "prosemirror-model"; import { TextSelection } from "prosemirror-state"; +import { Fragment, Node, Slice } from "prosemirror-model"; import * as ReactDOM from 'react-dom'; import React = require("react"); -// import { dom } from "@fortawesome/fontawesome-svg-core"; -// import { observer } from "mobx-react"; +// an elidable textblock that collapses when its '<-' is clicked and expands when its '...' anchor is clicked. +// this node actively edits prosemirror (as opposed to just changing how things are rendered) and thus doesn't +// really need a react view. However, it would be cleaner to figure out how to do this just as a react rendering +// method instead of changing prosemirror's text when the expand/elide buttons are clicked. export class SummaryView { - - _fieldWrapper: HTMLDivElement; // container for label + _fieldWrapper: HTMLSpanElement; // container for label and value constructor(node: any, view: any, getPos: any) { - console.log("You are here") - this._fieldWrapper = document.createElement("div"); - this._fieldWrapper.style.fontWeight = "bold"; - this._fieldWrapper.style.position = "relative"; - this._fieldWrapper.style.display = "inline-block"; + const self = this; + this._fieldWrapper = document.createElement("span"); + this._fieldWrapper.className = this.className(node.attrs.visibility); + this._fieldWrapper.onpointerdown = function (e: any) { self.onPointerDown(e, node, view, getPos); } + this._fieldWrapper.onkeypress = function (e: any) { e.stopPropagation(); }; + this._fieldWrapper.onkeydown = function (e: any) { e.stopPropagation(); }; + this._fieldWrapper.onkeyup = function (e: any) { e.stopPropagation(); }; + this._fieldWrapper.onmousedown = function (e: any) { e.stopPropagation(); }; const js = node.toJSON; - node.toJSON = function () { - return js.apply(this, arguments); - }; + node.toJSON = function () { return js.apply(this, arguments); }; - console.log("rendering new SummaryViewInternal") - ReactDOM.render(, this._fieldWrapper); + ReactDOM.render(, this._fieldWrapper); (this as any).dom = this._fieldWrapper; } + className = (visible: boolean) => "formattedTextBox-summarizer" + (visible ? "" : "-collapsed"); + destroy() { ReactDOM.unmountComponentAtNode(this._fieldWrapper); } selectNode() { } - deselectNode() { } - - destroy() { - ReactDOM.unmountComponentAtNode(this._fieldWrapper); - } -} - -interface ISummaryViewInternal { - node: any; - view: any; - getPos: any; -} - -export class SummaryViewInternal extends React.Component{ - _className: any; - _view: any; - _reactionDisposer: IReactionDisposer | undefined; - - constructor(props: ISummaryViewInternal) { - super(props); - - this._className = this.className(this.props.node.attrs.visibility); - this._view = this.props.view; - this.onPointerDownCollapsed = this.onPointerDownCollapsed.bind(this); - this.updateSummarizedText = this.updateSummarizedText.bind(this); - } - - componentWillUnmount() { - this._reactionDisposer?.(); - } - - - className(visible: boolean) { - return "formattedTextBox-summarizer" + (visible ? "" : "-collapsed"); - } - - onPointerDownCollapsed(e: any) { - const visible = !this.props.node.attrs.visibility; - const attrs = { ...this.props.node.attrs, visibility: visible }; - let textSelection = TextSelection.create(this.props.view.state.doc, this.props.getPos() + 1); - - - if (!visible) { // update summarized text and save in attrs - textSelection = this.updateSummarizedText(this.props.getPos() + 1); - attrs.text = textSelection.content(); - attrs.textslice = attrs.text.toJSON(); - } - - this.props.view.dispatch(this.props.view.state.tr. - setSelection(textSelection). // select the current summarized text (or where it will be if its collapsed) - replaceSelection(!visible ? new Slice(Fragment.fromArray([]), 0, 0) : this.props.node.attrs.text). // collapse/expand it - setNodeMarkup(this.props.getPos(), undefined, attrs)); // update the attrs - - e.preventDefault(); - e.stopPropagation(); - - this._className = this.className(visible); - - } - - updateSummarizedText(start?: any) { - const mtype = this.props.view.state.schema.marks.summarize; - const mtypeInc = this.props.view.state.schema.marks.summarizeInclusive; + updateSummarizedText(start: any, view: any) { + const mtype = view.state.schema.marks.summarize; + const mtypeInc = view.state.schema.marks.summarizeInclusive; let endPos = start; const visited = new Set(); - for (let i: number = start + 1; i < this.props.view.state.doc.nodeSize - 1; i++) { + for (let i: number = start + 1; i < view.state.doc.nodeSize - 1; i++) { let skip = false; - this.props.view.state.doc.nodesBetween(start, i, (node: Node, pos: number, parent: Node, index: number) => { + view.state.doc.nodesBetween(start, i, (node: Node, pos: number, parent: Node, index: number) => { if (node.isLeaf && !visited.has(node) && !skip) { if (node.marks.find((m: any) => m.type === mtype || m.type === mtypeInc)) { visited.add(node); @@ -112,18 +49,33 @@ export class SummaryViewInternal extends React.Component{ } }); } - return TextSelection.create(this.props.view.state.doc, start, endPos); + return TextSelection.create(view.state.doc, start, endPos); } - render() { - return ( - - - - ); - + onPointerDown = (e: any, node: any, view: any, getPos: any) => { + const visible = !node.attrs.visibility; + const attrs = { ...node.attrs, visibility: visible }; + let textSelection = TextSelection.create(view.state.doc, getPos() + 1); + if (!visible) { // update summarized text and save in attrs + textSelection = this.updateSummarizedText(getPos() + 1, view); + attrs.text = textSelection.content(); + attrs.textslice = attrs.text.toJSON(); + } + view.dispatch(view.state.tr. + setSelection(textSelection). // select the current summarized text (or where it will be if its collapsed) + replaceSelection(!visible ? new Slice(Fragment.fromArray([]), 0, 0) : node.attrs.text). // collapse/expand it + setNodeMarkup(getPos(), undefined, attrs)); // update the attrs + e.preventDefault(); + e.stopPropagation(); + this._fieldWrapper.className = this.className(visible); } +} +interface ISummaryView { } +// currently nothing needs to be rendered for the internal view of a summary. +export class SummaryViewInternal extends React.Component { + render() { + return <> ; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1a03c645e5801fe0cfe71e1b1744313a41523de6 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 17 Jun 2020 20:07:44 -0400 Subject: made docFilters a prop on everything --- src/Utils.ts | 2 ++ src/client/views/GestureOverlay.tsx | 3 ++- src/client/views/GlobalKeyHandler.ts | 4 ++-- src/client/views/MainView.tsx | 6 +++++- src/client/views/OverlayView.tsx | 3 ++- src/client/views/Palette.tsx | 3 ++- src/client/views/RecommendationsBox.tsx | 3 ++- src/client/views/TemplateMenu.tsx | 3 ++- src/client/views/collections/CollectionDockingView.tsx | 4 ++-- src/client/views/collections/CollectionLinearView.tsx | 1 + src/client/views/collections/CollectionSchemaCells.tsx | 3 ++- src/client/views/collections/CollectionSchemaView.tsx | 1 + src/client/views/collections/CollectionStackingView.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 9 +++++++-- src/client/views/collections/CollectionTreeView.tsx | 6 ++++-- src/client/views/collections/CollectionView.tsx | 3 ++- .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 + .../collectionMulticolumn/CollectionMulticolumnView.tsx | 1 + .../collections/collectionMulticolumn/CollectionMultirowView.tsx | 1 + src/client/views/nodes/DocHolderBox.tsx | 2 ++ src/client/views/nodes/DocumentView.tsx | 2 ++ src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/ImageBox.tsx | 1 + src/client/views/nodes/KeyValuePair.tsx | 3 ++- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 1 + src/client/views/nodes/WebBox.tsx | 1 + src/client/views/nodes/formattedText/DashDocView.tsx | 3 ++- src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx | 3 ++- src/client/views/nodes/formattedText/RichTextSchema.tsx | 1 + src/client/views/pdf/PDFViewer.tsx | 1 + src/client/views/presentationview/PresElementBox.tsx | 1 + src/client/views/search/SearchItem.tsx | 3 ++- src/mobile/MobileInterface.tsx | 5 ++++- 34 files changed, 66 insertions(+), 22 deletions(-) (limited to 'src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index e527634fd..dba802f98 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -395,6 +395,8 @@ export function returnZero() { return 0; } export function returnEmptyString() { return ""; } +export function returnEmptyFilter() { return [] as string[]; } + export let emptyPath = []; export function emptyFunction() { } diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 79d407c7a..aeac1d4a9 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -8,7 +8,7 @@ import MobileInkOverlay from "../../mobile/MobileInkOverlay"; import MobileInterface from "../../mobile/MobileInterface"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; import { MobileInkOverlayContent } from "../../server/Message"; -import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from "../../Utils"; +import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, returnEmptyFilter } from "../../Utils"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { DocServer } from "../DocServer"; import { DocUtils } from "../documents/Documents"; @@ -845,6 +845,7 @@ export default class GestureOverlay extends Touchable { parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} + docFilters={returnEmptyFilter} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} />; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index fead46301..f5adeeb00 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -267,8 +267,8 @@ export default class KeyManager { const text = `__DashDocId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.SelectedDocuments().map(dv => dv.Document[Id]).join(":"); SelectionManager.SelectedDocuments().length && navigator.clipboard.writeText(text); stopPropagation = false; - preventDefault = false; - } else preventDefault = false + } + preventDefault = false; break; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 2f68004f9..4a09f9ff3 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -20,7 +20,7 @@ import { listSpec } from '../../fields/Schema'; import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; -import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils'; +import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils, returnEmptyFilter } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; @@ -310,6 +310,7 @@ export class MainView extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} + docFilters={returnEmptyFilter} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} />; @@ -412,6 +413,7 @@ export class MainView extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} + docFilters={returnEmptyFilter} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} /> @@ -438,6 +440,7 @@ export class MainView extends React.Component { parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} + docFilters={returnEmptyFilter} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} />