From 237b5f67733b25686b825573298818f3ea443876 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 26 Aug 2019 17:42:19 -0400
Subject: try another branch

---
 src/client/util/RichTextSchema.tsx | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index f128162c2..6e3d9ab77 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -178,6 +178,14 @@ export const nodes: { [index: string]: NodeSpec } = {
             bulletStyle: { default: "decimal" },
         },
         toDOM(node: Node<any>) {
+            let first = node.firstChild;
+            while (first) {
+                if (first.marks.find((m) => m.type === schema.marks.mbulletType)) {
+                    let x = first.marks.find((m) => m.type === schema.marks.mbulletType);
+                    return ['ol', { style: `list-style: ${(x as any).attrs.bulletType}` }, 0]
+                }
+                first = first.firstChild;
+            }
             return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
         }
     },
@@ -319,13 +327,15 @@ export const marks: { [index: string]: MarkSpec } = {
         toDOM: () => ['sup']
     },
 
-    malphabet_list: {
-    },
-    mcap_alphabet_list: {
-    },
-    mroman_list: {
-    },
-    mo_list: {
+    mbulletType: {
+        attrs: {
+            bulletType: { default: "decimal" }
+        },
+        toDOM(node: any) {
+            return ['span', {
+                style: `background: ${node.attrs.bulletType == "decimal" ? "yellow" : node.attrs.bulletType === "upper-alpha" ? "blue" : "green"}`
+            }];
+        }
     },
 
     highlight: {
-- 
cgit v1.2.3-70-g09d2


From 32c0388d9334ce1f0be04962e00ba3d389c50303 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 26 Aug 2019 21:36:29 -0400
Subject: testing things

---
 src/client/util/RichTextSchema.tsx           | 13 ++++++++++++-
 src/client/views/nodes/FormattedTextBox.scss |  9 +++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 6e3d9ab77..b5d81a359 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -243,7 +243,18 @@ export const nodes: { [index: string]: NodeSpec } = {
     // },
     list_item: {
         ...listItem,
-        content: 'paragraph block*'
+        content: 'paragraph block*',
+        toDOM(node: any) {
+            let first = node.firstChild;
+            while (first) {
+                if (first.marks.find((m: any) => m.type === schema.marks.mbulletType)) {
+                    let x = first.marks.find((m: any) => m.type === schema.marks.mbulletType);
+                    return ["li", { class: "XXX" }, 0];
+                }
+                first = first.firstChild;
+            }
+            return ["li", 0];
+        }
     },
 };
 
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 1b537cc52..9d5dc76d3 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -65,4 +65,13 @@
 
 .em {
     font-style: italic;
+}
+
+ol { counter-reset: item }
+.XXX:before {
+     content: counters(item, ".") " ";
+     counter-increment: item ;
+}
+p {
+    display:inline;
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 58300460307b2c944f1dd2d0d3b8e2515f529f72 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 00:17:22 -0400
Subject: more tweaks

---
 src/client/util/ProsemirrorExampleTransfer.ts | 35 +++++++++++++++++++--------
 src/client/util/RichTextSchema.tsx            |  8 ------
 2 files changed, 25 insertions(+), 18 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 8bec2015e..238d37800 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -98,10 +98,17 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
+            let path = (resolvedPos as any).path as any;
+            for (let i = path.length - 1; i > 0; i--) {
+                if (path[i].type === schema.nodes.ordered_list) {
+                    path[i].attrs.bulletStyle = (nodeTypeMark as any).attrs.bulletType;
+                    break;
+                }
+            }
             let ns = new NodeSelection(resolvedPos);
-            let tx3 = tx2.removeMark(ns.from - 1, ns.to, created).removeMark(ns.from - 1, ns.to, nodeTypeMark as any).addMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, nodeTypeMark).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
-            marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
-            marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
+            let tx3 = tx2.removeMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
+            marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+            marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
             dispatch(tx3);
         })) {
             let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
@@ -109,10 +116,10 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             if (!wrapInList(nodeType)(newstate.state, (tx2: Transaction) => {
                 const resolvedPos = tx2.doc.resolve(range!.start);
                 let ns = new TextSelection(resolvedPos, tx2.doc.resolve(range!.end + 1)); // new NodeSelection(resolvedPos);
-                let tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).removeMark(ns.from, ns.to, nodeTypeMark as any).addMark(ns.from, ns.to, nodeTypeMark as any).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
+                let tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
                 let tx4 = depth > 0 ? tx3.insertText(" ").setSelection(TextSelection.create(tx2.doc, ns.to - 2, ns.to + 2)).deleteSelection() : tx3;
-                marks && tx4.ensureMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
-                marks && tx4.setStoredMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
+                marks && tx4.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+                marks && tx4.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
 
                 dispatch(tx4);
             })) {
@@ -133,14 +140,22 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
                 let nodeIndex = resolvedPos.pos - (resolvedPos.nodeBefore && resolvedPos.nodeBefore.type.name === "text" ? resolvedPos.nodeBefore!.nodeSize : 0);
+
+                let path = (resolvedPos as any).path as any;
+                for (let i = path.length - 1; i > 0; i--) {
+                    if (path[i].type === schema.nodes.ordered_list) {
+                        path[i].attrs.bulletStyle = (nodeTypeMark as any).attrs.bulletType;
+                        break;
+                    }
+                }
+
                 let ns = new NodeSelection(tx2.doc.resolve(nodeIndex));
                 if (resolvedPos.nodeAfter && resolvedPos.nodeAfter.type.name === "list_item")
                     ns = new NodeSelection(tx2.doc.resolve(nodeIndex + 1));
-                let tx3 = tx2.setSelection(ns).removeMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, created)
-                    .removeMark(ns.from - 1, ns.to, nodeTypeMark).addMark(ns.from - 1, ns.to, nodeTypeMark).setSelection(TextSelection.create(tx2.doc, ns.to));
+                let tx3 = tx2.setSelection(ns).removeMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
 
-                marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
-                marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.mbulletType && m.type !== schema.marks.pFontSize), created, nodeTypeMark]);
+                marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+                marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
                 dispatch(tx3);
             } catch (e) {
                 dispatch(tx2);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index b5d81a359..37813958a 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -178,14 +178,6 @@ export const nodes: { [index: string]: NodeSpec } = {
             bulletStyle: { default: "decimal" },
         },
         toDOM(node: Node<any>) {
-            let first = node.firstChild;
-            while (first) {
-                if (first.marks.find((m) => m.type === schema.marks.mbulletType)) {
-                    let x = first.marks.find((m) => m.type === schema.marks.mbulletType);
-                    return ['ol', { style: `list-style: ${(x as any).attrs.bulletType}` }, 0]
-                }
-                first = first.firstChild;
-            }
             return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
         }
     },
-- 
cgit v1.2.3-70-g09d2


From 249038c576845027e91fe9e20cc791602c22d25d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 00:38:19 -0400
Subject: working except for moving multiple nodes at different levels at the
 same time

---
 src/client/util/ProsemirrorExampleTransfer.ts | 30 +++++++++------------------
 src/client/util/RichTextSchema.tsx            |  5 +++--
 2 files changed, 13 insertions(+), 22 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 238d37800..052fb0c6d 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -79,14 +79,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
 
     bind("Mod-s", TooltipTextMenu.insertStar);
 
-
-    let levelMark = (depth: number) => {
-        let p10 = schema.marks.pFontSize.create({ fontSize: 10 });
-        let p14 = schema.marks.pFontSize.create({ fontSize: 14 });
-        let p18 = schema.marks.pFontSize.create({ fontSize: 18 });
-        let p24 = schema.marks.pFontSize.create({ fontSize: 24 });
-        return depth == 0 ? p24 : depth == 2 ? p18 : depth == 4 ? p14 : p10;
-    }
     let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
         var range = ref.$from.blockRange(ref.$to);
@@ -94,7 +86,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         let depth = range && range.depth ? range.depth : 0;
         let nodeType = depth == 2 ? schema.nodes.cap_alphabet_list : depth == 4 ? schema.nodes.roman_list : depth == 6 ? schema.nodes.alphabet_list : schema.nodes.ordered_list;
         let nodeTypeMark = schema.marks.mbulletType.create({ bulletType: depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal" });
-        let created = levelMark(depth);
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
@@ -106,9 +97,9 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
                 }
             }
             let ns = new NodeSelection(resolvedPos);
-            let tx3 = tx2.removeMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
-            marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
-            marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+            let tx3 = tx2.setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
+            marks && tx3.ensureMarks([...marks]);
+            marks && tx3.setStoredMarks([...marks]);
             dispatch(tx3);
         })) {
             let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
@@ -116,10 +107,10 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             if (!wrapInList(nodeType)(newstate.state, (tx2: Transaction) => {
                 const resolvedPos = tx2.doc.resolve(range!.start);
                 let ns = new TextSelection(resolvedPos, tx2.doc.resolve(range!.end + 1)); // new NodeSelection(resolvedPos);
-                let tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
-                let tx4 = depth > 0 ? tx3.insertText(" ").setSelection(TextSelection.create(tx2.doc, ns.to - 2, ns.to + 2)).deleteSelection() : tx3;
-                marks && tx4.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
-                marks && tx4.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+                let tx3 = tx2.setSelection(ns).setSelection(TextSelection.create(tx2.doc, ns.to));
+                let tx4 = tx3;
+                marks && tx4.ensureMarks([...marks]);
+                marks && tx4.setStoredMarks([...marks]);
 
                 dispatch(tx4);
             })) {
@@ -135,7 +126,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth > 3 ? range.depth - 4 : 0;
         let nodeTypeMark = schema.marks.mbulletType.create({ bulletType: depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal" });
-        let created = levelMark(range && range.depth ? range.depth - 4 : 0);
         liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
@@ -152,10 +142,10 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
                 let ns = new NodeSelection(tx2.doc.resolve(nodeIndex));
                 if (resolvedPos.nodeAfter && resolvedPos.nodeAfter.type.name === "list_item")
                     ns = new NodeSelection(tx2.doc.resolve(nodeIndex + 1));
-                let tx3 = tx2.setSelection(ns).removeMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to));
+                let tx3 = tx2.setSelection(ns).setSelection(TextSelection.create(tx2.doc, ns.to));
 
-                marks && tx3.ensureMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
-                marks && tx3.setStoredMarks([...marks.filter(m => m.type !== schema.marks.pFontSize), created]);
+                marks && tx3.ensureMarks([...marks]);
+                marks && tx3.setStoredMarks([...marks]);
                 dispatch(tx3);
             } catch (e) {
                 dispatch(tx2);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 37813958a..26960e889 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -178,7 +178,8 @@ export const nodes: { [index: string]: NodeSpec } = {
             bulletStyle: { default: "decimal" },
         },
         toDOM(node: Node<any>) {
-            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
+            let fsize = node.attrs.bulletStyle === "decimal" ? 24 : node.attrs.bulletStyle === "upper-alpha" ? 18 : node.attrs.bulletStyle === "lower-roman" ? 14 : 10;
+            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}; font-size: ${fsize}` }, 0]
         }
     },
     alphabet_list: {
@@ -278,7 +279,7 @@ export const marks: { [index: string]: MarkSpec } = {
     // :: MarkSpec An emphasis mark. Rendered as an `<em>` element.
     // Has parse rules that also match `<i>` and `font-style: italic`.
     em: {
-        parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
+        parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style: italic" }],
         toDOM() { return emDOM; }
     },
 
-- 
cgit v1.2.3-70-g09d2


From e13dc44532ea5f94bdc13a2103bc4a00438ee617 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 01:29:35 -0400
Subject: simplified things.

---
 src/client/util/ProsemirrorExampleTransfer.ts | 43 ++++++++++-----------------
 src/client/util/RichTextSchema.tsx            | 33 --------------------
 src/client/util/TooltipTextMenu.tsx           |  3 --
 3 files changed, 15 insertions(+), 64 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 052fb0c6d..d602ce4a1 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -84,35 +84,28 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         var range = ref.$from.blockRange(ref.$to);
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth ? range.depth : 0;
-        let nodeType = depth == 2 ? schema.nodes.cap_alphabet_list : depth == 4 ? schema.nodes.roman_list : depth == 6 ? schema.nodes.alphabet_list : schema.nodes.ordered_list;
-        let nodeTypeMark = schema.marks.mbulletType.create({ bulletType: depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal" });
+        let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
             let path = (resolvedPos as any).path as any;
             for (let i = path.length - 1; i > 0; i--) {
                 if (path[i].type === schema.nodes.ordered_list) {
-                    path[i].attrs.bulletStyle = (nodeTypeMark as any).attrs.bulletType;
+                    path[i].attrs.bulletStyle = nodeTypeMark;
                     break;
                 }
             }
-            let ns = new NodeSelection(resolvedPos);
-            let tx3 = tx2.setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1)));
-            marks && tx3.ensureMarks([...marks]);
-            marks && tx3.setStoredMarks([...marks]);
-            dispatch(tx3);
+            marks && tx2.ensureMarks([...marks]);
+            marks && tx2.setStoredMarks([...marks]);
+            dispatch(tx2);
         })) {
             let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
             let newstate = state.applyTransaction(sxf);
-            if (!wrapInList(nodeType)(newstate.state, (tx2: Transaction) => {
-                const resolvedPos = tx2.doc.resolve(range!.start);
-                let ns = new TextSelection(resolvedPos, tx2.doc.resolve(range!.end + 1)); // new NodeSelection(resolvedPos);
-                let tx3 = tx2.setSelection(ns).setSelection(TextSelection.create(tx2.doc, ns.to));
-                let tx4 = tx3;
-                marks && tx4.ensureMarks([...marks]);
-                marks && tx4.setStoredMarks([...marks]);
-
-                dispatch(tx4);
+            if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
+                marks && tx2.ensureMarks([...marks]);
+                marks && tx2.setStoredMarks([...marks]);
+
+                dispatch(tx2);
             })) {
                 console.log("bullet fail");
             }
@@ -125,28 +118,22 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         var range = ref.$from.blockRange(ref.$to);
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth > 3 ? range.depth - 4 : 0;
-        let nodeTypeMark = schema.marks.mbulletType.create({ bulletType: depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal" });
+        let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
         liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
-                let nodeIndex = resolvedPos.pos - (resolvedPos.nodeBefore && resolvedPos.nodeBefore.type.name === "text" ? resolvedPos.nodeBefore!.nodeSize : 0);
 
                 let path = (resolvedPos as any).path as any;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
-                        path[i].attrs.bulletStyle = (nodeTypeMark as any).attrs.bulletType;
+                        path[i].attrs.bulletStyle = nodeTypeMark;
                         break;
                     }
                 }
 
-                let ns = new NodeSelection(tx2.doc.resolve(nodeIndex));
-                if (resolvedPos.nodeAfter && resolvedPos.nodeAfter.type.name === "list_item")
-                    ns = new NodeSelection(tx2.doc.resolve(nodeIndex + 1));
-                let tx3 = tx2.setSelection(ns).setSelection(TextSelection.create(tx2.doc, ns.to));
-
-                marks && tx3.ensureMarks([...marks]);
-                marks && tx3.setStoredMarks([...marks]);
-                dispatch(tx3);
+                marks && tx2.ensureMarks([...marks]);
+                marks && tx2.setStoredMarks([...marks]);
+                dispatch(tx2);
             } catch (e) {
                 dispatch(tx2);
             }
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 26960e889..255f4a60d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -182,39 +182,6 @@ export const nodes: { [index: string]: NodeSpec } = {
             return ['ol', { style: `list-style: ${node.attrs.bulletStyle}; font-size: ${fsize}` }, 0]
         }
     },
-    alphabet_list: {
-        ...orderedList,
-        content: 'list_item+',
-        group: 'block',
-        attrs: {
-            bulletStyle: { default: "lower-alpha" },
-        },
-        toDOM(node: Node<any>) {
-            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
-        }
-    },
-    cap_alphabet_list: {
-        ...orderedList,
-        content: 'list_item+',
-        group: 'block',
-        attrs: {
-            bulletStyle: { default: "upper-alpha" },
-        },
-        toDOM(node: Node<any>) {
-            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
-        }
-    },
-    roman_list: {
-        ...orderedList,
-        content: 'list_item+',
-        group: 'block',
-        attrs: {
-            bulletStyle: { default: "lower-roman" },
-        },
-        toDOM(node: Node<any>) {
-            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0]
-        }
-    },
     //this doesn't currently work for some reason
     bullet_list: {
         ...bulletList,
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 77396c829..7f6ba3aac 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -180,9 +180,6 @@ export class TooltipTextMenu {
         this.listTypeToIcon = new Map();
         this.listTypeToIcon.set(schema.nodes.bullet_list, ":");
         this.listTypeToIcon.set(schema.nodes.ordered_list, "1)");
-        this.listTypeToIcon.set(schema.nodes.alphabet_list, "a)");
-        this.listTypeToIcon.set(schema.nodes.cap_alphabet_list, "A)");
-        this.listTypeToIcon.set(schema.nodes.roman_list, "i.");
         // this.listTypeToIcon.set(schema.nodes.bullet_list, "⬜");
         this.listTypes = Array.from(this.listTypeToIcon.keys());
 
-- 
cgit v1.2.3-70-g09d2


From 074961d68788d2d19b6bfbcc9b95712a7b3940eb Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 09:13:07 -0400
Subject: not quite working...

---
 src/client/util/RichTextSchema.tsx           |  9 +++++++--
 src/client/views/nodes/FormattedTextBox.scss | 13 ++++++++++++-
 2 files changed, 19 insertions(+), 3 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 255f4a60d..655edb68a 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -178,8 +178,10 @@ export const nodes: { [index: string]: NodeSpec } = {
             bulletStyle: { default: "decimal" },
         },
         toDOM(node: Node<any>) {
+            (node.content as any).content.map((x: any) => x.type.attrs.className = node.attrs.bulletStyle);
             let fsize = node.attrs.bulletStyle === "decimal" ? 24 : node.attrs.bulletStyle === "upper-alpha" ? 18 : node.attrs.bulletStyle === "lower-roman" ? 14 : 10;
-            return ['ol', { style: `list-style: ${node.attrs.bulletStyle}; font-size: ${fsize}` }, 0]
+            return ['ol', { class: `${node.attrs.bulletStyle}-ol`, style: `list-style: none; font-size: ${fsize}` }, 0]
+            //return ['ol', { class: `${node.attrs.bulletStyle}`, style: `list-style: ${node.attrs.bulletStyle}; font-size: ${fsize}` }, 0]
         }
     },
     //this doesn't currently work for some reason
@@ -202,6 +204,9 @@ export const nodes: { [index: string]: NodeSpec } = {
     //select: state => true,
     // },
     list_item: {
+        attrs: {
+            className: { default: "" }
+        },
         ...listItem,
         content: 'paragraph block*',
         toDOM(node: any) {
@@ -213,7 +218,7 @@ export const nodes: { [index: string]: NodeSpec } = {
                 }
                 first = first.firstChild;
             }
-            return ["li", 0];
+            return ["li", { class: node.type.attrs.className }, 0];
         }
     },
 };
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 1b537cc52..1e429e4be 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -65,4 +65,15 @@
 
 .em {
     font-style: italic;
-}
\ No newline at end of file
+}
+
+
+ol { counter-reset: deci 0;}
+.decimal-ol {counter-reset: deci 0;}
+.upper-alpha-ol {counter-reset: ualph; }
+.lower-roman-ol {counter-reset: lroman; }
+.lower-alpha-ol {counter-reset: lalpha; }
+.decimal:before { content: counter(deci) " "; counter-increment: deci }
+.upper-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) " "; counter-increment: ualph }
+.lower-roman:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) " "; counter-increment: lroman }
+.lower-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) "." counter(lalpha, lower-alpha)" "; counter-increment: lalpha }
-- 
cgit v1.2.3-70-g09d2


From d31999dd3fce11a886bd402c27f34c35c7c85935 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 10:16:21 -0400
Subject: mostly working. some glitches though.

---
 src/client/util/ProsemirrorExampleTransfer.ts |  9 +++++----
 src/client/util/RichTextSchema.tsx            | 17 ++++-------------
 src/client/views/nodes/FormattedTextBox.scss  | 23 ++++++++++++++---------
 3 files changed, 23 insertions(+), 26 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index d602ce4a1..4ca19eff1 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -79,19 +79,21 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
 
     bind("Mod-s", TooltipTextMenu.insertStar);
 
+    // let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
+    let nodeTypeMark = (depth: number) => { return depth == 2 ? "decimal2" : depth == 4 ? "decimal3" : depth == 6 ? "decimal4" : "decimal" }
+
     let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
         var range = ref.$from.blockRange(ref.$to);
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth ? range.depth : 0;
-        let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
             let path = (resolvedPos as any).path as any;
             for (let i = path.length - 1; i > 0; i--) {
                 if (path[i].type === schema.nodes.ordered_list) {
-                    path[i].attrs.bulletStyle = nodeTypeMark;
+                    path[i].attrs.bulletStyle = nodeTypeMark(depth);
                     break;
                 }
             }
@@ -118,7 +120,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         var range = ref.$from.blockRange(ref.$to);
         var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks());
         let depth = range && range.depth > 3 ? range.depth - 4 : 0;
-        let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
         liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
@@ -126,7 +127,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
                 let path = (resolvedPos as any).path as any;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
-                        path[i].attrs.bulletStyle = nodeTypeMark;
+                        path[i].attrs.bulletStyle = nodeTypeMark(depth);
                         break;
                     }
                 }
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 655edb68a..2df49d8a4 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -178,10 +178,9 @@ export const nodes: { [index: string]: NodeSpec } = {
             bulletStyle: { default: "decimal" },
         },
         toDOM(node: Node<any>) {
-            (node.content as any).content.map((x: any) => x.type.attrs.className = node.attrs.bulletStyle);
-            let fsize = node.attrs.bulletStyle === "decimal" ? 24 : node.attrs.bulletStyle === "upper-alpha" ? 18 : node.attrs.bulletStyle === "lower-roman" ? 14 : 10;
-            return ['ol', { class: `${node.attrs.bulletStyle}-ol`, style: `list-style: none; font-size: ${fsize}` }, 0]
-            //return ['ol', { class: `${node.attrs.bulletStyle}`, style: `list-style: ${node.attrs.bulletStyle}; font-size: ${fsize}` }, 0]
+            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = node.attrs.bulletStyle;
+            return ['ol', { class: `${node.attrs.bulletStyle}-ol`, style: `list-style: none;` }, 0]
+            //return ['ol', { class: `${node.attrs.bulletStyle}`, style: `list-style: ${node.attrs.bulletStyle};`, 0]
         }
     },
     //this doesn't currently work for some reason
@@ -210,15 +209,7 @@ export const nodes: { [index: string]: NodeSpec } = {
         ...listItem,
         content: 'paragraph block*',
         toDOM(node: any) {
-            let first = node.firstChild;
-            while (first) {
-                if (first.marks.find((m: any) => m.type === schema.marks.mbulletType)) {
-                    let x = first.marks.find((m: any) => m.type === schema.marks.mbulletType);
-                    return ["li", { class: "XXX" }, 0];
-                }
-                first = first.firstChild;
-            }
-            return ["li", { class: node.type.attrs.className }, 0];
+            return ["li", { class: node.attrs.className }, 0];
         }
     },
 };
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 1e429e4be..e93ceda21 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -67,13 +67,18 @@
     font-style: italic;
 }
 
-
 ol { counter-reset: deci 0;}
-.decimal-ol {counter-reset: deci 0;}
-.upper-alpha-ol {counter-reset: ualph; }
-.lower-roman-ol {counter-reset: lroman; }
-.lower-alpha-ol {counter-reset: lalpha; }
-.decimal:before { content: counter(deci) " "; counter-increment: deci }
-.upper-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) " "; counter-increment: ualph }
-.lower-roman:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) " "; counter-increment: lroman }
-.lower-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) "." counter(lalpha, lower-alpha)" "; counter-increment: lalpha }
+.decimal-ol { counter-reset: deci 0; p { display: inline }; font-size: 24 }
+.decimal2-ol {counter-reset: deci2; p { display: inline }; font-size: 18 }
+.decimal3-ol {counter-reset: deci3; p { display: inline }; font-size: 14 }
+.decimal4-ol {counter-reset: deci4; p { display: inline }; font-size: 10 }
+.upper-alpha-ol {counter-reset: ualph; p { display: inline }; font-size: 18 }
+.lower-roman-ol {counter-reset: lroman;  p { display: inline }; font-size: 14; }
+.lower-alpha-ol {counter-reset: lalpha;  p { display: inline }; font-size: 10;}
+.decimal:before { content: counter(deci) " "; counter-increment: deci; display:inline-block; width: 30}
+.decimal2:before { content: counter(deci) "." counter(deci2) " "; counter-increment: deci2; display:inline-block; width: 35}
+.decimal3:before { content: counter(deci) "." counter(deci2) "." counter(deci3) " "; counter-increment: deci3; display:inline-block; width: 35}
+.decimal4:before { content: counter(deci) "." counter(deci2) "." counter(deci3) "." counter(deci4) " "; counter-increment: deci4; display:inline-block; width: 40}
+.upper-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) " "; counter-increment: ualph; display:inline-block; width: 35 }
+.lower-roman:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) " "; counter-increment: lroman;display:inline-block; width: 50 }
+.lower-alpha:before { content: counter(deci) "." counter(ualph, upper-alpha) "." counter(lroman, lower-roman) "." counter(lalpha, lower-alpha)" "; counter-increment: lalpha; display:inline-block; width: 35}
-- 
cgit v1.2.3-70-g09d2


From 2b1035aa307a0cea6076030822cd5bb3c9793fb4 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 10:27:50 -0400
Subject: last refinements for now.

---
 src/client/util/ProsemirrorExampleTransfer.ts | 8 ++++++++
 src/client/util/RichTextSchema.tsx            | 9 +++++----
 2 files changed, 13 insertions(+), 4 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 4ca19eff1..8b6936748 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -104,6 +104,14 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end));
             let newstate = state.applyTransaction(sxf);
             if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
+                const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
+                let path = (resolvedPos as any).path as any;
+                for (let i = path.length - 1; i > 0; i--) {
+                    if (path[i].type === schema.nodes.ordered_list) {
+                        path[i].attrs.bulletStyle = nodeTypeMark(depth);
+                        break;
+                    }
+                }
                 marks && tx2.ensureMarks([...marks]);
                 marks && tx2.setStoredMarks([...marks]);
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 2df49d8a4..bbced3b77 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -175,7 +175,7 @@ export const nodes: { [index: string]: NodeSpec } = {
         content: 'list_item+',
         group: 'block',
         attrs: {
-            bulletStyle: { default: "decimal" },
+            bulletStyle: { default: "" },
         },
         toDOM(node: Node<any>) {
             for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = node.attrs.bulletStyle;
@@ -189,9 +189,10 @@ export const nodes: { [index: string]: NodeSpec } = {
         content: 'list_item+',
         group: 'block',
         // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
-        // toDOM() { return ['ol', {
-        //     style: 'list-type: hebrew'
-        // }] }
+        toDOM(node: Node<any>) {
+            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = "";
+            return ['ul', 0]
+        }
     },
 
     //bullet_list: {
-- 
cgit v1.2.3-70-g09d2


From 5da0459ad76c614e455ea99798c940d4e93707bb Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 17:29:58 -0400
Subject: multi-user marks.

---
 src/client/util/RichTextSchema.tsx          | 13 +++++++++++++
 src/client/views/nodes/FormattedTextBox.tsx | 11 ++++++++++-
 2 files changed, 23 insertions(+), 1 deletion(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index bbced3b77..76c45e6c1 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -1,6 +1,7 @@
 import { DOMOutputSpecArray, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model";
 import { bulletList, listItem, orderedList } from 'prosemirror-schema-list';
 import { TextSelection } from "prosemirror-state";
+import { Doc } from "../../new_fields/Doc";
 
 const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -324,6 +325,18 @@ export const marks: { [index: string]: MarkSpec } = {
         }
     },
 
+    // the id of the user who entered the text
+    user_mark: {
+        attrs: {
+            userid: { default: "" }
+        },
+        toDOM(node: any) {
+            return ['span', {
+                style: `background: ${node.attrs.userid.indexOf(Doc.CurrentUserEmail) === -1 ? "rgba(255, 255, 0, 0.267)" : undefined};`
+            }];
+        }
+    },
+
 
     // :: MarkSpec Code font mark. Represented as a `<code>` element.
     code: {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 49189c5f3..667bac3be 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -5,7 +5,7 @@ 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 } from "prosemirror-model";
+import { Fragment, Node, Node as ProsNode, NodeType, Slice, Mark } from "prosemirror-model";
 import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { DateField } from '../../../new_fields/DateField';
@@ -37,6 +37,7 @@ import { DocumentDecorations } from '../DocumentDecorations';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 import { DocumentType } from '../../documents/DocumentTypes';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -171,6 +172,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
+            var markerss = tx.storedMarks || (tx.selection.$to.parentOffset && tx.selection.$from.marks());
+            let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+            tx.ensureMarks(newMarks);
+            tx.setStoredMarks(newMarks);
             const state = this._editorView.state.apply(tx);
             FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true);
             this._editorView.updateState(state);
@@ -267,6 +272,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
             return;
         }
+        var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
+        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+        this._editorView!.state.storedMarks = newMarks;
+
         if (e.key === "R" && e.altKey) {
             e.stopPropagation();
             e.preventDefault();
-- 
cgit v1.2.3-70-g09d2


From 1fbf7d7e10bb4dfa7e3a323ee0641d7bbf97b6a8 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 27 Aug 2019 23:24:18 -0400
Subject: fixed several lint errors, and minor issues with bullets

---
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/util/ProsemirrorExampleTransfer.ts      | 17 ++++-----
 src/client/util/RichTextSchema.tsx                 | 13 ++++---
 src/client/util/TooltipTextMenu.tsx                | 31 ++++++++++++----
 src/client/views/DocumentDecorations.tsx           |  2 +-
 .../views/collections/CollectionTreeView.tsx       | 42 +++++++++++-----------
 .../views/collections/CollectionViewChromes.tsx    |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  6 ++--
 8 files changed, 71 insertions(+), 44 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 124faf266..ec731da84 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -204,4 +204,4 @@ export class DocumentManager {
         }
     }
 }
-Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)) })
\ No newline at end of file
+Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); });
\ No newline at end of file
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 8b6936748..12ad28199 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -79,8 +79,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
 
     bind("Mod-s", TooltipTextMenu.insertStar);
 
-    // let nodeTypeMark = depth == 2 ? "upper-alpha" : depth == 4 ? "lower-roman" : depth == 6 ? "lower-alpha" : "decimal";
-    let nodeTypeMark = (depth: number) => { return depth == 2 ? "decimal2" : depth == 4 ? "decimal3" : depth == 6 ? "decimal4" : "decimal" }
+    let nodeTypeMark = (depth: number) => depth === 2 ? "indent2" : depth === 4 ? "indent3" : depth === 6 ? "indent4" : "indent1";
 
     let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
@@ -90,7 +89,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => {
             const resolvedPos = tx2.doc.resolve(range!.start);
 
-            let path = (resolvedPos as any).path as any;
+            let path = (resolvedPos as any).path;
             for (let i = path.length - 1; i > 0; i--) {
                 if (path[i].type === schema.nodes.ordered_list) {
                     path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -105,7 +104,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             let newstate = state.applyTransaction(sxf);
             if (!wrapInList(schema.nodes.ordered_list)(newstate.state, (tx2: Transaction) => {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
-                let path = (resolvedPos as any).path as any;
+                let path = (resolvedPos as any).path;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
                         path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -120,8 +119,9 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
                 console.log("bullet fail");
             }
         }
-    }
-    bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => bulletFunc(state, dispatch));
+    };
+
+    bind("Tab", bulletFunc);
 
     bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
         var ref = state.selection;
@@ -132,7 +132,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             try {
                 const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
 
-                let path = (resolvedPos as any).path as any;
+                let path = (resolvedPos as any).path;
                 for (let i = path.length - 1; i > 0; i--) {
                     if (path[i].type === schema.nodes.ordered_list) {
                         path[i].attrs.bulletStyle = nodeTypeMark(depth);
@@ -159,7 +159,8 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
             if (!splitBlockKeepMarks(state, (tx3: Transaction) => {
                 marks && tx3.ensureMarks(marks);
                 marks && tx3.setStoredMarks(marks);
-                if (!liftListItem(schema.nodes.list_item)(state, (tx4: Transaction) => dispatch(tx4))) {
+                if (!liftListItem(schema.nodes.list_item)(state, dispatch as ((tx: Transaction<Schema<any, any>>) => void))
+                ) {
                     dispatch(tx3);
                 }
             })) {
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 76c45e6c1..4e18f410d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -177,10 +177,15 @@ export const nodes: { [index: string]: NodeSpec } = {
         group: 'block',
         attrs: {
             bulletStyle: { default: "" },
+            mapStyle: { default: "decimal" }
         },
         toDOM(node: Node<any>) {
-            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = node.attrs.bulletStyle;
-            return ['ol', { class: `${node.attrs.bulletStyle}-ol`, style: `list-style: none;` }, 0]
+            const bs = node.attrs.bulletStyle;
+            const decMap = bs === "indent1" ? "decimal" : bs === "indent2" ? "decimal2" : bs === "indent3" ? "decimal3" : bs === "indent4" ? "decimal4" : "";
+            const multiMap = bs === "indent1" ? "decimal" : bs === "indent2" ? "upper-alpha" : bs === "indent3" ? "lower-roman" : bs === "indent4" ? "lower-alpha" : "";
+            let map = node.attrs.mapStyle === "decimal" ? decMap : multiMap;
+            for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = map;
+            return ['ol', { class: `${map}-ol`, style: `list-style: none;` }, 0];
             //return ['ol', { class: `${node.attrs.bulletStyle}`, style: `list-style: ${node.attrs.bulletStyle};`, 0]
         }
     },
@@ -192,7 +197,7 @@ export const nodes: { [index: string]: NodeSpec } = {
         // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
         toDOM(node: Node<any>) {
             for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = "";
-            return ['ul', 0]
+            return ['ul', 0];
         }
     },
 
@@ -302,7 +307,7 @@ export const marks: { [index: string]: MarkSpec } = {
         },
         toDOM(node: any) {
             return ['span', {
-                style: `background: ${node.attrs.bulletType == "decimal" ? "yellow" : node.attrs.bulletType === "upper-alpha" ? "blue" : "green"}`
+                style: `background: ${node.attrs.bulletType === "decimal" ? "yellow" : node.attrs.bulletType === "upper-alpha" ? "blue" : "green"}`
             }];
         }
     },
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 7f6ba3aac..e979e6cde 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -28,11 +28,11 @@ export class TooltipTextMenu {
     private view: EditorView;
     private fontStyles: MarkType[];
     private fontSizes: MarkType[];
-    private listTypes: NodeType[];
+    private listTypes: (NodeType | any)[];
     private editorProps: FieldViewProps & FormattedTextBoxProps;
     private fontSizeToNum: Map<MarkType, number>;
     private fontStylesToName: Map<MarkType, string>;
-    private listTypeToIcon: Map<NodeType, string>;
+    private listTypeToIcon: Map<NodeType | any, string>;
     //private link: HTMLAnchorElement;
     private wrapper: HTMLDivElement;
     private extras: HTMLDivElement;
@@ -179,7 +179,8 @@ export class TooltipTextMenu {
         //list types
         this.listTypeToIcon = new Map();
         this.listTypeToIcon.set(schema.nodes.bullet_list, ":");
-        this.listTypeToIcon.set(schema.nodes.ordered_list, "1)");
+        this.listTypeToIcon.set(schema.nodes.ordered_list.create({ mapStyle: "decimal" }), "1.1");
+        this.listTypeToIcon.set(schema.nodes.ordered_list.create({ mapStyle: "multi" }), "1.A");
         // this.listTypeToIcon.set(schema.nodes.bullet_list, "⬜");
         this.listTypes = Array.from(this.listTypeToIcon.keys());
 
@@ -512,10 +513,28 @@ export class TooltipTextMenu {
 
     //remove all node typeand apply the passed-in one to the selected text
     changeToNodeType(nodeType: NodeType | undefined, view: EditorView) {
-        //remove old
-        liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
-        if (nodeType) { //add new
+        //remove oldif (nodeType) { //add new
+        if (nodeType === schema.nodes.bullet_list) {
             wrapInList(nodeType)(view.state, view.dispatch);
+        } else {
+            var ref = view.state.selection;
+            var range = ref.$from.blockRange(ref.$to);
+            var marks = view.state.storedMarks || (view.state.selection.$to.parentOffset && view.state.selection.$from.marks());
+            wrapInList(schema.nodes.ordered_list)(view.state, (tx2: any) => {
+                const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2));
+                let path = resolvedPos.path;
+                for (let i = path.length - 1; i > 0; i--) {
+                    if (path[i].type === schema.nodes.ordered_list) {
+                        path[i].attrs.bulletStyle = "indent1";
+                        path[i].attrs.mapStyle = (nodeType as any).attrs.mapStyle;
+                        break;
+                    }
+                }
+                marks && tx2.ensureMarks([...marks]);
+                marks && tx2.setStoredMarks([...marks]);
+
+                view.dispatch(tx2);
+            });
         }
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e93893586..203227241 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -201,7 +201,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     }
 
     @observable _forceUpdate = 0;
-    _lastBox = { x: 0, y: 0, r: 0, b: 0 }
+    _lastBox = { x: 0, y: 0, r: 0, b: 0 };
     @computed
     get Bounds(): { x: number, y: number, b: number, r: number } {
         let x = this._forceUpdate;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 04133fb5b..50f03005c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -432,26 +432,28 @@ class TreeView extends React.Component<TreeViewProps> {
         }
 
         let ascending = Cast(containingCollection.sortAscending, "boolean", null);
-        if (ascending !== undefined) docs.sort(function (a, b): 1 | -1 {
-            let descA = ascending ? b : a;
-            let descB = ascending ? a : b;
-            let first = descA.title;
-            let second = descB.title;
-            // TODO find better way to sort how to sort..................
-            if (typeof first === 'number' && typeof second === 'number') {
-                return (first - second) > 0 ? 1 : -1;
-            }
-            if (typeof first === 'string' && typeof second === 'string') {
-                return first > second ? 1 : -1;
-            }
-            if (typeof first === 'boolean' && typeof second === 'boolean') {
-                // if (first === second) { // bugfixing?: otherwise, the list "flickers" because the list is resorted during every load
-                //     return Number(descA.x) > Number(descB.x) ? 1 : -1;
-                // }
-                return first > second ? 1 : -1;
-            }
-            return ascending ? 1 : -1;
-        });
+        if (ascending !== undefined) {
+            docs.sort(function (a, b): 1 | -1 {
+                let descA = ascending ? b : a;
+                let descB = ascending ? a : b;
+                let first = descA.title;
+                let second = descB.title;
+                // TODO find better way to sort how to sort..................
+                if (typeof first === 'number' && typeof second === 'number') {
+                    return (first - second) > 0 ? 1 : -1;
+                }
+                if (typeof first === 'string' && typeof second === 'string') {
+                    return first > second ? 1 : -1;
+                }
+                if (typeof first === 'boolean' && typeof second === 'boolean') {
+                    // if (first === second) { // bugfixing?: otherwise, the list "flickers" because the list is resorted during every load
+                    //     return Number(descA.x) > Number(descB.x) ? 1 : -1;
+                    // }
+                    return first > second ? 1 : -1;
+                }
+                return ascending ? 1 : -1;
+            });
+        }
 
         let rowWidth = () => panelWidth() - 20;
         return docs.map((child, i) => {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 4b3f7c87e..c897af17e 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -53,7 +53,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     };
     _viewCommand = {
         title: "restore view", script: "this.target.panX = this.restoredPanX; this.target.panY = this.restoredPanY; this.target.scale = this.restoredScale;", params: ["target"],
-        immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document.panX = 0; this.props.CollectionView.props.Document.panY = 0; this.props.CollectionView.props.Document.scale = 1 },
+        immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document.panX = 0; this.props.CollectionView.props.Document.panY = 0; this.props.CollectionView.props.Document.scale = 1; },
         initialize: (button: Doc) => { button.restoredPanX = this.props.CollectionView.props.Document.panX; button.restoredPanY = this.props.CollectionView.props.Document.panY; button.restoredScale = this.props.CollectionView.props.Document.scale; }
     };
     _freeform_commands = [this._contentCommand, this._templateCommand, this._viewCommand];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ba558a0b2..36740fc66 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -331,8 +331,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     keymap(buildKeymap(schema)),
                     keymap(baseKeymap),
                 ]
-        }
-    };
+        };
+    }
 
     @action
     rebuildEditor() {
@@ -776,7 +776,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             SelectionManager.DeselectAll();
         }
         e.stopPropagation();
-        if (e.key === "Tab") {
+        if (e.key === "Tab" || e.key === "Enter") { // bullets typically change "levels" when tab or enter is used.  sometimes backspcae, so maybe that should be added.
             e.preventDefault();
             setTimeout(() => { // force re-rendering of bullet numbers that may have had their bullet labels change.  (Our prosemirrior code re-"marks" the changed bullets, but nothing causes the Dom to be re-rendered which is where the nubering takes place)
                 SelectionManager.DeselectAll();
-- 
cgit v1.2.3-70-g09d2


From 19ba56239796cc6a421bbb02affc47802ef824a7 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 28 Aug 2019 09:46:47 -0400
Subject: fixed collapse storedmarks

---
 src/client/util/RichTextSchema.tsx | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 4e18f410d..6c06cec4d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -595,6 +595,8 @@ export class SummarizedView {
                 attrs.textslice = newSelection.content().toJSON();
                 view.dispatch(view.state.tr.setNodeMarkup(y, undefined, attrs));
                 view.dispatch(view.state.tr.setSelection(newSelection).deleteSelection(view.state, () => { }));
+                let marks = view.state.storedMarks.filter((m: any) => m.type !== view.state.schema.marks.highlight);
+                view.state.storedMarks = marks;
                 self._collapsed.textContent = "㊉";
             } else {
                 // node.attrs.visibility = !node.attrs.visibility;
-- 
cgit v1.2.3-70-g09d2


From 4b7672c75fe5cdf6afe534e67213917b24980c3e Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 28 Aug 2019 15:02:20 -0400
Subject: added better support for usermarks and fledliging for accept changes.

---
 src/client/util/RichTextSchema.tsx           | 14 ++++++---
 src/client/views/nodes/FormattedTextBox.scss | 17 ++++++++++
 src/client/views/nodes/FormattedTextBox.tsx  | 47 +++++++++++++++++++++++++---
 3 files changed, 69 insertions(+), 9 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

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();
         }
-- 
cgit v1.2.3-70-g09d2


From 18cc66aaa90c5054268eac9520a963867c0c2f8e Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 29 Aug 2019 01:14:18 -0400
Subject: fixed expand/collapse of text.  added user tooltip

---
 src/client/util/RichTextSchema.tsx                 |  5 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 50 +++++---------
 .../views/nodes/FormattedTextBoxComment.scss       | 34 ++++++++++
 src/client/views/nodes/FormattedTextBoxComment.tsx | 78 ++++++++++++++++++++++
 4 files changed, 132 insertions(+), 35 deletions(-)
 create mode 100644 src/client/views/nodes/FormattedTextBoxComment.scss
 create mode 100644 src/client/views/nodes/FormattedTextBoxComment.tsx

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index f567d803e..ee0c0870a 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -343,7 +343,10 @@ export const marks: { [index: string]: MarkSpec } = {
             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] :
+                (node.attrs.opened ?
+                    ['span', { class: "userMarkOpen" }, 0] :
+                    ['span', { class: "userMark" }, ['span', { style: "font-size:2" }, 0]]
+                ) :
                 ['span', 0];
         }
     },
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 146281f2b..2485760df 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -37,7 +37,7 @@ import { DocumentDecorations } from '../DocumentDecorations';
 import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 import { DocumentType } from '../../documents/DocumentTypes';
-import { number } from 'prop-types';
+import { selectionSizePlugin, findStartOfMark, findUserMark, findEndOfMark, findOtherUserMark, SelectionSizeTooltip } from './FormattedTextBoxComment';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -325,7 +325,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     props: {
                         attributes: { class: "ProseMirror-example-setup-style" }
                     }
-                })
+                }),
+                selectionSizePlugin
             ] : [
                     history(),
                     keymap(buildKeymap(schema)),
@@ -643,6 +644,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._heightReactionDisposer && this._heightReactionDisposer();
         this._searchReactionDisposer && this._searchReactionDisposer();
         document.removeEventListener("paste", this.paste);
+        this._editorView && this._editorView.destroy();
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
@@ -707,45 +709,25 @@ 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 => {
         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);
+        let noselection = view.state.selection.$from === view.state.selection.$to;
+        if (pos && rpos) {
+            let nbef = findStartOfMark(rpos, view, findOtherUserMark);
+            let naft = findEndOfMark(rpos, view, findOtherUserMark);
             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)));
+            let child = rpos.nodeBefore || rpos.nodeAfter;
+            let mark = child && findOtherUserMark(child.marks);
+            if (mark && child && (nbef || naft) && (!mark.attrs.opened || noselection)) {
+                let opened = e.button === 2 ? false : !mark.attrs.opened;
+                SelectionSizeTooltip.tooltip.style.display = opened ? "" : "none";
+                let mid = opened ? epos : view.state.doc.resolve((spos.pos + epos.pos) / 2);
+                let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: e.button === 2 ? Doc.CurrentUserEmail : mark.attrs.userid, opened: opened });
+                view.dispatch(view.state.tr.addMark(ts.from, ts.to, nmark).setSelection(new TextSelection(mid, mid)));
             }
         }
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
diff --git a/src/client/views/nodes/FormattedTextBoxComment.scss b/src/client/views/nodes/FormattedTextBoxComment.scss
new file mode 100644
index 000000000..792cee182
--- /dev/null
+++ b/src/client/views/nodes/FormattedTextBoxComment.scss
@@ -0,0 +1,34 @@
+.FormattedTextBox-tooltip {
+    position: absolute;
+    pointer-events: none;
+    z-index: 20;
+    background: white;
+    border: 1px solid silver;
+    border-radius: 2px;
+    padding: 2px 10px;
+    margin-bottom: 7px;
+    -webkit-transform: translateX(-50%);
+    transform: translateX(-50%);
+  }
+  .FormattedTextBox-tooltip:before {
+    content: "";
+    height: 0; width: 0;
+    position: absolute;
+    left: 50%;
+    margin-left: -5px;
+    bottom: -6px;
+    border: 5px solid transparent;
+    border-bottom-width: 0;
+    border-top-color: silver;
+  }
+  .FormattedTextBox-tooltip:after {
+    content: "";
+    height: 0; width: 0;
+    position: absolute;
+    left: 50%;
+    margin-left: -5px;
+    bottom: -4.5px;
+    border: 5px solid transparent;
+    border-bottom-width: 0;
+    border-top-color: white;
+  }
\ No newline at end of file
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
new file mode 100644
index 000000000..e88c85a86
--- /dev/null
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -0,0 +1,78 @@
+import { Plugin, EditorState, TextSelection } from "prosemirror-state"
+import './FormattedTextBoxComment.scss'
+import { DragManager } from "../../util/DragManager";
+import { ResolvedPos, Mark } from "prosemirror-model";
+import { EditorView } from "prosemirror-view";
+import { Doc } from "../../../new_fields/Doc";
+
+export let selectionSizePlugin = new Plugin({
+    view(editorView) { return new SelectionSizeTooltip(editorView); }
+})
+export function findOtherUserMark(marks: Mark[]): Mark | undefined {
+    return marks.find(m => m.attrs.userid && m.attrs.userid !== Doc.CurrentUserEmail);
+}
+export function findUserMark(marks: Mark[]): Mark | undefined {
+    return marks.find(m => m.attrs.userid);
+}
+export function findStartOfMark(rpos: ResolvedPos, view: EditorView, finder: (marks: Mark[]) => Mark | undefined) {
+    let before = 0;
+    let nbef = rpos.nodeBefore;
+    while (nbef && finder(nbef.marks)) {
+        before += nbef.nodeSize;
+        rpos = view.state.doc.resolve(rpos.pos - nbef.nodeSize);
+        rpos && (nbef = rpos.nodeBefore);
+    }
+    return before;
+}
+export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (marks: Mark[]) => Mark | undefined) {
+    let after = 0;
+    let naft = rpos.nodeAfter;
+    while (naft && finder(naft.marks)) {
+        after += naft.nodeSize;
+        rpos = view.state.doc.resolve(rpos.pos + naft.nodeSize);
+        rpos && (naft = rpos.nodeAfter);
+    }
+    return after;
+}
+
+export class SelectionSizeTooltip {
+    static tooltip: any;
+    constructor(view: any) {
+        if (!SelectionSizeTooltip.tooltip) {
+            SelectionSizeTooltip.tooltip = document.createElement("div");
+            SelectionSizeTooltip.tooltip.className = "FormattedTextBox-tooltip";
+            DragManager.Root().appendChild(SelectionSizeTooltip.tooltip);
+        }
+
+        this.update(view, undefined);
+    }
+
+
+    update(view: EditorView, lastState?: EditorState) {
+        let 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)) return;
+
+        if (state.selection.$from) {
+            let nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark);
+            let naft = findEndOfMark(state.selection.$from, view, findOtherUserMark);
+            let child = state.selection.$from.nodeBefore;
+            let mark = child && findOtherUserMark(child.marks);
+            if (mark && child && nbef && naft && mark.attrs.opened && SelectionSizeTooltip.tooltip.offsetParent) {
+                SelectionSizeTooltip.tooltip.textContent = mark.attrs.userid;
+                // These are in screen coordinates
+                let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to);
+                // The box in which the tooltip is positioned, to use as base
+                let box = SelectionSizeTooltip.tooltip.offsetParent.getBoundingClientRect();
+                // Find a center-ish x position from the selection endpoints (when
+                // crossing lines, end may be more to the left)
+                let left = Math.max((start.left + end.left) / 2, start.left + 3);
+                SelectionSizeTooltip.tooltip.style.left = (left - box.left) + "px";
+                SelectionSizeTooltip.tooltip.style.bottom = (box.bottom - start.top) + "px";
+            }
+        }
+    }
+
+    destroy() { SelectionSizeTooltip.tooltip.style.display = "none" }
+}
-- 
cgit v1.2.3-70-g09d2


From 1079d90c5d6752a0a2c06a25d42c1192cb433ed3 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 29 Aug 2019 10:09:03 -0400
Subject: made text author tooltip interactive.

---
 src/client/util/RichTextSchema.tsx                 |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 21 ++++++-----
 src/client/views/nodes/FormattedTextBoxComment.tsx | 41 +++++++++++++++++-----
 3 files changed, 47 insertions(+), 17 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index ee0c0870a..f8da98f17 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -335,7 +335,7 @@ export const marks: { [index: string]: MarkSpec } = {
         attrs: {
             userid: { default: "" },
             hide_users: { default: [] },
-            opened: { default: false }
+            opened: { default: true }
         },
         group: "inline",
         inclusive: false,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2485760df..c23b85e83 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -714,27 +714,32 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         const pos = view.posAtCoords({ left: e.clientX, top: e.clientY });
         const rpos = pos && view.state.doc.resolve(pos.pos);
         let noselection = view.state.selection.$from === view.state.selection.$to;
+        let set = false;
         if (pos && rpos) {
             let nbef = findStartOfMark(rpos, view, findOtherUserMark);
             let naft = findEndOfMark(rpos, view, findOtherUserMark);
-            const spos = view.state.doc.resolve(pos.pos - nbef);
-            const epos = view.state.doc.resolve(pos.pos + naft);
-            let ts = new TextSelection(spos, epos);
+            const spos = pos.pos - nbef;
+            const epos = pos.pos + naft;
             let child = rpos.nodeBefore || rpos.nodeAfter;
             let mark = child && findOtherUserMark(child.marks);
             if (mark && child && (nbef || naft) && (!mark.attrs.opened || noselection)) {
-                let opened = e.button === 2 ? false : !mark.attrs.opened;
-                SelectionSizeTooltip.tooltip.style.display = opened ? "" : "none";
-                let mid = opened ? epos : view.state.doc.resolve((spos.pos + epos.pos) / 2);
-                let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: e.button === 2 ? Doc.CurrentUserEmail : mark.attrs.userid, opened: opened });
-                view.dispatch(view.state.tr.addMark(ts.from, ts.to, nmark).setSelection(new TextSelection(mid, mid)));
+                SelectionSizeTooltip.SetState(this, mark.attrs.opened, spos, epos, mark);
+                set = true;
             }
         }
+        !set && SelectionSizeTooltip.Hide();
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
             e.stopPropagation();
         }
     }
 
+    setAnnotation = (start: number, end: number, mark: Mark, opened: boolean, keep: boolean = false) => {
+        let view = this._editorView!;
+        let mid = view.state.doc.resolve(Math.round((start + end) / 2));
+        let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: keep ? Doc.CurrentUserEmail : mark.attrs.userid, opened: opened });
+        view.dispatch(view.state.tr.removeMark(start, end, nmark).addMark(start, end, nmark).setSelection(new TextSelection(mid, mid)));
+    }
+
     @action
     onFocused = (e: React.FocusEvent): void => {
         document.removeEventListener("keypress", this.recordKeyHandler);
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index e88c85a86..31eb06427 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -1,6 +1,5 @@
-import { Plugin, EditorState, TextSelection } from "prosemirror-state"
+import { Plugin, EditorState } from "prosemirror-state"
 import './FormattedTextBoxComment.scss'
-import { DragManager } from "../../util/DragManager";
 import { ResolvedPos, Mark } from "prosemirror-model";
 import { EditorView } from "prosemirror-view";
 import { Doc } from "../../../new_fields/Doc";
@@ -35,18 +34,43 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark
     return after;
 }
 
+
 export class SelectionSizeTooltip {
-    static tooltip: any;
+    static tooltip: HTMLElement;
+    static start: number;
+    static end: number;
+    static mark: Mark;
+    static opened: boolean;
+    static textBox: any;
     constructor(view: any) {
         if (!SelectionSizeTooltip.tooltip) {
+            const root = document.getElementById("root");
             SelectionSizeTooltip.tooltip = document.createElement("div");
             SelectionSizeTooltip.tooltip.className = "FormattedTextBox-tooltip";
-            DragManager.Root().appendChild(SelectionSizeTooltip.tooltip);
+            SelectionSizeTooltip.tooltip.style.pointerEvents = "all";
+            SelectionSizeTooltip.tooltip.onpointerdown = (e: PointerEvent) => {
+                SelectionSizeTooltip.opened = !SelectionSizeTooltip.opened;
+                SelectionSizeTooltip.textBox.setAnnotation(
+                    SelectionSizeTooltip.start, SelectionSizeTooltip.end, SelectionSizeTooltip.mark,
+                    SelectionSizeTooltip.opened, e.button == 2);
+            };
+            root && root.appendChild(SelectionSizeTooltip.tooltip);
         }
-
         this.update(view, undefined);
     }
 
+    public static Hide() {
+        SelectionSizeTooltip.textBox = undefined;
+        SelectionSizeTooltip.tooltip && (SelectionSizeTooltip.tooltip.style.display = "none");
+    }
+    public static SetState(textBox: any, opened: boolean, start: number, end: number, mark: Mark) {
+        SelectionSizeTooltip.textBox = textBox;
+        SelectionSizeTooltip.start = start;
+        SelectionSizeTooltip.end = end;
+        SelectionSizeTooltip.mark = mark;
+        SelectionSizeTooltip.opened = opened;
+        SelectionSizeTooltip.textBox && SelectionSizeTooltip.tooltip && (SelectionSizeTooltip.tooltip.style.display = "");
+    }
 
     update(view: EditorView, lastState?: EditorState) {
         let state = view.state;
@@ -59,12 +83,13 @@ export class SelectionSizeTooltip {
             let naft = findEndOfMark(state.selection.$from, view, findOtherUserMark);
             let child = state.selection.$from.nodeBefore;
             let mark = child && findOtherUserMark(child.marks);
-            if (mark && child && nbef && naft && mark.attrs.opened && SelectionSizeTooltip.tooltip.offsetParent) {
+            if (mark && child && nbef && naft) {
                 SelectionSizeTooltip.tooltip.textContent = mark.attrs.userid;
                 // These are in screen coordinates
-                let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to);
+                // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to);
+                let 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
-                let box = SelectionSizeTooltip.tooltip.offsetParent.getBoundingClientRect();
+                let box = (document.getElementById("main-div") as any).getBoundingClientRect();
                 // Find a center-ish x position from the selection endpoints (when
                 // crossing lines, end may be more to the left)
                 let left = Math.max((start.left + end.left) / 2, start.left + 3);
-- 
cgit v1.2.3-70-g09d2


From a46ae95ed6570342f03b7590ff70d6249e56f059 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 29 Aug 2019 10:34:08 -0400
Subject: added a timestamp for edit marks.

---
 src/client/util/RichTextSchema.tsx                 |  3 ++-
 src/client/views/nodes/FormattedTextBox.tsx        | 18 +++++++++++++++++-
 src/client/views/nodes/FormattedTextBoxComment.tsx |  2 +-
 3 files changed, 20 insertions(+), 3 deletions(-)

(limited to 'src/client/util/RichTextSchema.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index f8da98f17..a642ee46c 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -335,7 +335,8 @@ export const marks: { [index: string]: MarkSpec } = {
         attrs: {
             userid: { default: "" },
             hide_users: { default: [] },
-            opened: { default: true }
+            opened: { default: true },
+            modified: { default: "when?" }
         },
         group: "inline",
         inclusive: false,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index c23b85e83..0d4376d8d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -38,6 +38,7 @@ import { DictationManager } from '../../util/DictationManager';
 import { ReplaceStep } from 'prosemirror-transform';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { selectionSizePlugin, findStartOfMark, findUserMark, findEndOfMark, findOtherUserMark, SelectionSizeTooltip } from './FormattedTextBoxComment';
+import { date } from 'serializr';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -811,8 +812,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(this.props.Document, this.props.ContainingCollectionView)!, false);
             }, 0);
         }
+        function timenow() {
+            var now = new Date();
+            let ampm = 'am';
+            let h = now.getHours();
+            let m: any = now.getMinutes();
+            let s: any = now.getSeconds();
+            if (h >= 12) {
+                if (h > 12) h -= 12;
+                ampm = 'pm';
+            }
+
+            if (m < 10) m = '0' + m;
+            if (s < 10) s = '0' + s;
+            return now.toLocaleDateString() + ' ' + h + ':' + m + ':' + s + ' ' + ampm;
+        }
         var markerss = this._editorView!.state.storedMarks || (this._editorView!.state.selection.$to.parentOffset && this._editorView!.state.selection.$from.marks());
-        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail })];
+        let newMarks = [...(markerss ? markerss.filter(m => m.type !== schema.marks.user_mark) : []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: timenow() })];
         this._editorView!.state.storedMarks = newMarks;
 
         // stop propagation doesn't seem to stop propagation of native keyboard events.
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 31eb06427..4ec0d6064 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -84,7 +84,7 @@ export class SelectionSizeTooltip {
             let child = state.selection.$from.nodeBefore;
             let mark = child && findOtherUserMark(child.marks);
             if (mark && child && nbef && naft) {
-                SelectionSizeTooltip.tooltip.textContent = mark.attrs.userid;
+                SelectionSizeTooltip.tooltip.textContent = mark.attrs.userid + " " + mark.attrs.modified;
                 // These are in screen coordinates
                 // let start = view.coordsAtPos(state.selection.from), end = view.coordsAtPos(state.selection.to);
                 let start = view.coordsAtPos(state.selection.from - nbef), end = view.coordsAtPos(state.selection.from - nbef);
-- 
cgit v1.2.3-70-g09d2

