diff options
author | bob <bcz@cs.brown.edu> | 2019-08-28 15:02:20 -0400 |
---|---|---|
committer | bob <bcz@cs.brown.edu> | 2019-08-28 15:02:20 -0400 |
commit | 4b7672c75fe5cdf6afe534e67213917b24980c3e (patch) | |
tree | 1fc93c899e2965c73cf581f0ffe24dd78791b9ee | |
parent | 19ba56239796cc6a421bbb02affc47802ef824a7 (diff) |
added better support for usermarks and fledliging for accept changes.
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 14 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss | 17 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 47 |
3 files changed, 69 insertions, 9 deletions
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 6c06cec4d..f567d803e 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -333,12 +333,18 @@ export const marks: { [index: string]: MarkSpec } = { // the id of the user who entered the text user_mark: { attrs: { - userid: { default: "" } + userid: { default: "" }, + hide_users: { default: [] }, + opened: { default: false } }, + group: "inline", + inclusive: false, toDOM(node: any) { - return ['span', { - style: `background: ${node.attrs.userid.indexOf(Doc.CurrentUserEmail) === -1 ? "rgba(255, 255, 0, 0.267)" : undefined};` - }]; + let hideUsers = node.attrs.hide_users; + let hidden = hideUsers.indexOf(node.attrs.userid) !== -1 || (hideUsers.length === 0 && node.attrs.userid !== Doc.CurrentUserEmail); + return hidden ? + ['span', { class: node.attrs.opened ? "userMarkOpen" : "userMark" }, 0] : + ['span', 0]; } }, diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index e93ceda21..03e81bfca 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -67,6 +67,23 @@ font-style: italic; } +.userMarkOpen { + background: rgba(255, 255, 0, 0.267); + display: inline; +} +.userMark { + background: rgba(255, 255, 0, 0.267); + font-size: 2px; + display: inline-grid; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width:10px; + min-height:10px; + text-align:center; + align-content: center; +} + ol { counter-reset: deci 0;} .decimal-ol { counter-reset: deci 0; p { display: inline }; font-size: 24 } .decimal2-ol {counter-reset: deci2; p { display: inline }; font-size: 18 } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 1c5224e12..146281f2b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -5,8 +5,8 @@ import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; -import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark } from "prosemirror-model"; -import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state"; +import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark, ResolvedPos } from "prosemirror-model"; +import { EditorState, Plugin, Transaction, TextSelection, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { DateField } from '../../../new_fields/DateField'; import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc"; @@ -645,9 +645,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe document.removeEventListener("paste", this.paste); } - _down = false; onPointerDown = (e: React.PointerEvent): void => { - this._down = true; if (this.props.onClick && e.button === 0) { e.preventDefault(); } @@ -709,8 +707,47 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + findUserMark(marks: Mark[]) { + return marks.find(m => m.attrs && m.attrs.userid && m.attrs.userid !== Doc.CurrentUserEmail); + } + findStartOfMark(rpos: ResolvedPos) { + let before = 0; + let nbef = rpos.nodeBefore; + while (nbef && this.findUserMark(nbef.marks)) { + before += nbef.nodeSize; + rpos = this._editorView!.state.doc.resolve(rpos.pos - nbef.nodeSize); + rpos && (nbef = rpos.nodeBefore); + } + return before; + } + findEndOfMark(rpos: ResolvedPos) { + let after = 0; + let naft = rpos.nodeAfter; + while (naft && this.findUserMark(naft.marks)) { + after += naft.nodeSize; + rpos = this._editorView!.state.doc.resolve(rpos.pos + naft.nodeSize); + rpos && (naft = rpos.nodeAfter); + } + return after; + } + onPointerUp = (e: React.PointerEvent): void => { - this._down = false; + let view = this._editorView!; + const pos = view.posAtCoords({ left: e.clientX, top: e.clientY }); + const rpos = pos && view.state.doc.resolve(pos.pos); + if (pos && rpos && view.state.selection.$from === view.state.selection.$to) { + let nbef = this.findStartOfMark(rpos); + let naft = this.findEndOfMark(rpos); + const spos = view.state.doc.resolve(pos.pos - nbef); + const epos = view.state.doc.resolve(pos.pos + naft); + let ts = new TextSelection(spos, epos); + let child = rpos.nodeBefore; + let mark = child && this.findUserMark(child.marks); + if (mark && child && nbef && naft) { + let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: e.button === 2 ? Doc.CurrentUserEmail : mark.attrs.userid, opened: e.button === 2 ? false : !mark.attrs.opened }); + view.dispatch(view.state.tr.setSelection(ts).removeMark(ts.from, ts.to, nmark).addMark(ts.from, ts.to, nmark).setSelection(new TextSelection(epos, epos))); + } + } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } |