aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/formattedText/FormattedTextBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/formattedText/FormattedTextBox.tsx')
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx511
1 files changed, 151 insertions, 360 deletions
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b4fbda9f4..104d60fff 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -40,6 +40,7 @@ import { DashDocView } from "./RichTextSchema";
import { DashDocCommentView } from "./DashDocCommentView";
import { DashFieldView } from "./DashFieldView";
+import { EquationView } from "./EquationView";
import { SummaryView } from "./SummaryView";
import { OrderedListView } from "./OrderedListView";
import { FootnoteView } from "./FootnoteView";
@@ -47,7 +48,7 @@ import { FootnoteView } from "./FootnoteView";
import { schema } from "./schema_rts";
import { SelectionManager } from "../../../util/SelectionManager";
import { undoBatch, UndoManager } from "../../../util/UndoManager";
-import { CollectionFreeFormView, collectionFreeformViewProps } from '../../collections/collectionFreeForm/CollectionFreeFormView';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView';
import { ContextMenu } from '../../ContextMenu';
import { ContextMenuProps } from '../../ContextMenuItem';
import { ViewBoxAnnotatableComponent } from "../../DocComponent";
@@ -58,16 +59,13 @@ import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, findLinkMark } from './FormattedTextBoxComment';
import React = require("react");
import { CollectionStackingView } from '../../collections/CollectionStackingView';
-import { CollectionViewType } from '../../collections/CollectionView';
import { SnappingManager } from '../../../util/SnappingManager';
import { LinkDocPreview } from '../LinkDocPreview';
-import { SubCollectionViewProps } from '../../collections/CollectionSubView';
import { StyleProp } from '../../StyleProvider';
import { AnchorMenu } from '../../pdf/AnchorMenu';
import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
import { DocumentManager } from '../../../util/DocumentManager';
import { LightboxView } from '../../LightboxView';
-import { DocAfterFocusFunc } from '../DocumentView';
const translateGoogleApi = require("translate-google-api");
export interface FormattedTextBoxProps {
@@ -89,24 +87,38 @@ type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, da
export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); }
public static blankState = () => EditorState.create(FormattedTextBox.Instance.config);
+ public static get DefaultLayout() {
+ return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
+ }
public static CanAnnotate = true;
public static Instance: FormattedTextBox;
public ProseRef?: HTMLDivElement;
public get EditorView() { return this._editorView; }
public get SidebarKey() { return this.fieldKey + "-sidebar"; }
- private _boxRef: React.RefObject<HTMLDivElement> = React.createRef();
private _ref: React.RefObject<HTMLDivElement> = React.createRef();
private _scrollRef: React.RefObject<HTMLDivElement> = React.createRef();
private _editorView: Opt<EditorView>;
private _applyingChange: string = "";
private _searchIndex = 0;
+ private _lastTimedMark: Mark | undefined = undefined;
private _cachedLinks: Doc[] = [];
private _undoTyping?: UndoManager.Batch;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _dropDisposer?: DragManager.DragDropDisposer;
private _recordingStart: number = 0;
private _ignoreScroll = false;
+ private _lastText = "";
+ private _focusSpeed: Opt<number>;
+ private _keymap: any = undefined;
+ private _rules: RichTextRules | undefined;
+ @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
+ @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
+ @computed get autoHeight() { return this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight; }
+ @computed get textHeight() { return NumCast(this.rootDoc[this.fieldKey + "-height"]); }
+ @computed get scrollHeight() { return NumCast(this.rootDoc[this.fieldKey + "-scrollHeight"]); }
+ @computed get sidebarHeight() { return NumCast(this.rootDoc[this.SidebarKey + "-height"]); }
+ @computed get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
@computed get _recording() { return this.dataDoc?.audioState === "recording"; }
set _recording(value) { this.dataDoc.audioState = value ? "recording" : undefined; }
@@ -114,9 +126,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
public static SelectOnLoad = "";
public static PasteOnLoad: ClipboardEvent | undefined;
public static SelectOnLoadChar = "";
- public static IsFragment(html: string) {
- return html.indexOf("data-pm-slice") !== -1;
- }
+ public static IsFragment(html: string) { return html.indexOf("data-pm-slice") !== -1; }
public static GetHref(html: string): string {
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(html, 'text/html');
@@ -127,24 +137,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return "";
}
public static GetDocFromUrl(url: string) {
- if (url.startsWith(document.location.origin)) {
- const split = new URL(url).pathname.split("doc/");
- const docid = split[split.length - 1];
- return docid;
- }
- return "";
- }
-
- @undoBatch
- public setFontColor(color: string) {
- const view = this._editorView!;
- if (view.state.selection.from === view.state.selection.to) return false;
- if (view.state.selection.to - view.state.selection.from > view.state.doc.nodeSize - 3) {
- this.layoutDoc.color = color;
- }
- const colorMark = view.state.schema.mark(view.state.schema.marks.pFontColor, { color: color });
- view.dispatch(view.state.tr.addMark(view.state.selection.from, view.state.selection.to, colorMark));
- return true;
+ return url.startsWith(document.location.origin) ? new URL(url).pathname.split("doc/").lastElement() : ""; // docid
}
constructor(props: any) {
@@ -154,8 +147,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._recordingStart = Date.now();
}
- public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
-
// removes all hyperlink anchors for the removed linkDoc
// TODO: bcz: Argh... if a section of text has multiple anchors, this should just remove the intended one.
// but since removing one anchor from the list of attr anchors isn't implemented, this will end up removing nothing.
@@ -192,35 +183,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
getAnchor = () => this.makeLinkAnchor(undefined, "add:right", undefined, "Anchored Selection");
- linkOnDeselect: Map<string, string> = new Map();
-
- doLinkOnDeselect() {
-
- Array.from(this.linkOnDeselect.entries()).map(entry => {
- const key = entry[0];
- const value = entry[1];
-
- const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
- DocServer.GetRefField(value).then(doc => {
- DocServer.GetRefField(id).then(linkDoc => {
- this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500 }, value);
- DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument);
- if (linkDoc) {
- (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc;
- } else {
- DocUtils.MakeLink({ doc: this.rootDoc }, { doc: this.dataDoc[key] as Doc }, "portal link", "link to named target", id);
- }
- });
- });
- });
-
- this.linkOnDeselect.clear();
- }
-
@action
setupAnchorMenu = () => {
AnchorMenu.Instance.Status = "marquee";
- AnchorMenu.Instance.Highlight = action((color: string) => {
+ AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
this._editorView?.state && RichTextMenu.Instance.insertHighlight(color, this._editorView.state, this._editorView?.dispatch);
return undefined;
});
@@ -231,55 +197,21 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
AnchorMenu.Instance.StartDrag = action(async (e: PointerEvent, ele: HTMLElement) => {
e.preventDefault();
e.stopPropagation();
- const targetCreator = () => {
- const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.rootDoc.title, 0, 0, 100, 100);
+ const targetCreator = (annotationOn?: Doc) => {
+ const target = CurrentUserUtils.GetNewTextDoc("Note linked to " + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn);
FormattedTextBox.SelectOnLoad = target[Id];
return target;
};
- DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.rootDoc, () => this.rootDoc, targetCreator), e.pageX, e.pageY, {
- dragComplete: e => {
- const anchor = this.makeLinkAnchor(undefined, "add:right", undefined, "a link");
- if (!e.aborted && e.annoDragData && e.annoDragData.annotationDocument && e.annoDragData.dropDocument && !e.linkDocument) {
- e.linkDocument = DocUtils.MakeLink({ doc: anchor }, { doc: e.annoDragData.dropDocument }, "hyperlink", "link to note");
- e.annoDragData.annotationDocument.isPushpin = e.annoDragData?.dropDocument.annotationOn === this.rootDoc;
- }
- e.linkDocument && e.annoDragData?.linkDropCallback?.(e as { linkDocument: Doc });// bcz: typescript can't figure out that this is valid even though we tested e.linkDocument
- }
- });
+ DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.rootDoc, this.getAnchor, targetCreator), e.pageX, e.pageY);
});
const coordsT = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
const coordsB = this._editorView!.coordsAtPos(this._editorView!.state.selection.to);
this.props.isSelected(true) && AnchorMenu.Instance.jumpTo(Math.min(coordsT.left, coordsB.left), Math.max(coordsT.bottom, coordsB.bottom));
}
- _lastText = "";
dispatchTransaction = (tx: Transaction) => {
if (this._editorView) {
- const metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata);
- if (metadata) {
- const range = tx.selection.$from.blockRange(tx.selection.$to);
- let text = range ? tx.doc.textBetween(range.start, range.end) : "";
- let textEndSelection = tx.selection.to;
- for (; textEndSelection < range!.end && text[textEndSelection - range!.start] !== " "; textEndSelection++) { }
- text = text.substr(0, textEndSelection - range!.start);
- text = text.split(" ")[text.split(" ").length - 1];
- const split = text.split("::");
- if (split.length > 1 && split[1]) {
- const key = split[0];
- const value = split[split.length - 1];
- this.linkOnDeselect.set(key, value);
-
- const id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
- const allAnchors = [{ href: Utils.prepend("/doc/" + id), title: value, anchorId: id }];
- const link = this._editorView.state.schema.marks.linkAnchor.create({ allAnchors, location: "add:right", title: value });
- const mval = this._editorView.state.schema.marks.metadataVal.create();
- const offset = (tx.selection.to === range!.end - 1 ? -1 : 0);
- tx = tx.addMark(textEndSelection - value.length + offset, textEndSelection, link).addMark(textEndSelection - value.length + offset, textEndSelection, mval);
- this.dataDoc[key] = value;
- }
- }
-
const state = this._editorView.state.apply(tx);
this._editorView.updateState(state);
@@ -290,14 +222,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null); // the default text inherited from a prototype
const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
const json = JSON.stringify(state.toJSON());
- let unchanged = true;
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
- const removeSelection = (json: string | undefined) => {
- return json?.indexOf("\"storedMarks\"") === -1 ? json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
- };
+ const removeSelection = (json: string | undefined) => json?.indexOf("\"storedMarks\"") === -1 ?
+ json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
+ let unchanged = true;
if (this._applyingChange !== this.fieldKey && removeSelection(json) !== removeSelection(curProto?.Data)) {
this._applyingChange = this.fieldKey;
(curText !== Cast(this.dataDoc[this.fieldKey], RichTextField)?.Text) && (this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())));
@@ -309,9 +240,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
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 });
unchanged = false;
-
}
-
} else { // if we've deleted all the text in a note driven by a template, then restore the template data
this.dataDoc[this.props.fieldKey] = undefined;
this._editorView.updateState(EditorState.fromJSON(this.config, JSON.parse((curProto || curTemp).Data)));
@@ -321,7 +250,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._applyingChange = "";
if (!unchanged) {
this.updateTitle();
- this.tryUpdateHeight();
+ this.tryUpdateScrollHeight();
}
}
} else {
@@ -381,25 +310,29 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
let node = this._editorView.state.doc;
while (node.firstChild && node.firstChild.type.name !== "text") node = node.firstChild;
const str = node.textContent;
- const titlestr = str.substr(0, Math.min(40, str.length));
- this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
+ this.dataDoc.title = "-" + str.substr(0, Math.min(40, str.length)) + (str.length > 40 ? "..." : "");
}
}
// needs a better API for taking in a set of words with target documents instead of just one target
public hyperlinkTerms = (terms: string[], target: Doc) => {
if (this._editorView && (this._editorView as any).docView && terms.some(t => t)) {
- const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
- const tr = this._editorView.state.tr;
- const flattened: TextSelection[] = [];
- res.map(r => r.map(h => flattened.push(h)));
- const lastSel = Math.min(flattened.length - 1, this._searchIndex);
- this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
- const anchor = new Doc();
- const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!;
- const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }];
- const link = this._editorView.state.schema.marks.linkAnchor.create({ allAnchors, title: "a link", location });
- this._editorView.dispatch(tr.addMark(flattened[lastSel].from, flattened[lastSel].to, link));
+ const res1 = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+ let tr = this._editorView.state.tr;
+ const flattened1: TextSelection[] = [];
+ res1.map(r => r.map(h => flattened1.push(h)));
+ flattened1.forEach((flat, i) => {
+ const flattened: TextSelection[] = [];
+ const res = terms.filter(t => t).map(term => this.findInNode(this._editorView!, this._editorView!.state.doc, term));
+ res.map(r => r.map(h => flattened.push(h)));
+ this._searchIndex = ++this._searchIndex > flattened.length - 1 ? 0 : this._searchIndex;
+ const anchor = Docs.Create.TextanchorDocument();
+ const alink = DocUtils.MakeLink({ doc: anchor }, { doc: target }, "automatic")!;
+ const allAnchors = [{ href: Utils.prepend("/doc/" + anchor[Id]), title: "a link", anchorId: anchor[Id] }];
+ const link = this._editorView!.state.schema.marks.linkAnchor.create({ allAnchors, title: "auto link", location });
+ tr = tr.addMark(flattened[i].from, flattened[i].to, link);
+ });
+ this._editorView.dispatch(tr);
}
}
public highlightSearchTerms = (terms: string[], backward: boolean) => {
@@ -460,7 +393,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@undoBatch
@action
- drop = async (e: Event, de: DragManager.DropEvent) => {
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = this.getAnchor;
const dragData = de.complete.docDragData;
if (dragData) {
const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0];
@@ -483,22 +417,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
const view = this._editorView!;
view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
- this.tryUpdateHeight();
e.stopPropagation();
// }
} // otherwise, fall through to outer collection to handle drop
- } else if (de.complete.linkDragData) {
- de.complete.linkDragData.linkDropCallback = this.linkDrop;
- }
- else if (de.complete.annoDragData) {
- de.complete.annoDragData.linkDropCallback = this.linkDrop;
}
}
- linkDrop = (data: { linkDocument: Doc }) => {
- const anchor1Title = data.linkDocument.anchor1 instanceof Doc ? StrCast(data.linkDocument.anchor1.title) : "-untitled-";
- const anchor1 = data.linkDocument.anchor1 instanceof Doc ? data.linkDocument.anchor1 : undefined;
- this.makeLinkAnchor(anchor1, "add:right", undefined, anchor1Title);
- }
getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
let offset = 0;
@@ -523,7 +446,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
-
//Recursively finds matches within a given node
findInNode(pm: EditorView, node: Node, find: string) {
let ret: TextSelection[] = [];
@@ -544,8 +466,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
return ret;
}
- static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
+ static _highlights: string[] = ["Audio Tags", "Text from Others", "Todo Items", "Important Items", "Disagree Items", "Ignore Items"];
updateHighlights = () => {
clearStyleSheetRules(FormattedTextBox._userStyleSheet);
if (FormattedTextBox._highlights.indexOf("Audio Tags") === -1) {
@@ -591,22 +513,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
})), false);
}
sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => {
- const bounds = this.CurrentDiv.getBoundingClientRect();
+ const bounds = this._ref.current!.getBoundingClientRect();
this.layoutDoc._sidebarWidthPercent = "" + 100 * Math.max(0, (1 - (e.clientX - bounds.left) / bounds.width)) + "%";
this.layoutDoc._showSidebar = this.layoutDoc._sidebarWidthPercent !== "0%";
e.preventDefault();
return false;
}
- @undoBatch
- @action
- toggleNativeDimensions = () => {
- alert("need to fix");
- // Doc.toggleNativeDimensions(this.layoutDoc, 1, this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0);
- }
- public static get DefaultLayout(): Doc | string | undefined {
- return Cast(Doc.UserDoc().defaultTextLayout, Doc, null) || StrCast(Doc.UserDoc().defaultTextLayout, null);
- }
specificContextMenu = (e: React.MouseEvent): void => {
const cm = ContextMenu.Instance;
@@ -680,78 +593,17 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
Doc.AddDocToList(Cast(Doc.UserDoc()["template-notes"], Doc, null), "data", this.rootDoc);
}, icon: "eye"
});
- !Doc.UserDoc().noviceMode && appearanceItems.push({ description: "Create progressivized slide...", event: this.progressivizeText, icon: "desktop" });
cm.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
const options = cm.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
- !Doc.UserDoc().noviceMode && optionItems.push({ description: !this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
+ optionItems.push({ description: !this.Document._noSidebar ? "Hide Sidebar Handle" : "Show Sidebar Handle", event: () => this.layoutDoc._noSidebar = !this.layoutDoc._noSidebar, icon: "expand-arrows-alt" });
+ optionItems.push({ description: !this.Document._singleLine ? "Make Single Line" : "Make Multi Line", event: () => this.layoutDoc._singleLine = !this.layoutDoc._singleLine, icon: "expand-arrows-alt" });
optionItems.push({ description: `${this.Document._autoHeight ? "Lock" : "Auto"} Height`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
- optionItems.push({ description: `${!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? "Lock" : "Unlock"} Aspect`, event: this.toggleNativeDimensions, icon: "snowflake" });
!options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
this._downX = this._downY = Number.NaN;
}
- progressivizeText = () => {
- const list = this.ProseRef?.getElementsByTagName("li");
- const mainBulletText: string[] = [];
- const mainBulletList: Doc[] = [];
- if (list) {
- const newBullets: Doc[] = this.recursiveProgressivize(1, list)[0];
- mainBulletList.push.apply(mainBulletList, newBullets);
- }
- const title = Docs.Create.TextDocument(StrCast(this.rootDoc.title), { title: "Title", _width: 800, _height: 70, x: 20, y: -10, _fontSize: '20pt', backgroundColor: "rgba(0,0,0,0)", appearFrame: 0, _fontWeight: 700 });
- mainBulletList.push(title);
- const doc = Docs.Create.FreeformDocument(mainBulletList, {
- title: StrCast(this.rootDoc.title),
- x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document._height) + 10,
- _width: 400, _height: 225, _fitToBox: true,
- });
- this.props.addDocument?.(doc);
- }
-
- recursiveProgressivize = (nestDepth: number, list: HTMLCollectionOf<HTMLLIElement>, d?: number, y?: number, before?: string): [Doc[], number] => {
- const mainBulletList: Doc[] = [];
- let b = d ? d : 0;
- let yLoc = y ? y : 0;
- let nestCount = 0;
- let count: string = before ? before : '';
- const fontSize: string = (16 - (nestDepth * 2)) + 'pt';
- const xLoc: number = (nestDepth * 20);
- const width: number = 390 - xLoc;
- const height: number = 55 - (nestDepth * 5);
- Array.from(list).forEach(listItem => {
- const mainBullets: number = Number(listItem.getAttribute("data-bulletstyle"));
- if (mainBullets === nestDepth) {
- if (listItem.childElementCount > 1) {
- b++;
- nestCount++;
- yLoc += height;
- count = before ? count + nestCount + "." : nestCount + ".";
- const text = listItem.getElementsByTagName("p")[0].innerText;
- const length = text.length;
- const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
- // yLoc += NumCast(bullet1._height);
- mainBulletList.push(bullet1);
- const newList = this.recursiveProgressivize(nestDepth + 1, listItem.getElementsByTagName("li"), b, yLoc, count);
- mainBulletList.push.apply(mainBulletList, newList[0]);
- yLoc += newList.length * (55 - ((nestDepth + 1) * 5));
- } else {
- b++;
- nestCount++;
- yLoc += height;
- count = before ? count + nestCount + "." : nestCount + ".";
- const text = listItem.innerText;
- const length = text.length;
- const bullet1 = Docs.Create.TextDocument(count + " " + text, { title: "Slide text", _width: width, _autoHeight: true, x: xLoc, y: (yLoc), _fontSize: fontSize, backgroundColor: "rgba(0,0,0,0)", appearFrame: d ? d : b });
- // yLoc += NumCast(bullet1._height);
- mainBulletList.push(bullet1);
- }
- }
- });
- return [mainBulletList, yLoc];
- }
-
recordDictation = () => {
DictationManager.Controls.listen({
interimHandler: this.setDictationContent,
@@ -791,8 +643,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- _keymap: any = undefined;
- _rules: RichTextRules | undefined;
@computed get config() {
this._keymap = buildKeymap(schema, this.props);
this._rules = new RichTextRules(this.props.Document, this);
@@ -846,7 +696,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return this.active();//this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0;
}
- focusSpeed: Opt<number>;
scrollFocus = (doc: Doc, smooth: boolean) => {
const anchorId = doc[Id];
const findAnchorFrag = (frag: Fragment, editor: EditorView) => {
@@ -878,7 +727,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const ret = findAnchorFrag(editor.state.doc.content, editor);
if (ret.frag.size > 2 && ret.start >= 0) {
- smooth && (this.focusSpeed = 500);
+ smooth && (this._focusSpeed = 500);
let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
if (ret.frag.firstChild) {
selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
@@ -886,23 +735,32 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
const escAnchorId = anchorId[0] >= '0' && anchorId[0] <= '9' ? `\\3${anchorId[0]} ${anchorId.substr(1)}` : anchorId;
addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: "yellow" });
- setTimeout(() => this.focusSpeed = undefined, this.focusSpeed);
- setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this.focusSpeed || 0, 1500));
+ setTimeout(() => this._focusSpeed = undefined, this._focusSpeed);
+ setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 1500));
}
}
- return this.focusSpeed;
+ return this._focusSpeed;
+ }
+
+ // if the scroll height has changed and we're in autoHeight mode, then we need to update the textHeight component of the doc.
+ // Since we also monitor all component height changes, this will update the document's height.
+ resetNativeHeight = (scrollHeight: number) => {
+ const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
+ this.rootDoc[this.fieldKey + "-height"] = scrollHeight + this.titleHeight;
+ if (nh) this.layoutDoc._nativeHeight = scrollHeight;
}
componentDidMount() {
this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
this.props.contentsActive?.(this.IsActive);
this._cachedLinks = DocListCast(this.Document.links);
- this._disposers.sidebarheight = reaction(
- () => ({ annoHeight: NumCast(this.rootDoc[this.annotationKey + "-height"]), textHeight: NumCast(this.rootDoc[this.fieldKey + "-height"]) }),
- ({ annoHeight, textHeight }) => {
- this.layoutDoc._autoHeight && (this.rootDoc._height = Math.max(annoHeight, textHeight));
- });
+ this._disposers.autoHeight = reaction(() => ({ scrollHeight: this.scrollHeight, autoHeight: this.autoHeight, width: NumCast(this.layoutDoc._width) }),
+ ({ width, autoHeight, scrollHeight }) => width && autoHeight && this.resetNativeHeight(scrollHeight)
+ );
+ 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 }),
+ ({ sidebarHeight, textHeight, autoHeight }) => autoHeight && this.props.setHeight(Math.max(sidebarHeight, textHeight)));
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 => {
this._cachedLinks.forEach(l => !newLinks.includes(l) && this.RemoveLinkFromDoc(l));
@@ -930,7 +788,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const updatedState = JSON.parse(incomingValue.data.Data);
if (JSON.stringify(this._editorView.state.toJSON()) !== JSON.stringify(updatedState)) {
this._editorView.updateState(EditorState.fromJSON(this.config, updatedState));
- this.tryUpdateHeight();
+ this.tryUpdateScrollHeight();
}
} else if (incomingValue?.str) {
selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue.str)));
@@ -957,21 +815,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
);
- this._disposers.autoHeight = reaction(
- () => ({
- width: NumCast(this.layoutDoc._width),
- autoHeight: this.layoutDoc?._autoHeight
- }),
- ({ width, autoHeight }) => width !== undefined && setTimeout(() => this.tryUpdateHeight(), 0)
- );
- this._disposers.height = reaction(
- () => Cast(this.layoutDoc._height, "number", null),
- action(height => {
- if (height !== undefined && height <= 20 && height < NumCast(this.layoutDoc._delayAutoHeight, 20)) {
- this.layoutDoc._delayAutoHeight = height;
- }
- })
- );
this.setupEditor(this.config, this.props.fieldKey);
@@ -1016,8 +859,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}, { fireImmediately: true }
);
quickScroll = undefined;
-
- setTimeout(() => this.tryUpdateHeight(NumCast(this.layoutDoc.limitHeight)));
+ this.tryUpdateScrollHeight();
}
pushToGoogleDoc = async () => {
@@ -1114,10 +956,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return text;
}
- sliceSingleNode(slice: Slice) {
- return slice.openStart === 0 && slice.openEnd === 0 && slice.content.childCount === 1 ? slice.content.firstChild : null;
- }
-
handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
const cbe = event as ClipboardEvent;
const pdfDocId = cbe.clipboardData?.getData("dash/pdfOrigin");
@@ -1180,7 +1018,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- private isActiveTab(el: Element | null | undefined) {
+ isActiveTab(el: Element | null | undefined) {
while (el && el !== document.body) {
if (getComputedStyle(el).display === "none") return false;
el = el.parentNode as any;
@@ -1188,7 +1026,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return true;
}
- private setupEditor(config: any, fieldKey: string) {
+ richTextMenuPlugin() {
+ const self = this;
+ return new Plugin({
+ view(newView) {
+ runInAction(() => self.props.isSelected(true) && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView));
+ return new RichTextMenuPlugin({ editorProps: this.props });
+ }
+ });
+ }
+ setupEditor(config: any, fieldKey: string) {
const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null);
const rtfField = Cast((!curText?.Text && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
@@ -1202,8 +1049,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const scrollRef = self._scrollRef.current;
if ((docPos.top < viewRect.top || docPos.top > viewRect.bottom) && scrollRef) {
const scrollPos = scrollRef.scrollTop + (docPos.top - viewRect.top) * self.props.ScreenToLocalTransform().Scale;
- if (this.focusSpeed !== undefined) {
- scrollPos && smoothScroll(this.focusSpeed, scrollRef, scrollPos);
+ if (this._focusSpeed !== undefined) {
+ scrollPos && smoothScroll(this._focusSpeed, scrollRef, scrollPos);
} else {
scrollRef.scrollTo({ top: scrollPos });
}
@@ -1215,6 +1062,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
dashComment(node, view, getPos) { return new DashDocCommentView(node, view, getPos); },
dashDoc(node, view, getPos) { return new DashDocView(node, view, getPos, self); },
dashField(node, view, getPos) { return new DashFieldView(node, view, getPos, self); },
+ equation(node, view, getPos) { return new EquationView(node, view, getPos, self); },
summary(node, view, getPos) { return new SummaryView(node, view, getPos); },
ordered_list(node, view, getPos) { return new OrderedListView(); },
footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); }
@@ -1254,18 +1102,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._editorView!.state.storedMarks = [...(this._editorView!.state.storedMarks ?? []), schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })];
}
}
- getFont(font: string) {
- switch (font) {
- case "Arial": return schema.marks.arial.create();
- case "Times New Roman": return schema.marks.timesNewRoman.create();
- case "Georgia": return schema.marks.georgia.create();
- case "Comic Sans MS": return schema.marks.comicSans.create();
- case "Tahoma": return schema.marks.tahoma.create();
- case "Impact": return schema.marks.impact.create();
- case "ACrimson Textrial": return schema.marks.crimson.create();
- }
- return schema.marks.arial.create();
- }
componentWillUnmount() {
Object.values(this._disposers).forEach(disposer => disposer?.());
@@ -1308,7 +1144,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
this._downX = e.clientX;
this._downY = e.clientY;
- this.doLinkOnDeselect();
this._downEvent = true;
FormattedTextBoxComment.textBox = this;
if (e.button === 0 && (this.props.rootSelected(true) || this.props.isSelected(true)) && !e.altKey && !e.ctrlKey && !e.metaKey) {
@@ -1331,7 +1166,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
onPointerUp = (e: React.PointerEvent): void => {
- FormattedTextBox.CanAnnotate = true;
if (!this._editorView?.state.selection.empty && FormattedTextBox.CanAnnotate) this.setupAnchorMenu();
if (!this._downEvent) return;
this._downEvent = false;
@@ -1339,7 +1173,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const editor = this._editorView!;
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
!this.props.isSelected(true) && editor.dispatch(editor.state.tr.setSelection(new TextSelection(editor.state.doc.resolve(pcords?.pos || 0))));
- const target = (e.target as any).parentElement; // hrefs are store don the database of the <a> node that wraps the hyerlink <span>
+ let target = (e.target as any).parentElement; // hrefs are stored on the database of the <a> node that wraps the hyerlink <span>
+ while (target && !target.dataset?.targethrefs) target = target.parentElement;
FormattedTextBoxComment.update(this, editor, undefined, target?.dataset?.targethrefs);
}
(e.nativeEvent as any).formattedHandled = true;
@@ -1351,7 +1186,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
onDoubleClick = (e: React.MouseEvent): void => {
- this.doLinkOnDeselect();
FormattedTextBoxComment.textBox = this;
if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
if (e.clientX < this.ProseRef!.getBoundingClientRect().right) { // stop propagation if not in sidebar
@@ -1373,7 +1207,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
onFocused = (e: React.FocusEvent): void => {
FormattedTextBox.FocusedBox = this;
- this.tryUpdateHeight();
//applyDevTools.applyDevTools(this._editorView);
// see if we need to preserve the insertion point
@@ -1495,18 +1328,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- menuPlugin: any;
-
- richTextMenuPlugin() {
- const self = this;
- return new Plugin({
- view(newView) {
- runInAction(() => self.props.isSelected(true) && RichTextMenu.Instance && (RichTextMenu.Instance.view = newView));
- return self.menuPlugin = new RichTextMenuPlugin({ editorProps: this.props });
- }
- });
- }
-
public startUndoTypingBatch() {
!this._undoTyping && (this._undoTyping = UndoManager.StartBatch("undoTyping"));
}
@@ -1525,7 +1346,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
FormattedTextBox.HadSelection = window.getSelection()?.toString() !== "";
this.endUndoTypingBatch();
- this.doLinkOnDeselect();
FormattedTextBox.LiveTextUndo?.end();
FormattedTextBox.LiveTextUndo = undefined;
@@ -1544,7 +1364,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- _lastTimedMark: Mark | undefined = undefined;
onKeyDown = (e: React.KeyboardEvent) => {
// single line text boxes need to pass through tab/enter/backspace so that their containers can respond (eg, an outline container)
if (this.rootDoc._singleLine && ((e.key === "Backspace" && !this.dataDoc[this.fieldKey]?.Text) || ["Tab", "Enter"].includes(e.key))) {
@@ -1573,9 +1392,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
} else {
if (e.key === "Tab" || e.key === "Enter") {
- if (e.key === "Enter") {
- this.insertTime();
- }
+ if (e.key === "Enter") this.insertTime();
e.preventDefault();
}
if (e.key === " " || this._lastTimedMark?.attrs.userid !== Doc.CurrentUserEmail) {
@@ -1598,99 +1415,73 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
}
- get titleHeight() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin) || 0; }
-
- @action
- tryUpdateHeight(limitHeight?: number) {
- let scrollHeight = this.ProseRef?.scrollHeight || 0;
- if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight && !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
- scrollHeight = scrollHeight * NumCast(this.layoutDoc._viewScale, 1);
- if (limitHeight && scrollHeight > limitHeight) {
- scrollHeight = limitHeight;
- this.layoutDoc.limitHeight = undefined;
- this.layoutDoc._autoHeight = false;
- }
- const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight);
- const dh = NumCast(this.rootDoc._height);
- const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + this.titleHeight);
- if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) {
- // 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...
- console.log("Delayed height adjustment...");
- setTimeout(() => {
- this.rootDoc._height = newHeight;
- this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined;
- }, 10);
- } else {
- try {
- const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", "")) * NumCast(this.Document._viewScale, 1);
- const outer = this.rootDoc[HeightSym]() - boxHeight - this.titleHeight;
- this.rootDoc[this.fieldKey + "-height"] = newHeight + Math.max(0, outer);
- } catch (e) { console.log("Error in tryUpdateHeight"); }
- }
- } //else this.rootDoc[this.fieldKey + "-height"] = 0;
+ tryUpdateScrollHeight() {
+ const proseHeight = this.ProseRef?.scrollHeight || 0;
+ 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...
+ }
}
+ fitToBox = () => this.props.Document._fitToBox;
+ sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
+ sidebarAddDocument = (doc: Doc | Doc[]) => this.addDocument(doc, this.SidebarKey);
+ sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
+ sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
+ setSidebarHeight = (height: number) => this.rootDoc[this.SidebarKey + "-height"] = height;
+ sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
+ sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0).scale(1 / NumCast(this.layoutDoc._viewScale, 1));
+
@computed get audioHandle() {
- return !this.layoutDoc._showAudio ? (null) :
- <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
- <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
- </div>;
+ return <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} >
+ <FontAwesomeIcon className="formattedTextBox-audioFont" style={{ color: this._recording ? "red" : "blue", transitionDelay: "0.6s", opacity: this._recording ? 1 : 0.25, }} icon={"microphone"} size="sm" />
+ </div>;
}
-
@computed get sidebarHandle() {
const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length;
- return this.props.noSidebar || (!this.props.isSelected() && !(annotated && !this.sidebarWidth())) ? (null) :
- <div className="formattedTextBox-sidebar-handle"
- style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightblue" : this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor) }}
- onPointerDown={this.sidebarDown}
- />;
+ return <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown}
+ style={{
+ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`,
+ background: this.props.styleProvider?.(this.props.Document, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : ""))
+ }} />;
}
-
- sidebarContentScaling = () => (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
- fitToBox = () => this.props.Document._fitToBox;
- sidebarAddDocument = (doc: Doc | Doc[]) => this.addDocument(doc, this.SidebarKey);
- sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey);
- sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey);
@computed get sidebarCollection() {
- const collectionProps: SubCollectionViewProps & collectionFreeformViewProps = {
- ...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit,
- NativeWidth: returnZero,
- NativeHeight: returnZero,
- PanelHeight: this.props.PanelHeight,
- PanelWidth: this.sidebarWidth,
- xMargin: 0,
- yMargin: 0,
- chromeStatus: "enabled",
- scaleField: this.SidebarKey + "-scale",
- isAnnotationOverlay: false,
- fieldKey: this.SidebarKey,
- fitContentsToDoc: this.fitToBox,
- select: emptyFunction,
- active: this.annotationsActive,
- scaling: this.sidebarContentScaling,
- whenActiveChanged: this.whenActiveChanged,
- removeDocument: this.sidebarRemDocument,
- moveDocument: this.sidebarMoveDocument,
- addDocument: this.sidebarAddDocument,
- CollectionView: undefined,
- ScreenToLocalTransform: this.sidebarScreenToLocal,
- renderDepth: this.props.renderDepth + 1,
+ const renderComponent = (tag: string) => {
+ const ComponentTag = tag === "freeform" ? CollectionFreeFormView : tag === "translation" ? FormattedTextBox : CollectionStackingView;
+ return <ComponentTag
+ {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ NativeWidth={returnZero}
+ NativeHeight={returnZero}
+ PanelHeight={this.props.PanelHeight}
+ PanelWidth={this.sidebarWidth}
+ xMargin={0}
+ yMargin={0}
+ chromeStatus={"enabled"}
+ scaleField={this.SidebarKey + "-scale"}
+ isAnnotationOverlay={false}
+ setHeight={this.setSidebarHeight}
+ fitContentsToDoc={this.fitToBox}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ scaling={this.sidebarContentScaling}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.sidebarRemDocument}
+ moveDocument={this.sidebarMoveDocument}
+ addDocument={this.sidebarAddDocument}
+ CollectionView={undefined}
+ ScreenToLocalTransform={this.sidebarScreenToLocal}
+ renderDepth={this.props.renderDepth + 1}
+ noSidebar={true}
+ fieldKey={this.layoutDoc.sidebarViewType === "translation" ? `${this.fieldKey}-translation` : this.SidebarKey} />;
};
- return this.props.noSidebar || !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) :
- <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
- style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
- {this.layoutDoc.sidebarViewType === "translation" ?
- <FormattedTextBox {...collectionProps} noSidebar={true} fieldKey={`${this.fieldKey}-translation`} /> :
- this.layoutDoc.sidebarViewType === CollectionViewType.Freeform ?
- <CollectionFreeFormView {...collectionProps} /> :
- <CollectionStackingView {...collectionProps} />}
- </div>;
+ return <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
+ style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ {renderComponent(StrCast(this.layoutDoc.sidebarViewType))}
+ </div>;
}
-
- @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "0%"); }
- sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
- sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.scaling?.() || 1), 0).scale(1 / NumCast(this.layoutDoc._viewScale, 1));
- @computed get sidebarColor() { return StrCast(this.layoutDoc.sidebarColor, StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "#e4e4e4")); }
render() {
TraceMobx();
const selected = this.props.isSelected();
@@ -1705,19 +1496,19 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0);
const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
return (
- <div className="formattedTextBox-cont" ref={this._boxRef}
+ <div className="formattedTextBox-cont"
style={{
transform: `scale(${scale})`,
transformOrigin: "top left",
width: `${100 / scale}%`,
height: `${100 / scale}%`,
- overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
+ // overflowY: this.layoutDoc._autoHeight ? "hidden" : undefined,
...this.styleFromLayoutString(scale) // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' >
}}>
<div className={`formattedTextBox-cont`} ref={this._ref}
style={{
- overflow: this.layoutDoc._autoHeight ? "hidden" : undefined,
- height: this.props.height || (this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : undefined),
+ overflow: this.autoHeight ? "hidden" : undefined,
+ height: this.props.height || (this.autoHeight && this.props.renderDepth ? "max-content" : undefined),
background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor)),
color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color)),
pointerEvents: interactive ? undefined : "none",
@@ -1751,9 +1542,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}}
/>
</div>
- {this.sidebarCollection}
- {this.sidebarHandle}
- {this.audioHandle}
+ {(this.props.noSidebar || this.Document._noSidebar) || !this.layoutDoc._showSidebar || this.sidebarWidthPercent === "0%" ? (null) : this.sidebarCollection}
+ {(this.props.noSidebar || this.Document._noSidebar) || this.Document._singleLine ? (null) : this.sidebarHandle}
+ {!this.layoutDoc._showAudio ? (null) : this.audioHandle}
</div>
</div>
);