diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 66 | ||||
| -rw-r--r-- | src/client/views/nodes/FilterBox.tsx | 11 | ||||
| -rw-r--r-- | src/client/views/nodes/LinkAnchorBox.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 20 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 14 | ||||
| -rw-r--r-- | src/client/views/nodes/button/FontIconBox.tsx | 92 | ||||
| -rw-r--r-- | src/client/views/nodes/button/textButton/TextButton.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/button/textButton/index.ts | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/button/toggleButton/index.ts | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/DashFieldView.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.scss | 17 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 63 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.scss | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.tsx | 20 |
15 files changed, 181 insertions, 135 deletions
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 544125ede..fad905d6d 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -201,7 +201,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo if (splits.length > 1) { const code = XRegExp.matchRecursive(splits[1], "{", "}", "", { valueNames: ["between", "left", "match", "right", "between"] }); layoutFrame = splits[0] + ` ${func}={props.${func}} ` + splits[1].substring(code[1].end + 1); - return ScriptField.MakeScript(code[1].value, { this: Doc.name, self: Doc.name, scale: "number", value: "string" }); + const script = code[1].value.replace(/^‘/, "").replace(/’$/, ""); // ‘’ are not valid quotes in javascript so get rid of them -- they may be present to make it easier to write complex scripts - see headerTemplate in currentUserUtils.ts + return ScriptField.MakeScript(script, { this: Doc.name, self: Doc.name, scale: "number", value: "string" }); } return undefined; // add input function to props diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ebd0211e2..d88f1b9a4 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -13,7 +13,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty import { AudioField } from "../../../fields/URLField"; import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util'; import { MobileInterface } from '../../../mobile/MobileInterface'; -import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils } from "../../../Utils"; +import { emptyFunction, hasDescendantTarget, OmitKeys, returnTrue, returnVal, Utils, lightOrDark } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from '../../documents/DocumentTypes'; @@ -115,6 +115,7 @@ export interface DocumentViewSharedProps { docFilters: () => string[]; docRangeFilters: () => string[]; searchFilterDocs: () => Doc[]; + showTitle?: () => string; whenChildContentsActiveChanged: (isActive: boolean) => void; rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected addDocTab: (doc: Doc, where: string) => boolean; @@ -649,7 +650,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) { e.preventDefault(); e.stopPropagation(); - !this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); + //!this.props.isSelected(true) && SelectionManager.SelectView(this.props.DocumentView(), false); } // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 if (e) { @@ -704,13 +705,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps const zorders = cm.findByDescription("ZOrder..."); const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : []; - zorderItems.push({ description: "Bring to Front", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" }); - zorderItems.push({ description: "Send to Back", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" }); - zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: undoBatch(action(() => this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined)), icon: "expand-arrows-alt" }); + if (this.props.bringToFront !== emptyFunction) { + zorderItems.push({ description: "Bring to Front", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" }); + zorderItems.push({ description: "Send to Back", event: () => SelectionManager.Views().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" }); + zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: undoBatch(action(() => this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined)), icon: "expand-arrows-alt" }); + } !zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" }); onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" }); - onClicks.push({ description: "Toggle Detail", event: this.setToggleDetail, icon: "concierge-bell" }); + !Doc.UserDoc().noviceMode && onClicks.push({ description: "Toggle Detail", event: this.setToggleDetail, icon: "concierge-bell" }); onClicks.push({ description: (this.Document.followLinkZoom ? "Don't" : "") + " zoom following link", event: () => this.Document.followLinkZoom = !this.Document.followLinkZoom, icon: this.Document.ignoreClick ? "unlock" : "lock" }); if (!this.Document.annotationOn) { @@ -848,16 +851,28 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps default: return this.props.styleProvider?.(doc, props, property); } } - @computed get directLinks() { TraceMobx(); return LinkManager.Instance.getAllDirectLinks(this.rootDoc); } + // We need to use allrelatedLinks to get not just links to the document as a whole, but links to + // anchors that are not rendered as DocumentViews (marked as 'unrendered' with their 'annotationOn' set to this document). e.g., + // - PDF text regions are rendered as an Annotations without generating a DocumentView, ' + // - RTF selections are rendered via Prosemirror and have a mark which contains the Document ID for the annotation link + // - and links to PDF/Web docs at a certain scroll location never create an explicit view. + // For each of these, we create LinkAnchorBox's on the border of the DocumentView. + @computed get directLinks() { + TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc).filter(link => + Doc.AreProtosEqual(link.anchor1 as Doc, this.rootDoc) || + Doc.AreProtosEqual(link.anchor2 as Doc, this.rootDoc) || + ((link.anchor1 as Doc).unrendered && Doc.AreProtosEqual((link.anchor1 as Doc).annotationOn as Doc, this.rootDoc)) || + ((link.anchor2 as Doc).unrendered && Doc.AreProtosEqual((link.anchor2 as Doc).annotationOn as Doc, this.rootDoc)) + ); + } @computed get allLinks() { TraceMobx(); return LinkManager.Instance.getAllRelatedLinks(this.rootDoc); } @computed get allLinkEndpoints() { // the small blue dots that mark the endpoints of links TraceMobx(); - if (this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null; + if (this.layoutDoc.unrendered || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return null; if (this.layoutDoc.presBox || this.rootDoc.type === DocumentType.LINK || this.props.dontRegisterView) return (null); - // need to use allLinks for RTF since embedded linked text anchors are not rendered with DocumentViews. All other documents render their anchors with nested DocumentViews so we just need to render the directLinks here - const filtered = DocUtils.FilterDocs(this.rootDoc.type === DocumentType.RTF ? this.allLinks : this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => !d.hidden); + const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters?.() ?? [], []).filter(d => !d.hidden); return filtered.map((link, i) => - <div className="documentView-anchorCont" key={i + 1}> + <div className="documentView-anchorCont" key={link[Id]}> <DocumentView {...this.props} Document={link} PanelWidth={this.anchorPanelWidth} @@ -938,22 +953,41 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps hideOnLeave={true} styleProvider={this.captionStyleProvider} dontRegisterView={true} + isContentActive={this.isContentActive} onClick={this.onClickFunc} /> </div>; + const targetDoc = (showTitle?.startsWith("_") ? this.layoutDoc : this.rootDoc); + const background = StrCast(SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor, [DocumentType.RTF, DocumentType.COL].includes(this.rootDoc.type as any) ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)"); const titleView = !showTitle ? (null) : <div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{ position: this.headerMargin ? "relative" : "absolute", height: this.titleHeight, - background: StrCast(SharingManager.Instance.users.find(users => users.user.email === this.dataDoc.author)?.sharingDoc.userColor, this.rootDoc.type === DocumentType.RTF ? StrCast(Doc.SharingDoc().userColor) : "rgba(0,0,0,0.4)"), + color: lightOrDark(background), + background, pointerEvents: this.onClickHandler || this.Document.ignoreClick ? "none" : undefined, }}> <EditableView ref={this._titleRef} - contents={showTitle === "title" ? StrCast((this.dataDoc || this.props.Document).title) : showTitle.split(";").map(field => field + ":" + (this.dataDoc || this.props.Document)[field]?.toString()).join(" ")} + contents={showTitle.split(";").map(field => field.trim()).map(field => targetDoc[field]?.toString()).join("\\")} display={"block"} fontSize={10} - GetValue={() => Field.toString((this.dataDoc || this.props.Document)[showTitle.split(";")[0]] as any as Field)} - SetValue={undoBatch((value) => showTitle.includes("Date") ? true : (Doc.GetProto(this.dataDoc || this.props.Document)[showTitle] = value) ? true : true)} + GetValue={() => showTitle.split(";").length === 1 ? showTitle + "=" + Field.toString(targetDoc[showTitle.split(";")[0]] as any as Field) : "#" + showTitle} + SetValue={undoBatch(input => { + if (input?.startsWith("#")) { + if (this.props.showTitle) { + this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined; + } else { + Doc.UserDoc().showTitle = input?.substring(1) ? input.substring(1) : "creationDate"; + } + return true; + } else { + var value = input.replace(new RegExp(showTitle + "="), ""); + if (showTitle !== "title" && Number(value).toString() === value) value = Number(value); + if (showTitle.includes("Date") || showTitle === "author") return true; + return Doc.SetInPlace(targetDoc, showTitle, value, true) ? true : true; + } + return true; + })} /> </div>; return this.props.hideTitle || (!showTitle && !showCaption) ? @@ -1155,7 +1189,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { } componentWillUnmount() { Object.values(this._disposers).forEach(disposer => disposer?.()); - !this.props.dontRegisterView && DocumentManager.Instance.RemoveView(this); + !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.RemoveView(this); } render() { diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx index 7ad03e055..e9f19bf9e 100644 --- a/src/client/views/nodes/FilterBox.tsx +++ b/src/client/views/nodes/FilterBox.tsx @@ -9,7 +9,7 @@ import { List } from "../../../fields/List"; import { RichTextField } from "../../../fields/RichTextField"; import { listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, StrCast } from "../../../fields/Types"; +import { Cast, StrCast, NumCast } from "../../../fields/Types"; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; @@ -79,7 +79,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc * @returns the relevant doc according to the value of FilterBox._filterScope i.e. either the Current Dashboard or the Current Collection */ @computed static get targetDoc() { - return SelectionManager.Views().length ? SelectionManager.Views()[0].Document : CurrentUserUtils.ActiveDashboard; + return SelectionManager.Docs().length ? SelectionManager.Docs()[0] : CurrentUserUtils.ActiveDashboard; } @computed static get targetDocChildKey() { if (SelectionManager.Views().length) { @@ -88,10 +88,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc return "data"; } @computed static get targetDocChildren() { - if (SelectionManager.Views().length) { - return DocListCast(FilterBox.targetDoc[FilterBox.targetDocChildKey]); - } - return DocListCast(CurrentUserUtils.ActiveDashboard.data); + return DocListCast(FilterBox.targetDoc?.[FilterBox.targetDocChildKey] || CurrentUserUtils.ActiveDashboard.data); } @observable _loaded = false; @@ -347,7 +344,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc ); } setTreeHeight = (hgt: number) => { - this.layoutDoc._height = hgt + 140; // 50? need to add all the border sizes together. + this.layoutDoc._height = NumCast(this.layoutDoc._autoHeightMargins) + 150; // need to add all the border sizes together. } /** diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 8f9959693..1e0172d24 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -3,7 +3,6 @@ import { action, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; -import { Id } from "../../../fields/FieldSymbols"; import { makeInterface } from "../../../fields/Schema"; import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { TraceMobx } from "../../../fields/util"; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3a399bfdb..9706d73c7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -3,13 +3,13 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Doc, Opt, WidthSym, DocListCast } from "../../../fields/Doc"; +import { Doc, DocListCast, Opt, WidthSym } from "../../../fields/Doc"; import { documentSchema } from '../../../fields/documentSchemas'; import { makeInterface } from "../../../fields/Schema"; -import { Cast, NumCast, StrCast, BoolCast } from '../../../fields/Types'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { PdfField } from "../../../fields/URLField"; import { TraceMobx } from '../../../fields/util'; -import { Utils, setupMoveUpEvents, emptyFunction, returnOne } from '../../../Utils'; +import { emptyFunction, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { KeyCodes } from '../../util/KeyCodes'; import { undoBatch } from '../../util/UndoManager'; @@ -17,14 +17,14 @@ import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeF import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; +import { Colors } from '../global/globalEnums'; +import { AnchorMenu } from '../pdf/AnchorMenu'; import { PDFViewer } from "../pdf/PDFViewer"; import { SidebarAnnos } from '../SidebarAnnos'; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); -import { AnchorMenu } from '../pdf/AnchorMenu'; -import { Colors } from '../global/globalEnums'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); @@ -79,9 +79,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const anchor = AnchorMenu.Instance?.GetAnchor() ?? Docs.Create.TextanchorDocument({ - title: StrCast(this.rootDoc.title + " " + this.layoutDoc._scrollTop), - annotationOn: this.rootDoc, + title: StrCast(this.rootDoc.title + "@" + this.layoutDoc._scrollTop?.toFixed(0)), y: NumCast(this.layoutDoc._scrollTop), + unrendered: true }); this.addDocument(anchor); return anchor; @@ -210,13 +210,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps {this._pageControls ? pageBtns : (null)} </div> <div className="pdfBox-sidebarBtn" key="sidebar" title="Toggle Sidebar" - style={{ - display: !this.props.isContentActive() ? "none" : undefined, + style={{ + display: !this.props.isContentActive() ? "none" : undefined, top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5, backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK }} onPointerDown={this.sidebarBtnDown} > - <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> + <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> </div> </div>; } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 1f85219d6..7e46d8433 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as WebRequest from 'web-request'; import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; @@ -24,6 +24,7 @@ import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from "../DocComponent"; import { DocumentDecorations } from "../DocumentDecorations"; +import { Colors } from "../global/globalEnums"; import { LightboxView } from "../LightboxView"; import { MarqueeAnnotator } from "../MarqueeAnnotator"; import { AnchorMenu } from "../pdf/AnchorMenu"; @@ -33,7 +34,6 @@ import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from "./LinkDocPreview"; import "./WebBox.scss"; import React = require("react"); -import { Colors } from "../global/globalEnums"; const _global = (window /* browser */ || global /* node */) as any; const htmlToText = require("html-to-text"); @@ -187,8 +187,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps AnchorMenu.Instance?.GetAnchor(this._savedAnnotations) ?? Docs.Create.WebanchorDocument(this._url, { title: StrCast(this.rootDoc.title + " " + this.layoutDoc._scrollTop), - annotationOn: this.rootDoc, - y: NumCast(this.layoutDoc._scrollTop) + y: NumCast(this.layoutDoc._scrollTop), + unrendered: true }); this.addDocumentWrapper(anchor); return anchor; @@ -592,13 +592,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps removeDocument={this.removeDocument} /> <div className="webBox-overlayButton-sidebar" key="sidebar" title="Toggle Sidebar" - style={{ - display: !this.props.isContentActive() ? "none" : undefined, + style={{ + display: !this.props.isContentActive() ? "none" : undefined, top: StrCast(this.rootDoc._showTitle) === "title" ? 20 : 5, backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK }} onPointerDown={this.sidebarBtnDown} > - <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> + <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={"comment-alt"} size="sm" /> </div> </div>); } diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index b72f31ef8..df7c54f67 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -15,7 +15,7 @@ import { DocumentType } from '../../../documents/DocumentTypes'; import { Scripting } from "../../../util/Scripting"; import { SelectionManager } from '../../../util/SelectionManager'; import { ColorScheme } from '../../../util/SettingsManager'; -import { UndoManager } from '../../../util/UndoManager'; +import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { CollectionViewType } from '../../collections/CollectionView'; import { ContextMenu } from '../../ContextMenu'; import { DocComponent } from '../../DocComponent'; @@ -31,6 +31,7 @@ import { ToggleButton } from './toggleButton'; import { IButtonProps } from './ButtonInterface'; import { FontIconBadge } from './FontIconBadge'; import './FontIconBox.scss'; +import { undo } from 'prosemirror-history'; const FontIconSchema = createSchema({ icon: "string", }); @@ -247,14 +248,15 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon let noneSelected: boolean = false; if (script === 'setView') { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; - if (selected && StrCast(selected.Document.type) === DocumentType.COL) { - text = StrCast(selected.Document._viewType); - } else if (selected) { - dropdown = false; - text = StrCast(selected.Document.type); - if (text === DocumentType.RTF) text = "Text"; - icon = Doc.toIcon(selected.Document); + const selected = SelectionManager.Docs().lastElement(); + if (selected) { + if (StrCast(selected.type) === DocumentType.COL) { + text = StrCast(selected._viewType); + } else { + dropdown = false; + text = selected.type === DocumentType.RTF ? "Text" : StrCast(selected.type); + icon = Doc.toIcon(selected); + } } else { dropdown = false; icon = "globe-asia"; @@ -262,13 +264,8 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon } noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Stacking]; } else if (script === 'setFont') { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; - if (selected && StrCast(selected.Document.type) === DocumentType.RTF) { - text = StrCast(selected.Document._fontFamily); - } else { - const fontFamily = StrCast(Doc.UserDoc()._fontFamily); - text = fontFamily; - } + const selected = SelectionManager.Docs().lastElement(); + text = StrCast((selected?.type === DocumentType.RTF ? selected : Doc.UserDoc())._fontFamily); noviceList = ["Roboto", "Times New Roman", "Arial", "Georgia", "Comic Sans MS", "Tahoma", "Impact", "Crimson Text"]; } @@ -303,7 +300,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon <div className={`menuButton ${this.type} ${active}`} style={{ backgroundColor: this.rootDoc.dropDownOpen ? Colors.MEDIUM_BLUE : backgroundColor, color: color, display: dropdown ? undefined : "flex" }} onClick={dropdown ? () => this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen : undefined}> - {dropdown || noneSelected ? (null) : <FontAwesomeIcon style={{marginLeft: 5}} className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />} + {dropdown || noneSelected ? (null) : <FontAwesomeIcon style={{ marginLeft: 5 }} className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />} <div className="menuButton-dropdown-header"> {text && text[0].toUpperCase() + text.slice(1)} </div> @@ -348,7 +345,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon const colorOptions: string[] = ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', - '#FFFFFF', '#f1efeb']; + '#FFFFFF', '#f1efeb', "transparent"]; const colorBox = (func: (color: ColorState) => void) => <SketchPicker disableAlpha={!stroke} @@ -369,7 +366,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon const hex: string = value.hex; const s = ScriptField.MakeScript(script + '("' + hex + '", false)'); if (s) { - s.script.run().result; + undoBatch(() => s.script.run().result)(); } }; return ( @@ -493,7 +490,7 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon {this.label} </div>; - const buttonProps:IButtonProps = { + const buttonProps: IButtonProps = { type: this.type, rootDoc: this.rootDoc, label: label, @@ -512,9 +509,9 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon button = ( <div className={`menuButton ${this.type}`} style={{ color: color, backgroundColor: backgroundColor, opacity: 1, gridAutoColumns: `${NumCast(this.rootDoc._height)} auto` }}> <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> - {buttonText ? + {buttonText ? <div className="button-text"> - {buttonText} + {buttonText} </div> : null} {label} @@ -583,13 +580,13 @@ export class FontIconBox extends DocComponent<ButtonProps, FontIconDocument>(Fon // toggle: Set overlay status of selected document Scripting.addGlobal(function setView(view: string) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; - selected ? selected.Document._viewType = view : console.log("[FontIconBox.tsx] changeView failed"); + const selected = SelectionManager.Docs().lastElement(); + selected ? selected._viewType = view : console.log("[FontIconBox.tsx] changeView failed"); }); // toggle: Set overlay status of selected document Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: boolean) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; + const selected = SelectionManager.Docs().lastElement(); if (checkResult) { if (selected) { console.log("[Background] (selected): " + StrCast(selected._backgroundColor)); @@ -598,12 +595,19 @@ Scripting.addGlobal(function setBackgroundColor(color?: string, checkResult?: bo return "#FFFFFF"; } } - if (selected && selected.type === DocumentType.INK) selected.fillColor = color; + if (selected?.type === DocumentType.INK) selected.fillColor = color; if (selected) selected._backgroundColor = color; Doc.UserDoc()._fontColor = color; }); // toggle: Set overlay status of selected document +Scripting.addGlobal(function setHeaderColor(color?: string, checkResult?: boolean) { + Doc.SharingDoc().userColor = undefined; + Doc.GetProto(Doc.SharingDoc()).userColor = color; + Doc.UserDoc().showTitle = color === "transparent" ? undefined : StrCast(Doc.UserDoc().showTitle, "creationDate"); +}); + +// toggle: Set overlay status of selected document Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) { const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; if (checkResult && selected) { @@ -627,7 +631,7 @@ Scripting.addGlobal(function toggleOverlay(checkResult?: boolean) { // toggle: Set overlay status of selected document Scripting.addGlobal(function setFont(font: string, checkResult?: boolean) { - SelectionManager.Views().map(dv => dv.props.Document._fontFamily = font); + SelectionManager.Docs().map(doc => doc._fontFamily = font); const editorView = RichTextMenu.Instance.TextView?.EditorView; editorView?.state && RichTextMenu.Instance.setFontFamily(font, editorView); Doc.UserDoc()._fontFamily = font; @@ -657,7 +661,7 @@ Scripting.addGlobal(function setAlignment(align: "left" | "right" | "center", ch if (active === align) return Colors.MEDIUM_BLUE; else return "transparent"; } - SelectionManager.Views().map(dv => dv.props.Document.textAlign = align); + SelectionManager.Docs().map(doc => doc.textAlign = align); switch (align) { case "left": editorView?.state && RichTextMenu.Instance.alignLeft(editorView, editorView.dispatch); @@ -695,13 +699,13 @@ Scripting.addGlobal(function setBulletList(mapStyle: "bullet" | "decimal", check // toggle: Set overlay status of selected document Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; + const selected = SelectionManager.Docs().lastElement(); const editorView = RichTextMenu.Instance.TextView?.EditorView; if (checkResult) { if (selected) { - console.log("[Font color] (selected): " + StrCast(selected.rootDoc._fontColor)); - return selected.rootDoc._fontColor; + console.log("[Font color] (selected): " + StrCast(selected._fontColor)); + return selected._fontColor; } else { console.log("[Font color] (global): " + StrCast(Doc.UserDoc()._fontColor)); return Doc.UserDoc()._fontColor; @@ -709,7 +713,7 @@ Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean) } if (selected) { - selected.rootDoc._fontColor = color; + selected._fontColor = color; if (color) { editorView?.state && RichTextMenu.Instance.setColor(color, editorView, editorView?.dispatch); } @@ -719,18 +723,18 @@ Scripting.addGlobal(function setFontColor(color?: string, checkResult?: boolean) // toggle: Set overlay status of selected document Scripting.addGlobal(function setFontHighlight(color?: string, checkResult?: boolean) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; + const selected = SelectionManager.Docs().lastElement(); const editorView = RichTextMenu.Instance.TextView?.EditorView; if (checkResult) { if (selected) { - return selected.Document._fontHighlight; + return selected._fontHighlight; } else { return Doc.UserDoc()._fontHighlight; } } if (selected) { - selected.rootDoc._fontColor = color; + selected._fontColor = color; if (color) { editorView?.state && RichTextMenu.Instance.setHighlight(color, editorView, editorView?.dispatch); } @@ -761,7 +765,7 @@ Scripting.addGlobal(function toggleBold(checkResult?: boolean) { console.log("editorView"); editorView?.state && RichTextMenu.Instance.toggleBold(editorView, true); } - SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.bold = !dv.props.Document.bold); + SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.bold = !doc.bold); Doc.UserDoc().bold = !Doc.UserDoc().bold; return Doc.UserDoc().bold; }); @@ -776,7 +780,7 @@ Scripting.addGlobal(function toggleUnderline(checkResult?: boolean) { console.log("editorView"); editorView?.state && RichTextMenu.Instance.toggleUnderline(editorView, true); } - SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.underline = !dv.props.Document.underline); + SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.underline = !doc.underline); Doc.UserDoc().underline = !Doc.UserDoc().underline; return Doc.UserDoc().underline; }); @@ -791,7 +795,7 @@ Scripting.addGlobal(function toggleItalic(checkResult?: boolean) { console.log("editorView"); editorView?.state && RichTextMenu.Instance.toggleItalic(editorView, true); } - SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.RTF).map(dv => dv.props.Document.italic = !dv.props.Document.italic); + SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.RTF).map(doc => doc.italic = !doc.italic); Doc.UserDoc().italic = !Doc.UserDoc().italic; return Doc.UserDoc().italic; }); @@ -833,7 +837,7 @@ Scripting.addGlobal(function setActiveInkTool(tool: string, checkResult?: boolea Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean) { if (checkResult) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; + const selected = SelectionManager.Docs().lastElement(); if (selected && selected.type === DocumentType.INK) { return Number(selected.strokeWidth); } else { @@ -842,13 +846,13 @@ Scripting.addGlobal(function setStrokeWidth(width: number, checkResult?: boolean } } Doc.UserDoc().activeInkWidth = width; - SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.strokeWidth = Number(width)); + SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.INK).map(doc => doc.strokeWidth = Number(width)); }); // toggle: Set overlay status of selected document Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolean) { if (checkResult) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; + const selected = SelectionManager.Docs().lastElement(); if (selected && selected.type === DocumentType.INK) { return selected.color; } else { @@ -857,7 +861,7 @@ Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolea } } SetActiveInkColor(StrCast(color)); - SelectionManager.Views().filter(i => StrCast(i.rootDoc.type) === DocumentType.INK).map(i => i.rootDoc.color = String(color)); + SelectionManager.Docs().filter(doc => StrCast(doc.type) === DocumentType.INK).map(doc => doc.color = String(color)); }); @@ -865,7 +869,7 @@ Scripting.addGlobal(function setStrokeColor(color?: string, checkResult?: boolea * webSetURL **/ Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; + const selected = SelectionManager.Docs().lastElement(); console.log("URL: ", url); if (checkResult && selected && selected.type === DocumentType.WEB) { return Cast(selected.data, WebField, null).url; @@ -880,7 +884,7 @@ Scripting.addGlobal(function webSetURL(url: string, checkResult?: boolean) { * toggleSchemaPreview **/ Scripting.addGlobal(function toggleSchemaPreview(checkResult?: boolean) { - const selected = SelectionManager.Views().length ? SelectionManager.Views()[0].rootDoc : undefined; + const selected = SelectionManager.Docs().lastElement(); console.log(selected && selected.title); if (checkResult && selected) { const result: boolean = NumCast(selected.schemaPreviewWidth) > 0; diff --git a/src/client/views/nodes/button/textButton/TextButton.tsx b/src/client/views/nodes/button/textButton/TextButton.tsx index 414b50dcb..e18590a95 100644 --- a/src/client/views/nodes/button/textButton/TextButton.tsx +++ b/src/client/views/nodes/button/textButton/TextButton.tsx @@ -12,6 +12,6 @@ export class TextButton extends Component<IButtonProps> { return (<div className={`menuButton ${this.props.type}`} style={{ opacity: 1, backgroundColor: this.props.backgroundColor, color: this.props.color }}> <FontAwesomeIcon className={`fontIconBox-icon-${this.props.type}`} icon={this.props.icon} color={this.props.color} /> {this.props.label} - </div>) + </div>); } }
\ No newline at end of file diff --git a/src/client/views/nodes/button/textButton/index.ts b/src/client/views/nodes/button/textButton/index.ts index 01fcde54f..01d62eb7e 100644 --- a/src/client/views/nodes/button/textButton/index.ts +++ b/src/client/views/nodes/button/textButton/index.ts @@ -1 +1 @@ -export * from './TextButton'
\ No newline at end of file +export * from './TextButton';
\ No newline at end of file diff --git a/src/client/views/nodes/button/toggleButton/index.ts b/src/client/views/nodes/button/toggleButton/index.ts index 48b28fb4c..cdb9c527c 100644 --- a/src/client/views/nodes/button/toggleButton/index.ts +++ b/src/client/views/nodes/button/toggleButton/index.ts @@ -1 +1 @@ -export * from './ToggleButton'
\ No newline at end of file +export * from './ToggleButton';
\ No newline at end of file diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 62f65cdae..34908e54b 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -82,7 +82,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna // set the display of the field's value (checkbox for booleans, span of text for strings) @computed get fieldValueContent() { if (this._dashDoc) { - const dashVal = this._dashDoc[DataSym][this._fieldKey] ?? this._dashDoc[this._fieldKey] ?? (this._fieldKey === "PARAMS" ? this._textBoxDoc[this._fieldKey] : ""); + const dashVal = this._dashDoc[this._fieldKey] ?? this._dashDoc[DataSym][this._fieldKey] ?? (this._fieldKey === "PARAMS" ? this._textBoxDoc[this._fieldKey] : ""); const fval = dashVal instanceof List ? dashVal.join(this.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(this._textBoxDoc)[this._fieldKey] : dashVal; const boolVal = Cast(fval, "boolean", null); const strVal = Field.toString(fval as Field) || ""; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss index 56f5c5631..4134e3c67 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.scss +++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss @@ -66,11 +66,12 @@ audiotag:hover { .formattedTextBox-sidebar-handle { position: absolute; - top: 5px; + top: 0; + left: 17px; //top: calc(50% - 17.5px); // use this to center vertically -- make sure it looks okay for slide views - width: 25px; - height: 100%; - max-height: 25px; + width: 17px; + height: 17px; + border-radius: 3px; color: white; background: $medium-gray; border-radius: 5px; @@ -80,8 +81,9 @@ audiotag:hover { cursor:grabbing; box-shadow: $standard-box-shadow; // transition: 0.2s; - + opacity: 0.3; &:hover{ + opacity: 1 !important; filter: brightness(0.85); } @@ -425,12 +427,7 @@ footnote::after { .formattedTextBox-sidebar-handle { position: absolute; - top: 0; - //top: calc(50% - 17.5px); // use this to center vertically -- make sure it looks okay for slide views - width: 10px; - 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 59d43f8d7..78de1fd89 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { isEqual } from "lodash"; -import { action, computed, IReactionDisposer, reaction, runInAction, observable } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { baseKeymap, selectAll } from "prosemirror-commands"; import { history } from "prosemirror-history"; @@ -432,6 +432,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } protected createDropTarget = (ele: HTMLDivElement) => { this.ProseRef = ele; + this.setupEditor(this.config, this.props.fieldKey); this._dropDisposer?.(); ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc)); // if (this.autoHeight) this.tryUpdateScrollHeight(); @@ -573,12 +574,25 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const cm = ContextMenu.Instance; const changeItems: ContextMenuProps[] = []; - changeItems.push({ description: "plain", event: undoBatch(() => Doc.setNativeView(this.rootDoc)), icon: "eye" }); + changeItems.push({ + description: "plain", event: undoBatch(() => { + Doc.setNativeView(this.rootDoc); + this.layoutDoc.autoHeightMargins = undefined; + }), icon: "eye" + }); + changeItems.push({ + description: "metadata", event: undoBatch(() => { + this.dataDoc.layout_meta = Cast(Doc.UserDoc().emptyHeader, Doc, null)?.layout; + this.rootDoc.layoutKey = "layout_meta"; + setTimeout(() => this.rootDoc._headerHeight = this.rootDoc._autoHeightMargins = 50, 50); + }), icon: "eye" + }); const noteTypesDoc = Cast(Doc.UserDoc()["template-notes"], Doc, null); DocListCast(noteTypesDoc?.data).forEach(note => { const icon: IconProp = StrCast(note.icon) as IconProp; changeItems.push({ description: StrCast(note.title), event: undoBatch(() => { + this.layoutDoc.autoHeightMargins = undefined; Doc.setNativeView(this.rootDoc); DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.TreeDocument, StrCast(note.title), note); }), icon: icon @@ -713,7 +727,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const splitter = state.schema.marks.splitter.create({ id: Utils.GenerateGuid() }); let tr = state.tr.addMark(sel.from, sel.to, splitter); if (sel.from !== sel.to) { - const anchor = anchorDoc ?? Docs.Create.TextanchorDocument({ title: this._editorView?.state.doc.textBetween(sel.from, sel.to) }); + const anchor = anchorDoc ?? Docs.Create.TextanchorDocument({ title: this._editorView?.state.doc.textBetween(sel.from, sel.to), unrendered: true }); const href = targetHref ?? Doc.localServerPath(anchor); if (anchor !== anchorDoc) this.addDocument(anchor); tr.doc.nodesBetween(sel.from, sel.to, (node: any, pos: number, parent: any) => { @@ -864,8 +878,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } ); - this.setupEditor(this.config, this.props.fieldKey); - this._disposers.search = reaction(() => Doc.IsSearchMatch(this.rootDoc), search => search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms(), { fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false }); @@ -1144,8 +1156,8 @@ 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!.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) })]; + 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) })]; } } @@ -1360,6 +1372,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp this._undoTyping = undefined; return wasUndoing; } + @action onBlur = (e: any) => { FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined); @@ -1448,18 +1461,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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) { - var proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins); - var scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight); + 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(); - // setTimeout(() => { - // proseHeight = !this.ProseRef ? 0 : children.reduce((p, child) => p + Number(getComputedStyle(child).height.replace("px", "")), margins); - // scrollHeight = this.ProseRef && Math.min(NumCast(this.layoutDoc.docMaxAutoHeight, proseHeight), proseHeight); - // scrollHeight && setScrollHeight(); - // }, 10); - } 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... + } 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... + } } } } @@ -1486,14 +1496,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const annotated = DocListCast(this.dataDoc[this.SidebarKey]).filter(d => d?.author).length; const color = !annotated ? Colors.WHITE : Colors.BLACK; const backgroundColor = !annotated ? this.sidebarWidth() ? Colors.MEDIUM_BLUE : Colors.BLACK : this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.WidgetColor + (annotated ? ":annotated" : "")); - return (!annotated && !this.props.isContentActive()) ? (null) : <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} - style={{ - left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${"- 30px"}))`, - backgroundColor: backgroundColor, - color: color - }} > - <FontAwesomeIcon icon={"comment-alt"} /> - </div>; + return (!annotated && (!this.props.isContentActive() || SnappingManager.GetIsDragging())) ? (null) : + <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} + style={{ + left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 17px))`, + backgroundColor: backgroundColor, + color: color, + opacity: annotated ? 1 : undefined + }} > + <FontAwesomeIcon icon={"comment-alt"} /> + </div>; } @computed get sidebarCollection() { const renderComponent = (tag: string) => { @@ -1555,7 +1567,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp const selPad = Math.min(margins, 10); const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0); const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : ""; - return ( + const styleFromString = this.styleFromLayoutString(scale); // this converts any expressions in the format string to style props. e.g., <FormattedTextBox height='{this._headerHeight}px' > + return (styleFromString?.height === "0px" ? (null) : <div className="formattedTextBox-cont" onWheel={e => this.props.isContentActive() && e.stopPropagation()} style={{ @@ -1564,7 +1577,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp width: this.props.dontScale ? undefined : `${100 / scale}%`, height: this.props.dontScale ? undefined : `${100 / scale}%`, // 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' > + ...styleFromString }}> <div className={`formattedTextBox-cont`} ref={this._ref} style={{ diff --git a/src/client/views/nodes/formattedText/RichTextMenu.scss b/src/client/views/nodes/formattedText/RichTextMenu.scss index c94e93541..8afa0f6b5 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.scss +++ b/src/client/views/nodes/formattedText/RichTextMenu.scss @@ -2,6 +2,7 @@ .button-dropdown-wrapper { position: relative; + display: flex; .dropdown-button { width: 15px; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 3d9d9543d..3919fbf94 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -279,33 +279,33 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { }); } - toggleBold = (view: EditorView, forceBool?:boolean) => { - const mark = view.state.schema.mark(view.state.schema.marks.strong, {strong: forceBool}); + 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(); } - toggleUnderline = (view: EditorView, forceBool?:boolean) => { - const mark = view.state.schema.mark(view.state.schema.marks.underline, {underline: forceBool}); + 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(); } - toggleItalic = (view: EditorView, forceBool?:boolean) => { - const mark = view.state.schema.mark(view.state.schema.marks.em, {em: forceBool}); + 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(); } - setFontSize = (size:number, view: EditorView) => { + 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); } - setFontFamily = (family:string, view: EditorView) => { + 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(); @@ -516,7 +516,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { get TextView() { return (this.view as any)?.TextView as FormattedTextBox; } get TextViewFieldKey() { return this.TextView?.props.fieldKey; } - + @action setActiveHighlight(color: string) { this.activeHighlightColor = color; } @@ -566,7 +566,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { if (linkDoc instanceof Doc) { const anchor1 = await Cast(linkDoc.anchor1, Doc); const anchor2 = await Cast(linkDoc.anchor2, Doc); - const currentDoc = SelectionManager.Views().length && SelectionManager.Views()[0].props.Document; + const currentDoc = SelectionManager.Docs().lastElement(); if (currentDoc && anchor1 && anchor2) { if (Doc.AreProtosEqual(currentDoc, anchor1)) { return StrCast(anchor2.title); |
