aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2019-08-28 15:02:20 -0400
committerbob <bcz@cs.brown.edu>2019-08-28 15:02:20 -0400
commit4b7672c75fe5cdf6afe534e67213917b24980c3e (patch)
tree1fc93c899e2965c73cf581f0ffe24dd78791b9ee
parent19ba56239796cc6a421bbb02affc47802ef824a7 (diff)
added better support for usermarks and fledliging for accept changes.
-rw-r--r--src/client/util/RichTextSchema.tsx14
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss17
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx47
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();
}