diff options
Diffstat (limited to 'src/client/views')
11 files changed, 52 insertions, 31 deletions
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 97ed0a901..b1ad4868c 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -1,6 +1,10 @@ @import "globalCssVariables"; @import "nodeModuleOverrides"; +:root { + --flyoutHandleWidth: 28px; + --menuPanelWidth: 60px; +} html, body { width: 100%; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index a58edc604..3cc041e0b 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -533,7 +533,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu if (this.selectedDoc) { const layoutField = Doc.LayoutField(this.selectedDoc); const layoutStr = this.selectedDocumentView?.props.LayoutTemplateString || StrCast(layoutField); - return layoutStr.includes("FormattedText") || StrCast((layoutField as Doc)?.layout).includes("FormattedText"); + return (document.activeElement as any)?.className.includes("ProseMirror") || layoutStr.includes("FormattedText") || StrCast((layoutField as Doc)?.layout).includes("FormattedText"); } else return false; } diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cbc62be91..9c9dad2c9 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -187,7 +187,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) const opacity = () => this.Document._currentFrame === undefined ? this.props.childOpacity?.() : CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document._currentFrame))?.opacity; return <ContentFittingDocumentView Document={doc} - DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])} + DataDoc={dataDoc || (!Doc.AreProtosEqual(doc[DataSym], doc) && doc[DataSym])} backgroundColor={this.props.backgroundColor} LayoutTemplate={this.props.ChildLayoutTemplate} LayoutTemplateString={this.props.ChildLayoutString} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 276e0b873..47d4aad94 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -177,7 +177,7 @@ class TreeView extends React.Component<TreeViewProps> { } public static makeTextBullet() { - const bullet = Docs.Create.TextDocument("-text-", { title: "-title-", _viewType: CollectionViewType.Tree, hideLinkButton: true, treeViewOutlineMode: true, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _backgroundColor: "transparent", _width: 500, _height: 10, templates: new List<string>([Templates.Title.Layout]) }); + const bullet = Docs.Create.TextDocument("-text-", { title: "-title-", _viewType: CollectionViewType.Tree, hideLinkButton: true, _showSidebar: true, treeViewOutlineMode: true, x: 0, y: 0, _xMargin: 0, _yMargin: 0, _autoHeight: true, _singleLine: true, _backgroundColor: "transparent", _width: 1000, _height: 10, templates: new List<string>([Templates.Title.Layout]) }); Doc.GetProto(bullet).layout = CollectionView.LayoutString("data"); Doc.GetProto(bullet).title = ComputedField.MakeFunction('self.text?.Text'); Doc.GetProto(bullet).data = new List<Doc>([]); diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index d0c90edcb..1539d1399 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -38,10 +38,6 @@ $MINIMIZED_ICON_SIZE:25; $MAX_ROW_HEIGHT: 44px; $DFLT_IMAGE_NATIVE_DIM: 900px; $MENU_PANEL_WIDTH: 60px; -:root { - --flyoutHandleWidth: 28px; - --menuPanelWidth: 60px; -} :export { contextMenuZindex: $contextMenu-zindex; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b372f3691..ad99001dd 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -987,6 +987,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu yMargin={10} xMargin={10} hideOnLeave={true} + dontRegisterView={true} LayoutTemplateString={`<FormattedTextBox {...props} fieldKey={'${showCaption}'}/>`} ContentScaling={returnOne} ChromeHeight={this.chromeHeight} diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index f14a57e31..0332bb4fd 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -1,5 +1,5 @@ import { IReactionDisposer, observable, runInAction, computed, action } from "mobx"; -import { Doc, DocListCast, Field } from "../../../../fields/Doc"; +import { Doc, DocListCast, Field, LayoutSym } from "../../../../fields/Doc"; import { List } from "../../../../fields/List"; import { listSpec } from "../../../../fields/Schema"; import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; @@ -70,7 +70,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna DocServer.GetRefField(this.props.docid). then(action(async dashDoc => dashDoc instanceof Doc && (this._dashDoc = dashDoc))); } else { - this._dashDoc = this.props.tbox.props.DataDoc || this.props.tbox.dataDoc; + this._dashDoc = this.props.tbox.rootDoc; } } componentWillUnmount() { @@ -92,7 +92,10 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna return <input className="dashFieldView-fieldCheck" type="checkbox" checked={boolVal} - onChange={e => this._dashDoc![this._fieldKey] = e.target.checked} + onChange={e => { + if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = e.target.checked; + this._dashDoc![this._fieldKey] = e.target.checked; + }} />; } else // field value is a string, so display it as an editable span @@ -159,9 +162,16 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna } else if (nodeText.startsWith("=:=")) { Doc.Layout(this._textBoxDoc)[this._fieldKey] = ComputedField.MakeFunction(nodeText.substring(3)); } else { - const splits = newText.split(this.multiValueDelimeter); - if (this._fieldKey !== "PARAMS" || !this._textBoxDoc[this._fieldKey] || this._dashDoc?.PARAMS) { - this._dashDoc![this._fieldKey] = splits.length > 1 ? new List<string>(splits) : newText; + if (Number(newText).toString() === newText) { + if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = Number(newText); + this._dashDoc![this._fieldKey] = Number(newText); + } else { + const splits = newText.split(this.multiValueDelimeter); + if (this._fieldKey !== "PARAMS" || !this._textBoxDoc[this._fieldKey] || this._dashDoc?.PARAMS) { + const strVal = splits.length > 1 ? new List<string>(splits) : newText; + if (this._fieldKey.startsWith("_")) Doc.Layout(this._textBoxDoc)[this._fieldKey] = strVal; + this._dashDoc![this._fieldKey] = strVal; + } } } }); diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 847b1bb30..43e64d2d2 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -43,7 +43,7 @@ overflow: auto; display: inline-block; width: 100%; - height: 100%; + height: unset; } .formattedTextBox-sidebar-handle { @@ -51,7 +51,8 @@ top: 0; //top: calc(50% - 17.5px); // use this to center vertically -- make sure it looks okay for slide views width: 10px; - height: 35px; + height: 100%; + max-height: 35px; background: lightgray; border-radius: 20px; cursor:grabbing; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index a79e70017..4cc0309eb 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -64,6 +64,7 @@ export interface FormattedTextBoxProps { hideOnLeave?: boolean; // used by DocumentView for setting caption's hide on leave (bcz: would prefer to have caption-hideOnLeave field set or something similar) xMargin?: number; // used to override document's settings for xMargin --- see CollectionCarouselView yMargin?: number; + dontSelectOnLoad?: boolean; // suppress selecting the text box when loaded } export const GoogleRef = "googleDocId"; @@ -79,6 +80,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp public static Instance: FormattedTextBox; public ProseRef?: HTMLDivElement; public get EditorView() { return this._editorView; } + 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>; @@ -346,7 +348,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } updateTitle = () => { - if ((this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing + if (!this.props.dontRegisterView && // (this.props.Document.isTemplateForField === "text" || !this.props.Document.isTemplateForField) && // only update the title if the data document's data field is changing StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.dataDoc["title-custom"] && Doc.LayoutFieldKey(this.rootDoc) === this.fieldKey) { let node = this._editorView.state.doc; @@ -556,7 +558,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => { const bounds = this.CurrentDiv.getBoundingClientRect(); - this.layoutDoc._sidebarWidthPercent = "" + 100 * (1 - (e.clientX - bounds.left) / bounds.width) + "%"; + this.layoutDoc._sidebarWidthPercent = "" + 100 * Math.max(0, (1 - (e.clientX - bounds.left) / bounds.width)) + "%"; return false; } @undoBatch @@ -1144,7 +1146,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad; - if (selectOnLoad && !this.props.dontRegisterView) { + if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad) { FormattedTextBox.SelectOnLoad = ""; this.props.select(false); if (FormattedTextBox.SelectOnLoadChar) { @@ -1314,7 +1316,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } if (!node && this.ProseRef) { const lastNode = this.ProseRef.children[this.ProseRef.children.length - 1].children[this.ProseRef.children[this.ProseRef.children.length - 1].children.length - 1]; // get the last prosemirror div - if (e.clientY > lastNode?.getBoundingClientRect().bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document + const boundsRect = lastNode?.getBoundingClientRect(); + if (e.clientX > boundsRect.left && e.clientX < boundsRect.right && + e.clientY > boundsRect.bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document + this._editorView?.focus(); this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, this._editorView!.state.doc.content.size))); } } else if ([this._editorView!.state.schema.nodes.ordered_list, this._editorView!.state.schema.nodes.listItem].includes(node?.type) && @@ -1473,7 +1478,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } @action tryUpdateHeight(limitHeight?: number) { - let scrollHeight = this._ref.current?.scrollHeight; + let scrollHeight = this.ProseRef?.scrollHeight || 0; if (this.props.renderDepth && this.layoutDoc._autoHeight && !this.props.ignoreAutoHeight && scrollHeight) { // 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) { @@ -1493,14 +1498,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, 10); } else { try { - this.layoutDoc._height = newHeight; + const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", "")); + const outer = this.rootDoc[HeightSym]() - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0); + this.rootDoc._height = newHeight + outer; this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined; } catch (e) { console.log("Error in tryUpdateHeight"); } } } } - @computed get sidebarWidthPercent() { return StrCast(this.layoutDoc._sidebarWidthPercent, "20%"); } + @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.ContentScaling(), 0); @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); } @@ -1516,7 +1523,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selPad = this.props.isSelected() && !this.layoutDoc._singleLine ? -10 : 0; const selclass = this.props.isSelected() && !this.layoutDoc._singleLine ? "-selected" : ""; return ( - <div className={"formattedTextBox-cont"} + <div className={"formattedTextBox-cont"} ref={this._boxRef} style={{ transform: `scale(${scale})`, transformOrigin: "top left", @@ -1594,7 +1601,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp ContainingCollectionDoc={this.props.ContainingCollectionDoc} /> } </div> - {this.props.isSelected() ? <div className="formattedTextBox-sidebar-handle" style={{ left: `calc(100% - ${this.sidebarWidthPercent} - 5px)` }} onPointerDown={this.sidebarDown} /> : (null)} + {this.props.isSelected() ? <div className="formattedTextBox-sidebar-handle" style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 5px))` }} onPointerDown={this.sidebarDown} /> : (null)} </>} {!this.layoutDoc._showAudio ? (null) : <div className="formattedTextBox-dictation" onClick={action(e => this._recording = !this._recording)} > diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index 9895940d1..f1a0188c5 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -49,7 +49,7 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey /// bcz; Argh!! replace with an onEnter func that conditionally handles Enter const addTextBox = (below: boolean, force?: boolean) => { - if (props.LayoutTemplateString) return true; + if (props.Document.treeViewOutlineMode) return true; // bcz: Arghh .. need to determine if this is an treeViewOutlineBox in which case Enter's are ignored.. const layoutDoc = props.Document; const originalDoc = layoutDoc.rootDocument || layoutDoc; if (force || props.Document._singleLine) { @@ -217,11 +217,13 @@ export function buildKeymap<S extends Schema<any>>(schema: S, props: any, mapKey const fromattrs = state.selection.$from.node().attrs; if (!splitBlockKeepMarks(state, (tx3: Transaction) => { const tonode = tx3.selection.$to.node(); - const tx4 = tx3.setNodeMarkup(tx3.selection.to - 1, tonode.type, fromattrs, tonode.marks); - splitMetadata(marks, tx4); - if (!liftListItem(schema.nodes.list_item)(tx4, dispatch as ((tx: Transaction<Schema<any, any>>) => void))) { - dispatch(tx4); - } + if (tx3.doc.nodeAt(tx3.selection.to - 1)) { + const tx4 = tx3.setNodeMarkup(tx3.selection.to - 1, tonode.type, fromattrs, tonode.marks); + splitMetadata(marks, tx4); + if (!liftListItem(schema.nodes.list_item)(tx4, dispatch as ((tx: Transaction<Schema<any, any>>) => void))) { + dispatch(tx4); + } + } else dispatch(tx3.insertText("\r")); })) { return false; } diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 02f9c6268..06c73265a 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -324,7 +324,7 @@ export class RichTextRules { this.Document[DataSym]["#" + tag] = "#" + tag; const tags = StrCast(this.Document.tags, ":"); if (!tags.includes(`#${tag}:`)) { - this.Document[DataSym].tags = `"${tags + "#" + tag + ':'}"`; + this.Document[DataSym].tags = `${tags + "#" + tag + ':'}`; } const fieldView = state.schema.nodes.dashField.create({ fieldKey: "#" + tag }); return state.tr.deleteRange(start, end).insert(start, fieldView); |
