diff options
Diffstat (limited to 'src/client/util')
| -rw-r--r-- | src/client/util/DocumentManager.ts | 2 | ||||
| -rw-r--r-- | src/client/util/ProsemirrorExampleTransfer.ts | 84 | ||||
| -rw-r--r-- | src/client/util/RichTextRules.ts | 3 | ||||
| -rw-r--r-- | src/client/util/RichTextSchema.tsx | 98 | ||||
| -rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 44 |
5 files changed, 158 insertions, 73 deletions
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 b928532d6..3979d8a49 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,31 +79,76 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?: bind("Mod-s", TooltipTextMenu.insertStar); - bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => 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 nodeTypeMark = (depth: number) => depth === 2 ? "indent2" : depth === 4 ? "indent3" : depth === 6 ? "indent4" : "indent1"; let bulletFunc = (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { var ref = state.selection; 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; - - if (!wrapInList(nodeType)(state, (tx2: Transaction) => { - marks && tx2.ensureMarks(marks); - marks && tx2.setStoredMarks(marks); + if (!sinkListItem(schema.nodes.list_item)(state, (tx2: Transaction) => { + const resolvedPos = tx2.doc.resolve(range!.start); + + 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); + break; + } + } + marks && tx2.ensureMarks([...marks]); + marks && tx2.setStoredMarks([...marks]); dispatch(tx2); })) { - console.log("bullet fail"); + 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; + for (let i = path.length - 1; i > 0; i--) { + if (path[i].type === schema.nodes.ordered_list) { + path[i].attrs.bulletStyle = nodeTypeMark(depth); + break; + } + } + // 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); + })) { + console.log("bullet fail"); + } } - } - bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => bulletFunc(state, dispatch)); + }; + + bind("Tab", bulletFunc); + + bind("Shift-Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { + var ref = state.selection; + 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; + liftListItem(schema.nodes.list_item)(state, (tx2: Transaction) => { + try { + const resolvedPos = tx2.doc.resolve(Math.round((range!.start + range!.end) / 2)); + + 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); + break; + } + } + + marks && tx2.ensureMarks([...marks]); + marks && tx2.setStoredMarks([...marks]); + dispatch(tx2); + } catch (e) { + dispatch(tx2); + } + }); + }); bind("Enter", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => { var marks = state.storedMarks || (state.selection.$to.parentOffset && state.selection.$from.marks()); @@ -115,7 +160,8 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?: if (!splitBlockKeepMarks(state, (tx3: Transaction) => { marks && tx3.ensureMarks(marks); marks && tx3.setStoredMarks(marks); - if (!liftListItem(schema.nodes.list_item)(state, (tx4: Transaction) => dispatch(tx4))) { + if (!liftListItem(schema.nodes.list_item)(state, dispatch as ((tx: Transaction<Schema<any, any>>) => void)) + ) { dispatch(tx3); } })) { diff --git a/src/client/util/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 d9e1d6ae1..df33589bf 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]; @@ -175,43 +176,17 @@ export const nodes: { [index: string]: NodeSpec } = { content: 'list_item+', group: 'block', attrs: { - bulletStyle: { default: "decimal" }, + bulletStyle: { default: "" }, + mapStyle: { default: "decimal" } }, toDOM(node: Node<any>) { - return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0] - } - }, - alphabet_list: { - ...orderedList, - content: 'list_item+', - group: 'block', - attrs: { - bulletStyle: { default: "lower-alpha" }, - }, - toDOM(node: Node<any>) { - return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0] - } - }, - cap_alphabet_list: { - ...orderedList, - content: 'list_item+', - group: 'block', - attrs: { - bulletStyle: { default: "upper-alpha" }, - }, - toDOM(node: Node<any>) { - return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0] - } - }, - roman_list: { - ...orderedList, - content: 'list_item+', - group: 'block', - attrs: { - bulletStyle: { default: "lower-roman" }, - }, - toDOM(node: Node<any>) { - return ['ol', { style: `list-style: ${node.attrs.bulletStyle}` }, 0] + 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] } }, //this doesn't currently work for some reason @@ -220,9 +195,10 @@ export const nodes: { [index: string]: NodeSpec } = { content: 'list_item+', group: 'block', // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], - // toDOM() { return ['ol', { - // style: 'list-type: hebrew' - // }] } + toDOM(node: Node<any>) { + for (let i = 0; i < node.childCount; i++) node.child(i).attrs.className = ""; + return ['ul', 0]; + } }, //bullet_list: { @@ -234,8 +210,14 @@ export const nodes: { [index: string]: NodeSpec } = { //select: state => true, // }, list_item: { + attrs: { + className: { default: "" } + }, ...listItem, - content: 'paragraph block*' + content: 'paragraph block*', + toDOM(node: any) { + return ["li", { class: node.attrs.className }, 0]; + } }, }; @@ -268,7 +250,7 @@ export const marks: { [index: string]: MarkSpec } = { // :: MarkSpec An emphasis mark. Rendered as an `<em>` element. // Has parse rules that also match `<i>` and `font-style: italic`. em: { - parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], + parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style: italic" }], toDOM() { return emDOM; } }, @@ -320,6 +302,17 @@ export const marks: { [index: string]: MarkSpec } = { toDOM: () => ['sup'] }, + 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: { parseDOM: [{ style: 'color: blue' }], toDOM() { @@ -338,6 +331,28 @@ export const marks: { [index: string]: MarkSpec } = { } }, + // the id of the user who entered the text + user_mark: { + attrs: { + userid: { default: "" }, + hide_users: { default: [] }, + opened: { default: true }, + modified: { default: "when?" } + }, + group: "inline", + inclusive: false, + toDOM(node: any) { + let hideUsers = node.attrs.hide_users; + let hidden = hideUsers.indexOf(node.attrs.userid) !== -1 || (hideUsers.length === 0 && node.attrs.userid !== Doc.CurrentUserEmail); + return hidden ? + (node.attrs.opened ? + ['span', { class: "userMarkOpen" }, 0] : + ['span', { class: "userMark" }, ['span', { style: "font-size:2" }, 0]] + ) : + ['span', 0]; + } + }, + // :: MarkSpec Code font mark. Represented as a `<code>` element. code: { @@ -413,7 +428,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;` @@ -592,6 +606,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; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4eaee35d7..eda5fe09c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -28,11 +28,11 @@ export class TooltipTextMenu { private view: EditorView; private fontStyles: MarkType[]; private fontSizes: MarkType[]; - private listTypes: NodeType[]; + private listTypes: (NodeType | any)[]; private editorProps: FieldViewProps & FormattedTextBoxProps; private fontSizeToNum: Map<MarkType, number>; private fontStylesToName: Map<MarkType, string>; - private listTypeToIcon: Map<NodeType, string>; + private listTypeToIcon: Map<NodeType | any, string>; //private link: HTMLAnchorElement; private wrapper: HTMLDivElement; private extras: HTMLDivElement; @@ -165,16 +165,22 @@ 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 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.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()); @@ -509,10 +515,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); + }); } } |
