diff options
Diffstat (limited to 'src/client/util/RichTextRules.ts')
-rw-r--r-- | src/client/util/RichTextRules.ts | 184 |
1 files changed, 168 insertions, 16 deletions
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 3b8396510..ebb9bda8a 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -1,14 +1,12 @@ -import { - inputRules, - wrappingInputRule, - textblockTypeInputRule, - smartQuotes, - emDash, - ellipsis -} from "prosemirror-inputrules"; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; - +import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from "prosemirror-inputrules"; import { schema } from "./RichTextSchema"; +import { wrappingInputRule } from "./prosemirrorPatches"; +import { NodeSelection, TextSelection } from "prosemirror-state"; +import { NumCast, Cast } from "../../new_fields/Types"; +import { Doc } from "../../new_fields/Doc"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; +import { Docs } from "../documents/Documents"; +import { Id } from "../../new_fields/FieldSymbols"; export const inpRules = { rules: [ @@ -21,10 +19,29 @@ export const inpRules = { // 1. ordered list wrappingInputRule( - /^(\d+)\.\s$/, + /^1\.\s$/, + schema.nodes.ordered_list, + () => { + return ({ mapStyle: "decimal", bulletStyle: 1 }); + }, + (match: any, node: any) => { + return node.childCount + node.attrs.order === +match[1]; + }, + (type: any) => ({ type: type, attrs: { mapStyle: "decimal", bulletStyle: 1 } }) + ), + // a. alphabbetical list + wrappingInputRule( + /^a\.\s$/, schema.nodes.ordered_list, - match => ({ order: +match[1] }), - (match, node) => node.childCount + node.attrs.order === +match[1] + // match => { + () => { + return ({ mapStyle: "alpha", bulletStyle: 1 }); + // return ({ order: +match[1] }) + }, + (match: any, node: any) => { + return node.childCount + node.attrs.order === +match[1]; + }, + (type: any) => ({ type: type, attrs: { mapStyle: "alpha", bulletStyle: 1 } }) ), // * bullet list @@ -35,9 +52,144 @@ export const inpRules = { // # heading textblockTypeInputRule( - new RegExp("^(#{1,6})\\s$"), + new RegExp(/^(#{1,6})\s$/), schema.nodes.heading, - match => ({ level: match[1].length }) - ) + match => { + return ({ level: match[1].length }); + } + ), + + new InputRule( + new RegExp(/^#([0-9]+)\s$/), + (state, match, start, end) => { + let size = Number(match[1]); + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + (Cast(FormattedTextBox.InputBoxOverlay!.props.Document, Doc) as Doc).heading = Number(match[1]); + return state.tr.deleteRange(start, end); + } + return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: Number(match[1]) })); + }), + new InputRule( + new RegExp(/t/), + (state, match, start, end) => { + if (state.selection.to === state.selection.from) return null; + let node = (state.doc.resolve(start) as any).nodeAfter; + return node ? state.tr.addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: "todo", modified: Math.round(Date.now() / 1000 / 60) })) : state.tr; + }), + new InputRule( + new RegExp(/i/), + (state, match, start, end) => { + if (state.selection.to === state.selection.from) return null; + let node = (state.doc.resolve(start) as any).nodeAfter; + return node ? state.tr.addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: "ignore", modified: Math.round(Date.now() / 1000 / 60) })) : state.tr; + }), + new InputRule( + new RegExp(/\!/), + (state, match, start, end) => { + if (state.selection.to === state.selection.from) return null; + let node = (state.doc.resolve(start) as any).nodeAfter; + return node ? state.tr.addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: "important", modified: Math.round(Date.now() / 1000 / 60) })) : state.tr; + }), + new InputRule( + new RegExp(/\x/), + (state, match, start, end) => { + if (state.selection.to === state.selection.from) return null; + let node = (state.doc.resolve(start) as any).nodeAfter; + return node ? state.tr.addMark(start, end, schema.marks.user_tag.create({ userid: Doc.CurrentUserEmail, tag: "disagree", modified: Math.round(Date.now() / 1000 / 60) })) : state.tr; + }), + new InputRule( + new RegExp(/^\^\^\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "center"; + return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; + } + let replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "center" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))); + }), + new InputRule( + new RegExp(/^\[\[\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "left"; + return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; + } + let replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "left" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))); + }), + new InputRule( + new RegExp(/^\]\]\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let ruleProvider = FormattedTextBox.InputBoxOverlay!.props.ruleProvider; + let heading = NumCast(FormattedTextBox.InputBoxOverlay!.props.Document.heading); + if (ruleProvider && heading) { + ruleProvider["ruleAlign_" + heading] = "right"; + return node ? state.tr.deleteRange(start, end).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; + } + let replaced = node ? state.tr.replaceRangeWith(start, end, schema.nodes.paragraph.create({ align: "right" })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))); + }), + new InputRule( + new RegExp(/##\s$/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let target = Docs.Create.TextDocument({ width: 75, height: 35, autoHeight: true, fontSize: 9, title: "inline comment" }); + let replaced = node ? state.tr.insertText("←", start).replaceRangeWith(start + 1, end + 1, schema.nodes.dashDoc.create({ + width: 75, height: 35, + title: "dashDoc", docid: target[Id], + float: "right" + })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 1))); + }), + new InputRule( + new RegExp(/\(\(/), + (state, match, start, end) => { + let node = (state.doc.resolve(start) as any).nodeAfter; + let sm = state.storedMarks || undefined; + let mark = state.schema.marks.highlight.create(); + let selected = state.tr.setSelection(new TextSelection(state.doc.resolve(start), state.doc.resolve(end))).addMark(start, end, mark); + let content = selected.selection.content(); + let replaced = node ? selected.replaceRangeWith(start, start, + schema.nodes.star.create({ visibility: true, text: content, textslice: content.toJSON() })).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : + state.tr; + return replaced.setSelection(new TextSelection(replaced.doc.resolve(end + 1))); + }), + new InputRule( + new RegExp(/\)\)/), + (state, match, start, end) => { + let mark = state.schema.marks.highlight.create(); + return state.tr.removeStoredMark(mark); + }), + new InputRule( + new RegExp(/\^f\s$/), + (state, match, start, end) => { + let newNode = schema.nodes.footnote.create({}); + let tr = state.tr; + tr.deleteRange(start, end).replaceSelectionWith(newNode); // replace insertion with a footnote. + return tr.setSelection(new NodeSelection( // select the footnote node to open its display + tr.doc.resolve( // get the location of the footnote node by subtracting the nodesize of the footnote from the current insertion point anchor (which will be immediately after the footnote node) + tr.selection.anchor - tr.selection.$anchor.nodeBefore!.nodeSize))); + }), + // let newNode = schema.nodes.footnote.create({}); + // if (dispatch && state.selection.from === state.selection.to) { + // return true; + // } ] }; |