aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/DictationManager.ts2
-rw-r--r--src/client/util/RichTextRules.ts17
-rw-r--r--src/client/util/RichTextSchema.tsx53
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