diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 15 | ||||
-rw-r--r-- | src/client/util/Scripting.ts | 8 | ||||
-rw-r--r-- | src/client/views/DocComponent.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 20 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/DashFieldView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 31 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.scss | 1 | ||||
-rw-r--r-- | src/client/views/pdf/AnchorMenu.scss | 29 | ||||
-rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 13 |
10 files changed, 86 insertions, 38 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index eb9184e88..816503b37 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -22,6 +22,7 @@ import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMu import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; +import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; import { LabelBox } from "../views/nodes/LabelBox"; import { OverlayView } from "../views/OverlayView"; @@ -37,8 +38,6 @@ import { ColorScheme } from "./SettingsManager"; import { SharingManager } from "./SharingManager"; import { SnappingManager } from "./SnappingManager"; import { UndoManager } from "./UndoManager"; -import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; -import { IconName } from "@fortawesome/fontawesome-svg-core"; interface Button { title?: string; @@ -447,16 +446,16 @@ export class CurrentUserUtils { storedMarks: [] }; const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { - title: "text", version: headerViewVersion, target: doc, _height: 70, _headerPointerEvents: "all", + title: "text", version: headerViewVersion, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, _fitWidth: true, cloneFieldFilter: new List<string>(["system"]) }, "header"); const headerBtnHgt = 10; headerTemplate[DataSym].layout = "<HTMLdiv transformOrigin='top left' width='{100/scale}%' height='{100/scale}%' transform='scale({scale})'>" + - ` <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._headerHeight}px)'/>` + - " <FormattedTextBox {...props} dontScale='true' fieldKey={'header'} dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._headerFontSize}px' height='{(this._headerHeight||1)}px' background='{this._headerColor ||this.target.mySharedDocs.userColor||`lightGray`}' />" + - ` <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' background='yellow' onClick={‘(this._headerHeight=scale*Math.min(Math.max(1,this._height-30),this._headerHeight===1?50:1)) && (this._autoHeightMargins=this._headerHeight+${headerBtnHgt})’} >Metadata</HTMLdiv>` + + ` <FormattedTextBox {...props} dontScale='true' fieldKey={'text'} height='calc(100% - ${headerBtnHgt}px - {this._headerHeight||0}px)'/>` + + " <FormattedTextBox {...props} dontScale='true' fieldKey={'header'} dontSelectOnLoad='true' ignoreAutoHeight='true' fontSize='{this._headerFontSize||9}px' height='{(this._headerHeight||0)}px' background='{this._headerColor || MySharedDocs().userColor||`lightGray`}' />" + + ` <HTMLdiv fontSize='${headerBtnHgt - 1}px' height='${headerBtnHgt}px' background='yellow' onClick={‘(this._headerHeight=scale*Math.min(Math.max(0,this._height-30),this._headerHeight===0?50:0)) && (this._autoHeightMargins=this._headerHeight+${headerBtnHgt})’} >Metadata</HTMLdiv>` + "</HTMLdiv>"; // "<div style={'height:100%'}>" + @@ -562,7 +561,7 @@ export class CurrentUserUtils { if (dragCreatorSet === undefined) { doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true, _chromeHidden: true, - _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, + _autoHeight: true, _width: 500, _height: 300, _fitWidth: true, _columnWidth: 40, ignoreClick: true, _lockedPosition: true, _forceActive: true, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true })); } else { @@ -1554,6 +1553,8 @@ Scripting.addGlobal(function openDragFactory(dragFactory: Doc) { view && SelectionManager.SelectView(view, false); } }); +Scripting.addGlobal(function MySharedDocs() { return Doc.SharingDoc(); }, + "document containing all shared Docs"); Scripting.addGlobal(function IsNoviceMode() { return Doc.UserDoc().noviceMode; }, "is Dash in novice mode"); Scripting.addGlobal(function snapshotDashboard() { CurrentUserUtils.snapshotDashboard(Doc.UserDoc()); }, diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index efee37419..40b94024e 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -171,7 +171,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an if (!options.editable) { batch = Doc.MakeReadOnly(); } - + const result = compiledFunction.apply(thisParam, params).apply(thisParam, argsArray); if (batch) { batch.end(); @@ -316,9 +316,9 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp paramList.push(`${key}: ${typeof val === "object" ? Object.getPrototypeOf(val).constructor.name : typeof val}`); } const paramString = paramList.join(", "); - const funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} { - ${addReturn ? `return ${script};` : `return ${script};`} - })`; + const body = addReturn ? `return ${script};` : `return ${script};`; + const reqTypes = requiredType ? `: ${requiredType}` : ''; + const funcScript = `(function(${paramString})${reqTypes} { ${body} })`; host.writeFile("file.ts", funcScript); if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 33dff9da5..cb36f4270 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -115,7 +115,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T const style: { [key: string]: any } = {}; const divKeys = ["width", "height", "fontSize", "transform", "left", "background", "left", "right", "top", "bottom", "pointerEvents", "position"]; const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a property expression string: { script } into a value - return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result as string || ""; + return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result?.toString() ?? ""; }; divKeys.map((prop: string) => { const p = (this.props as any)[prop]; 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 6eeb51ffe..6f97cdbd8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -712,7 +712,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps !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) { @@ -970,19 +970,19 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps display={"block"} fontSize={10} GetValue={() => showTitle.split(";").length === 1 ? showTitle + "=" + Field.toString(targetDoc[showTitle.split(";")[0]] as any as Field) : "#" + showTitle} - SetValue={undoBatch(value => { - if (value?.startsWith(showTitle + "=")) { - value = value.substring((showTitle + "=").length); - 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; - } else if (value?.startsWith("#")) { + SetValue={undoBatch(input => { + if (input?.startsWith("#")) { if (this.props.showTitle) { - this.rootDoc._showTitle = value?.substring(1) ? value.substring(1) : undefined; + this.rootDoc._showTitle = input?.substring(1) ? input.substring(1) : undefined; } else { - Doc.UserDoc().showTitle = value?.substring(1) ? value.substring(1) : "creationDate"; + 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; })} 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.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index fbb291858..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 @@ -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) })]; } } @@ -1487,7 +1499,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp 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"}))`, + left: `max(0px, calc(100% - ${this.sidebarWidthPercent} - 17px))`, backgroundColor: backgroundColor, color: color, opacity: annotated ? 1 : undefined @@ -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/pdf/AnchorMenu.scss b/src/client/views/pdf/AnchorMenu.scss index b7afb26a5..6990bdcf1 100644 --- a/src/client/views/pdf/AnchorMenu.scss +++ b/src/client/views/pdf/AnchorMenu.scss @@ -4,6 +4,35 @@ padding: 5px; grid-template-columns: 90px 20px 90px; } +.anchorMenu-highlighter { + padding-right: 5px; + .antimodeMenu-button { + padding: 0; + padding: 0; + padding-right: 0px; + padding-left: 0px; + width: 5px; + } +} +.anchor-color-preview-button { + width: 25px !important; + .anchor-color-preview { + display: flex; + flex-direction: column; + padding-right: 3px; + width: unset !important; + .color-preview { + width: 60%; + top: 80%; + height: 4px; + position: relative; + top: unset; + width: 15px; + margin-top: 5px; + display: block; + } + } +} .color-wrapper { display: flex; diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index 3bf1f0828..3ba427c29 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -41,7 +41,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { @observable private highlightColor: string = "rgba(245, 230, 95, 0.616)"; @observable private _showLinkPopup: boolean = false; - @observable public _colorBtn = false; @observable public Highlighting: boolean = false; @observable public Status: "marquee" | "annotation" | "" = ""; @@ -97,9 +96,11 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { @computed get highlighter() { const button = - <button className="antimodeMenu-button color-preview-button" title="" key="highlighter-button" onClick={this.highlightClicked}> - <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} /> - <div className="color-preview" style={{ backgroundColor: this.highlightColor }}></div> + <button className="antimodeMenu-button anchor-color-preview-button" title="" key="highlighter-button" onClick={this.highlightClicked}> + <div className="anchor-color-preview" > + <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} /> + <div className="color-preview" style={{ backgroundColor: this.highlightColor }}></div> + </div> </button>; const dropdownContent = @@ -117,7 +118,9 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { </div>; return ( <Tooltip key="highlighter" title={<div className="dash-tooltip">{"Click to Highlight"}</div>}> - <ButtonDropdown key={"highlighter"} button={button} dropdownContent={dropdownContent} pdf={true} /> + <div className="anchorMenu-highlighter"> + <ButtonDropdown key={"highlighter"} button={button} dropdownContent={dropdownContent} pdf={true} /> + </div> </Tooltip> ); } |