aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText/RichTextRules.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/formattedText/RichTextRules.ts')
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts83
1 files changed, 28 insertions, 55 deletions
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index c332c592b..f26a75fe4 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -1,7 +1,6 @@
import { ellipsis, emDash, InputRule, smartQuotes, textblockTypeInputRule } from 'prosemirror-inputrules';
import { NodeType } from 'prosemirror-model';
import { NodeSelection, TextSelection } from 'prosemirror-state';
-import { ClientUtils } from '../../../../ClientUtils';
import { Doc, DocListCast, FieldResult, StrListCast } from '../../../../fields/Doc';
import { DocData } from '../../../../fields/DocSymbols';
import { Id } from '../../../../fields/FieldSymbols';
@@ -21,7 +20,6 @@ import { schema } from './schema_rts';
export class RichTextRules {
public Document: Doc;
public TextBox: FormattedTextBox;
- public EnteringStyle: boolean = false;
constructor(doc: Doc, textBox: FormattedTextBox) {
this.Document = doc;
this.TextBox = textBox;
@@ -84,9 +82,8 @@ export class RichTextRules {
// Create annotation to a field on the text document
new InputRule(/>::$/, (state, match, start, end) => {
const creator = (doc: Doc) => {
- const textDoc = this.Document[DocData];
- const numInlines = NumCast(textDoc.inlineTextCount);
- textDoc.inlineTextCount = numInlines + 1;
+ const numInlines = NumCast(this.Document.$inlineTextCount);
+ this.Document.$inlineTextCount = numInlines + 1;
const node = state.doc.resolve(start).nodeAfter;
const newNode = schema.nodes.dashComment.create({ docId: doc[Id], reflow: false });
const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: doc[Id], float: 'right' });
@@ -109,28 +106,25 @@ export class RichTextRules {
}),
// Create annotation to a field on the text document
new InputRule(/>>$/, (state, match, start, end) => {
- const textDoc = this.Document[DocData];
- const numInlines = NumCast(textDoc.inlineTextCount);
- textDoc.inlineTextCount = numInlines + 1;
+ const numInlines = NumCast(this.Document.$inlineTextCount);
+ this.Document.$inlineTextCount = numInlines + 1;
const inlineFieldKey = 'inline' + numInlines; // which field on the text document this annotation will write to
const inlineLayoutKey = 'layout_' + inlineFieldKey; // the field holding the layout string that will render the inline annotation
const textDocInline = Docs.Create.TextDocument('', {
- _layout_fieldKey: inlineLayoutKey,
_width: 75,
_height: 35,
- annotationOn: textDoc,
_layout_fitWidth: true,
_layout_autoHeight: true,
- text_fontSize: '9px',
- title: 'inline comment',
});
+ textDocInline.layout_fieldKey = inlineLayoutKey;
+ textDocInline.annotationOn = this.Document[DocData];
textDocInline.title = inlineFieldKey; // give the annotation its own title
textDocInline.title_custom = true; // And make sure that it's 'custom' so that editing text doesn't change the title of the containing doc
- textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
+ //textDocInline.isTemplateForField = inlineFieldKey; // this is needed in case the containing text doc is converted to a template at some point
textDocInline.isDataDoc = true;
- textDocInline.proto = textDoc; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
- textDoc[inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
- textDoc[inlineFieldKey] = ''; // set a default value for the annotation
+ textDocInline.proto = this.Document[DocData]; // make the annotation inherit from the outer text doc so that it can resolve any nested field references, e.g., [[field]]
+ this.Document['$' + inlineLayoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); // create a layout string for the layout key that will render the annotation text
+ this.Document['$' + inlineFieldKey] = ''; // set a default value for the annotation
const node = state.doc.resolve(start).nodeAfter;
const newNode = schema.nodes.dashComment.create({ docId: textDocInline[Id], reflow: true });
const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: 'dashDoc', docId: textDocInline[Id], float: 'right' });
@@ -145,9 +139,8 @@ export class RichTextRules {
return replaced;
}),
- // set the First-line indent node type for the selection's paragraph (assumes % was used to initiate an EnteringStyle mode)
- new InputRule(/(%d|d)$/, (state, match, start, end) => {
- if (!match[0].startsWith('%') && !this.EnteringStyle) return null;
+ // set the First-line indent node type for the selection's paragraph
+ new InputRule(/%d$/, (state, match, start, end) => {
const pos = state.doc.resolve(start);
for (let depth = pos.depth; depth >= 0; depth--) {
const node = pos.node(depth);
@@ -160,9 +153,8 @@ export class RichTextRules {
return null;
}),
- // set the Hanging indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode)
- new InputRule(/(%h|h)$/, (state, match, start, end) => {
- if (!match[0].startsWith('%') && !this.EnteringStyle) return null;
+ // set the Hanging indent node type for the current selection's paragraph
+ new InputRule(/%h$/, (state, match, start, end) => {
const pos = state.doc.resolve(start);
for (let depth = pos.depth; depth >= 0; depth--) {
const node = pos.node(depth);
@@ -175,9 +167,8 @@ export class RichTextRules {
return null;
}),
- // set the Quoted indent node type for the current selection's paragraph (assumes % was used to initiate an EnteringStyle mode)
- new InputRule(/(%q|q)$/, (state, match, start, end) => {
- if (!match[0].startsWith('%') && !this.EnteringStyle) return null;
+ // set the Quoted indent node type for the current selection's paragraph
+ new InputRule(/%q$/, (state, match, start, end) => {
const pos = state.doc.resolve(start);
if (state.selection instanceof NodeSelection && state.selection.node.type === schema.nodes.ordered_list) {
const { node } = state.selection;
@@ -294,7 +285,8 @@ export class RichTextRules {
editor.dispatch(estate.tr.setSelection(new TextSelection(estate.doc.resolve(start), estate.doc.resolve(end - prefixLength))));
}
- DocUtils.MakeLink(this.TextBox.getAnchor(true), target, { link_relationship: 'portal to:portal from' });
+ const tanchor = this.TextBox.getAnchor(true);
+ tanchor && DocUtils.MakeLink(tanchor, target, { link_relationship: 'portal to:portal from' });
const teditor = this.TextBox.EditorView;
if (teditor && selection) {
@@ -319,10 +311,10 @@ export class RichTextRules {
}),
// create a text display of a metadata field on this or another document, or create a hyperlink portal to another document
- // [@{this,doctitle,}.fieldKey{:,=,:=,=:=}value]
- // [@{this,doctitle,}.fieldKey]
+ // @{this,doctitle,}.fieldKey{:,=,:=,=:=}value
+ // @{this,doctitle,}.fieldKey
new InputRule(
- /\[(@|@this\.|@[a-zA-Z_? \-0-9]+\.)([a-zA-Z_?\-0-9]+)((:|=|:=|=:=)([a-zA-Z,_().@?+\-*/ 0-9()]*))?\]/,
+ /(@|@this\.|@[a-zA-Z_? \-0-9]+\.)([a-zA-Z_?\-0-9]+)((:|=|:=|=:=)([a-zA-Z,_().@?+\-*/ 0-9()]*))?\s/,
(state, match, start, end) => {
const docTitle = match[1].substring(1).replace(/\.$/, '');
const fieldKey = match[2];
@@ -334,18 +326,14 @@ export class RichTextRules {
if (value?.includes(',') && !value.startsWith('((')) {
const values = value.split(',');
const strs = values.some(v => !v.match(/^[-]?[0-9.]$/));
- this.Document[DocData][fieldKey] = strs ? new List<string>(values) : new List<number>(values.map(v => Number(v)));
+ this.Document['$' + fieldKey] = strs ? new List<string>(values) : new List<number>(values.map(v => Number(v)));
} else if (value) {
Doc.SetField(
this.Document,
fieldKey,
assign + value,
Doc.IsDataProto(this.Document) ? true : undefined,
- assign.includes(':=')
- ? undefined
- : (gptval: FieldResult) => {
- (dataDoc ? this.Document[DocData] : this.Document)[fieldKey] = gptval as string;
- }
+ assign.includes(':=') ? undefined : (gptval: FieldResult) => (this.Document[(dataDoc ? '$' : '_') + fieldKey] = gptval as string)
);
if (fieldKey === this.TextBox.fieldKey) return this.TextBox.EditorView!.state.tr;
}
@@ -361,7 +349,8 @@ export class RichTextRules {
let count = 0; // ignore first return value which will be the notation that chat is pending a result
Doc.SetField(this.Document, '', match[2], false, (gptval: FieldResult) => {
if (count) {
- const tr = this.TextBox.EditorView?.state.tr.insertText(' ' + (gptval as string));
+ this.TextBox.EditorView?.pasteText(' ' + (gptval as string), undefined);
+ const tr = this.TextBox.EditorView?.state.tr; //.insertText(' ' + (gptval as string));
tr && this.TextBox.EditorView?.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(end + 2), tr.doc.resolve(end + 2 + (gptval as string).length))));
RichTextMenu.Instance?.elideSelection(this.TextBox.EditorView?.state, true);
}
@@ -399,11 +388,11 @@ export class RichTextRules {
new InputRule(/#(@?[a-zA-Z_-]+[a-zA-Z_\-0-9]*)\s$/, (state, match, start, end) => {
const tag = match[1];
if (!tag) return state.tr;
- // this.Document[DocData]['#' + tag] = '#' + tag;
- const tags = StrListCast(this.Document[DocData].tags);
+ // this.Document[['$#' + tag] = '#' + tag;
+ const tags = StrListCast(this.Document.$tags);
if (!tags.includes(tag)) {
tags.push(tag);
- this.Document[DocData].tags = new List<string>(tags);
+ this.Document.$tags = new List<string>(tags);
this.Document._layout_showTags = true;
}
const fieldView = state.schema.nodes.dashField.create({ fieldKey: tag.startsWith('@') ? tag.replace(/^@/, '') : '#' + tag });
@@ -416,22 +405,6 @@ export class RichTextRules {
// # heading
textblockTypeInputRule(/^(#{1,6})\s$/, schema.nodes.heading, match => ({ level: match[1].length })),
- // set the Todo user-tag on the current selection (assumes % was used to initiate an EnteringStyle mode)
- new InputRule(/[ti!x]$/, (state, match, start, end) => {
- if (state.selection.to === state.selection.from || !this.EnteringStyle) return null;
-
- const tag = match[0] === 't' ? 'todo' : match[0] === 'i' ? 'ignore' : match[0] === 'x' ? 'disagree' : match[0] === '!' ? 'important' : '??';
- const node = state.doc.resolve(start).nodeAfter;
-
- if (node?.marks.findIndex(m => m.type === schema.marks.user_tag) !== -1) return state.tr.removeMark(start, end, schema.marks.user_tag);
- return node
- ? state.tr
- .removeMark(start, end, schema.marks.user_mark)
- .addMark(start, end, schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) }))
- .addMark(start, end, schema.marks.user_tag.create({ userid: ClientUtils.CurrentUserEmail(), tag: tag, modified: Math.round(Date.now() / 1000 / 60) }))
- : state.tr;
- }),
-
new InputRule(/%\(/, (state, match, start, end) => {
const node = state.doc.resolve(start).nodeAfter;
const sm = state.storedMarks?.slice() || [];