diff options
Diffstat (limited to 'src/client/util')
| -rw-r--r-- | src/client/util/DictationManager.ts | 2 | ||||
| -rw-r--r-- | src/client/util/RichTextRules.ts | 17 | ||||
| -rw-r--r-- | src/client/util/RichTextSchema.tsx | 53 |
3 files changed, 67 insertions, 5 deletions
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index fa7f63965..3394cb93d 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -332,7 +332,7 @@ export namespace DictationManager { ["new outline", { action: (target: DocumentView) => { - const newBox = Docs.Create.TextDocument({ _width: 400, _height: 200, title: "My Outline", _autoHeight: true }); + const newBox = Docs.Create.TextDocument("", { _width: 400, _height: 200, title: "My Outline", _autoHeight: true }); const proto = newBox.proto!; const prompt = "Press alt + r to start dictating here..."; const head = 3; diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 02b7502d8..bc8a0abb1 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -2,7 +2,7 @@ import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from import { schema } from "./RichTextSchema"; import { wrappingInputRule } from "./prosemirrorPatches"; import { NodeSelection, TextSelection } from "prosemirror-state"; -import { NumCast, Cast } from "../../new_fields/Types"; +import { StrCast, Cast } from "../../new_fields/Types"; import { Doc } from "../../new_fields/Doc"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { Docs, DocUtils } from "../documents/Documents"; @@ -72,6 +72,19 @@ export const inpRules = { // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode) new InputRule( + new RegExp(/!$/), + (state, match, start, end) => { + if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null; + const value = state.doc.textBetween(start, end); + + const node = (state.doc.resolve(start) as any).nodeAfter; + const sm = state.storedMarks || undefined; + const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(value) }); + const replaced = node ? state.tr.replaceRangeWith(start, end, fieldView).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; + return replaced.doc.nodeSize > end - 2 ? replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))) : replaced; + }), + // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode) + new InputRule( new RegExp(/@$/), (state, match, start, end) => { if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null; @@ -196,7 +209,7 @@ export const inpRules = { new InputRule( new RegExp(/%#$/), (state, match, start, end) => { - const target = Docs.Create.TextDocument({ _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" }); + const target = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" }); const node = (state.doc.resolve(start) as any).nodeAfter; const newNode = schema.nodes.dashComment.create({ docid: target[Id] }); const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: target[Id], float: "right" }); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index d64098e5f..21916e3d6 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -8,7 +8,7 @@ import { EditorState, NodeSelection, TextSelection, Plugin } from "prosemirror-s import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, WidthSym, HeightSym } from "../../new_fields/Doc"; +import { Doc, WidthSym, HeightSym, DataSym, Field } from "../../new_fields/Doc"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { DocumentView } from "../views/nodes/DocumentView"; @@ -16,7 +16,7 @@ import { DocumentManager } from "./DocumentManager"; import ParagraphNodeSpec from "./ParagraphNodeSpec"; import { Transform } from "./Transform"; import React = require("react"); -import { BoolCast, NumCast, Cast } from "../../new_fields/Types"; +import { BoolCast, NumCast, StrCast } from "../../new_fields/Types"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], @@ -175,6 +175,19 @@ export const nodes: { [index: string]: NodeSpec } = { } }, + dashField: { + inline: true, + attrs: { + fieldKey: { default: "" }, + }, + group: "inline", + draggable: false, + toDOM(node) { + const attrs = { style: `width: ${node.attrs.width}, height: ${node.attrs.height}` }; + return ["div", { ...node.attrs, ...attrs }]; + } + }, + video: { inline: true, attrs: { @@ -799,6 +812,42 @@ export class DashDocView { } } +export class DashFieldView { + _fieldWrapper: HTMLDivElement; + _labelSpan: HTMLSpanElement; + _fieldSpan: HTMLSpanElement; + _reactionDisposer: IReactionDisposer | undefined; + _textBoxDoc: Doc; + + constructor(node: any, view: any, getPos: any, tbox: FormattedTextBox) { + this._textBoxDoc = tbox.props.Document; + this._fieldWrapper = document.createElement("div"); + this._fieldWrapper.style.width = node.attrs.width; + this._fieldWrapper.style.height = node.attrs.height; + this._fieldWrapper.style.position = "relative"; + this._fieldWrapper.style.display = "inline"; + + this._fieldSpan = document.createElement("span"); + this._fieldSpan.style.position = "relative"; + this._fieldSpan.style.display = "inline"; + + this._labelSpan = document.createElement("span"); + this._labelSpan.style.position = "relative"; + this._labelSpan.style.display = "inline"; + this._labelSpan.style.fontWeight = "bold"; + this._labelSpan.style.fontSize = "larger"; + this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; + this._reactionDisposer && this._reactionDisposer(); + this._reactionDisposer = reaction(() => this._textBoxDoc[DataSym][node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true }); + this._fieldWrapper.appendChild(this._labelSpan); + this._fieldWrapper.appendChild(this._fieldSpan); + (this as any).dom = this._fieldWrapper; + } + destroy() { + this._reactionDisposer && this._reactionDisposer(); + } +} + export class OrderedListView { update(node: any) { return false; // if attr's of an ordered_list (e.g., bulletStyle) change, return false forces the dom node to be recreated which is necessary for the bullet labels to update |
