aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/formattedText')
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx62
-rw-r--r--src/client/views/nodes/formattedText/DashFieldView.scss2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx56
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx194
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts4
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts6
6 files changed, 174 insertions, 150 deletions
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 8915d7c47..364be461f 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -1,7 +1,7 @@
import { IReactionDisposer, reaction, observable, action } from "mobx";
import { NodeSelection } from "prosemirror-state";
import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc";
-import { Cast, StrCast } from "../../../../fields/Types";
+import { Cast, StrCast, NumCast } from "../../../../fields/Types";
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, Utils, returnTransparent } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -12,6 +12,7 @@ import { FormattedTextBox } from "./FormattedTextBox";
import React = require("react");
import * as ReactDOM from 'react-dom';
import { observer } from "mobx-react";
+import { ColorScheme } from "../../../util/SettingsManager";
export class DashDocView {
_fieldWrapper: HTMLSpanElement; // container for label and value
@@ -20,7 +21,7 @@ export class DashDocView {
this._fieldWrapper = document.createElement("span");
this._fieldWrapper.style.position = "relative";
this._fieldWrapper.style.textIndent = "0";
- this._fieldWrapper.style.border = "1px solid " + StrCast(tbox.layoutDoc.color, (CurrentUserUtils.ActiveDashboard.darkScheme ? "dimGray" : "lightGray"));
+ this._fieldWrapper.style.border = "1px solid " + StrCast(tbox.layoutDoc.color, (CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark ? "dimgray" : "lightGray"));
this._fieldWrapper.style.width = node.attrs.width;
this._fieldWrapper.style.height = node.attrs.height;
this._fieldWrapper.style.display = node.attrs.hidden ? "none" : "inline-block";
@@ -69,30 +70,31 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
@observable _finalLayout: any;
@observable _resolvedDataDoc: any;
- constructor(props: IDashDocViewInternal) {
- super(props);
- this._textBox = this.props.tbox;
- const updateDoc = action((dashDoc: Doc) => {
- this._dashDoc = dashDoc;
- this._finalLayout = this.props.docid ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey);
+ updateDoc = action((dashDoc: Doc) => {
+ this._dashDoc = dashDoc;
+ this._finalLayout = this.props.docid ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey);
- if (this._finalLayout) {
- if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) {
- this._finalLayout.rootDocument = dashDoc.aliasOf;
- }
- this._resolvedDataDoc = Cast(this._finalLayout.resolvedDataDoc, Doc, null);
+ if (this._finalLayout) {
+ if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) {
+ this._finalLayout.rootDocument = dashDoc.aliasOf;
}
- if (this.props.width !== (this._dashDoc?._width ?? "") + "px" || this.props.height !== (this._dashDoc?._height ?? "") + "px") {
- try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made
- this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, {
- ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px"
- }));
- } catch (e) {
- console.log("DashDocView:" + e);
- }
+ this._resolvedDataDoc = Cast(this._finalLayout.resolvedDataDoc, Doc, null);
+ }
+ if (this.props.width !== (this._dashDoc?._width ?? "") + "px" || this.props.height !== (this._dashDoc?._height ?? "") + "px") {
+ try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made
+ this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, {
+ ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px"
+ }));
+ } catch (e) {
+ console.log("DashDocView:" + e);
}
- });
+ }
+ });
+
+ constructor(props: IDashDocViewInternal) {
+ super(props);
+ this._textBox = this.props.tbox;
DocServer.GetRefField(this.props.docid + this.props.alias).then(async dashDoc => {
if (!(dashDoc instanceof Doc)) {
@@ -101,15 +103,27 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docid + this.props.alias);
aliasedDoc.layoutKey = "layout";
this.props.fieldKey && DocUtils.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, this.props.fieldKey, undefined);
- updateDoc(aliasedDoc);
+ this.updateDoc(aliasedDoc);
}
});
} else {
- updateDoc(dashDoc);
+ this.updateDoc(dashDoc);
}
});
}
+ componentDidMount() {
+ this._disposers.upater = reaction(() => this._dashDoc && (NumCast(this._dashDoc._height) + NumCast(this._dashDoc._width)),
+ () => {
+ if (this._dashDoc) {
+ this.props.view.dispatch(this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, {
+ ...this.props.node.attrs, width: (this._dashDoc?._width ?? "") + "px", height: (this._dashDoc?._height ?? "") + "px"
+ }));
+ }
+ });
+ }
+
+
removeDoc = () => {
this.props.view.dispatch(this.props.view.state.tr
.setSelection(new NodeSelection(this.props.view.state.doc.resolve(this.props.getPos())))
diff --git a/src/client/views/nodes/formattedText/DashFieldView.scss b/src/client/views/nodes/formattedText/DashFieldView.scss
index e7dd286a5..c36e6804b 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.scss
+++ b/src/client/views/nodes/formattedText/DashFieldView.scss
@@ -8,7 +8,7 @@
height: 10px;
position: relative;
display: inline-block;
- background: dimGray;
+ background: dimgray;
}
.dashFieldView-fieldCheck {
min-width: 12px;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 0d38bd5b8..cfbd1962e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -280,8 +280,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
(curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
if ((!curTemp && !curProto) || curText || json.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended)
if (removeSelection(json) !== removeSelection(curLayout?.Data)) {
- !curText && tx.storedMarks?.filter(m => m.type.name === "pFontSize").map(m => Doc.UserDoc().fontSize = this.layoutDoc._fontSize = (m.attrs.fontSize + "px"));
- !curText && tx.storedMarks?.filter(m => m.type.name === "pFontFamily").map(m => Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily);
this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText);
this.dataDoc[this.props.fieldKey + "-noTemplate"] = true;//(curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited
ScriptCast(this.layoutDoc.onTextChanged, null)?.script.run({ this: this.layoutDoc, self: this.rootDoc, text: curText });
@@ -463,10 +461,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const target = dragData.droppedDocuments[0];
target._fitToBox = true;
const node = schema.nodes.dashDoc.create({
- width: target[WidthSym](), height: target[HeightSym](),
+ width: target[WidthSym](),
+ height: target[HeightSym](),
title: "dashDoc",
docid: target[Id],
- float: "right"
+ float: "unset"
});
const view = this._editorView!;
view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
@@ -833,7 +832,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._disposers.componentHeights = reaction( // set the document height when one of the component heights changes and autoHeight is on
() => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }),
({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => {
- autoHeight && this.props.setHeight(marginsHeight + Math.max(sidebarHeight, textHeight));
+ autoHeight && this.props.setHeight?.(marginsHeight + Math.max(sidebarHeight, textHeight));
}, { fireImmediately: true });
this._disposers.links = reaction(() => DocListCast(this.Document.links), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks
newLinks => {
@@ -894,11 +893,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
{ fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false });
this._disposers.selected = reaction(() => this.props.isSelected(),
- action((selected) => {
+ action(selected => {
if (RichTextMenu.Instance?.view === this._editorView && !selected) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
}
- }));
+ if (this._editorView && selected) {
+ RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props);
+ }
+ }), { fireImmediately: true });
if (!this.props.dontRegisterView) {
this._disposers.record = reaction(() => this._recording,
@@ -959,7 +961,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
GoogleApiClientUtils.Docs.write({ reference, content, mode });
}
};
- UndoManager.AddEvent({ undo, redo });
+ UndoManager.AddEvent({ undo, redo, prop: "" });
redo();
});
}
@@ -1168,7 +1170,14 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
selectOnLoad && this._editorView!.focus();
// add user mark for any first character that was typed since the user mark that gets set in KeyPress won't have been called yet.
if (this._editorView && !this._editorView.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark)) {
- this._editorView.state.storedMarks = [...(this._editorView.state.storedMarks ?? []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
+ this._editorView.state.storedMarks = [...(this._editorView.state.storedMarks ?? []),
+ schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) }),
+ ...(Doc.UserDoc().fontColor !== "transparent" && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []),
+ ...(Doc.UserDoc().fontStyle === "italics" ? [schema.mark(schema.marks.em)] : []),
+ ...(Doc.UserDoc().textDecoration === "underline" ? [schema.mark(schema.marks.underline)] : []),
+ ...(Doc.UserDoc().fontFamily ? [schema.mark(schema.marks.pFontFamily, { family: StrCast(Doc.UserDoc().fontFamily) })] : []),
+ ...(Doc.UserDoc().fontSize ? [schema.mark(schema.marks.pFontSize, { fontSize: StrCast(Doc.UserDoc().fontSize, "") })] : []),
+ ...(Doc.UserDoc().fontWeight === "bold" ? [schema.mark(schema.marks.strong)] : [])];
}
}
@@ -1187,9 +1196,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if ((e.target as any).tagName === "AUDIOTAG") {
e.preventDefault();
e.stopPropagation();
+ const timecode = Number((e.target as any)?.dataset?.timecode);
DocServer.GetRefField((e.target as any)?.dataset?.audioid || 0).then(anchor => {
if (anchor instanceof Doc) {
- const timecode = NumCast(anchor.timecodeToShow, 0);
+ // const timecode = NumCast(anchor.timecodeToShow, 0);
const audiodoc = anchor.annotationOn as Doc;
const func = () => {
const docView = DocumentManager.Instance.getDocumentView(audiodoc);
@@ -1468,19 +1478,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
tryUpdateScrollHeight = () => {
- if (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath())) {
- const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
- const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
- if (children) {
- const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
- const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
- if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
- const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
- if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
- setScrollHeight();
- } else {
- setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
- }
+ const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
+ const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
+ if (children) {
+ const proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins);
+ const scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight);
+ if (scrollHeight && this.props.renderDepth && !this.props.dontRegisterView) { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
+ const setScrollHeight = () => this.rootDoc[this.fieldKey + "-scrollHeight"] = scrollHeight;
+ if (this.rootDoc === this.layoutDoc.doc || this.layoutDoc.resolvedDataDoc) {
+ setScrollHeight();
+ } else {
+ setTimeout(setScrollHeight, 10); // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template. So set a timeout and hope its arrived...
}
}
}
@@ -1601,7 +1609,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
background: this.props.background ? this.props.background : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
color: this.props.color ? this.props.color : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
fontSize: this.props.fontSize ? this.props.fontSize : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize),
- fontWeight: Cast(this.layoutDoc._fontWeight, "number", null),
+ fontWeight: Cast(this.layoutDoc._fontWeight, "string", null) as any,
fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
pointerEvents: interactive ? undefined : "none",
}}
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 9904a7939..bd05af977 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -1,8 +1,7 @@
import React = require("react");
-import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from "@material-ui/core";
-import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { action, IReactionDisposer, observable, reaction, runInAction, computed } from "mobx";
import { observer } from "mobx-react";
import { lift, wrapIn } from "prosemirror-commands";
import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos } from "prosemirror-model";
@@ -10,10 +9,7 @@ import { wrapInList } from "prosemirror-schema-list";
import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { Doc } from "../../../../fields/Doc";
-import { DarkPastelSchemaPalette, PastelSchemaPalette } from '../../../../fields/SchemaHeaderField';
import { Cast, StrCast } from "../../../../fields/Types";
-import { TraceMobx } from "../../../../fields/util";
-import { unimplementedFunction, Utils } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
import { LinkManager } from "../../../util/LinkManager";
import { SelectionManager } from "../../../util/SelectionManager";
@@ -29,7 +25,7 @@ const { toggleMark } = require("prosemirror-commands");
@observer
export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
- static Instance: RichTextMenu;
+ @observable static Instance: RichTextMenu;
public overMenu: boolean = false; // kind of hacky way to prevent selects not being selectable
private _linkToRef = React.createRef<HTMLInputElement>();
@@ -39,22 +35,22 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
public _brushMap: Map<string, Set<Mark>> = new Map();
@observable private collapsed: boolean = false;
- @observable private boldActive: boolean = false;
- @observable private italicsActive: boolean = false;
- @observable private underlineActive: boolean = false;
- @observable private strikethroughActive: boolean = false;
- @observable private subscriptActive: boolean = false;
- @observable private superscriptActive: boolean = false;
-
- @observable private activeFontSize: string = "";
- @observable private activeFontFamily: string = "";
+ @observable private _boldActive: boolean = false;
+ @observable private _italicsActive: boolean = false;
+ @observable private _underlineActive: boolean = false;
+ @observable private _strikethroughActive: boolean = false;
+ @observable private _subscriptActive: boolean = false;
+ @observable private _superscriptActive: boolean = false;
+
+ @observable private _activeFontSize: string = "13px";
+ @observable private _activeFontFamily: string = "";
@observable private activeListType: string = "";
@observable private activeAlignment: string = "left";
@observable private brushMarks: Set<Mark> = new Set();
@observable private showBrushDropdown: boolean = false;
- @observable private activeFontColor: string = "black";
+ @observable private _activeFontColor: string = "black";
@observable private showColorDropdown: boolean = false;
@observable private activeHighlightColor: string = "transparent";
@@ -67,10 +63,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
_delayHide = false;
constructor(props: Readonly<{}>) {
super(props);
- RichTextMenu.Instance = this;
- this._canFade = false;
- //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
- runInAction(() => this.Pinned = true);
+ runInAction(() => {
+ RichTextMenu.Instance = this;
+ this._canFade = false;
+ //this.Pinned = BoolCast(Doc.UserDoc()["menuRichText-pinned"]);
+ this.Pinned = true;
+ });
}
componentDidMount() {
@@ -81,6 +79,14 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this._reaction?.();
}
+ @computed get bold() { return this._boldActive; }
+ @computed get underline() { return this._underlineActive; }
+ @computed get italics() { return this._italicsActive; }
+ @computed get strikeThrough() { return this._strikethroughActive; }
+ @computed get fontColor() { return this._activeFontColor; }
+ @computed get fontFamily() { return this._activeFontFamily; }
+ @computed get fontSize() { return this._activeFontSize; }
+
public delayHide = () => this._delayHide = true;
@action
@@ -110,10 +116,10 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
this.activeListType = this.getActiveListStyle();
this.activeAlignment = this.getActiveAlignment();
- this.activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various";
- this.activeFontSize = !activeSizes.length ? "13px" : activeSizes.length === 1 ? String(activeSizes[0]) : "...";
- this.activeFontColor = !activeColors.length ? "black" : activeColors.length === 1 ? String(activeColors[0]) : "...";
- this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length === 1 ? String(activeHighlights[0]) : "...";
+ this._activeFontFamily = !activeFamilies.length ? "Arial" : activeFamilies.length === 1 ? String(activeFamilies[0]) : "various";
+ this._activeFontSize = !activeSizes.length ? "13px" : activeSizes[0];
+ this._activeFontColor = !activeColors.length ? "black" : activeColors.length > 0 ? String(activeColors[0]) : "...";
+ this.activeHighlightColor = !activeHighlights.length ? "" : activeHighlights.length > 0 ? String(activeHighlights[0]) : "...";
// update link in current selection
this.getTextLinkTargetTitle().then(targetTitle => this.setCurrentLink(targetTitle));
@@ -125,7 +131,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
if (node?.type === schema.nodes.ordered_list) {
let attrs = node.attrs;
if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, fontFamily: mark.attrs.family };
- if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, fontSize: `${mark.attrs.fontSize}px` };
+ if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, fontSize: mark.attrs.fontSize };
if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, fontColor: mark.attrs.color };
const tr = updateBullets(state.tr.setNodeMarkup(state.selection.from, node.type, attrs), state.schema);
dispatch(tr.setSelection(new NodeSelection(tr.doc.resolve(state.selection.from))));
@@ -142,17 +148,6 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
}
- getBoldStatus() {
- if (this.view && this.TextView.props.isSelected(true)) {
- const path = (this.view.state.selection.$from as any).path;
- for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) {
- if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) {
- return path[i].attrs.strong;
- }
- }
- }
- }
-
// finds font sizes and families in selection
getActiveAlignment() {
if (this.view && this.TextView.props.isSelected(true)) {
@@ -193,25 +188,22 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
if (this.TextView.props.isSelected(true)) {
const state = this.view.state;
const pos = this.view.state.selection.$from;
- const ref_node = this.reference_node(pos);
- if (ref_node && ref_node !== this.view.state.doc && ref_node.isText) {
- const marks = Array.from(ref_node.marks);
- marks.push(...(this.view.state.storedMarks as any));
- marks.forEach(m => {
- m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family);
- m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color);
- m.type === state.schema.marks.pFontSize && activeSizes.push(String(m.attrs.fontSize) + "px");
- m.type === state.schema.marks.marker && activeHighlights.push(String(m.attrs.highlight));
+ const marks: Mark<any>[] = [...(state.storedMarks ?? [])];
+ if (state.selection.empty) {
+ const ref_node = this.reference_node(pos);
+ marks.push(...(ref_node !== this.view.state.doc && ref_node?.isText ? Array.from(ref_node.marks) : []));
+ } else {
+ state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
+ node.marks?.filter(mark => !mark.isInSet(marks)).map(mark => marks.push(mark));
});
}
- !activeFamilies.length && (activeFamilies.push(StrCast(this.TextView.layoutDoc._fontFamily, StrCast(Doc.UserDoc().fontFamily))));
- !activeSizes.length && (activeSizes.push(StrCast(this.TextView.layoutDoc._fontSize, StrCast(Doc.UserDoc().fontSize))));
- !activeColors.length && (activeColors.push(StrCast(this.TextView.layoutDoc.color, StrCast(Doc.UserDoc().fontColor))));
+ marks.forEach(m => {
+ m.type === state.schema.marks.pFontFamily && activeFamilies.push(m.attrs.family);
+ m.type === state.schema.marks.pFontColor && activeColors.push(m.attrs.color);
+ m.type === state.schema.marks.pFontSize && activeSizes.push(m.attrs.fontSize);
+ m.type === state.schema.marks.marker && activeHighlights.push(String(m.attrs.highlight));
+ });
}
- !activeFamilies.length && (activeFamilies.push(StrCast(Doc.UserDoc().fontFamily)));
- !activeSizes.length && (activeSizes.push(StrCast(Doc.UserDoc().fontSize)));
- !activeColors.length && (activeColors.push(StrCast(Doc.UserDoc().fontColor, "black")));
- !activeHighlights.length && (activeHighlights.push(StrCast(Doc.UserDoc().fontHighlight, "")));
return { activeFamilies, activeSizes, activeColors, activeHighlights };
}
@@ -251,11 +243,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return [];
}
activeMarks = markGroup.filter(mark_type => {
- if (mark_type === state.schema.marks.pFontSize) {
- return ref_node.marks.some(m => m.type.name === state.schema.marks.pFontSize.name);
- }
+ // if (mark_type === state.schema.marks.pFontSize) {
+ // return mark.isINSet
+ // ref_node.marks.some(m => m.type.name === state.schema.marks.pFontSize.name);
+ // }
const mark = state.schema.mark(mark_type);
- return ref_node.marks.includes(mark);
+ return mark.isInSet(ref_node.marks);
});
}
}
@@ -270,56 +263,66 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
setActiveMarkButtons(activeMarks: MarkType[] | undefined) {
if (!activeMarks) return;
- this.boldActive = false;
- this.italicsActive = false;
- this.underlineActive = false;
- this.strikethroughActive = false;
- this.subscriptActive = false;
- this.superscriptActive = false;
+ this._boldActive = false;
+ this._italicsActive = false;
+ this._underlineActive = false;
+ this._strikethroughActive = false;
+ this._subscriptActive = false;
+ this._superscriptActive = false;
activeMarks.forEach(mark => {
switch (mark.name) {
- case "strong": this.boldActive = true; break;
- case "em": this.italicsActive = true; break;
- case "underline": this.underlineActive = true; break;
- case "strikethrough": this.strikethroughActive = true; break;
- case "subscript": this.subscriptActive = true; break;
- case "superscript": this.superscriptActive = true; break;
+ case "strong": this._boldActive = true; break;
+ case "em": this._italicsActive = true; break;
+ case "underline": this._underlineActive = true; break;
+ case "strikethrough": this._strikethroughActive = true; break;
+ case "subscript": this._subscriptActive = true; break;
+ case "superscript": this._superscriptActive = true; break;
}
});
}
- toggleBold = (view: EditorView, forceBool?: boolean) => {
- const mark = view.state.schema.mark(view.state.schema.marks.strong, { strong: forceBool });
- this.setMark(mark, view.state, view.dispatch, false);
- view.focus();
+ toggleBold = () => {
+ if (this.view) {
+ const mark = this.view.state.schema.mark(this.view.state.schema.marks.strong);
+ this.setMark(mark, this.view.state, this.view.dispatch, false);
+ this.view.focus();
+ }
}
- toggleUnderline = (view: EditorView, forceBool?: boolean) => {
- const mark = view.state.schema.mark(view.state.schema.marks.underline, { underline: forceBool });
- this.setMark(mark, view.state, view.dispatch, false);
- view.focus();
+ toggleUnderline = () => {
+ if (this.view) {
+ const mark = this.view.state.schema.mark(this.view.state.schema.marks.underline);
+ this.setMark(mark, this.view.state, this.view.dispatch, false);
+ this.view.focus();
+ }
}
- toggleItalic = (view: EditorView, forceBool?: boolean) => {
- const mark = view.state.schema.mark(view.state.schema.marks.em, { em: forceBool });
- this.setMark(mark, view.state, view.dispatch, false);
- view.focus();
+ toggleItalics = () => {
+ if (this.view) {
+ const mark = this.view.state.schema.mark(this.view.state.schema.marks.em);
+ this.setMark(mark, this.view.state, this.view.dispatch, false);
+ this.view.focus();
+ }
}
- setFontSize = (size: number, view: EditorView) => {
- const fmark = view.state.schema.marks.pFontSize.create({ fontSize: size });
- this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true);
- view.focus();
- this.updateMenu(view, undefined, this.props);
+ setFontSize = (fontSize: string) => {
+ if (this.view) {
+ const fmark = this.view.state.schema.marks.pFontSize.create({ fontSize });
+ this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
+ this.view.focus();
+ this.updateMenu(this.view, undefined, this.props);
+ }
}
- setFontFamily = (family: string, view: EditorView) => {
- const fmark = view.state.schema.marks.pFontFamily.create({ family: family });
- this.setMark(fmark, view.state, (tx: any) => view.dispatch(tx.addStoredMark(fmark)), true);
- view.focus();
- this.updateMenu(view, undefined, this.props);
+ setFontFamily = (family: string) => {
+ if (this.view) {
+ const fmark = this.view.state.schema.marks.pFontFamily.create({ family: family });
+ this.setMark(fmark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(fmark)), true);
+ this.view.focus();
+ this.updateMenu(this.view, undefined, this.props);
+ }
}
setHighlight(color: String, view: EditorView, dispatch: any) {
@@ -330,13 +333,12 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
setColor(color: String, view: EditorView, dispatch: any) {
- const colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color: color });
- if (view.state.selection.empty) {
- dispatch(view.state.tr.addStoredMark(colorMark));
- return false;
+ if (this.view) {
+ const colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color });
+ this.setMark(colorMark, this.view.state, (tx: any) => this.view!.dispatch(tx.addStoredMark(colorMark)), true);
+ view.focus();
+ this.updateMenu(this.view, undefined, this.props);
}
- this.setMark(colorMark, view.state, dispatch, true);
- view.focus();
}
// TODO: remove doesn't work
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 3fd7d61fa..711136469 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -282,7 +282,7 @@ export class RichTextRules {
if (rstate) {
this.TextBox.EditorView?.dispatch(rstate.tr.setSelection(new TextSelection(rstate.doc.resolve(start), rstate.doc.resolve(end - 3))));
}
- const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: rawdocid, _width: 500, _height: 500, }, docid);
+ const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: rawdocid.replace(/^:/, ""), _width: 500, _height: 500, }, docid);
DocUtils.MakeLink({ doc: this.TextBox.getAnchor() }, { doc: target }, "portal to", undefined);
const fstate = this.TextBox.EditorView?.state;
@@ -290,7 +290,7 @@ export class RichTextRules {
this.TextBox.EditorView?.dispatch(fstate.tr.setSelection(new TextSelection(fstate.doc.resolve(selection))));
}
});
- return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2);
+ return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 3);
}
return state.tr;
}
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 655ee7e44..6103a28d6 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -61,13 +61,13 @@ export const marks: { [index: string]: MarkSpec } = {
/** FONT SIZES */
pFontSize: {
- attrs: { fontSize: { default: 10 } },
+ attrs: { fontSize: { default: "10px" } },
parseDOM: [{
tag: "span", getAttrs(dom: any) {
- return { fontSize: dom.style.fontSize ? Number(dom.style.fontSize.replace("px", "")) : "" };
+ return { fontSize: dom.style.fontSize ? dom.style.fontSize.toString() : "" };
}
}],
- toDOM: (node) => node.attrs.fontSize ? ['span', { style: `font-size: ${node.attrs.fontSize}px;` }] : ['span', 0]
+ toDOM: (node) => node.attrs.fontSize ? ['span', { style: `font-size: ${node.attrs.fontSize};` }] : ['span', 0]
},
/* FONTS */