From 094bbd52f2b55f501357a9f6b057042ad7684f27 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 26 Aug 2019 16:58:24 -0400 Subject: playing more with bulleted lists. --- src/client/util/ProsemirrorExampleTransfer.ts | 70 +++++++++++++++++++++------ src/client/util/RichTextRules.ts | 3 +- src/client/util/RichTextSchema.tsx | 10 +++- src/client/util/TooltipTextMenu.tsx | 10 +++- src/client/views/nodes/FormattedTextBox.tsx | 12 ++--- 5 files changed, 78 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index b928532d6..3cdfba59a 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -2,8 +2,8 @@ import { chainCommands, exitCode, joinDown, joinUp, lift, selectParentNode, setB import { redo, undo } from "prosemirror-history"; import { undoInputRule } from "prosemirror-inputrules"; import { Schema } from "prosemirror-model"; -import { liftListItem, splitListItem, wrapInList } from "prosemirror-schema-list"; -import { EditorState, Transaction } from "prosemirror-state"; +import { liftListItem, splitListItem, wrapInList, sinkListItem } from "prosemirror-schema-list"; +import { EditorState, Transaction, TextSelection, NodeSelection } from "prosemirror-state"; import { TooltipTextMenu } from "./TooltipTextMenu"; const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; @@ -79,32 +79,72 @@ export default function buildKeymap>(schema: S, mapKeys?: bind("Mod-s", TooltipTextMenu.insertStar); - bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { - var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); - liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => { - marks && tx2.ensureMarks(marks); - marks && tx2.setStoredMarks(marks); - dispatch(tx2); - }); - }); + 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, dispatch: (tx: Transaction) => 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 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 = depth == 2 ? schema.marks.mcap_alphabet_list : depth == 4 ? schema.marks.mroman_list : depth == 6 ? schema.marks.malphabet_list : schema.marks.mordered_list; + let created = levelMark(depth); + if (!sinkListItem(nodeType /*schema.nodes.list_item */)(state, (tx2: Transaction) => { + const resolvedPos = tx2.doc.resolve(range!.start); + + let ns = new NodeSelection(resolvedPos); + let tx3 = tx2.addMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, nodeTypeMark as any).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1))); + marks && tx3.ensureMarks([...marks, created]); + marks && tx3.setStoredMarks([...marks, created]); - if (!wrapInList(nodeType)(state, (tx2: Transaction) => { - marks && tx2.ensureMarks(marks); - marks && tx2.setStoredMarks(marks); - dispatch(tx2); + dispatch(tx3); })) { - console.log("bullet fail"); + 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).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, created]); + marks && tx4.setStoredMarks([...marks, created]); + + dispatch(tx4); + })) { + console.log("bullet fail"); + } } } bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => bulletFunc(state, dispatch)); + bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => 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 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)); + let nodeIndex = resolvedPos.pos - (resolvedPos.nodeBefore && resolvedPos.nodeBefore.type.name === "text" ? resolvedPos.nodeBefore!.nodeSize : 0); + 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, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to)); + marks && tx3.ensureMarks([...marks, created]); + marks && tx3.setStoredMarks([...marks, created]); + dispatch(tx3); + } catch (e) { + dispatch(tx2); + } + }); + }); + bind("Enter", (state: EditorState, dispatch: (tx: Transaction) => void) => { var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); if (!splitListItem(schema.nodes.list_item)(state, (tx3: Transaction) => { diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 89933650b..8c4c76027 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -26,7 +26,7 @@ export const inpRules = { match => ({ order: +match[1] }), (match, node) => node.childCount + node.attrs.order === +match[1] ), - // 1. ordered list + // a. alphabbetical list wrappingInputRule( /^([a-z]+)\.\s$/, schema.nodes.alphabet_list, @@ -34,7 +34,6 @@ export const inpRules = { (match, node) => node.childCount + node.attrs.order === +match[1] ), - // * bullet list wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list), diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index a8ce4731c..f128162c2 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -319,6 +319,15 @@ export const marks: { [index: string]: MarkSpec } = { toDOM: () => ['sup'] }, + malphabet_list: { + }, + mcap_alphabet_list: { + }, + mroman_list: { + }, + mo_list: { + }, + highlight: { parseDOM: [{ style: 'color: blue' }], toDOM() { @@ -412,7 +421,6 @@ export const marks: { [index: string]: MarkSpec } = { attrs: { fontSize: { default: 10 } }, - inclusive: false, parseDOM: [{ style: 'font-size: 10px;' }], toDOM: (node) => ['span', { style: `font-size: ${node.attrs.fontSize}px;` diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 7a0c6f8c5..77396c829 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -165,7 +165,15 @@ export class TooltipTextMenu { this.fontSizeToNum.set(schema.marks.p48, 48); this.fontSizeToNum.set(schema.marks.p72, 72); this.fontSizeToNum.set(schema.marks.pFontSize, 10); - this.fontSizeToNum.set(schema.marks.pFontSize, 10); + // this.fontSizeToNum.set(schema.marks.pFontSize, 12); + // this.fontSizeToNum.set(schema.marks.pFontSize, 14); + // this.fontSizeToNum.set(schema.marks.pFontSize, 16); + // this.fontSizeToNum.set(schema.marks.pFontSize, 18); + // this.fontSizeToNum.set(schema.marks.pFontSize, 20); + // this.fontSizeToNum.set(schema.marks.pFontSize, 24); + // this.fontSizeToNum.set(schema.marks.pFontSize, 32); + // this.fontSizeToNum.set(schema.marks.pFontSize, 48); + // this.fontSizeToNum.set(schema.marks.pFontSize, 72); this.fontSizes = Array.from(this.fontSizeToNum.keys()); //list types diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d6ba1700a..acfd2a3b8 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -115,7 +115,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe @undoBatch public setFontColor(color: string) { - let self = this; if (this._editorView!.state.selection.from === this._editorView!.state.selection.to) return false; if (this._editorView!.state.selection.to - this._editorView!.state.selection.from > this._editorView!.state.doc.nodeSize - 3) { this.props.Document.color = color; @@ -176,15 +175,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true); this._editorView.updateState(state); FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = false); - if (state.selection.empty && FormattedTextBox._toolTipTextMenu) { - const marks = tx.storedMarks; - if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); } + if (state.selection.empty && FormattedTextBox._toolTipTextMenu && tx.storedMarks) { + FormattedTextBox._toolTipTextMenu.mark_key_pressed(tx.storedMarks); } this._applyingChange = true; - const fieldkey = "preview"; - if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"); - if (this.extensionDoc) this.extensionDoc.lastModified = new DateField(new Date(Date.now())); + this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n")); + this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now()))); this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON())); this._applyingChange = false; let title = StrCast(this.dataDoc.title); @@ -198,7 +195,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe public highlightSearchTerms = (terms: String[]) => { if (this._editorView && (this._editorView as any).docView) { - const fieldkey = "preview"; const doc = this._editorView.state.doc; const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight); doc.nodesBetween(0, doc.content.size, (node: ProsNode, pos: number, parent: ProsNode, index: number) => { -- cgit v1.2.3-70-g09d2 From 237b5f67733b25686b825573298818f3ea443876 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 26 Aug 2019 17:42:19 -0400 Subject: try another branch --- src/client/util/ProsemirrorExampleTransfer.ts | 8 ++++---- src/client/util/RichTextSchema.tsx | 24 +++++++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 3cdfba59a..78b992ac8 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -93,13 +93,13 @@ export default function buildKeymap>(schema: S, mapKeys?: 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 = depth == 2 ? schema.marks.mcap_alphabet_list : depth == 4 ? schema.marks.mroman_list : depth == 6 ? schema.marks.malphabet_list : schema.marks.mordered_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(nodeType /*schema.nodes.list_item */)(state, (tx2: Transaction) => { + if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => { const resolvedPos = tx2.doc.resolve(range!.start); let ns = new NodeSelection(resolvedPos); - let tx3 = tx2.addMark(ns.from - 1, ns.to, created).addMark(ns.from - 1, ns.to, nodeTypeMark as any).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1))); + 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 as any).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1))); marks && tx3.ensureMarks([...marks, created]); marks && tx3.setStoredMarks([...marks, created]); @@ -110,7 +110,7 @@ export default function buildKeymap>(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 tx3 = tx2.setSelection(ns).removeMark(ns.from, ns.to, created).removeMark(ns.from, ns.to, nodeTypeMark as any).addMark(ns.from - 1, ns.to, nodeTypeMark as any).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, created]); marks && tx4.setStoredMarks([...marks, created]); 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) { + 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 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') 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 674cbf8d796351e607edd93ef520d662893c13b0 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 26 Aug 2019 22:41:41 -0400 Subject: working better --- src/client/util/ProsemirrorExampleTransfer.ts | 23 +++++++++++++---------- src/client/views/nodes/FormattedTextBox.scss | 9 --------- 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 78b992ac8..8bec2015e 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -99,10 +99,9 @@ export default function buildKeymap>(schema: S, mapKeys?: const resolvedPos = tx2.doc.resolve(range!.start); 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 as any).setSelection(TextSelection.create(tx2.doc, ns.to - (depth == 0 ? 3 : 1))); - marks && tx3.ensureMarks([...marks, created]); - marks && tx3.setStoredMarks([...marks, created]); - + 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]); dispatch(tx3); })) { let sxf = state.tr.setSelection(TextSelection.create(state.doc, range!.start, range!.end)); @@ -110,10 +109,10 @@ export default function buildKeymap>(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 - 1, 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).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 tx4 = depth > 0 ? tx3.insertText(" ").setSelection(TextSelection.create(tx2.doc, ns.to - 2, ns.to + 2)).deleteSelection() : tx3; - marks && tx4.ensureMarks([...marks, created]); - marks && tx4.setStoredMarks([...marks, created]); + 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]); dispatch(tx4); })) { @@ -127,6 +126,8 @@ export default function buildKeymap>(schema: S, mapKeys?: 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 > 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 { @@ -135,9 +136,11 @@ export default function buildKeymap>(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, ns.to, created).addMark(ns.from, ns.to, created).setSelection(TextSelection.create(tx2.doc, ns.to)); - marks && tx3.ensureMarks([...marks, created]); - marks && tx3.setStoredMarks([...marks, created]); + 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)); + + 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]); dispatch(tx3); } catch (e) { dispatch(tx2); diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 9d5dc76d3..1b537cc52 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -65,13 +65,4 @@ .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 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') 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>(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>(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>(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) { - 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 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') 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>(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, dispatch: (tx: Transaction) => void) => { var ref = state.selection; var range = ref.$from.blockRange(ref.$to); @@ -94,7 +86,6 @@ export default function buildKeymap>(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>(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>(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>(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>(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) { - 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 `` element. // Has parse rules that also match `` 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 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') 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>(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>(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) { - 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) { - 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) { - 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 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') 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) { + (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 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') 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>(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, dispatch: (tx: Transaction) => 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>(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>(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) { - (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 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') 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>(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) { 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) { + 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 8b210d872e3a9c540825be0e9fbb912514092def Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 27 Aug 2019 12:03:16 -0400 Subject: fixes for doc decorations with resizing textboxes. --- src/client/views/DocumentDecorations.tsx | 17 +++++++++++------ src/client/views/MainOverlayTextBox.tsx | 14 ++++++++++++-- src/client/views/collections/CollectionStackingView.tsx | 3 ++- .../collections/CollectionStackingViewFieldColumn.tsx | 2 +- 4 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 579806a89..e93893586 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -200,14 +200,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this.onBackgroundUp(e); } + @observable _forceUpdate = 0; + _lastBox = { x: 0, y: 0, r: 0, b: 0 } @computed get Bounds(): { x: number, y: number, b: number, r: number } { - return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { + let x = this._forceUpdate; + this._lastBox = SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { if (documentView.props.renderDepth === 0 || Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) { return bounds; } let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse(); + if (transform.TranslateX === 0 && transform.TranslateY === 0) { + setTimeout(action(() => this._forceUpdate++), 0); // bcz: fix CollectionStackingView's getTransform() somehow... + return this._lastBox; + } + var [sptX, sptY] = transform.transformPoint(0, 0); let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight()); return { @@ -215,6 +223,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) }; }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); + return this._lastBox; } onBackgroundDown = (e: React.PointerEvent): void => { @@ -821,11 +830,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let templates: Map = new Map(); Array.from(Object.values(Templates.TemplateList)).map(template => { - let sorted = SelectionManager.ViewsSortedVertically(); // slice().sort((doc1, doc2) => { - // if (NumCast(doc1.props.Document.y) > NumCast(doc2.props.Document.x)) return 1; - // if (NumCast(doc1.props.Document.x) < NumCast(doc2.props.Document.x)) return -1; - // return 0; - // }); + let sorted = SelectionManager.ViewsSortedVertically(); let docTemps = sorted.reduce((res: string[], doc: DocumentView, i) => { let temps = doc.props.Document.templates; if (temps instanceof List) { diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index e95e5b777..65a291d99 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -2,7 +2,7 @@ import { action, observable, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; -import { Doc } from '../../new_fields/Doc'; +import { Doc, DocListCast } from '../../new_fields/Doc'; import { BoolCast } from '../../new_fields/Types'; import { emptyFunction, returnTrue, returnZero, Utils, returnOne } from '../../Utils'; import { DragManager } from '../util/DragManager'; @@ -42,13 +42,23 @@ export class MainOverlayTextBox extends React.Component return this._textBox && this._textBox.setFontColor(color); } - constructor(props: MainOverlayTextBoxProps) { super(props); this._textProxyDiv = React.createRef(); MainOverlayTextBox.Instance = this; reaction(() => FormattedTextBox.InputBoxOverlay, (box?: FormattedTextBox) => { + const tb = this._textBox; + const container = tb && tb.props.ContainingCollectionView; + if (tb && container) { // this hacky section is needed to force the edited text box to completely recreate itself since things can get out synch -- specifically, the bullet label state which is computed when the dom elements are created + var dl = DocListCast(container.props.Document[container.props.fieldKey]); + let dli = dl.indexOf(tb.props.Document); + if (dli !== -1) { + let prev = dli > 0 ? dl[dli - 1] : undefined; + tb.props.removeDocument && tb.props.removeDocument(tb.props.Document); + setTimeout(() => Doc.AddDocToList(container.props.Document, container.props.fieldKey, tb.props.Document, prev, false, dli === 0), 0); + } + } this._textBox = box; if (box) { this.ChromeHeight = box.props.ChromeHeight; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6f22f2d2a..97b31bf2a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -278,7 +278,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } getDocTransform(doc: Doc, dref: HTMLDivElement) { - let y = this._scroll; + if (!dref) return Transform.Identity(); + let y = this._scroll; // required for document decorations to update when the text box container is scrolled let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index f30e99362..bc4fe7dd7 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, observable } from "mobx"; +import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Doc, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; -- cgit v1.2.3-70-g09d2 From 32f066ebc70684fe410b89fcb87cf550bd3537e3 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Tue, 27 Aug 2019 14:16:26 -0400 Subject: pdf + new npm version fixes --- src/client/views/pdf/PDFViewer.tsx | 6 ++++++ src/client/views/pdf/Page.tsx | 7 ++++--- src/server/authentication/config/passport.ts | 10 ++++++---- src/server/index.ts | 8 ++++---- 4 files changed, 20 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 258e218f0..e3bfea237 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -152,12 +152,18 @@ export class PDFViewer extends React.Component { if (this._pageSizes.length === 0) { this._isPage = Array(this.props.pdf.numPages); this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); + this._visibleElements = Array(this.props.pdf.numPages); await Promise.all(this._pageSizes.map>((val, i) => this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => { this._pageSizes.splice(i, 1, { width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]) * scale, height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) * scale }); + this._visibleElements.splice(i, 1, +
+ "PAGE IS LOADING... " +
) this.getPlaceholderPage(i); })))); this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 0de1777e6..8df2dce29 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -64,13 +64,14 @@ export default class Page extends React.Component { // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes if (this._state !== "rendering" && !this._page && this._canvas.current && this._textLayer.current) { this._state = "rendering"; - let viewport = page.getViewport(scale); + let viewport = page.getViewport({ scale: scale }); this._canvas.current.width = this._width = viewport.width; this._canvas.current.height = this._height = viewport.height; this.props.pageLoaded(viewport); let ctx = this._canvas.current.getContext("2d"); if (ctx) { - page.render({ canvasContext: ctx, viewport: viewport }); // renders the page onto the canvas context + //@ts-ignore + page.render({ canvasContext: ctx, viewport: viewport, enableWebGL: true }); // renders the page onto the canvas context page.getTextContent().then(res => // renders text onto the text container //@ts-ignore Pdfjs.renderTextLayer({ @@ -258,7 +259,7 @@ export default class Page extends React.Component { } } } - let text = selRange.extractContents().textContent; + let text = selRange.cloneContents().textContent; text && this.props.setSelectionText(text); // clear selection diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts index d42741410..10b17de71 100644 --- a/src/server/authentication/config/passport.ts +++ b/src/server/authentication/config/passport.ts @@ -42,9 +42,11 @@ export let isAuthenticated = (req: Request, res: Response, next: NextFunction) = export let isAuthorized = (req: Request, res: Response, next: NextFunction) => { const provider = req.path.split("/").slice(-1)[0]; - if (_.find(req.user.tokens, { kind: provider })) { - next(); - } else { - res.redirect(`/auth/${provider}`); + if (req.user) { + if (_.find((req.user as any).tokens, { kind: provider })) { + next(); + } else { + res.redirect(`/auth/${provider}`); + } } }; \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index 34a0a19f1..fca90a585 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -116,7 +116,7 @@ function addSecureRoute(method: Method, ) { let abstracted = (req: express.Request, res: express.Response) => { if (req.user) { - handler(req.user, res, req); + handler(req.user as any, res, req); } else { req.session!.target = req.originalUrl; onRejection(res, req); @@ -447,7 +447,7 @@ function LoadPage(file: string, pageNumber: number, res: Response) { console.log(pageNumber); pdf.getPage(pageNumber).then((page: Pdfjs.PDFPageProxy) => { console.log("reading " + page); - let viewport = page.getViewport(1); + let viewport = page.getViewport({ scale: 1 }); let canvasAndContext = factory.create(viewport.width, viewport.height); let renderContext = { canvasContext: canvasAndContext.context, @@ -811,8 +811,8 @@ const EndpointHandlerMap = new Map { - let sector = req.params.sector; - let action = req.params.action; + let sector: any = req.params.sector; + let action: any = req.params.action; GoogleApiServerUtils.GetEndpoint(GoogleApiServerUtils.Service[sector], { credentials, token }).then(endpoint => { let handler = EndpointHandlerMap.get(action); if (endpoint && handler) { -- cgit v1.2.3-70-g09d2 From 34e0b1cf34474ec6765e212b6a35defefbfb49c9 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 27 Aug 2019 15:46:03 -0400 Subject: removed selectOnLoad prop. fixed textboxes from deselecting on carriage return. --- src/client/views/MainOverlayTextBox.tsx | 2 +- src/client/views/MainView.tsx | 2 -- src/client/views/OverlayView.tsx | 1 - src/client/views/collections/CollectionDockingView.tsx | 1 - src/client/views/collections/CollectionSchemaCells.tsx | 1 - src/client/views/collections/CollectionSchemaView.tsx | 1 - .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +++----------- src/client/views/nodes/DocumentView.tsx | 4 +--- src/client/views/nodes/FieldView.tsx | 2 -- src/client/views/nodes/FormattedTextBox.tsx | 9 ++++++--- src/client/views/nodes/KeyValuePair.tsx | 1 - src/client/views/presentationview/PresentationElement.tsx | 1 - src/client/views/search/SearchItem.tsx | 1 - 13 files changed, 11 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 65a291d99..f15b60347 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -156,7 +156,7 @@ export class MainOverlayTextBox extends React.Component DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc} onClick={undefined} ChromeHeight={this.ChromeHeight} - isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true} + isSelected={returnTrue} select={emptyFunction} renderDepth={0} ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne} ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} pinToPres={returnZero} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} /> diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index a02214deb..6b856443b 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -326,7 +326,6 @@ export class MainView extends React.Component { PanelHeight={this.getPHeight} renderDepth={0} backgroundColor={returnEmptyString} - selectOnLoad={false} focus={emptyFunction} parentActive={returnTrue} whenActiveChanged={emptyFunction} @@ -389,7 +388,6 @@ export class MainView extends React.Component { PanelWidth={this.flyoutWidthFunc} PanelHeight={this.getPHeight} renderDepth={0} - selectOnLoad={false} focus={emptyFunction} backgroundColor={returnEmptyString} parentActive={returnTrue} diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index a60dc591c..538614089 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -153,7 +153,6 @@ export class OverlayView extends React.Component { PanelHeight={returnOne} ScreenToLocalTransform={Transform.Identity} renderDepth={1} - selectOnLoad={false} parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index dc0cbda0b..95f94875c 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -636,7 +636,6 @@ export class DockedFrameRenderer extends React.Component { PanelHeight={this.panelHeight} ScreenToLocalTransform={this.ScreenToLocalTransform} renderDepth={0} - selectOnLoad={false} parentActive={returnTrue} whenActiveChanged={emptyFunction} focus={emptyFunction} diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 551b485e7..9c26a08f0 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -153,7 +153,6 @@ export class CollectionSchemaCell extends React.Component { isSelected: returnFalse, select: emptyFunction, renderDepth: this.props.renderDepth + 1, - selectOnLoad: false, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, active: returnFalse, diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 4008dea51..9d83aa6c1 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1006,7 +1006,6 @@ export class CollectionSchemaPreview extends React.Component this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); private addLiveTextBox = (newBox: Doc) => { - this._selectOnLoaded = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed + FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed this.addDocument(newBox, false); } private addDocument = (newBox: Doc, allowDuplicates: boolean) => { @@ -642,7 +640,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onClick: this.props.onClick, ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform, renderDepth: this.props.renderDepth + 1, - selectOnLoad: childLayout[Id] === this._selectOnLoaded, PanelWidth: childLayout[WidthSym], PanelHeight: childLayout[HeightSym], ContentScaling: returnOne, @@ -668,7 +665,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onClick: this.props.onClick, ScreenToLocalTransform: this.getTransform, renderDepth: this.props.renderDepth, - selectOnLoad: layoutDoc[Id] === this._selectOnLoaded, PanelWidth: layoutDoc[WidthSym], PanelHeight: layoutDoc[HeightSym], ContentScaling: returnOne, @@ -768,13 +764,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { return prev; }, elements); - this.resetSelectOnLoaded(); - return docviews; } - resetSelectOnLoaded = () => setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way .... - @computed.struct get views() { let source = this.elements; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 3cf86b6f9..f7ebfb75a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -92,7 +92,6 @@ export interface DocumentViewProps { PanelWidth: () => number; PanelHeight: () => number; focus: (doc: Doc, willZoom: boolean, scale?: number) => void; - selectOnLoad: boolean; parentActive: () => boolean; whenActiveChanged: (isActive: boolean) => void; bringToFront: (doc: Doc, sendToBack?: boolean) => void; @@ -717,7 +716,6 @@ export class DocumentView extends DocComponent(Docu isSelected={this.isSelected} select={this.select} onClick={this.onClickHandler} - selectOnLoad={this.props.selectOnLoad} layoutKey={"layout"} fitToBox={BoolCast(this.props.Document.fitToBox) ? true : this.props.fitToBox} DataDoc={this.dataDoc} />); @@ -808,7 +806,7 @@ export class DocumentView extends DocComponent(Docu } {!showCaption ? (null) :
- +
} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f0f1b3b73..d9774303b 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -36,7 +36,6 @@ export interface FieldViewProps { isSelected: () => boolean; select: (isCtrlPressed: boolean) => void; renderDepth: number; - selectOnLoad: boolean; addDocument?: (document: Doc, allowDuplicates?: boolean) => boolean; addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void; pinToPres: (document: Doc) => void; @@ -108,7 +107,6 @@ export class FieldView extends React.Component { // PanelWidth={returnHundred} // PanelHeight={returnHundred} // renderDepth={0} //TODO Why is renderDepth reset? - // selectOnLoad={false} // focus={emptyFunction} // isSelected={this.props.isSelected} // select={returnFalse} diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index acfd2a3b8..c28bf1821 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -622,12 +622,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - if (this.props.selectOnLoad) { - if (!this.props.isOverlay) this.props.select(false); - else this._editorView!.focus(); + if (this.props.Document[Id] == FormattedTextBox.SelectOnLoad) { + FormattedTextBox.SelectOnLoad = ""; + this.props.select(false); } + else if (this.props.isOverlay) this._editorView!.focus(); } + public static SelectOnLoad = ""; + componentWillUnmount() { this._editorView && this._editorView.destroy(); this._reactionDisposer && this._reactionDisposer(); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 8001b24a7..5afd4d834 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -60,7 +60,6 @@ export class KeyValuePair extends React.Component { isSelected: returnFalse, select: emptyFunction, renderDepth: 1, - selectOnLoad: false, active: returnFalse, whenActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx index 83413814f..80aa25f48 100644 --- a/src/client/views/presentationview/PresentationElement.tsx +++ b/src/client/views/presentationview/PresentationElement.tsx @@ -359,7 +359,6 @@ export default class PresentationElement extends React.Component 90} focus={emptyFunction} backgroundColor={returnEmptyString} - selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} bringToFront={emptyFunction} diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 41fc49c2e..672892fdf 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -209,7 +209,6 @@ export class SearchItem extends React.Component { PanelHeight={returnYDimension} focus={emptyFunction} backgroundColor={returnEmptyString} - selectOnLoad={false} parentActive={returnFalse} whenActiveChanged={returnFalse} bringToFront={emptyFunction} -- cgit v1.2.3-70-g09d2 From 656a08a130124870c9f652f7b1529b2b496cdac7 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 27 Aug 2019 15:52:25 -0400 Subject: lint fixes. --- src/client/views/PreviewCursor.tsx | 2 +- src/client/views/collections/CollectionViewChromes.tsx | 2 ++ src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index d8e161ab6..1329dc02c 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -51,7 +51,7 @@ export class PreviewCursor extends React.Component<{}> { // tests for URL and makes web document let re: any = /^https?:\/\//g; if (re.test(e.clipboardData.getData("text/plain"))) { - const url = e.clipboardData.getData("text/plain") + const url = e.clipboardData.getData("text/plain"); PreviewCursor._addDocument(Docs.Create.WebDocument(url, { title: url, width: 300, height: 300, // nativeWidth: 300, nativeHeight: 472.5, diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index b2df0e747..4b3f7c87e 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -42,11 +42,13 @@ export class CollectionViewBaseChrome extends React.Component this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined }; _contentCommand = { // title: "set content", script: "getProto(this.target).data = aliasDocs(this.source.map(async p => await p));", params: ["target", "source"], // bcz: doesn't look like we can do async stuff in scripting... title: "set content", script: "getProto(this.target).data = aliasDocs(this.source);", params: ["target", "source"], + initialize: emptyFunction, immediate: (draggedDocs: Doc[]) => Doc.GetProto(this.props.CollectionView.props.Document).data = new List(draggedDocs.map((d: any) => Doc.MakeAlias(d))) }; _viewCommand = { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f7ebfb75a..4d5307c88 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -600,7 +600,7 @@ export class DocumentView extends DocComponent(Docu this.makeBtnClicked(); }, icon: "window-restore" }); - makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" }) + makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" }); !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" }); let existing = ContextMenu.Instance.findByDescription("Layout..."); let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : []; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index c28bf1821..49189c5f3 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -622,7 +622,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - if (this.props.Document[Id] == FormattedTextBox.SelectOnLoad) { + if (this.props.Document[Id] === FormattedTextBox.SelectOnLoad) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index f0140d04b..642f58daf 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -18,7 +18,7 @@ import { Docs } from "../../documents/Documents"; import { faStickyNote } from "@fortawesome/free-solid-svg-icons"; import { library } from "@fortawesome/fontawesome-svg-core"; -library.add(faStickyNote) +library.add(faStickyNote); @observer export class WebBox extends React.Component { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e3bfea237..e5917fefc 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -163,7 +163,7 @@ export class PDFViewer extends React.Component {
"PAGE IS LOADING... " -
) + ); this.getPlaceholderPage(i); })))); this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages); -- cgit v1.2.3-70-g09d2 From 5da0459ad76c614e455ea99798c940d4e93707bb Mon Sep 17 00:00:00 2001 From: bob 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') 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 `` 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 a7515d1e80e32fcc19096c73335f624042b85d51 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 27 Aug 2019 21:20:52 -0400 Subject: added auto-reformatting after shift-tab. --- src/client/views/MainOverlayTextBox.tsx | 10 +- src/client/views/nodes/FormattedTextBox.tsx | 144 +++++++++++++--------------- 2 files changed, 67 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index f15b60347..755e5de14 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -50,14 +50,8 @@ export class MainOverlayTextBox extends React.Component (box?: FormattedTextBox) => { const tb = this._textBox; const container = tb && tb.props.ContainingCollectionView; - if (tb && container) { // this hacky section is needed to force the edited text box to completely recreate itself since things can get out synch -- specifically, the bullet label state which is computed when the dom elements are created - var dl = DocListCast(container.props.Document[container.props.fieldKey]); - let dli = dl.indexOf(tb.props.Document); - if (dli !== -1) { - let prev = dli > 0 ? dl[dli - 1] : undefined; - tb.props.removeDocument && tb.props.removeDocument(tb.props.Document); - setTimeout(() => Doc.AddDocToList(container.props.Document, container.props.fieldKey, tb.props.Document, prev, false, dli === 0), 0); - } + if (tb && container) { + tb.rebuildEditor();// this forces the edited text box to completely recreate itself to avoid get out of sync -- e.g., bullet labels are only computed when the dom elements are created } this._textBox = box; if (box) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 667bac3be..5cbbc3b55 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -15,7 +15,7 @@ import { List } from '../../../new_fields/List'; import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField"; import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types"; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Utils } from '../../../Utils'; +import { Utils, numberRange } from '../../../Utils'; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; @@ -37,7 +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'; +import { number } from 'prop-types'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -69,25 +69,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(FormattedTextBox, fieldStr); } - public static Instance: FormattedTextBox; - private _ref: React.RefObject; + private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined; + private _ref: React.RefObject = React.createRef(); private _proseRef?: HTMLDivElement; private _editorView: Opt; - private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined; private _applyingChange: boolean = false; private _linkClicked = ""; + private _undoTyping?: UndoManager.Batch; private _reactionDisposer: Opt; private _searchReactionDisposer?: Lambda; private _textReactionDisposer: Opt; private _heightReactionDisposer: Opt; private _proxyReactionDisposer: Opt; - private pullReactionDisposer: Opt; - private pushReactionDisposer: Opt; + private _pullReactionDisposer: Opt; + private _pushReactionDisposer: Opt; private dropDisposer?: DragManager.DragDropDisposer; - public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } - @observable _entered = false; + @observable private _entered = false; @observable public static InputBoxOverlay?: FormattedTextBox = undefined; + public static SelectOnLoad = ""; public static InputBoxOverlayScroll: number = 0; public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; @@ -128,15 +128,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe constructor(props: FieldViewProps) { super(props); - FormattedTextBox.Instance = this; - this._ref = React.createRef(); if (this.props.isOverlay) { DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined); } - - document.addEventListener("paste", this.paste); } + public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } + @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); } @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); } @@ -172,10 +170,12 @@ 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); + // 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 })]; + // if (!this._down) { // if the pointer is down, we're likely doing a drag selection. If setStoreMarks is called during + // tx.ensureMarks(newMarks); // this operation, then it is likely (but not guaranteed) that nothing will be selected due to strange prosemirror behavior. + // tx.setStoredMarks(newMarks); + // } const state = this._editorView.state.apply(tx); FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true); this._editorView.updateState(state); @@ -240,12 +240,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe protected createDropTarget = (ele: HTMLDivElement) => { this._proseRef = ele; - if (this.dropDisposer) { - this.dropDisposer(); - } - if (ele) { - this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); - } + this.dropDisposer && this.dropDisposer(); + ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } })); } @undoBatch @@ -269,17 +265,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } recordKeyHandler = (e: KeyboardEvent) => { - 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(); - this.recordBullet(); + if (this.props.Document === SelectionManager.SelectedDocuments()[0].props.Document) { + if (e.key === "R" && e.altKey) { + e.stopPropagation(); + e.preventDefault(); + this.recordBullet(); + } } } @@ -323,15 +314,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } private newListItems = (count: number) => { - let listItems: any[] = []; - for (let i = 0; i < count; i++) { - listItems.push(schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create())); - } - return listItems; + return numberRange(count).map(x => schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create())); } - componentDidMount() { - const config = { + @computed get config() { + return { schema, inpRules, //these currently don't do anything, but could eventually be helpful plugins: this.props.isOverlay ? [ @@ -350,7 +337,16 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe keymap(buildKeymap(schema)), keymap(baseKeymap), ] - }; + } + }; + + @action + rebuildEditor() { + this.setupEditor(this.config, this.dataDoc, this.props.fieldKey); + } + + componentDidMount() { + document.addEventListener("paste", this.paste); if (!this.props.isOverlay) { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), @@ -373,13 +369,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe incomingValue => { if (this._editorView && !this._applyingChange) { let updatedState = JSON.parse(incomingValue); - this._editorView.updateState(EditorState.fromJSON(config, updatedState)); + this._editorView.updateState(EditorState.fromJSON(this.config, updatedState)); this.tryUpdateHeight(); } } ); - this.pullReactionDisposer = reaction( + this._pullReactionDisposer = reaction( () => this.props.Document[Pulls], () => { if (!DocumentDecorations.hasPulledHack) { @@ -390,7 +386,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } ); - this.pushReactionDisposer = reaction( + this._pushReactionDisposer = reaction( () => this.props.Document[Pushes], () => { if (!DocumentDecorations.hasPushedHack) { @@ -415,7 +411,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this.dataDoc.lastModified = undefined; } }, { fireImmediately: true }); - this.setupEditor(config, this.dataDoc, this.props.fieldKey); + + + this.setupEditor(this.config, this.dataDoc, this.props.fieldKey); this._searchReactionDisposer = reaction(() => { return StrCast(this.props.Document.search_string); @@ -515,7 +513,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - clipboardTextSerializer = (slice: Slice): string => { let text = "", separated = true; const from = 0, to = slice.content.size; @@ -615,6 +612,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } if (this._proseRef) { + this._editorView && this._editorView.destroy(); this._editorView = new EditorView(this._proseRef, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, @@ -638,20 +636,20 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe else if (this.props.isOverlay) this._editorView!.focus(); } - public static SelectOnLoad = ""; - componentWillUnmount() { - this._editorView && this._editorView.destroy(); this._reactionDisposer && this._reactionDisposer(); this._proxyReactionDisposer && this._proxyReactionDisposer(); this._textReactionDisposer && this._textReactionDisposer(); - this.pushReactionDisposer && this.pushReactionDisposer(); - this.pullReactionDisposer && this.pullReactionDisposer(); + this._pushReactionDisposer && this._pushReactionDisposer(); + this._pullReactionDisposer && this._pullReactionDisposer(); this._heightReactionDisposer && this._heightReactionDisposer(); this._searchReactionDisposer && this._searchReactionDisposer(); + document.removeEventListener("paste", this.paste); } + _down = false; onPointerDown = (e: React.PointerEvent): void => { + this._down = true; if (this.props.onClick && e.button === 0) { e.preventDefault(); } @@ -712,10 +710,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe e.preventDefault(); } } + onPointerUp = (e: React.PointerEvent): void => { - if (FormattedTextBox._toolTipTextMenu && FormattedTextBox._toolTipTextMenu.tooltip) { - //this._toolTipTextMenu.tooltip.style.opacity = "1"; - } + this._down = false; if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } @@ -763,7 +760,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe return self._toolTipTextMenu = new TooltipTextMenu(_editorView, myprops); } }); - //this.props.Document.tooltip = self._toolTipTextMenu; } tooltipLinkingMenuPlugin() { @@ -781,13 +777,22 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this._undoTyping = undefined; } } - public _undoTyping?: UndoManager.Batch; onKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Escape") { SelectionManager.DeselectAll(); } e.stopPropagation(); - if (e.key === "Tab") e.preventDefault(); + if (e.key === "Tab") { + 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(); + SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(this.props.Document, this.props.ContainingCollectionView)!, false); + }, 0); + } + 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; + // stop propagation doesn't seem to stop propagation of native keyboard events. // so we set a flag on the native event that marks that the event's been handled. (e.nativeEvent as any).DASHFormattedTextBoxHandled = true; @@ -814,24 +819,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } - @action - onPointerEnter = (e: React.PointerEvent) => { - this._entered = true; - } - @action - onPointerLeave = (e: React.PointerEvent) => { - this._entered = false; - } - - specificContextMenu = (e: React.MouseEvent): void => { - // let subitems: ContextMenuProps[] = []; - // subitems.push({ - // description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height", - // event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt" - // }); - // ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" }); - } - render() { let self = this; @@ -854,14 +841,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onKeyDown={this.onKeyPress} onFocus={this.onFocused} onClick={this.onClick} - onContextMenu={this.specificContextMenu} onBlur={this.onBlur} onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onMouseDown={this.onMouseDown} onWheel={this.onPointerWheel} - onPointerEnter={this.onPointerEnter} - onPointerLeave={this.onPointerLeave} + onPointerEnter={action(() => this._entered = true)} + onPointerLeave={action(() => this._entered = false)} >
-- cgit v1.2.3-70-g09d2 From 41c79ceb4b52965f374db750d06a04a94ecc8212 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 27 Aug 2019 21:21:30 -0400 Subject: from last --- src/client/views/nodes/FormattedTextBox.tsx | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5cbbc3b55..ba558a0b2 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -170,12 +170,6 @@ 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 })]; - // if (!this._down) { // if the pointer is down, we're likely doing a drag selection. If setStoreMarks is called during - // tx.ensureMarks(newMarks); // this operation, then it is likely (but not guaranteed) that nothing will be selected due to strange prosemirror behavior. - // tx.setStoredMarks(newMarks); - // } const state = this._editorView.state.apply(tx); FormattedTextBox._toolTipTextMenu && (FormattedTextBox._toolTipTextMenu.HackToFixTextSelectionGlitch = true); this._editorView.updateState(state); -- cgit v1.2.3-70-g09d2 From 1fbf7d7e10bb4dfa7e3a323ee0641d7bbf97b6a8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik 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') 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>(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, dispatch: (tx: Transaction) => void) => { var ref = state.selection; @@ -90,7 +89,7 @@ export default function buildKeymap>(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>(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>(schema: S, mapKeys?: console.log("bullet fail"); } } - } - bind("Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => bulletFunc(state, dispatch)); + }; + + bind("Tab", bulletFunc); bind("Shift-Tab", (state: EditorState, dispatch: (tx: Transaction) => void) => { var ref = state.selection; @@ -132,7 +132,7 @@ export default function buildKeymap>(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>(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>) => 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) { - 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) { 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; private fontStylesToName: Map; - private listTypeToIcon: Map; + private listTypeToIcon: Map; //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 { } 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 { 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 3dba9c0fdaaaa65339190aa0126b3b1cf1b2ffa1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 27 Aug 2019 23:36:01 -0400 Subject: from last --- src/client/util/ProsemirrorExampleTransfer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index 12ad28199..3979d8a49 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -111,8 +111,9 @@ export default function buildKeymap>(schema: S, mapKeys?: break; } } - marks && tx2.ensureMarks([...marks]); - marks && tx2.setStoredMarks([...marks]); + // when promoting to a list, assume list will format things so don't copy the stored marks. + // marks && tx2.ensureMarks([...marks]); + // marks && tx2.setStoredMarks([...marks]); dispatch(tx2); })) { -- cgit v1.2.3-70-g09d2 From be517c301997b617ba642d7f0745a254a6510bf1 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 28 Aug 2019 09:34:52 -0400 Subject: fixed initial storedmarks --- src/client/views/nodes/FormattedTextBox.tsx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 36740fc66..1c5224e12 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -628,6 +628,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe this.props.select(false); } else if (this.props.isOverlay) this._editorView!.focus(); + 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; + } componentWillUnmount() { -- cgit v1.2.3-70-g09d2 From 19ba56239796cc6a421bbb02affc47802ef824a7 Mon Sep 17 00:00:00 2001 From: bob 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') 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 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') 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 24f87285011b4cff8518a12442410a99f0a97cb8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 28 Aug 2019 21:40:12 -0400 Subject: fixed template bug related to childLayouts --- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 62f848a2b..a7acd9e91 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -182,18 +182,29 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { private get _pheight() { return this.props.PanelHeight(); } private inkKey = "ink"; private _childLayoutDisposer?: IReactionDisposer; + private _childDisposer?: IReactionDisposer; componentDidMount() { - this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)], - async (args) => { - this.childDocs.filter(doc => args[1] instanceof Doc || doc.layout instanceof Doc).map(async doc => { - if (!Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc)) { - Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined); + this._childDisposer = reaction(() => this.childDocs, + async (childDocs) => { + let childLayout = Cast(this.props.Document.childLayout, Doc) as Doc; + childLayout && childDocs.map(async doc => { + if (!Doc.AreProtosEqual(childLayout, (await doc).layout as Doc)) { + Doc.ApplyTemplateTo(childLayout, doc, undefined); + } + }); + }); + this._childLayoutDisposer = reaction(() => Cast(this.props.Document.childLayout, Doc), + async (childLayout) => { + this.childDocs.map(async doc => { + if (!Doc.AreProtosEqual(childLayout as Doc, (await doc).layout as Doc)) { + Doc.ApplyTemplateTo(childLayout as Doc, doc, undefined); } }); }); } componentWillUnmount() { + this._childDisposer && this._childDisposer(); this._childLayoutDisposer && this._childLayoutDisposer(); } -- cgit v1.2.3-70-g09d2 From 18cc66aaa90c5054268eac9520a963867c0c2f8e Mon Sep 17 00:00:00 2001 From: Bob Zeleznik 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') 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 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') 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 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') 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 From 22a5999626b11cf75cafbcd421601e668438f6ad Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 29 Aug 2019 10:46:42 -0400 Subject: added keep checkbox --- src/client/views/nodes/FormattedTextBoxComment.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index 4ec0d6064..9123f8aed 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -37,6 +37,7 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark export class SelectionSizeTooltip { static tooltip: HTMLElement; + static tooltipText: HTMLElement; static start: number; static end: number; static mark: Mark; @@ -45,14 +46,20 @@ export class SelectionSizeTooltip { constructor(view: any) { if (!SelectionSizeTooltip.tooltip) { const root = document.getElementById("root"); + let input = document.createElement("input"); + input.type = "checkbox"; SelectionSizeTooltip.tooltip = document.createElement("div"); + SelectionSizeTooltip.tooltipText = document.createElement("div"); + SelectionSizeTooltip.tooltip.appendChild(SelectionSizeTooltip.tooltipText); SelectionSizeTooltip.tooltip.className = "FormattedTextBox-tooltip"; SelectionSizeTooltip.tooltip.style.pointerEvents = "all"; + SelectionSizeTooltip.tooltip.appendChild(input); SelectionSizeTooltip.tooltip.onpointerdown = (e: PointerEvent) => { - SelectionSizeTooltip.opened = !SelectionSizeTooltip.opened; + let keep = e.target && (e.target as any).type === "checkbox"; + SelectionSizeTooltip.opened = keep || !SelectionSizeTooltip.opened; SelectionSizeTooltip.textBox.setAnnotation( SelectionSizeTooltip.start, SelectionSizeTooltip.end, SelectionSizeTooltip.mark, - SelectionSizeTooltip.opened, e.button == 2); + SelectionSizeTooltip.opened, keep); }; root && root.appendChild(SelectionSizeTooltip.tooltip); } @@ -84,7 +91,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 + " " + mark.attrs.modified; + SelectionSizeTooltip.tooltipText.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